版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/su749520/article/details/84303579
1. UsageStatsService 的功能介绍
- frameworks/base/services/usage/java/com/android/server/usage/UsageStatsService.java
2. SystemServer 启动 UsageStatsService
- frameworks/base/services/java/com/android/server/SystemServer.java
package com.android.server;
public final class SystemServer {
/**
* Starts some essential services that are not tangled up in the bootstrap process.
*/
private void startCoreServices() {
// 启动 USS 服务
// Tracks application usage stats.
traceBeginAndSlog("StartUsageService");
mSystemServiceManager.startService(UsageStatsService.class);
mActivityManagerService.setUsageStatsManager(
LocalServices.getService(UsageStatsManagerInternal.class));
traceEnd();
3. 启动 UsageStatsService
- frameworks/base/services/usage/java/com/android/server/usage/UsageStatsService.java
package com.android.server.usage;
/**
* A service that collects, aggregates, and persists application usage data.
* This data can be queried by apps that have been granted permission by AppOps.
*/
public class UsageStatsService extends SystemService implements
UserUsageStatsService.StatsUpdatedListener {
3.1 UsageStatsService.onStart()
初始化参数新信息
@Override
public void onStart() {
// 权限管理服务
mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
// 访客模式服务或者多用户服务
mUserManager = (UserManager) getContext().getSystemService(Context.USER_SERVICE);
// 包管理服务
mPackageManager = getContext().getPackageManager();
// 包管理服务的内部使用
mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
mHandler = new H(BackgroundThread.get().getLooper());
// 文件存放的路径 data/system/usagestats
File systemDataDir = new File(Environment.getDataDirectory(), "system");
mUsageStatsDir = new File(systemDataDir, "usagestats");
mUsageStatsDir.mkdirs();
if (!mUsageStatsDir.exists()) {
throw new IllegalStateException("Usage stats directory does not exist: "
+ mUsageStatsDir.getAbsolutePath());
}
// 多用户被移除广播
IntentFilter filter = new IntentFilter(Intent.ACTION_USER_REMOVED);
filter.addAction(Intent.ACTION_USER_STARTED);
getContext().registerReceiverAsUser(new UserActionsReceiver(), UserHandle.ALL, filter,
null, mHandler);
// 应用安装、卸载、状态变化广播
IntentFilter packageFilter = new IntentFilter();
packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
packageFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
packageFilter.addDataScheme("package");
getContext().registerReceiverAsUser(new PackageReceiver(), UserHandle.ALL, packageFilter,
null, mHandler);
// 是否自启动开启省电模式
mAppIdleEnabled = getContext().getResources().getBoolean(
com.android.internal.R.bool.config_enableAutoPowerModes);
// 注册电池广播、拔除充电线、待机模式改变广播
if (mAppIdleEnabled) {
IntentFilter deviceStates = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
deviceStates.addAction(BatteryManager.ACTION_DISCHARGING);
deviceStates.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
getContext().registerReceiver(new DeviceStateReceiver(), deviceStates);
}
synchronized (mLock) {
cleanUpRemovedUsersLocked();
}
synchronized (mAppIdleLock) {
// 应用待机下历史数据
mAppIdleHistory = new AppIdleHistory(SystemClock.elapsedRealtime());
}
mRealTimeSnapshot = SystemClock.elapsedRealtime();
mSystemTimeSnapshot = System.currentTimeMillis();
// 初始化省电策略接口
mPowerControllerHelper = new PowerControllerHelper();
// 相当于 LocalServices.addService(LocalService())
publishLocalService(UsageStatsManagerInternal.class, new LocalService());
// 相当于 ServiceManager.addService(BinderService())
publishBinderService(Context.USAGE_STATS_SERVICE, new BinderService());
}
3.2 UsageStatsService.publishLocalService
//参数中的LocalService继承自PowerManagerInternal类
protected final <t> void publishLocalService(Class<t> type, T service) {
LocalServices.addService(type, service);
}
/**
* Adds a service instance of the specified interface to the global registry of local services.
*/
public static <t> void addService(Class<t> type, T service) {
synchronized (sLocalServiceObjects) {
if (sLocalServiceObjects.containsKey(type)) {
throw new IllegalStateException("Overriding service registration");
}
sLocalServiceObjects.put(type, service);
}
}
3.3 UsageStatsService.publishBinderService
//PMS中的BinderService继承自IPowerManager.Stub,实现了IBinder接口
//name为PMS的名称,power
protected final void publishBinderService(String name, IBinder service) {
publishBinderService(name, service, false);
}
protected final void publishBinderService(String name, IBinder service,
boolean allowIsolated) {
//调用ServiceManger的接口,实际上利用Binder通信向Service Manger进程注册服务
ServiceManager.addService(name, service, allowIsolated);
}
3.4 BinderService
private final class BinderService extends IUsageStatsManager.Stub {
private boolean hasPermission(String callingPackage) {
final int callingUid = Binder.getCallingUid();
// 系统 UIS 默认有权限
if (callingUid == Process.SYSTEM_UID) {
return true;
}
// 是否注册了使用用户数据OP_GET_USAGE_STATS的权限
final int mode = mAppOps.checkOp(AppOpsManager.OP_GET_USAGE_STATS,
callingUid, callingPackage);
if (mode == AppOpsManager.MODE_DEFAULT) {
// The default behavior here is to check if PackageManager has given the app
// permission.
return getContext().checkCallingPermission(Manifest.permission.PACKAGE_USAGE_STATS)
== PackageManager.PERMISSION_GRANTED;
}
return mode == AppOpsManager.MODE_ALLOWED;
}
// 上层调用的应用使用数据状态接口,传入类型:间隔类型、开始时间、结束时间、调用包名
@Override
public ParceledListSlice<UsageStats> queryUsageStats(int bucketType, long beginTime,
long endTime, String callingPackage) {
// 权限检查
if (!hasPermission(callingPackage)) {
return null;
}
final boolean obfuscateInstantApps = shouldObfuscateInstantAppsForCaller(
Binder.getCallingUid(), UserHandle.getCallingUserId());
final int userId = UserHandle.getCallingUserId();
final long token = Binder.clearCallingIdentity();
try {
final List<UsageStats> results = UsageStatsService.this.queryUsageStats(
userId, bucketType, beginTime, endTime, obfuscateInstantApps);
if (results != null) {
return new ParceledListSlice<>(results);
}
} finally {
Binder.restoreCallingIdentity(token);
}
return null;
}
@Override
public ParceledListSlice<ConfigurationStats> queryConfigurationStats(int bucketType,
long beginTime, long endTime, String callingPackage) throws RemoteException {
if (!hasPermission(callingPackage)) {
return null;
}
final int userId = UserHandle.getCallingUserId();
final long token = Binder.clearCallingIdentity();
try {
final List<ConfigurationStats> results =
UsageStatsService.this.queryConfigurationStats(userId, bucketType,
beginTime, endTime);
if (results != null) {
return new ParceledListSlice<>(results);
}
} finally {
Binder.restoreCallingIdentity(token);
}
return null;
}
// 上层调用的应用使用数据状态接口,传入类型:间隔类型、开始时间、结束时间、调用包名
@Override
public UsageEvents queryEvents(long beginTime, long endTime, String callingPackage) {
if (!hasPermission(callingPackage)) {
return null;
}
final boolean obfuscateInstantApps = shouldObfuscateInstantAppsForCaller(
Binder.getCallingUid(), UserHandle.getCallingUserId());
final int userId = UserHandle.getCallingUserId();
final long token = Binder.clearCallingIdentity();
try {
return UsageStatsService.this.queryEvents(userId, beginTime, endTime,
obfuscateInstantApps);
} finally {
Binder.restoreCallingIdentity(token);
}
}
// 是否应用为活动状态
@Override
public boolean isAppInactive(String packageName, int userId) {
try {
userId = ActivityManager.getService().handleIncomingUser(Binder.getCallingPid(),
Binder.getCallingUid(), userId, false, true, "isAppInactive", null);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
final boolean obfuscateInstantApps = shouldObfuscateInstantAppsForCaller(
Binder.getCallingUid(), userId);
final long token = Binder.clearCallingIdentity();
try {
return UsageStatsService.this.isAppIdleFilteredOrParoled(packageName, userId,
SystemClock.elapsedRealtime(), obfuscateInstantApps);
} finally {
Binder.restoreCallingIdentity(token);
}
}
@Override
public void setAppInactive(String packageName, boolean idle, int userId) {
final int callingUid = Binder.getCallingUid();
try {
userId = ActivityManager.getService().handleIncomingUser(
Binder.getCallingPid(), callingUid, userId, false, true,
"setAppInactive", null);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
getContext().enforceCallingPermission(Manifest.permission.CHANGE_APP_IDLE_STATE,
"No permission to change app idle state");
final long token = Binder.clearCallingIdentity();
try {
final int appId = getAppId(packageName);
if (appId < 0) return;
UsageStatsService.this.setAppIdleAsync(packageName, idle, userId);
} finally {
Binder.restoreCallingIdentity(token);
}
}
@Override
public void whitelistAppTemporarily(String packageName, long duration, int userId)
throws RemoteException {
StringBuilder reason = new StringBuilder(32);
reason.append("from:");
UserHandle.formatUid(reason, Binder.getCallingUid());
mDeviceIdleController.addPowerSaveTempWhitelistApp(packageName, duration, userId,
reason.toString());
}
@Override
public void onCarrierPrivilegedAppsChanged() {
if (DEBUG) {
Slog.i(TAG, "Carrier privileged apps changed");
}
getContext().enforceCallingOrSelfPermission(
android.Manifest.permission.BIND_CARRIER_SERVICES,
"onCarrierPrivilegedAppsChanged can only be called by privileged apps.");
UsageStatsService.this.clearCarrierPrivilegedApps();
}
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpAndUsageStatsPermission(getContext(), TAG, pw)) return;
UsageStatsService.this.dump(args, pw);
}
@Override
public void reportChooserSelection(String packageName, int userId, String contentType,
String[] annotations, String action) {
if (packageName == null) {
Slog.w(TAG, "Event report user selecting a null package");
return;
}
UsageEvents.Event event = new UsageEvents.Event();
event.mPackage = packageName;
// This will later be converted to system time.
event.mTimeStamp = SystemClock.elapsedRealtime();
event.mEventType = Event.CHOOSER_ACTION;
event.mAction = action;
event.mContentType = contentType;
event.mContentAnnotations = annotations;
mHandler.obtainMessage(MSG_REPORT_EVENT, userId, 0, event).sendToTarget();
}
}
3.5 LocalService
/**
* This local service implementation is primarily used by ActivityManagerService.
* ActivityManagerService will call these methods holding the 'am' lock, which means we
* shouldn't be doing any IO work or other long running tasks in these methods.
*/
private final class LocalService extends UsageStatsManagerInternal {
@Override
public void reportEvent(ComponentName component, int userId, int eventType) {
if (component == null) {
Slog.w(TAG, "Event reported without a component name");
return;
}
UsageEvents.Event event = new UsageEvents.Event();
event.mPackage = component.getPackageName();
event.mClass = component.getClassName();
// This will later be converted to system time.
event.mTimeStamp = SystemClock.elapsedRealtime();
event.mEventType = eventType;
mHandler.obtainMessage(MSG_REPORT_EVENT, userId, 0, event).sendToTarget();
}
@Override
public void reportEvent(String packageName, int userId, int eventType) {
if (packageName == null) {
Slog.w(TAG, "Event reported without a package name");
return;
}
UsageEvents.Event event = new UsageEvents.Event();
event.mPackage = packageName;
// This will later be converted to system time.
event.mTimeStamp = SystemClock.elapsedRealtime();
event.mEventType = eventType;
mHandler.obtainMessage(MSG_REPORT_EVENT, userId, 0, event).sendToTarget();
}
@Override
public void reportConfigurationChange(Configuration config, int userId) {
if (config == null) {
Slog.w(TAG, "Configuration event reported with a null config");
return;
}
UsageEvents.Event event = new UsageEvents.Event();
event.mPackage = "android";
// This will later be converted to system time.
event.mTimeStamp = SystemClock.elapsedRealtime();
event.mEventType = UsageEvents.Event.CONFIGURATION_CHANGE;
event.mConfiguration = new Configuration(config);
mHandler.obtainMessage(MSG_REPORT_EVENT, userId, 0, event).sendToTarget();
}
@Override
public void reportShortcutUsage(String packageName, String shortcutId, int userId) {
if (packageName == null || shortcutId == null) {
Slog.w(TAG, "Event reported without a package name or a shortcut ID");
return;
}
UsageEvents.Event event = new UsageEvents.Event();
event.mPackage = packageName.intern();
event.mShortcutId = shortcutId.intern();
// This will later be converted to system time.
event.mTimeStamp = SystemClock.elapsedRealtime();
event.mEventType = Event.SHORTCUT_INVOCATION;
mHandler.obtainMessage(MSG_REPORT_EVENT, userId, 0, event).sendToTarget();
}
@Override
public void reportContentProviderUsage(String name, String packageName, int userId) {
SomeArgs args = SomeArgs.obtain();
args.arg1 = name;
args.arg2 = packageName;
args.arg3 = userId;
mHandler.obtainMessage(MSG_REPORT_CONTENT_PROVIDER_USAGE, args)
.sendToTarget();
}
// 用户是否休眠
@Override
public boolean isAppIdle(String packageName, int uidForAppId, int userId) {
return UsageStatsService.this.isAppIdleFiltered(packageName, uidForAppId, userId,
SystemClock.elapsedRealtime());
}
@Override
public int[] getIdleUidsForUser(int userId) {
return UsageStatsService.this.getIdleUidsForUser(userId);
}
@Override
public boolean isAppIdleParoleOn() {
return isParoledOrCharging();
}
@Override
public void prepareShutdown() {
// This method *WILL* do IO work, but we must block until it is finished or else
// we might not shutdown cleanly. This is ok to do with the 'am' lock held, because
// we are shutting down.
shutdown();
}
@Override
public void addAppIdleStateChangeListener(AppIdleStateChangeListener listener) {
UsageStatsService.this.addListener(listener);
listener.onParoleStateChanged(isAppIdleParoleOn());
}
@Override
public void removeAppIdleStateChangeListener(
AppIdleStateChangeListener listener) {
UsageStatsService.this.removeListener(listener);
}
@Override
public byte[] getBackupPayload(int user, String key) {
// Check to ensure that only user 0's data is b/r for now
synchronized (UsageStatsService.this.mLock) {
if (user == UserHandle.USER_SYSTEM) {
final UserUsageStatsService userStats =
getUserDataAndInitializeIfNeededLocked(user, checkAndGetTimeLocked());
return userStats.getBackupPayload(key);
} else {
return null;
}
}
}
@Override
public void applyRestoredPayload(int user, String key, byte[] payload) {
synchronized (UsageStatsService.this.mLock) {
if (user == UserHandle.USER_SYSTEM) {
final UserUsageStatsService userStats =
getUserDataAndInitializeIfNeededLocked(user, checkAndGetTimeLocked());
userStats.applyRestoredPayload(key, payload);
}
}
}
@Override
public List<UsageStats> queryUsageStatsForUser(
int userId, int intervalType, long beginTime, long endTime,
boolean obfuscateInstantApps) {
return UsageStatsService.this.queryUsageStats(
userId, intervalType, beginTime, endTime, obfuscateInstantApps);
}
// NOTE: Bug #627645 low power Feature BEG-->
@Override
public void addAppStateEventChangeListener(AppStateEventChangeListener listener) {
if (mPowerControllerHelper != null)
mPowerControllerHelper.addAppStateEventChangeListener(listener);
}
@Override
public void removeAppStateEventChangeListener(AppStateEventChangeListener listener) {
if (mPowerControllerHelper != null)
mPowerControllerHelper.removeAppStateEventChangeListener(listener);
}
@Override
public void setAppInactive(String packageName, boolean idle, int userId) {
if (mPowerControllerHelper != null)
mPowerControllerHelper.setAppInactive(packageName, idle, userId);
}
@Override
public void setAppIdleEnabled(boolean enable) {
if (mPowerControllerHelper != null)
mPowerControllerHelper.setAppIdleEnabled(enable);
}
// <-- NOTE: Bug #627645 low power Feature END
}
3.6 PowerControllerHelper
这里重点采集 reportEvent
//
// ----------------- PowerController helper -- low power Feature BEG----------------------
//
private PowerControllerHelper mPowerControllerHelper;
// impletement functions that need for PowerController
private final class PowerControllerHelper {
static final int MSG_INFORM_APP_STATE = MSG_ONE_TIME_CHECK_IDLE_STATES + 1;
static final int MSG_SET_FORCEIDLE_FLAG = MSG_ONE_TIME_CHECK_IDLE_STATES + 2;
private ArrayList<UsageStatsManagerInternal.AppStateEventChangeListener>
mAppStateEventListeners = new ArrayList<>();
public boolean reportEvent(UsageEvents.Event event, int userId, boolean previouslyIdle, long elapsedRealtime) {
final boolean forceIdle = mAppIdleHistory.isForceIdleFlagSet(
event.mPackage, userId, elapsedRealtime);
if (!forceIdle
|| event.mEventType == Event.MOVE_TO_FOREGROUND
|| event.mEventType == Event.USER_INTERACTION) {
mAppIdleHistory.reportUsage(event.mPackage, userId, elapsedRealtime);
if (previouslyIdle) {
mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS, userId,
/* idle = */ 0, event.mPackage));
notifyBatteryStats(event.mPackage, userId, false);
}
}
mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_APP_STATE, userId, event.mEventType, event.mPackage));
return true;
}
public void informAppStateEventChangeListeners(String packageName, int userId, int state) {
for (UsageStatsManagerInternal.AppStateEventChangeListener listener : mAppStateEventListeners) {
listener.onAppStateEventChanged(packageName, userId, state);
}
}
public boolean handleMessage(Message msg) {
boolean ret = false;
switch (msg.what) {
case MSG_INFORM_APP_STATE:
informAppStateEventChangeListeners((String)msg.obj, msg.arg1, msg.arg2);
ret = true;
break;
case MSG_SET_FORCEIDLE_FLAG:
setAppForceIdleFlagInternal((String) msg.obj, msg.arg1, msg.arg2 == 1);
ret = true;
break;
}
return ret;
}
public void addAppStateEventChangeListener(UsageStatsManagerInternal.AppStateEventChangeListener listener) {
synchronized (mLock) {
if (!mAppStateEventListeners.contains(listener)) {
mAppStateEventListeners.add(listener);
}
}
}
public void removeAppStateEventChangeListener(
UsageStatsManagerInternal.AppStateEventChangeListener listener) {
synchronized (mLock) {
mAppStateEventListeners.remove(listener);
}
}
public void setAppInactive(String packageName, boolean idle, int userId) {
try {
PackageInfo pi = AppGlobals.getPackageManager()
.getPackageInfo(packageName, 0, userId);
if (pi == null) return;
UsageStatsService.this.setAppIdleAsync(packageName, idle, userId);
setAppForceIdleFlag(packageName, idle, userId);
} catch (RemoteException re) {
} finally {
}
}
public void setAppIdleEnabled(boolean enable) {
if (mAppIdleEnabled != enable) {
mAppIdleEnabled = enable;
if (mAppIdleEnabled) {
IntentFilter deviceStates = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
deviceStates.addAction(BatteryManager.ACTION_DISCHARGING);
deviceStates.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
getContext().registerReceiver(new DeviceStateReceiver(), deviceStates);
}
}
}
private void setAppForceIdleFlag(String packageName, boolean idle, int userId) {
if (packageName == null) return;
mHandler.obtainMessage(MSG_SET_FORCEIDLE_FLAG, userId, idle ? 1 : 0, packageName)
.sendToTarget();
}
/**
* set the force idle flag.
* then it will not exit idle, until call forceIdleState
*/
private void setAppForceIdleFlagInternal(String packageName, int userId, boolean idle) {
final int appId = getAppId(packageName);
if (appId < 0) return;
synchronized (mAppIdleLock) {
final long elapsedRealtime = SystemClock.elapsedRealtime();
mAppIdleHistory.setForceIdleFlag(packageName, userId, idle, elapsedRealtime);
}
}
}
3.7 UsageStatsService.reportEvent
/**
* Called by the Binder stub.
*/
void reportEvent(UsageEvents.Event event, int userId) {
....
if (mPowerControllerHelper != null
&& mPowerControllerHelper.reportEvent(event, userId, previouslyIdle, elapsedRealtime)) {
return;
}
...
这里重点看下 AMS 调用该接口情况
4. ActivityManagerService 与 UsageStatsService
- frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
package com.android.server.am;
public class ActivityManagerService extends ActivityManagerServiceExAbs
implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
/**
* Information about component usage
*/
UsageStatsManagerInternal mUsageStatsService;
public void setUsageStatsManager(UsageStatsManagerInternal usageStatsManager) {
mUsageStatsService = usageStatsManager;
}
/**
* Information about component usage
*/
UsageStatsManagerInternal mUsageStatsService;
4.1 ActivityManagerService.updateUsageStats
void updateUsageStats(ActivityRecord component, boolean resumed) {
if (DEBUG_SWITCH) Slog.d(TAG_SWITCH,
"updateUsageStats: comp=" + component + "res=" + resumed);
final BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
if (resumed) {
if (mUsageStatsService != null) {
// 进程切换到前台
mUsageStatsService.reportEvent(component.realActivity, component.userId,
UsageEvents.Event.MOVE_TO_FOREGROUND);
}
synchronized (stats) {
//SPRD: bug 871622, check the process of the activity before using.
if (component.app != null) {
stats.noteActivityResumedLocked(component.app.uid);
}
}
} else {
if (mUsageStatsService != null) {
// 进程切换到后台
mUsageStatsService.reportEvent(component.realActivity, component.userId,
UsageEvents.Event.MOVE_TO_BACKGROUND);
}
synchronized (stats) {
if (component.app != null) {
stats.noteActivityPausedLocked(component.app.uid);
}
}
}
}
4.2 ActivityManagerService.maybeUpdateUsageStatsLocked
private void maybeUpdateUsageStatsLocked(ProcessRecord app, long nowElapsed) {
...
if (packages != null) {
for (int i = 0; i < packages.length; i++) {
mUsageStatsService.reportEvent(packages[i], app.userId,
//
UsageEvents.Event.SYSTEM_INTERACTION);
4.3 UsageEvents 的状态解释
- frameworks/base/core/java/android/app/usage/UsageEvents.java
package android.app.usage;
/**
* A result returned from {@link android.app.usage.UsageStatsManager#queryEvents(long, long)}
* from which to read {@link android.app.usage.UsageEvents.Event} objects.
*/
public final class UsageEvents implements Parcelable {
/**
* An event representing a state change for a component.
*/
public static final class Event {
/**
* An event type denoting that a component moved to the foreground.
*/
// 该事件类似表示该进程进入前台
public static final int MOVE_TO_FOREGROUND = 1;
/**
* An event type denoting that a component moved to the background.
*/
// 该事件类似表示该进程进入后台
public static final int MOVE_TO_BACKGROUND = 2;
/**
* An event type denoting that a package was interacted with in some way by the system.
* @hide
*/
// 该事件类型表示该进程正与系统进行交互
public static final int SYSTEM_INTERACTION = 6;
5. 收集应用的事件类型 UsageStatsService.reportEvent
收集应用的事件模块与AMS和USS的逻辑链路如下
package com.android.server.usage;
/**
* A service that collects, aggregates, and persists application usage data.
* This data can be queried by apps that have been granted permission by AppOps.
*/
public class UsageStatsService extends SystemService implements
UserUsageStatsService.StatsUpdatedListener {
/**
* Called by the Binder stub.
*/
// 这里接受进程的Event状态信息(MOVE_TO_FOREGROUND, MOVE_TO_BACKGROUND, SYSTEM_INTERACTION)
void reportEvent(UsageEvents.Event event, int userId) {
...
synchronized (mAppIdleLock) {
...
if (mPowerControllerHelper != null
&& mPowerControllerHelper.reportEvent(event, userId, previouslyIdle, elapsedRealtime)) {
return;
}
}
6. PowerControllerHelper.reportEvent
package com.android.server.usage;
/**
* A service that collects, aggregates, and persists application usage data.
* This data can be queried by apps that have been granted permission by AppOps.
*/
public class UsageStatsService extends SystemService implements
UserUsageStatsService.StatsUpdatedListener {
// impletement functions that need for PowerController
private final class PowerControllerHelper {
public boolean reportEvent(UsageEvents.Event event, int userId, boolean previouslyIdle, long elapsedRealtime) {
// 获取当前是否为强制进入idle模式状态
final boolean forceIdle = mAppIdleHistory.isForceIdleFlagSet(
event.mPackage, userId, elapsedRealtime);
// 是否满足以下任一条件
// 1. 非强制进入idle模式
// 2. 事件状态为移动到前台
// 3. 事件状态为用户交互状态
if (!forceIdle
|| event.mEventType == Event.MOVE_TO_FOREGROUND
|| event.mEventType == Event.USER_INTERACTION) {
// 记录应用idle模式历史
mAppIdleHistory.reportUsage(event.mPackage, userId, elapsedRealtime);
// 是否之前为待机休眠模式
if (previouslyIdle) {
//
mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS, userId,
/* idle = */ 0, event.mPackage));
notifyBatteryStats(event.mPackage, userId, false);
}
}
mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_APP_STATE, userId, event.mEventType, event.mPackage));
return true;
}
6.1 MSG_INFORM_LISTENERS
通知应用待机状态发生改变
class H extends Handler {
public H(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_INFORM_LISTENERS:
informListeners((String) msg.obj, msg.arg1, msg.arg2 == 1);
break;
...
}
void informListeners(String packageName, int userId, boolean isIdle) {
for (AppIdleStateChangeListener listener : mPackageAccessListeners) {
listener.onAppIdleStateChanged(packageName, userId, isIdle);
}
}
6.2 notifyBatteryStats
刷新电池状态活动或非活动
private void notifyBatteryStats(String packageName, int userId, boolean idle) {
try {
final int uid = mPackageManager.getPackageUidAsUser(packageName,
PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
if (idle) {
mBatteryStats.noteEvent(BatteryStats.HistoryItem.EVENT_PACKAGE_INACTIVE,
packageName, uid);
} else {
mBatteryStats.noteEvent(BatteryStats.HistoryItem.EVENT_PACKAGE_ACTIVE,
packageName, uid);
}
} catch (NameNotFoundException | RemoteException e) {
}
}
7. USS.PowerControllerHelper.informAppStateEventChangeListeners
- mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_APP_STATE, userId, event.mEventType, event.mPackage));
通知所有注册AppStateEventChangeListener事件更新应用状态事件
package com.android.server.usage;
/**
* A service that collects, aggregates, and persists application usage data.
* This data can be queried by apps that have been granted permission by AppOps.
*/
public class UsageStatsService extends SystemService implements
UserUsageStatsService.StatsUpdatedListener {
private PowerControllerHelper mPowerControllerHelper;
// impletement functions that need for PowerController
private final class PowerControllerHelper {
static final int MSG_INFORM_APP_STATE = MSG_ONE_TIME_CHECK_IDLE_STATES + 1;
public boolean handleMessage(Message msg) {
boolean ret = false;
switch (msg.what) {
case MSG_INFORM_APP_STATE:
informAppStateEventChangeListeners((String)msg.obj, msg.arg1, msg.arg2);
ret = true;
break;
....
public void informAppStateEventChangeListeners(String packageName, int userId, int state) {
for (UsageStatsManagerInternal.AppStateEventChangeListener listener : mAppStateEventListeners) {
listener.onAppStateEventChanged(packageName, userId, state);
}
}
8. PowerController 处理onAppStateEventChanged回调事件
- frameworks/base/services/core/java/com/android/server/power/PowerController.java
PowerController 处理onAppStateEventChanged事件
至此完成 应用事件统计-USS到PowerController的逻辑链路
package com.android.server.power;
public class PowerController //extends IPowerController.Stub
// 这里继承了 UsageStatsManagerInternal.AppStateEventChangeListener 应用事件变化状态
extends UsageStatsManagerInternal.AppStateEventChangeListener {
//Message define
static final int MSG_APP_STATE_CHANGED = 0;
public void onAppStateEventChanged(String packageName, int userId, int state) {
msgHandler.sendMessage(msgHandler.obtainMessage(MSG_APP_STATE_CHANGED, userId, state, packageName));
}
@Override public void handleMessage(Message msg) {
if (DEBUG) Slog.d(TAG, "handleMessage(" + Msg2Str(msg.what) + ")");
switch (msg.what) {
case MSG_APP_STATE_CHANGED:
handleAppStateChanged((String)msg.obj, msg.arg1, msg.arg2);
break;
9. PowerController.onAppStateEventChanged 模块
private void handleAppStateChanged(String packageName, int userId, int state) {
int oldState = state;
// 获取APP状态
AppState appState = mAppStateInfoCollector.getAppState(packageName, userId);
if (DEBUG) Slog.d(TAG, "- handleAppStateChanged() E -");
// 如果状态相同则不进行更新
if (appState != null) {
oldState = appState.mState;
if (oldState == state)
return;
}
// 是否记录应用事件状态流
if (mAppStateInfoCollector.reportAppStateEventInfo(packageName, userId, state)) {
// Note: Bug 698133 appIdle cts fail -->BEG
// Ugly: we have to check if doing cts/gts test
// is cts/gts test, then
// 若存在该进程,则检查是否是CTS应用运行
checkCtsGtsTesting(packageName);
// Note: Bug 698133 appIdle cts fail <--END
}
if (DEBUG) Slog.d(TAG, "packageName:" + packageName + " state:" + Util.AppState2Str(state)+ " user:" + userId);
// get new app state
// 重新获取应用状态信息
appState = mAppStateInfoCollector.getAppState(packageName, userId);
if (appState == null) {
Slog.w(TAG, "null appState for packageName:" + packageName + " state:" + Util.AppState2Str(state)+ " user:" + userId);
return;
}
//SPRD:Bug 814570 About apps auto run BEG
// 应用状态为前台进程且应用启动次数为1
if (Event.MOVE_TO_FOREGROUND == state
&& appState.mTotalLaunchCount == 1) {
if (DEBUG) Slog.d(TAG, "- handleAppStateChanged() NEW -");
if (mBackgroundCleanHelper != null) {
// 通知应用为第一次启动状态
mBackgroundCleanHelper.noteAppFirstStarted(packageName, userId);
}
}
//SPRD:Bug 814570 About apps auto run END
// 算法更新应用状态事件
mRecogAlgorithm.reportEvent(packageName, appState.mUid, RecogAlgorithm.EVENT_TYPE_FG_STATE, state);
// 如果是充电或者亮屏,则结束流程
if (mCharging || mScreenOn)
return;
// 检查是否要记录应用网络使用情况
// recode the traffic stats if needed
// should be called before doing Evaluated time stamp update
appState.updateAppTrafficStats(false);
// notify helpers to update time stamp
// 更新时间戳,有些help类需要
updateAppEvaluatedTimeStamp(appState);
// 状态变化详情
// 1. STATE_NOCHANGE 没有改变
// 2. STATE_BG2FG 后台变更前台
// 3. 前台变更后台
int stateChange = getStateChange(oldState, state);
// if app is already set in standby state, then its app state changed
// UsageStatsService will make the app to exit standby state
if (stateChange != STATE_NOCHANGE && appState.mInAppStandby) {
if (DEBUG) Slog.d(TAG, "packageName:" + packageName + " may exit standby by UsageStatsService");
}
if (stateChange == STATE_BG2FG) { //if bg2fg, clear list, remove from powerguru & appstandby
if (DEBUG) Slog.d(TAG, "packageName:" + packageName + " change from BG2FG");
// notify helpers to handle the app state changed
// 如果是后台转前台,则移除powerguru和appstandby相关状态
updateAppStateChanged(appState, stateChange);
} else { // if not bg2fg, just resend MSG_CHECK
}
cancelAlarmLocked();
msgHandler.removeMessages(MSG_CHECK);
msgHandler.sendMessage(msgHandler.obtainMessage(MSG_CHECK));
}
9.1 AppStateInfoCollector.reportAppStateEventInfo
主要更新应用状态信息和统计一些启动次数和时间
- frameworks/base/services/core/java/com/android/server/power/AppStateInfoCollector.java
// return true: for new app state
// false: for others
public boolean reportAppStateEventInfo(String packageName, int userId, int stateEvent) {
ArrayMap<String, AppState> mAppStateInfoList = getAppStateInfoList(userId);
//update mAppStateInfoList
// 获取包名对应的下标
int index = mAppStateInfoList.indexOfKey(packageName);
AppState appState = null;
boolean ret = true;
if (DEBUG) Slog.d(TAG, "- reportAppStateEventInfo() E -");
// 如果下标非0.表示AppState数据已存在,则更新应用状态
if (index >= 0) {
appState = mAppStateInfoList.valueAt(index);
appState.updateAppState(stateEvent);
ret = false;
// 如果下标为0,表示AppState数据未被创建,则创建一组数据
} else {
appState = buildAppState(packageName, userId, stateEvent);
mAppStateInfoList.put(packageName, appState);
}
return ret;
}
9.1.1 创建AppState数据
- buildAppState(packageName, userId, stateEvent)
package com.android.server.power;
public class AppStateInfoCollector {
private AppState buildAppState(String packageName, int userId, int stateEvent) {
ApplicationInfo app = null;
int uid = 0;
int procState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
int flags = 0;
try {
// 从PMS中获取应用程序信息
// 1. uid
// 2. flags
app = AppGlobals.getPackageManager().
getApplicationInfo(packageName, 0, userId);
} catch (RemoteException e) {
// can't happen; package manager is process-local
}
if (app != null) {
uid = app.uid;
flags = app.flags;
synchronized (mUidStateLock) {
// 获取当前进程的优先级adj
procState = mUidState.get(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
}
}
// 参数类型:包名,userId,uid,应用事件状态,进程优先级,flags
AppState retVal = new AppState(packageName, userId, uid, stateEvent, procState, flags);
// check if is input method
// 是否为输入法
retVal.mIsEnabledInputMethod = isEnabledIMEApp(packageName);
//if (DEBUG) Slog.d(TAG, "- buildAppState() :" + packageName);
return retVal;
}
9.1.2 更新AppState数据
- frameworks/base/services/core/java/com/android/server/power/AppState.java
- appState.updateAppState(参数类型为进程的事件变化[前台或者后台或者与系统交互]stateEvent)
package com.android.server.power;
public class AppState {
static final String TAG = "PowerController.AppState";
// return the old state
public int updateAppState(int stateEvent) {
int oldState = mState;
// 更新应用事件stateEvent
mLastState = mState;
mState = state;
// 如果当前是前台进程
if (Event.MOVE_TO_FOREGROUND == mState) {
// 更新启动次数,总启动次数,上一次启动时间
mLaunchCount++;
mTotalLaunchCount++;
mLastLaunchTime = SystemClock.elapsedRealtime();
}
// 如果当前为与系统交互事件
if (Event.SYSTEM_INTERACTION != mState) {
mLastTimeUsed = SystemClock.elapsedRealtime();
if (mTrackingLaunchCountWhenStandby && Event.MOVE_TO_FOREGROUND == mState) {
// 统计待机模式下启动次数
mLaunchCountWhenStandby++;
if (DEBUG) Slog.d(TAG, "uid:" + mUid + " packageName:" + mPackageName
+ " mLaunchCountWhenStandby:" + mLaunchCountWhenStandby);
}
}
// 当前进程优先级为缓存进程或者空进程
// if target app exit
if (mProcState == ActivityManager.PROCESS_STATE_CACHED_EMPTY
&& Event.NONE == mState) {
if (mStartRunningTime > 0)
// 统计应用运行时间
mRunningDuration += (SystemClock.elapsedRealtime() - mStartRunningTime);
// clear mStartRunningTime
mStartRunningTime = 0;
} else if (mStartRunningTime == 0) {
mStartRunningTime = SystemClock.elapsedRealtime();
}
return oldState;
}
9.2 appState.updateAppTrafficStats
检查是否要记录应用网络使用情况
/**
* update the RxBytes && socket stats
* only for app with procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE
*/
public boolean updateAppTrafficStats(boolean clear) {
if (clear) {
mRxBytesWhenStartEvaluated = 0;
mTimeStampForRxBytes = 0;
mSocketStreams.clear();
mUsedTimeSliceCount = 0;
mDoingDownload = false;
} else if (mRxBytesWhenStartEvaluated == 0
&& mProcState <= ActivityManager.PROCESS_STATE_SERVICE
&& mUid > Process.FIRST_APPLICATION_UID) {
mRxBytesWhenStartEvaluated = TrafficStats.getUidRxBytes(mUid);
mTimeStampForRxBytes = SystemClock.elapsedRealtime();
if (DEBUG) Slog.d(TAG, "uid:" + mUid + " packageName:" + mPackageName
+ " RxBytes:" + mRxBytesWhenStartEvaluated);
// get socket stream info
// getAppSocketStreams(state); // --> in fact this is not needed
}
return true;
}
9.3 getStateChange
状态变化详情
- STATE_NOCHANGE 没有改变
- STATE_BG2FG 后台变更前台
- 前台变更后台
- int stateChange = getStateChange(oldState, state);
static final int STATE_NOCHANGE = 0;
static final int STATE_BG2FG = -2;
static final int STATE_FG2BG = 2;
private int getStateChange(int oldState, int newState) {
int oldFlag = isBGState(oldState)?-1:1;
int newFlag = isBGState(newState)?-1:1;
return(oldFlag - newFlag);
}
private boolean isBGState(int state) {
return (state == Event.MOVE_TO_BACKGROUND) ;
}
9.4 updateAppStateChanged
// notify helpers to handle the app state changed
private void updateAppStateChanged(AppState appState, int stateChange) {
for (int i = 0; i < mHelpers.size(); i++) {
PowerSaveHelper helper = mHelpers.get(i);
helper.updateAppStateChanged(appState, stateChange);
}
}
/*
* BackgroundCleanHelper
* handle the case:
* app move from BG2FG, and it can not be constrained again.
*/
void updateAppStateChanged(AppState appState, int stateChange) {
}
9.5 cancelAlarmLocked()
取消对齐唤醒相关的唤醒检查
private static final String ACTION_CHECK_APPSTATE =
"com.android.server.powercontroller.CHECK_APPSTATE";
Intent intent = new Intent(ACTION_CHECK_APPSTATE)
.setPackage("android")
.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
mAlarmIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
void cancelAlarmLocked() {
mAlarmManager.cancel(mAlarmIntent);
}
void scheduleAlarmLocked(long delay) {
mAlarmManager.set(AlarmManager.ELAPSED_REALTIME,
(SystemClock.elapsedRealtime()) + delay, mAlarmIntent);
}
mContext.registerReceiver(
new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (ACTION_CHECK_APPSTATE.equals(action)) {
msgHandler.removeMessages(MSG_CHECK);
msgHandler.sendMessage(msgHandler.obtainMessage(MSG_CHECK));
// for PowerGuru Interval upadate
// 对齐唤醒相关
if (mPowerGuruAligningStart) {
msgHandler.removeMessages(MSG_UPDATE_POWERGURU_INTERVAL);
msgHandler.sendMessage(msgHandler.obtainMessage(MSG_UPDATE_POWERGURU_INTERVAL));
}
9.6 MSG_CHECK
检查所有应用状态 checkAllAppStateInfo
static final int MSG_CHECK = 1;
@Override public void handleMessage(Message msg) {
if (DEBUG) Slog.d(TAG, "handleMessage(" + Msg2Str(msg.what) + ")");
switch (msg.what) {
case MSG_CHECK:
checkAllAppStateInfo();
break;
//Check period 5 分钟间隔
private long CHECK_INTERVAL = (TEST ? 5 * 60 * 1000L : 5 * 60 * 1000L);
private void checkAllAppStateInfo() {
if (DEBUG) Slog.d(TAG, "- checkAllAppStateInfo() E -");
if (DEBUG) Slog.d(TAG, "mCharging:" + mCharging + " mScreenOn:" + mScreenOn + " mMobileConnected:" + mMobileConnected);
//set next check
//msgHandler.removeMessages(MSG_CHECK);
//msgHandler.sendMessageDelayed(msgHandler.obtainMessage(MSG_CHECK), CHECK_INTERVAL);
// 设置5分钟一次间隔检查alram
scheduleAlarmLocked(CHECK_INTERVAL);
if (mCharging || mScreenOn) {
if (mNeedCheckPowerModeForCall) {
// 更新省电状态
updatePowerSaveMode();
}
return;
}
// 更新系统从开机到现在的毫秒数,且每隔30秒刷新一次
checkSystemUpTime();
boolean bChanged = false;
// Note:use the same now elapsed time for all the AppStateInfo
// otherwise, when checking app Parole, some app may have not
// opportunity to exit app standby.
long now = SystemClock.elapsedRealtime();
// 更新省电模式
updatePowerSaveMode();
try {
final List<UserInfo> users = mUserManager.getUsers();
for (int ui = users.size() - 1; ui >= 0; ui--) {
UserInfo user = users.get(ui);
if (DEBUG) Slog.d(TAG, "- checkAllAppStateInfo() for user: " + user.id);
final ArrayMap<String, AppState> appStateInfoList = mAppStateInfoCollector.getAppStateInfoList(user.id);
for (int i=0;i<appStateInfoList.size();i++) {
AppState appState = appStateInfoList.valueAt(i);
//let app to be parole
// AppIdleHelper应用假释
mAppIdleHelper.checkAppParole(appState, now);
// check app state info
if (checkAppStateInfo(appState, now)) {
bChanged = true;
}
}
}
} catch (Exception e) {
}
// note AppidleHelper all check done
mAppIdleHelper.noteCheckAllAppStateInfoDone();
// note mWakelockConstraintHelper all check done
mWakelockConstraintHelper.noteCheckAllAppStateInfoDone();
//send notification to powerguru & appstandby
if (bChanged) msgHandler.sendMessage(msgHandler.obtainMessage(MSG_NOTIFY_CHANGED));
if (needCheckNetworkConnection(now)) {
if (DEBUG) Slog.d(TAG, "- checkNetworkConnection() in checkAllAppStateInfo -");
checkNetworkConnection(true);
}
// check doze state
checkDozeState();
}
9.6.1 checkSystemUpTime
更新系统从开机到现在的毫秒数(手机睡眠的时间不包括在内),其中判断是否系统休眠
private static long SYSTEM_UP_CHECK_INTERVAL = (30 * 1000L); // 30s
// the time stamp of last system is up using elapsed realtime
// 上一次开机到现在的毫秒的时间戳
private long mLastSystemUpTimeStamp = 0;
// next time stamp to check system up using elapsed realtime
// 下一次检查开机到现在的毫秒的时间戳
private long mNextCheckSystemUpTimeStamp = 0;
// the time stamp of last check using up time
// 上一次检查开机到现在的毫秒的时间戳
private long mLastCheckTimeStampUptime = 0;
private void checkSystemUpTime() {
// 如果是充电或者亮屏,初始化使用系统相关的时间戳
if (mCharging || mScreenOn) {
mLastSystemUpTimeStamp = 0;
mNextCheckSystemUpTimeStamp = 0;
mLastCheckTimeStampUptime = 0;
return;
}
long now = SystemClock.elapsedRealtime();
// 下一次检查系统的时间戳大于当前,则结束流程
if (mNextCheckSystemUpTimeStamp > now)
return;
// 从开机到现在的毫秒数(手机睡眠的时间不包括在内)
long nowUptime = SystemClock.uptimeMillis();
if (DEBUG) Slog.d(TAG, "checkSystemUpTime : mLastSystemUpTimeStamp:" + mLastSystemUpTimeStamp
+ " now:" + now + " nowUptime:" + nowUptime);
// 如果开机到现在的时间戳为0
if (mLastSystemUpTimeStamp == 0) {
// 赋值当前开机到现在的时间戳
mLastSystemUpTimeStamp = now;
// 如果满足如下:
// 1. 上一次检查开机到现在的毫秒的时间戳大于0
// 2. 下一次检查开机到现在的毫秒的时间戳大于0
} else if (mNextCheckSystemUpTimeStamp > 0
&& mLastCheckTimeStampUptime > 0) {
// upDuration = 当前开机到现在的时间戳 - 上一次检查开机到现在的毫秒的时间戳
long upDuration = nowUptime - mLastCheckTimeStampUptime;
// totalDuration = 当前开机到现在的时间戳 - 下一次检查开机到现在的毫秒的时间戳 + 30s
long totalDuration = now-mNextCheckSystemUpTimeStamp + SYSTEM_UP_CHECK_INTERVAL;
if ((totalDuration-upDuration) > 2*SYSTEM_UP_CHECK_INTERVAL) {
if (DEBUG) Slog.d(TAG, "system has sleep for : " + (totalDuration-upDuration));
// 系统休眠了,更新上一次检查开机到现在的毫秒的时间戳为当前
mLastSystemUpTimeStamp = now;
}
}
mLastCheckTimeStampUptime = nowUptime;
mNextCheckSystemUpTimeStamp = now + SYSTEM_UP_CHECK_INTERVAL;
// 每隔30秒更新一下,当前开机到现在的时间戳,最终还是调用checkSystemUpTime
msgHandler.removeMessages(MSG_CHECK_SYSTEM_UP);
msgHandler.sendMessageDelayed(msgHandler.obtainMessage(MSG_CHECK_SYSTEM_UP), SYSTEM_UP_CHECK_INTERVAL);
}