13 展讯Sprd设置-电池-应用事件变化数据收集(8.0 Android O)

版权声明:本文为博主原创文章,未经博主允许不得转载。 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的逻辑链路如下

收集应用的事件模块与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

PowerControllerHelper-reportEvent.jpg

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的逻辑链路.jpg

至此完成 应用事件统计-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

状态变化详情

  1. STATE_NOCHANGE 没有改变
  2. STATE_BG2FG 后台变更前台
  3. 前台变更后台
  • 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);
    }

猜你喜欢

转载自blog.csdn.net/su749520/article/details/84303579
今日推荐