Android省電力管理開発(1)APPステータスモニタリング

1つは、最初にAPPステータス監視の2つの入り口を紹介します。

1. UsageStatsServiceは、アプリケーションの使用状況データを収集、集約、および保持するサービスです。

2.IUidObserverはプロセスステータスの変更を監視します

私たちが行うアプリステータスの監視は、この接続エントリに基づいています

次に、フレームワークが構築されます

AppState.java APP状態のオブジェクトクラス、各APPは個別のオブジェクトとして処理されます

AppStateInfoCollector.javaAPP状態管理クラス

PowerController.java省電力管理全体の管理クラス

Util.javaツールクラス

3、UsageStatsService関連クラスの概要、およびソースコードの変更

UsageEvents.javaは、主にアプリのイベントを記録するために使用される内部クラスEventを実装します

UsageStatsManagerInternal.java抽象クラス。UsageStatsService.javaに実装されています

UsageStatsManager.javaUsageStatsService管理クラス

PowerController.javaを省電力管理全体の管理クラスとして作成したため、APPステータスのリアルタイムの変更を取得するためのインターフェイスを公開するUsageStatsServiceが必要です。

したがって、最初にUsageStatsManagerInternal.javaに抽象クラスAppStateEventChangeListenerを追加し、onAppStateEventChanged()抽象メソッドを追加し、抽象リスナーインターフェイスとリスナーをキャンセルするインターフェイスを追加します。

    //add by lzq for power 20200915 start
    public abstract void addAppStateEventChangeListener(
            AppStateEventChangeListener listener);

    public abstract void removeAppStateEventChangeListener(
            AppStateEventChangeListener listener);

    public static abstract class AppStateEventChangeListener {
        public abstract void onAppStateEventChanged(String packageName, int userId, int stateEvent);
    }
    //add by lzq for power 20200915 end

UsageStatsServiceの内部クラスLocalServiceはUsageStatsManagerInternalを継承するため、これら2つの抽象メソッドをLocalServiceに実装する必要があります。

        /*add by lzq for power 20200916 start*/
        @Override
        public void addAppStateEventChangeListener(AppStateEventChangeListener listener) {
            if (mPowerControllerHelper != null)
                mPowerControllerHelper.addAppStateEventChangeListener(listener);
        }

        @Override
        public void removeAppStateEventChangeListener(AppStateEventChangeListener listener) {
            if (mPowerControllerHelper != null)
                mPowerControllerHelper.removeAppStateEventChangeListener(listener);
        }
        /*add by lzq for power 20200916 end*/

PowerControllerHelperは、UsageStatsServiceとPowerControllerの間の中間ブリッジとしてUsageStatsServiceに追加される内部クラスです。

    /*add by lzq for power 20200916 start*/
    private PowerControllerHelper mPowerControllerHelper;

    private final class PowerControllerHelper {
        static final int MSG_INFORM_APP_STATE = MSG_UID_STATE_CHANGED + 2;

        private ArrayList<UsageStatsManagerInternal.AppStateEventChangeListener>
                mAppStateEventListeners = new ArrayList<>();


        public boolean reportEvent(UsageEvents.Event event, int userId, long elapsedRealtime) {

            mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_APP_STATE, userId, event.mEventType, event.mPackage));

            return true;
        }

        public void informAppStateEventChangeListeners(String packageName, int userId, int state) {
            synchronized (mAppStateEventListeners) {
                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;
            }

            return ret;
        }

        public void addAppStateEventChangeListener(UsageStatsManagerInternal.AppStateEventChangeListener listener) {
            synchronized (mAppStateEventListeners) {
                if (!mAppStateEventListeners.contains(listener)) {
                    mAppStateEventListeners.add(listener);
                }
            }
        }

        public void removeAppStateEventChangeListener(
                UsageStatsManagerInternal.AppStateEventChangeListener listener) {
            synchronized (mAppStateEventListeners) {
                mAppStateEventListeners.remove(listener);
            }
        }

    }
    /*add by lzq for power 20200916 end*/

PowerController.javaにUsageStatsManagerInternal.AppStateEventChangeListenerを継承させ、onAppStateEventChanged()メソッドを実装し、リスナーを登録します

        mUsageStatsInternal = LocalServices.getService(UsageStatsManagerInternal.class);        
        // register
        mUsageStatsInternal.addAppStateEventChangeListener(this);

UsageStatsServiceは、アプリのステータスの変更を監視するときに、PowerControllerHelperのreportEvent()を呼び出します。

    void reportEvent(Event event, int userId) {
            ......
            /*add by lzq for power 20200916 start*/
            if (mPowerControllerHelper != null) {
                mPowerControllerHelper.reportEvent(event, userId, elapsedRealtime);
            }
            /*add by lzq for power 20200916 end*/
            ......
    }

reportEvent()でMSG_INFORM_APP_STATE情報を送信し、informAppStateEventChangeListeners()を呼び出します。ここで、インターフェースonAppStateEventChanged()が呼び出され、PowerController.javaがこのインターフェースを実装します。これは、UsageStatsServiceとPowerControllerの間の一般的な対話プロセスです。

第四に、IUidObserverの紹介とプロセスの主な状況

IUidObserverには5つのメソッドがあり、通常はonUidGone(プロセスが強制終了されて呼び出される)とonUidStateChanged(プロセスの作成とプロセス状態の変更が呼び出される)にのみ注意を払う必要があります。


/** {@hide} */
oneway interface IUidObserver {
    // WARNING: when these transactions are updated, check if they are any callers on the native
    // side. If so, make sure they are using the correct transaction ids and arguments.
    // If a transaction which will also be used on the native side is being inserted, add it to
    // below block of transactions.

    // Since these transactions are also called from native code, these must be kept in sync with
    // the ones in frameworks/native/include/binder/IActivityManager.h
    // =============== Beginning of transactions used on native side as well ======================

    /**
     * Report that there are no longer any processes running for a uid.
     */
    void onUidGone(int uid, boolean disabled);

    /**
     * Report that a uid is now active (no longer idle).
     */
    void onUidActive(int uid);

    /**
     * Report that a uid is idle -- it has either been running in the background for
     * a sufficient period of time, or all of its processes have gone away.
     */
    void onUidIdle(int uid, boolean disabled);

    /**
     * General report of a state change of an uid.
     *
     * @param uid The uid for which the state change is being reported.
     * @param procState The updated process state for the uid.
     * @param procStateSeq The sequence no. associated with process state change of the uid,
     *                     see UidRecord.procStateSeq for details.
     */
    void onUidStateChanged(int uid, int procState, long procStateSeq);

    // =============== End of transactions used on native side as well ============================

    /**
     * Report when the cached state of a uid has changed.
     * If true, a uid has become cached -- that is, it has some active processes that are
     * all in the cached state.  It should be doing as little as possible at this point.
     * If false, that a uid is no longer cached.  This will only be called after
     * onUidCached() has been reported true.  It will happen when either one of its actively
     * running processes is no longer cached, or it no longer has any actively running processes.
     */
    void onUidCachedChanged(int uid, boolean cached);
}

 プロセスの主な状態であるこれらの変数は、ActivityManager.javaで定義されています。

    /** @hide Not a real process state. */
    public static final int PROCESS_STATE_UNKNOWN = -1;//Not a real process state

    /** @hide Process is a persistent system process. */
    public static final int PROCESS_STATE_PERSISTENT = 0;//persistent系统进程

    /** @hide Process is a persistent system process and is doing UI. */
    public static final int PROCESS_STATE_PERSISTENT_UI = 1;//persistent系统进程,并正在执行UI操作

    /** @hide Process is hosting the current top activities.  Note that this covers
     * all activities that are visible to the user. */
    @UnsupportedAppUsage
    public static final int PROCESS_STATE_TOP = 2;//拥有当前用户可见的top Activity

    /** @hide Process is hosting a foreground service with location type. */
    public static final int PROCESS_STATE_FOREGROUND_SERVICE_LOCATION = 3;//进程正在托管具有位置类型的前台服务

    /** @hide Process is bound to a TOP app. This is ranked below SERVICE_LOCATION so that
     * it doesn't get the capability of location access while-in-use. */
    public static final int PROCESS_STATE_BOUND_TOP = 4;//进程绑定到TOP应用程序。 它的排名低于SERVICE_LOCATION,因此在使用中无法获得位置访问的功能。

    /** @hide Process is hosting a foreground service. */
    @UnsupportedAppUsage
    public static final int PROCESS_STATE_FOREGROUND_SERVICE = 5;//拥有一个前台Service

    /** @hide Process is hosting a foreground service due to a system binding. */
    @UnsupportedAppUsage
    public static final int PROCESS_STATE_BOUND_FOREGROUND_SERVICE = 6;//拥有一个前台Service,且由系统绑定

    /** @hide Process is important to the user, and something they are aware of. */
    public static final int PROCESS_STATE_IMPORTANT_FOREGROUND = 7;//对用户很重要的进程,用户可感知其存在

    /** @hide Process is important to the user, but not something they are aware of. */
    @UnsupportedAppUsage
    public static final int PROCESS_STATE_IMPORTANT_BACKGROUND = 8;//进程对用户很重要,但对用户而言并不重要

    /** @hide Process is in the background transient so we will try to keep running. */
    public static final int PROCESS_STATE_TRANSIENT_BACKGROUND = 9;//进程处于后台过渡状态,因此我们将尝试继续运行

    /** @hide Process is in the background running a backup/restore operation. */
    public static final int PROCESS_STATE_BACKUP = 10;//后台进程,正在运行backup/restore操作

    /** @hide Process is in the background running a service.  Unlike oom_adj, this level
     * is used for both the normal running in background state and the executing
     * operations state. */
    @UnsupportedAppUsage
    public static final int PROCESS_STATE_SERVICE = 11;//后台进程,且正在运行service

    /** @hide Process is in the background running a receiver.   Note that from the
     * perspective of oom_adj, receivers run at a higher foreground level, but for our
     * prioritization here that is not necessary and putting them below services means
     * many fewer changes in some process states as they receive broadcasts. */
    @UnsupportedAppUsage
    public static final int PROCESS_STATE_RECEIVER = 12;//后台进程,且正在运行receiver

    /** @hide Same as {@link #PROCESS_STATE_TOP} but while device is sleeping. */
    public static final int PROCESS_STATE_TOP_SLEEPING = 13;//拥有当前用户可见的top Activity,but while device is sleeping.

    /** @hide Process is in the background, but it can't restore its state so we want
     * to try to avoid killing it. */
    public static final int PROCESS_STATE_HEAVY_WEIGHT = 14;//后台进程,但无法执行restore,因此尽量避免kill该进程

    /** @hide Process is in the background but hosts the home activity. */
    @UnsupportedAppUsage
    public static final int PROCESS_STATE_HOME = 15;//后台进程,且拥有home Activity

    /** @hide Process is in the background but hosts the last shown activity. */
    public static final int PROCESS_STATE_LAST_ACTIVITY = 16;//后台进程,且拥有上一次显示的Activity

    /** @hide Process is being cached for later use and contains activities. */
    @UnsupportedAppUsage
    public static final int PROCESS_STATE_CACHED_ACTIVITY = 17;//进程处于cached状态,且内含Activity

    /** @hide Process is being cached for later use and is a client of another cached
     * process that contains activities. */
    public static final int PROCESS_STATE_CACHED_ACTIVITY_CLIENT = 18;//进程处于cached状态,且为另一个cached进程(内含Activity)的client进程

    /** @hide Process is being cached for later use and has an activity that corresponds
     * to an existing recent task. */
    public static final int PROCESS_STATE_CACHED_RECENT = 19;//进程被缓存以供以后使用,并且具有与现有的最近task相对应的activity

    /** @hide Process is being cached for later use and is empty. */
    public static final int PROCESS_STATE_CACHED_EMPTY = 20;//进程处于cached状态,且为空进程

    /** @hide Process does not exist. */
    public static final int PROCESS_STATE_NONEXISTENT = 21;//不存在的进程

5、AppState.javaの紹介

public class AppState {

    static final String TAG = "PowerController.AppState";

    private final boolean DEBUG = true;

    String mPackageName;
    int mUserId;

    // The kernel user-ID that has been assigned to this application
    int mUid;

    // flags from ApplicationInfo
    int mFlags;

    // App status, BG/FG/USER ACTIVE/...
    int mState;
    int mLastState;
    // the launch count during current running, will clear when app is force stopped by BgClean
    int mLaunchCount;
    // the total launch count from system boot up
    int mTotalLaunchCount;
    // the last using time during current running, will clear when app is force stopped by BgClean
    long mLastTimeUsed; // elapsed time instead
    // the last launch time during current running, will clear when app is force stopped by BgClean
    long mLastLaunchTime;  // elapsed time instead

    // Process state: PROCESS_STATE_PERSISTENT / PROCESS_STATE_PERSISTENT_UI /...
    int mProcState;

    // if this app is visible
    boolean mVisible;
    long mLastVisibleTime;
    long mLastStopTime;
    long mLastInvisibleTime;

    // if set to true, then will not try to kill this app
    boolean mAvoidKilling;

    // if this app need using gps,
    // such as doing a navigation or location tracker (sports)
    boolean mNeedUsingGps;

    long mStartRunningTime; // the start time of this running
    long mRunningDuration; // the running duration of the app

    public AppState (String packageName, int userId, int uid, int state, int procState, int flags) {
        mPackageName = packageName;
        mUserId = userId;
        mUid = uid;
        mState = state;
        mProcState = procState;
        mFlags = flags;

        mLastState = mState;
        if (Event.MOVE_TO_FOREGROUND == state) {
            mLaunchCount = 1;
            mTotalLaunchCount = 1;
            mLastLaunchTime = SystemClock.elapsedRealtime();
        } else {
            mLaunchCount = 0;
            mTotalLaunchCount = 0;
            mLastLaunchTime = 0;
        }

        if (Event.SYSTEM_INTERACTION != state)
            mLastTimeUsed = SystemClock.elapsedRealtime();
        else
            mLastTimeUsed = 0;

        mAvoidKilling = false;
        mVisible = false;
        mLastVisibleTime = 0;
        mLastStopTime = 0;
        mLastInvisibleTime = 0;
        mNeedUsingGps = false;

        mStartRunningTime = SystemClock.elapsedRealtime();
        mRunningDuration = 0;
    }

    // return the old state
    public int updateAppState(int state) {
        int oldState = mState;

        mLastState = mState;
        mState = state;
        if (Event.MOVE_TO_FOREGROUND == mState) {
            mLaunchCount++;
            mTotalLaunchCount++;
            mLastLaunchTime = SystemClock.elapsedRealtime();
        }

        // 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;
    }


    // To clear the information about a launched app
    public void clearLaunchInfo() {
        mProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
        mState = Event.NONE;
        mLastState = mState;
        mLaunchCount = 0;
        mLastLaunchTime = 0;
        mLastTimeUsed = 0;
        mAvoidKilling = false;

        mLastStopTime = SystemClock.elapsedRealtime();
    }

}

6、AppStateInfoCollector.java

AppStateInfoCollectorは、AppStateの管理コレクションクラスとして、PowerControllerを介してアプリの状態の変更を取得し、AppStateを管理します。

主な方法の紹介:

reportAppStateEventInfo()

UsageStatsService-> PowerControllerを通じて更新されたアプリ情報を受信する責任があります

    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 -");

        if (index >= 0) {
            appState = mAppStateInfoList.valueAt(index);
            appState.updateAppState(stateEvent);
            ret = false;
        } else {
            appState = buildAppState(packageName, userId, stateEvent);
            mAppStateInfoList.put(packageName, appState);
        }

        return ret;
    }

reportAppProcStateInfo()

IUidObserverを通じて更新されたアプリ情報を受信する責任があります

    public boolean reportAppProcStateInfo(String packageName, int uid, int procState) {
        int userId = UserHandle.getUserId(uid);
        ArrayMap<String, AppState> mAppStateInfoList = getAppStateInfoList(userId);

        //update mAppStateInfoList
        int index = mAppStateInfoList.indexOfKey(packageName);
        AppState appState = null;
        boolean ret = true;

        //if (DEBUG) Slog.d(TAG, "- reportAppProcStateInfo() E -");

        if (index >= 0) {
            appState = mAppStateInfoList.valueAt(index);
            // update procState
            appState.mProcState = procState;
            if (uid != appState.mUid) appState.mUid = uid;
            ret = false;
        } else {
            if (DEBUG) Slog.d(TAG, "reportAppProcStateInfo: appName:" + packageName + " uid:" + uid + " is not exist, create it");
            appState = buildAppState(packageName, userId, Event.NONE);
            mAppStateInfoList.put(packageName, appState);
        }

        return ret;
    }

buildAppState()

新しいAppStateを作成します

    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 {
            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) {
                procState = mUidState.get(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
            }
        }

        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;
    }

セブン、PowerController.java

電力の全体的な管理

1.PowerControllerはUsageStatsManagerInternal.AppStateEventChangeListenerを拡張します

onAppStateEventChangedを実装し、UsageStatsServiceから情報を受け取ります

    public void onAppStateEventChanged(String packageName, int userId, int state) {
        if (state == UsageEvents.Event.STANDBY_BUCKET_CHANGED || packageName == null) {
            if (DEBUG) Slog.d(TAG, " ignore event: STANDBY_BUCKET_CHANGED or null packageName for " + packageName);
            return;
        }
        android.util.Log.i("lzq", " onAppStateEventChanged packageName : " + packageName + "-- userId :" + userId + "-- state : " +state);
        msgHandler.sendMessage(msgHandler.obtainMessage(MSG_APP_STATE_CHANGED, userId, state, packageName));
    }

MSG_APP_STATE_CHANGEDを​​送信し、handleAppStateChanged()を呼び出します。これは、主にAppStateInfoCollector.javaのreportAppStateEventInfoに通知してアプリ情報を更新する役割を果たします。

    private void handleAppStateChanged(String packageName, int userId, int state) {
        int oldState = state;
        AppState appState = mAppStateInfoCollector.getAppState(packageName, userId);

        if (DEBUG) Slog.d(TAG, "- handleAppStateChanged() E -");

        /*if (mAppStatsCollectEnabled && mAppStatsServiceLoader != null) {
            mAppStatsServiceLoader.reportAppStateChanged(packageName, userId, state);
        }*/

        if (appState != null) {
            oldState = appState.mState;
            if (oldState == state)
                return;
        }

        if (mAppStateInfoCollector.reportAppStateEventInfo(packageName, userId, state)) {
            // Note: Bug 698133 appIdle fail -->BEG
            // Ugly: we have to check if doing special test
            // is special test, then
            //checkSpecialTesting(packageName);
            // Note: Bug 698133 appIdle 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;
        }

    }

2.実装されたIUidObserver

    final private IUidObserver mUidObserver = new IUidObserver.Stub() {
        @Override public void onUidStateChanged(int uid, int procState, long procStateSeq) throws RemoteException {
            synchronized (mUidStateLock) {
                updateUidStateLocked(uid, procState);
            }
            mAppStateInfoCollector.updateUidState(uid, procState);
        }

        @Override public void onUidGone(int uid, boolean disabled) throws RemoteException {
            synchronized (mUidStateLock) {
                removeUidStateLocked(uid);
            }
            mAppStateInfoCollector.removeUidState(uid);
        }

        @Override public void onUidActive(int uid) throws RemoteException {

        }


        @Override public void onUidIdle(int uid, boolean disabled) throws RemoteException {

        }

        @Override public void onUidCachedChanged(int uid, boolean cached) throws RemoteException {
        }

    };

アプリのプロセスが変更されると、onUidStateChangedが呼び出され、updateUidStateLocked()が呼び出されます。

    private void updateUidStateLocked(int uid, int uidState) {
        final int oldUidState = mUidState.get(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
        if (oldUidState != uidState) {
            String appName = null;
            // state changed, push updated rules
            mUidState.put(uid, uidState);

            try {
                appName = AppGlobals.getPackageManager().getNameForUid(uid);
            } catch (RemoteException e) {
                // can't happen; package manager is process-local
            }
            //android.util.Log.i("lzq", " updateUidStateLocked packageName : " + appName + "-- oldUidState :" + oldUidState + "-- uidState : " + uidState + " uid : " + uid);
            if (DEBUG) Slog.d(TAG, "updateUidStateLocked: packageName:" + appName + ", uid:" + uid
                + " state change from "  + Util.ProcState2Str(oldUidState) + " to " + Util.ProcState2Str(uidState));
            if (uidState == ActivityManager.PROCESS_STATE_CACHED_EMPTY) {
                if (DEBUG)
                    Slog.d(TAG, "updateUidStateLocked: packageName:" + appName + ", uid:" + uid + " changed from non-cached to cached_empty, just return!");
                return;
            }
            if ((null != appName) ) {
                msgHandler.sendMessage(msgHandler.obtainMessage(MSG_UID_STATE_CHANGED, uid, uidState, appName));
            }
        }

    }

これは主にMSG_UID_STATE_CHANGED情報を送信するためのもので、handleProcStateChanged()を呼び出します。

                case MSG_UID_STATE_CHANGED:
                    handleProcStateChanged((String)msg.obj, msg.arg1, msg.arg2);
                    break;
    private void handleProcStateChanged(String appName, int uid, int procState) {
        if (DEBUG) Slog.d(TAG, "- handleProcstateChanged() E - packageName:" + appName
            + " uid:" + uid + " procState:" + Util.ProcState2Str(procState));

        /*if (mAppStatsCollectEnabled && mAppStatsServiceLoader != null) {
            mAppStatsServiceLoader.reportAppProcStateChanged(appName, uid, procState);
        }*/

        if (mAppStateInfoCollector.reportAppProcStateInfo(appName, uid, procState)) {
            // Note: Bug 698133 appIdle fail -->BEG
            // Ugly: we have to check if doing special test
            // is special test, then
            //checkSpecialTesting(appName);
            // Note: Bug 698133 appIdle fail <--END
        }

        int userId = UserHandle.getUserId(uid);
        AppState appState = mAppStateInfoCollector.getAppState(appName, userId);

        if (appState == null) {
            Slog.w(TAG, "null appState for packageName:" + appName
                + " uid:" + uid + " procState:" + Util.ProcState2Str(procState));
            return;
        }

        // if app is stopped, notify WakelockConstraintHelper
        if (appState.mProcState == ActivityManager.PROCESS_STATE_CACHED_EMPTY) {
            appState.updateAppState(Event.NONE);
            appState.clearLaunchInfo();
            //mWakelockConstraintHelper.noteAppStopped(appState);
        }
    }

AppStateInfoCollectorのreportAppProcStateInfo()を呼び出して、アプリ情報を更新します

 

おすすめ

転載: blog.csdn.net/liu362732346/article/details/108652531