Android 省电管理开发(一)APP状态监听

一,首先介绍下APP状态监听的两个入口:

1.UsageStatsService 收集,汇总和保留应用程序使用情况数据的服务。

2.IUidObserver 监听进程状态变化

我们做的App状态监听都是基于这连个入口展开

二,框架搭建

AppState.java APP状态的对象类,每个APP都作为一个单独的对象处理

AppStateInfoCollector.java APP状态管理类

PowerController.java 省电管理统筹管理类

Util.java 工具类

三,UsageStatsService 相关类介绍,以及源码修改

UsageEvents.java 实现了内部类Event,主要用于记录app的event

UsageStatsManagerInternal.java 抽象类,在UsageStatsService.java中实现

UsageStatsManager.java UsageStatsService的管理类

因为我们新建了PowerController.java作为省电管理统筹管理类,所以我们需要UsageStatsService给我们暴露出一个接口来实时获取到APP状态的变化

所以先在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,所以需要在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中添加的一个内部类,作为UsageStatsService和PowerController的中间桥梁

    /*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监听到app状态变化的时候,调用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 有五个方法,一般我们只需要关注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;//不存在的进程

五,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();
    }

}

六,AppStateInfoCollector.java

AppStateInfoCollector作为AppState的管理收集类,通过PowerController获取到app状态的变化,从而管理AppState

主要方法介绍:

reportAppStateEventInfo()

负责接收通过UsageStatsService-->PowerController更新的app信息

    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更新的app信息

    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

统筹管理Power

1.PowerController extends 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去更新app信息

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

    };

当app进程变化的时候,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()来更新app的信息

猜你喜欢

转载自blog.csdn.net/liu362732346/article/details/108652531