1. 程式人生 > >6 展訊Sprd設定-電池-PowerController.onPowerSaveModeChanged 函式介面

6 展訊Sprd設定-電池-PowerController.onPowerSaveModeChanged 函式介面

0. 前言

  1. 展訊Sprd設定-電池-setPowerSaveMode
  1. 展訊Sprd設定-電池-省電白名單設定-appPowerSaveConfig.xml
  1. 展訊Sprd設定-電池-onPowerSaveModeChanging介面
  1. 展訊Sprd設定-電池-PowerController.exitPowerSaveMode函式介面
  1. 展訊Sprd設定-電池-PowerController.enterPowerSaveMode 函式介面

原始碼走讀的開始位置

  • vendor/sprd/platform/frameworks/base/services/core/java/com/android/server/power/PowerController.java

1. PowerController.handlePowerSaveModeChanged

package com.android.server.power;

public class PowerController //extends IPowerController.Stub

    private List<PowerSaveHelper> mHelpers;

    // handle the power save mode changed
    private void handlePowerSaveModeChanged(int newMode) {

        if (mInitFinished && mPowerSaveMode == newMode) return;

        // notify helpers power save mode changing
        for (int i = 0; i < mHelpers.size(); i++) {
            PowerSaveHelper helper = mHelpers.get(i);
            helper.onPowerSaveModeChanging(newMode);
        }

        exitPowerSaveMode(mPowerSaveMode);

        enterPowerSaveMode(newMode);

        if (mPowerSaveMode != newMode) {
            Slog.e(TAG, "Something error!! mPowerSaveMode change fail!!old mode:" + mPowerSaveMode
                + " new mode:" + newMode);
        }

        // notify helpers power save mode changed
        for (int i = 0; i < mHelpers.size(); i++) {
            PowerSaveHelper helper = mHelpers.get(i);
            helper.onPowerSaveModeChanged(newMode);
        }

    }

其中註冊監聽的類分別為下面

[email protected]:/home/suhuazhi/8.1/op54# grep -irn "onPowerSaveModeChanged" vendor/sprd/platform/frameworks/
vendor/sprd/platform/frameworks/base/services/core/java/com/android/server/power/GpsConstraintHelper.java:171:    void onPowerSaveModeChanged(int mode) {
vendor/sprd/platform/frameworks/base/services/core/java/com/android/server/power/PowerGuruHelper.java:189:    void onPowerSaveModeChanged(int mode) {
vendor/sprd/platform/frameworks/base/services/core/java/com/android/server/power/BackgroundCleanHelper.java:404:    void onPowerSaveModeChanged(int mode) {
vendor/sprd/platform/frameworks/base/services/core/java/com/android/server/power/WakelockConstraintHelper.java:260:    void onPowerSaveModeChanged(int mode) {
vendor/sprd/platform/frameworks/base/services/core/java/com/android/server/power/PowerSaveHelper.java:48:    void onPowerSaveModeChanged(int mode) {
vendor/sprd/platform/frameworks/base/services/core/java/com/android/server/power/PowerController.java:3105:            helper.onPowerSaveModeChanged(newMode);
vendor/sprd/platform/frameworks/base/services/core/java/com/android/server/power/AppIdleHelper.java:201:    void onPowerSaveModeChanged(int mode) {

2. PowerSaveHelper.onPowerSaveModeChanged

PowerSaveHelper.onPowerSaveModeChanged 中涉及的資訊量很大,每個不同的Helper類都值得進行深入單獨瞭解。這塊展訊做的很詳細尤其是應用狀態的細化,音樂程序、下載進行、前臺程序、使用者活動程序、錄音程序、應用的執行狀態等等。

public class AppState {

    static final String TAG = "PowerController.AppState";

    private final boolean DEBUG = true;


    static final int TCP_TYPE_IPV4 = 0;
    static final int TCP_TYPE_IPV6 = 1;

    static final String NET_TCP_IPV4_PATH = "/proc/net/tcp";
    static final String NET_TCP_IPV6_PATH = "/proc/net/tcp6";

    // Audio type: 'IN' for recoder; 'OUT' for play music
    public static int AUDIO_TYPE_NONE = 0;
    public static int AUDIO_TYPE_IN = 1<<1;
    public static int AUDIO_TYPE_OUT = 1<<2;

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

    // if true, then track the count of Launch (MOVE_TO_FOREGROUND) during standby
    boolean mTrackingLaunchCountWhenStandby;
    int mLastLaunchCountWhenStandby;
    int mLaunchCountWhenStandby;
    boolean mStateChangedToFGDuringStandby;
    boolean mStateChangedStudyDone;

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

    // timestamp when app enter a state that can be evaluated to be put to PowerGuru blacklist
    long mBeginPowerGuruEvaluatedTimeStamp;

    // timestamp when app enter a state that can be evaluated to enter standby
    long mBeginEvaluatedTimeStamp;

    String mPackageName;
    int mUserId;

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

    // flags from ApplicationInfo
    int mFlags;

    // if this app is already set in PowerGuru constrained list
    boolean mInPowerGuruBlackList;

    // if this app is already set in App Idle state
    boolean mInAppStandby;
    // timestamp at entering AppStandby
    long mBeginStanbyTimeStamp;

    // Received bytes when starting Evaluated
    // only for the app that its procState is < PROCESS_STATE_FOREGROUND_SERVICE
    long mRxBytesWhenStartEvaluated;
    // timestamp at recoding rxBytes
    long mTimeStampForRxBytes;

    // the socket stream for this app
    ArrayList<String> mSocketStreams;
     // if doing download
    boolean mDoingDownload;
     // download is checked using a time slice (default 30s)
     // if the count of time slice using to complete detecting download
     // is >= 1, then we can sure that user use this app doing download
     // before standby
    int mUsedTimeSliceCount;

    // if set to true, this app is constrained for hold partial wake lock
    boolean mWakeLockContrained;

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


    // if set to true, then this app is constraint for GPS access
    boolean mGpsConstrained;

    // if set to true, then this app has active notification when enter standby
    boolean mHasNotification;
    boolean mHasNoClearNotification;

    // if set to true, then this app is playing music for a loop
    boolean mPlayingMusic;

    // if this a input method
    boolean mIsEnabledInputMethod;
    boolean mIsDefaultInputMethod;

    // current audio type
    int mAudioFlag;
    // last time a playing music behavior is observed
    long mLastTimePlayingMusicSeen;

    // wakeup alarm info
    long mStartRunningTime; // the start time of this running
    long mRunningDuration; // the running duration of the app
    int mTotalWakeupAlarmCount;

    // gps request info
    long mStartRequestGpsTime;
    long mRequestGpsDuration;
    int mRequestGpsCount; // the current request gps count

分別以下監聽事件

2.1 GpsConstraintHelper.onPowerSaveModeChanged

細節後續詳細研究,這裡是設定不同模式下,有個GPS超時後執行限制應用GPS行為的省電操作

package com.android.server.power;

public class GpsConstraintHelper extends PowerSaveHelper {

    // the idle time (ms) for app that can be stopped
    private long GPS_CONSTRAINT_IDLE_THRESHOLD = DEFAULT_GPS_CONSTRAINT_IDLE_THRESHOLD;

    @Override
    void onPowerSaveModeChanged(int mode) {
        if (DEBUG) Slog.d(TAG, "Current PowerSaveMode:" + mode);

        switch (mode) {
            case PowerManagerEx.MODE_LOWPOWER: // 低電量模式
            case PowerManagerEx.MODE_ULTRASAVING: // 超級省電模式
            case PowerManagerEx.MODE_POWERSAVING:// 省電模式
                GPS_CONSTRAINT_IDLE_THRESHOLD = mConstants.GPS_INACTIVE_TIMEOUT_LOWPOWER; // 5min
                break;

            case PowerManagerEx.MODE_PERFORMANCE:// 效能模式
            case PowerManagerEx.MODE_SMART:// 智慧省電模式
                GPS_CONSTRAINT_IDLE_THRESHOLD = mConstants.GPS_INACTIVE_TIMEOUT; // 30min
                break;
        }
    }
  • 限制APP使用GPS
import com.android.server.LocationManagerService;

    /**
     * appName: name of the app
     * enable: ture: the app can access GPS. false: the app cannot access GPS
     */
    public void noteGpsConstraintStateChanged(String appName, int uid, boolean enable) {
            updateGpsConstraintAppList(appName, uid, enable);
            if (mLocationService != null && mLocationService.needApplyAllProviderRequirements(appName, uid)) {
                mLocationService.applyAllProviderRequirements();
            }
    }
  • frameworks/base/services/core/java/com/android/server/LocationManagerService.java
    // NOTE: Bug #627645 low power Feature BEG-->
    public void applyAllProviderRequirements() {
        synchronized (mLock) {
            applyAllProviderRequirementsLocked();
        }
    }

    public boolean needApplyAllProviderRequirements(String packageName, int uid) {
        if (packageName == null) return false;

        synchronized (mLock) {
            for (LocationProviderInterface p : mProviders) {
                // If provider is already disabled, don't need to do anything
                if (p == null) {
                    continue;
                }
                ArrayList<UpdateRecord> records = mRecordsByProvider.get(p.getName());
                if (records != null) {
                    for (UpdateRecord record : records) {
                        //Slog.d(TAG, "App: " + record.mReceiver.mIdentity.mPackageName
                        //    + " uid:" + record.mReceiver.mIdentity.mUid + "  has location request!!");
                        if ( packageName.equals(record.mReceiver.mIdentity.mPackageName)
                            && uid == record.mReceiver.mIdentity.mUid) {
                            return true;
                        }
                    }
                }
            }
        }
        return false;
    }
    // <-- NOTE: Bug #627645 low power Feature END

2.2 PowerGuruHelper.onPowerSaveModeChanged

主要進行 AppState 中的狀態更新,黑白名單的智慧管理

package com.android.server.power;

// Class PowerGuruHelper to make decision of What apps should be put
// into the PowerGuru Constrained App List
public class PowerGuruHelper extends PowerSaveHelper{


    //Config Value
    //Max time in app bg state before to be added to powerguru blacklist
    private long POWERGURU_TIMEOUT =  (TEST ? 5 * 60 * 1000L : 20 * 60 * 1000L);

    @Override
    void onPowerSaveModeChanged(int mode) {
        if (DEBUG) Slog.d(TAG, "Current PowerSaveMode:" + mode);

        switch (mode) {
            case PowerManagerEx.MODE_LOWPOWER:// 低電量模式
            case PowerManagerEx.MODE_POWERSAVING:// 省電模式
            case PowerManagerEx.MODE_ULTRASAVING:// 超級省電模式
                POWERGURU_TIMEOUT = mConstants.POWERGURU_INACTIVE_TIMEOUT_LOWPOWER; //default (5 * 60 * 1000L);
                break;
            case PowerManagerEx.MODE_PERFORMANCE: // 效能模式
            case PowerManagerEx.MODE_SMART: // 智慧省電模式
                POWERGURU_TIMEOUT = mConstants.POWERGURU_INACTIVE_TIMEOUT; //default (20 * 60 * 1000L);
                break;
        }
    }
  • vendor\sprd\platform\frameworks\base\services\core\java\com\android\server\power\AppState.java
package com.android.server.power;

public class AppState {

    static final String TAG = "PowerController.AppState";
    
    // if this app is already set in PowerGuru constrained list
    boolean mInPowerGuruBlackList;
    
    
    public boolean updateAppPowerGuruState(boolean inBlacklist) {
        mInPowerGuruBlackList = inBlacklist;
        return true;
    }

2.3 BackgroundCleanHelper.onPowerSaveModeChanged

package com.android.server.power;

public class BackgroundCleanHelper extends PowerSaveHelper {

    // 當後臺清理,保留多少個應用
    // when doing bg app clean, max launched app that can be kept
    private int MAX_LAUNCHED_APP_KEEP = DEFAULT_MAX_LAUNCHED_APP_KEEP; //including the launcher app

    /**
     * This is MAX app will be keep, when doing background app clean
     */
    int BG_MAX_LAUNCHED_APP_KEEP = 3;
    int BG_MAX_LAUNCHED_APP_KEEP_LOWPOWER = 2;

    @Override
    void onPowerSaveModeChanged(int mode) {
        if (DEBUG) Slog.d(TAG, "Current PowerSaveMode:" + mode);

        int preMode = mPowerSaveMode;
        mPowerSaveMode = mode;

        //if (PowerManagerEx.MODE_ULTRASAVING == preMode
        //    && mode != preMode) {

        //    if (DEBUG) Slog.d(TAG, "Exit ultra saving mode kill com.sprd.powersavemodelauncher!");
        //    try {
        //        mActivityManager.forceStopPackage("com.sprd.powersavemodelauncher", UserHandle.myUserId());
        //    } catch (Exception e) {}
        //}

        switch (mode) {
            case PowerManagerEx.MODE_ULTRASAVING:// 超級省電模式
                List<String> ultramodeAppList = mPowerControllerInternal.getAppList_UltraMode();
                try {
                    List<RunningAppProcessInfo> runAppList = mRunAppList;
                    mRunAppList = null;
                    if (runAppList == null) {
                        Slog.d(TAG, "mRunAppList is null ");
                        // 獲取正在執行的應用
                        runAppList = mActivityManager.getRunningAppProcesses();
                    }
                    for (int i=0;i<runAppList.size();i++) {
                        RunningAppProcessInfo info = runAppList.get(i);
                        // 不殺超級省電白名單
                        if (ultramodeAppList.contains(info.pkgList[0])) {
                            Slog.d(TAG, "pkgList[0]: " + info.pkgList[0] + " in ultramodeAppList, skip it");
                            continue;
                        }

                        // not app in whitelist
                        // 不殺白名單應用
                        if (inCommonWhiteAppList(info.pkgList[0])) {
                            Slog.d(TAG, "pkgList[0]: " + info.pkgList[0] + " in CommonWhiteAppList, skip it");
                            continue;
                        }
                        
                        // 不殺 appState 狀態未知的應用
                        AppState appState = mAppStateInfoCollector.getAppState(info.pkgList[0], UserHandle.myUserId());
                        if (appState == null) {
                            Slog.d(TAG, "pkgList[0]: " + info.pkgList[0] + ", appState is null, skip it");
                            continue;
                        }
                        
                        // 不殺輸入法應用
                        // avoid kill input method
                        if (appState.mIsEnabledInputMethod) {
                            Slog.d(TAG, "pkgList[0]: " + info.pkgList[0] + " mIsEnabledInputMethod, skip it");
                            continue;
                        }
                        boolean bFind = false;
                        // 是否為輸入法應用
                        if (isSystemApp(appState)) {
                            // 是否為超級省電的黑名單
                            for(String s : mBlackAppListForUltraSaving) {
                                if(info.pkgList[0].contains(s)) {
                                    bFind = true;
                                    Slog.d(TAG, "pkgList[0]: " + info.pkgList[0] + " is system app in black list");
                                    break;
                                }
                            }
                            if (!bFind) {
                                Slog.d(TAG, "pkgList[0]: " + info.pkgList[0] + " is system app, skip it");
                                continue;
                            }
                        }
                        // 呼叫 ActivityManager.forceStopPackage 程序查殺
                        mActivityManager.forceStopPackage(info.pkgList[0], UserHandle.myUserId());
                        // do some cleaning for appState
                        if (appState != null) appState.clearLaunchInfo();
                        Slog.d(TAG, "enter ultrasaving mode, force stop:" + info.pkgList[0]);
                    }
                } catch (RemoteException e) {
                }
                //no break
            case PowerManagerEx.MODE_LOWPOWER:// 低電量模式
            case PowerManagerEx.MODE_POWERSAVING: // 省電模式 
                MAX_LAUNCHED_APP_KEEP = mConstants.BG_MAX_LAUNCHED_APP_KEEP_LOWPOWER; //including the launcher app// 當前 2 個
                break;

            case PowerManagerEx.MODE_PERFORMANCE:// 效能模式
            case PowerManagerEx.MODE_SMART:// 智慧省電模式
                MAX_LAUNCHED_APP_KEEP = mConstants.BG_MAX_LAUNCHED_APP_KEEP; //including the launcher app// 當前 3 個
                break;
        }

        // mPowerSaveMode = mode;
    }

2.4 WakelockConstraintHelper.onPowerSaveModeChanged

package com.android.server.power;

// Class WakeLockConstrainHelper to make decision of What apps should be put
// into a wake lock constrained list
// 決定一段時間後是否將APP進行後臺喚醒限制
public class WakelockConstraintHelper extends PowerSaveHelper {

    @Override
    void onPowerSaveModeChanged(int mode) {
        if (DEBUG) Slog.d(TAG, "Current PowerSaveMode:" + mode);

        switch (mode) {
            case PowerManagerEx.MODE_LOWPOWER:
            case PowerManagerEx.MODE_ULTRASAVING:
                WAKELOCK_CONSTRAIN_IDLE_THRESHOLD = mConstants.WAKELOCK_INACTIVE_TIMEOUT_LOWPOWER; // default 5min
                WAKE_LOCK_DISABLE_THRESHOLD = mConstants.WAKELOCK_CONSTRAINT_DURATION_LOWPOWER; // default 5s
                break;

            case PowerManagerEx.MODE_POWERSAVING:
                WAKELOCK_CONSTRAIN_IDLE_THRESHOLD = mConstants.WAKELOCK_INACTIVE_TIMEOUT_LOWPOWER; // default 5min
                WAKE_LOCK_DISABLE_THRESHOLD = mConstants.WAKELOCK_CONSTRAINT_DURATION; //30S
                break;

            case PowerManagerEx.MODE_PERFORMANCE:
            case PowerManagerEx.MODE_SMART:
                WAKELOCK_CONSTRAIN_IDLE_THRESHOLD = mConstants.WAKELOCK_INACTIVE_TIMEOUT; // 20min
                WAKE_LOCK_DISABLE_THRESHOLD = mConstants.WAKELOCK_CONSTRAINT_DURATION; //30S
                break;


        }
    }
}

2.5 AppIdleHelper.onPowerSaveModeChanged

package com.android.server.power;

// Class AppIdleHelper to make decision of What apps should be put
// into AppIdle state
// 智慧更新APP idle 狀態
public class AppIdleHelper extends PowerSaveHelper{

    @Override
    void onPowerSaveModeChanged(int mode) {
        if (DEBUG) Slog.d(TAG, "Current PowerSaveMode:" + mode);

        switch (mode) {
            case PowerManagerEx.MODE_LOWPOWER:
            case PowerManagerEx.MODE_POWERSAVING:
            case PowerManagerEx.MODE_ULTRASAVING:
                APPSTANDBY_TIMEOUT = mConstants.APPIDLE_INACTIVE_TIMEOUT_LOWPOWER; // 5min
                break;
            case PowerManagerEx.MODE_PERFORMANCE:
            case PowerManagerEx.MODE_SMART:
                APPSTANDBY_TIMEOUT = mConstants.APPIDLE_INACTIVE_TIMEOUT; // 20min
                break;
        }
    }
    
    /*
     * App cannot be constrained for App Idle:
     * 1. system app (app.uid <= Process.FIRST_APPLICATION_UID, this is enough ???)
     * 2. message app
     * 3. non-message app, but doing Download
     * 4. music app and is playing music
     * 5. unknown app type, and its procState <= PROCESS_STATE_FOREGROUND_SERVICE
     * 6. app in Doze white list
     * 7. Carrier App
     */
    private boolean canBeConstrained(AppState appState) {
        int procState = appState.mProcState;

        if (DEBUG_MORE) Slog.d(TAG, "appStandbyCanBeConstrained: uid:" + appState.mUid
            + " :" + appState.mPackageName + " procState:" + Util.ProcState2Str(procState)
            + " Group State:" + Util.AppState2Str(appState.mState));

        // 系統應用不進行管控
        // system app can not be constrained
        if (appState.mUid <= Process.FIRST_APPLICATION_UID)
            return false;

        // 白名單應用不進行管控
        if (inWhiteAppList(appState.mPackageName)) {
            if (DEBUG) Slog.d(TAG, "appStandbyCanBeConstrained:" +appState.mPackageName +" in my whitelist");
            return false;
        } else if (mBlackList.contains(appState.mPackageName)) {
            if (DEBUG) Slog.d(TAG, "appStandbyCanBeConstrained:" +appState.mPackageName +" in my blacklist");
            return true;
        }

        // 社交即時類應用不進行管控
        // message App can not be constrained
        int appType = mPowerControllerInternal.getAppCategoryType(appState.mPackageName);
        if (PowerDataBaseControl.MESSAGE == appType) {
            if (DEBUG) Slog.d(TAG, "appStandbyCanBeConstrained: " + appState.mPackageName + " Message App");

            return false;
        }

        // 應用程序不進行管控
        // playing music App can not be constrained
        if (PowerDataBaseControl.MUSIC == appType
            /*&& procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE*/) {
            if (mPowerControllerInternal.isPlayingMusic(appState)) {
                if (DEBUG) Slog.d(TAG, "appStandbyCanBeConstrained: " + appState.mPackageName + " Music is playing");

                return false;
            }
        }

        if (PowerDataBaseControl.UNKNOWN != appType
            && procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE
            && appState.mLaunchCount > 0) {
            if (mPowerControllerInternal.isPlayingMusic(appState)) {
                if (DEBUG) Slog.d(TAG, "appStandbyCanBeConstrained: " + appState.mPackageName + " Music is playing");

                return false;
            }
        }

        // doing download App can not be constrained
        if (procState <= ActivityManager.PROCESS_STATE_SERVICE) {
            // 正在進行下載的應用不進行管控,超級感興趣這個判斷
            if (mPowerControllerInternal.isAppDoingDownload(appState)) {
                if (DEBUG) Slog.d(TAG, "appStandbyCanBeConstrained: " + appState.mPackageName + " Doing Download");

                return false;
            }
        }

        // app type is unknown
        // and procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE
        // can not be constrained
        if (PowerDataBaseControl.UNKNOWN == appType
            && procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE
            && appState.mLaunchCount > 0
            && !mPowerControllerInternal.isAdminApp(appState.mPackageName)) {
            if (DEBUG) Slog.d(TAG, "appStandbyCanBeConstrained: " + appState.mPackageName + " UNKNOWN App type");

            return false;
        }


        // Carrier App can not be constrained
        if (isCarrierApp(appState.mPackageName)) {
            if (DEBUG) Slog.d(TAG, "appStandbyCanBeConstrained: " + appState.mPackageName + " a Carrier App");
            return false;
        }

        return true;
    }
}