美文网首页Android
Android之Doze分析

Android之Doze分析

作者: 锄禾豆 | 来源:发表于2022-01-17 09:16 被阅读0次

概述

从 Android 6.0(API 级别 23)开始,Android 引入了两项省电功能,通过管理应用在设备未连接至电源时的行为方式,
帮助用户延长电池寿命。当用户长时间未使用设备时,低电耗模式会延迟应用的后台 CPU 和网络活动,从而降低耗电量.
当设备处于低电耗模式时,应用对某些高耗电量资源的访问会延迟到维护期。电源管理限制中列出了具体的限制。

如果用户未插接设备的电源,在屏幕关闭的情况下,让设备在一段时间内保持不活动状态,那么设备就会进入低电耗模式。在低电耗模式下,系统会尝试通过限制应用访问占用大量网络和 CPU 资源的服务来节省电量。它还会阻止应用访问网络,并延迟其作业、同步和标准闹钟。
系统会定期退出低电耗模式一小段时间,让应用完成其延迟的活动。在此维护期内,系统会运行所有待处理的同步、作业和闹钟,并允许应用访问网络。

在每个维护期结束时,系统会再次进入低电耗模式,暂停网络访问并推迟作业、同步和闹钟。随着时间的推移,系统安排维护期的次数越来越少,这有助于在设备未连接至充电器的情况下长期处于不活动状态时降低耗电量。
一旦用户通过移动设备、打开屏幕或连接至充电器唤醒设备,系统就会立即退出低电耗模式,并且所有应用都会恢复正常活动。

adb查询

adb shell dumpsys deviceidle/adb shell cmd deviceidle

增加白名单
adb shell dumpsys deviceidle +com.android.test

删除白名单
adb shell dumpsys deviceidle -com.android.test

注意:
+后面直接跟包名
-后面直接跟包名

详情:
Device idle controller (deviceidle) commands:
  help
    Print this help text.
  step [light|deep]
    Immediately step to next state, without waiting for alarm.
  force-idle [light|deep]
    Force directly into idle mode, regardless of other device state.
  force-inactive
    Force to be inactive, ready to freely step idle states.
  unforce
    Resume normal functioning after force-idle or force-inactive.
  get [light|deep|force|screen|charging|network]
    Retrieve the current given state.
  disable [light|deep|all]
    Completely disable device idle mode.
  enable [light|deep|all]
    Re-enable device idle mode after it had previously been disabled.
  enabled [light|deep|all]
    Print 1 if device idle mode is currently enabled, else 0.
  whitelist
    Print currently whitelisted apps.
  whitelist [package ...]
    Add (prefix with +) or remove (prefix with -) packages.
  tempwhitelist
    Print packages that are temporarily whitelisted.
  tempwhitelist [-u] [package ..]
    Temporarily place packages in whitelist for 10 seconds.

代码简要分析

frameworks/base/services/core/java/com/android/server/SystemServer.java
frameworks/base/services/core/java/com/android/server/DeviceController.java

注:
1)7.1
2)无对应的Manager供三方应用使用

1.启动
SystemServer.java::ServerThread:run --> startOtherServices

    private void startOtherServices() {
      ···
      mSystemServiceManager.startService(DeviceIdleController.class);
      ···
    }

SystemServiceManager.startService即先创建DeviceIdleController对象,再执行onStart方法。根据初始化阶段会执行onBootPhase方法

2.DeviceIdleController构造函数

    public DeviceIdleController(Context context) {
        super(context);
        mConfigFile = new AtomicFile(new File(getSystemDir(), "deviceidle.xml"));//初始化配置文件/data/system/deviceidle.xml
        mHandler = new MyHandler(BackgroundThread.getHandler().getLooper());//使用后台线程创建对应的Handler
    }

2.DeviceIdleController.onStart

    public void onStart() {
        final PackageManager pm = getContext().getPackageManager();

        synchronized (this) {
            //设置是否开启Doze模式。从framework-res.apk中获取config_enableAutoPowerModes
            mLightEnabled = mDeepEnabled = getContext().getResources().getBoolean(
                    com.android.internal.R.bool.config_enableAutoPowerModes);
                    
            //初始化除doze模式之外,可以运行的系统应用白名单
            //来自/system/etc/sysconfig or permissions中xml allow-in-power-save-except-idle
            SystemConfig sysConfig = SystemConfig.getInstance();
            ArraySet<String> allowPowerExceptIdle = sysConfig.getAllowInPowerSaveExceptIdle();
            for (int i=0; i<allowPowerExceptIdle.size(); i++) {
                String pkg = allowPowerExceptIdle.valueAt(i);
                try {
                    ApplicationInfo ai = pm.getApplicationInfo(pkg,
                            PackageManager.MATCH_SYSTEM_ONLY);//系统应用的标签
                    int appid = UserHandle.getAppId(ai.uid);
                    
                    //mPowerSaveWhitelistAppsExceptIdle  包名对应appid
                    //mPowerSaveWhitelistSystemAppIdsExceptIdle appid对应true
                    //mPowerSaveWhitelistAppsExceptIdle 和 mPowerSaveWhitelistSystemAppIdsExceptIdle是共同体
                    mPowerSaveWhitelistAppsExceptIdle.put(ai.packageName, appid);
                    mPowerSaveWhitelistSystemAppIdsExceptIdle.put(appid, true);
                } catch (PackageManager.NameNotFoundException e) {
                }
            }
            
            //初始化在doze模式中也可以运行的系统应用白名单
            //来自/system/etc/sysconfig or permissions中xml allow-in-power-save
            ArraySet<String> allowPower = sysConfig.getAllowInPowerSave();
            for (int i=0; i<allowPower.size(); i++) {
                String pkg = allowPower.valueAt(i);
                try {
                    ApplicationInfo ai = pm.getApplicationInfo(pkg,
                            PackageManager.MATCH_SYSTEM_ONLY);
                    int appid = UserHandle.getAppId(ai.uid);
                    // These apps are on both the whitelist-except-idle as well
                    // as the full whitelist, so they apply in all cases.
                    mPowerSaveWhitelistAppsExceptIdle.put(ai.packageName, appid);
                    mPowerSaveWhitelistSystemAppIdsExceptIdle.put(appid, true);
                    mPowerSaveWhitelistApps.put(ai.packageName, appid);
                    mPowerSaveWhitelistSystemAppIds.put(appid, true);
                } catch (PackageManager.NameNotFoundException e) {
                }
            }

            //回绕Doze模式,展开数据监听。例如,doze模式进入的时长:INACTIVE_TIMEOUT
            mConstants = new Constants(mHandler, getContext().getContentResolver());

            //初始化用户设置Doze模式白名单:mPowerSaveWhitelistUserApps,可通过接口(addPowerSaveWhitelistApp)设置
            readConfigFileLocked();
            
            //将白名单更新到PowerManagerService和AlarmManagerService
            updateWhitelistAppIdsLocked();

            mNetworkConnected = true;
            mScreenOn = true;
            // Start out assuming we are charging.  If we aren't, we will at least get
            // a battery update the next time the level drops.
            mCharging = true;
            mState = STATE_ACTIVE;
            mLightState = LIGHT_STATE_ACTIVE;
            mInactiveTimeout = mConstants.INACTIVE_TIMEOUT;
        }

        mBinderService = new BinderService();
        //发布跨进程的共享服务
        publishBinderService(Context.DEVICE_IDLE_CONTROLLER, mBinderService);
        //发布本地进程内部的共享服务
        publishLocalService(LocalService.class, new LocalService());
    }

onStart做了初始化数据的业务

4.DeviceIdleController.onBootPhase

    public void onBootPhase(int phase) {
        if (phase == PHASE_SYSTEM_SERVICES_READY) {
            synchronized (this) {
                //初始化doze模式需要的对象。
                //mAlarmManager/mPowerManager/mConnectivityService/mNetworkPolicyManager/mDisplayManager/mSensorManager/mLocationManager
                mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
                mBatteryStats = BatteryStatsService.getService();
                mLocalPowerManager = getLocalService(PowerManagerInternal.class);
                mPowerManager = getContext().getSystemService(PowerManager.class);
                mActiveIdleWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
                        "deviceidle_maint");
                mActiveIdleWakeLock.setReferenceCounted(false);
                mGoingIdleWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
                        "deviceidle_going_idle");
                mGoingIdleWakeLock.setReferenceCounted(true);
                mConnectivityService = (ConnectivityService)ServiceManager.getService(
                        Context.CONNECTIVITY_SERVICE);
                mLocalAlarmManager = getLocalService(AlarmManagerService.LocalService.class);
                mNetworkPolicyManager = INetworkPolicyManager.Stub.asInterface(
                        ServiceManager.getService(Context.NETWORK_POLICY_SERVICE));
                mDisplayManager = (DisplayManager) getContext().getSystemService(
                        Context.DISPLAY_SERVICE);
                mSensorManager = (SensorManager) getContext().getSystemService(Context.SENSOR_SERVICE);
                //获取自定义的sensorid。默认0
                int sigMotionSensorId = getContext().getResources().getInteger(
                        com.android.internal.R.integer.config_autoPowerModeAnyMotionSensor);
                if (sigMotionSensorId > 0) {
                    mMotionSensor = mSensorManager.getDefaultSensor(sigMotionSensorId, true);
                }
                //是否采用手腕监测sensor
                if (mMotionSensor == null && getContext().getResources().getBoolean(
                        com.android.internal.R.bool.config_autoPowerModePreferWristTilt)) {
                    mMotionSensor = mSensorManager.getDefaultSensor(
                            Sensor.TYPE_WRIST_TILT_GESTURE, true);
                }
                if (mMotionSensor == null) {
                    // As a last ditch, fall back to SMD.
                    mMotionSensor = mSensorManager.getDefaultSensor(
                            Sensor.TYPE_SIGNIFICANT_MOTION, true);
                }

                //是否开启位置监测
                if (getContext().getResources().getBoolean(
                        com.android.internal.R.bool.config_autoPowerModePrefetchLocation)) {
                    mLocationManager = (LocationManager) getContext().getSystemService(
                            Context.LOCATION_SERVICE);
                    mLocationRequest = new LocationRequest()
                        .setQuality(LocationRequest.ACCURACY_FINE)
                        .setInterval(0)
                        .setFastestInterval(0)
                        .setNumUpdates(1);
                }

                //获取默认的偏移角度
                float angleThreshold = getContext().getResources().getInteger(
                        com.android.internal.R.integer.config_autoPowerModeThresholdAngle) / 100f;
                mAnyMotionDetector = new AnyMotionDetector(
                        (PowerManager) getContext().getSystemService(Context.POWER_SERVICE),
                        mHandler, mSensorManager, this, angleThreshold);

                mIdleIntent = new Intent(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
                mIdleIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
                        | Intent.FLAG_RECEIVER_FOREGROUND);
                mLightIdleIntent = new Intent(PowerManager.ACTION_LIGHT_DEVICE_IDLE_MODE_CHANGED);
                mLightIdleIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
                        | Intent.FLAG_RECEIVER_FOREGROUND);

                //通过广播监听充电状态、app状态、网络状态
                IntentFilter filter = new IntentFilter();
                filter.addAction(Intent.ACTION_BATTERY_CHANGED);
                getContext().registerReceiver(mReceiver, filter);

                filter = new IntentFilter();
                filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
                filter.addDataScheme("package");
                getContext().registerReceiver(mReceiver, filter);

                filter = new IntentFilter();
                filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
                getContext().registerReceiver(mReceiver, filter);

                //将doze白名单更新至PMS、AlarmManagerService
                mLocalPowerManager.setDeviceIdleWhitelist(mPowerSaveWhitelistAllAppIdArray);
                mLocalAlarmManager.setDeviceIdleUserWhitelist(mPowerSaveWhitelistUserAppIdArray);
                //监听屏幕显示状态,例如亮屏或息屏。注意:常规用监听SCREEN_ON/OFF形式
                mDisplayManager.registerDisplayListener(mDisplayListener, null);
                
                //更新屏幕显示状态
                updateDisplayLocked();
            }
            //更新网络状态
            updateConnectivityState(null);
        }
    }

onBootPhase主要做了一些初始化对象及监听事件

5.小结

1.如果想要关闭doze模式,处理如下参数:
config_enableAutoPowerModes=false
config_autoPowerModePrefetchLocation=false
config_autoPowerModePreferWristTilt=false
config_autoPowerModeAnyMotionSensor=0


2.如果在不关闭的情况下,对于某些app加白处理:
创建xml文件,并放在system/etc/sysconfig目录下
<config>
  <allow-in-power-save package="com.android.test"/>
</config>

3.Android 7开始,Doze有两者模式:轻度模式和深度模式,具体的差异大概如下:
LightDoze模式=灭屏+未充电
DeepDoze模式=灭屏+未充电+设备静止
注意:
设备静止=sensor未达到要求+location未达到要求

案例分析
LightDoze模式
1.状态介绍

//当前系统处于活动状态,比如亮屏
LIGHT_STATE_ACTIVE = 0;

//当前系统处于非活动状态,比如灭屏
LIGHT_STATE_INACTIVE = 1;

//当前系统还有没有完成的任务,需要等待任务完成才能进入到idle状态
LIGHT_STATE_PRE_IDLE = 3;

//当前系统处于lightDoze状态,此时网络、wakelock等都会受到限制
LIGHT_STATE_IDLE = 4;

//当前系统仍然处于lightDoze状态,但是需要等待系统有网络之后才能进入到维护状态
LIGHT_STATE_WAITING_FOR_NETWORK = 5;

//当前系统处于维护状态
LIGHT_STATE_IDLE_MAINTENANCE = 6;

//当前系统的lightDoze状态被覆盖了,开始进入DeepDoze状态
LIGHT_STATE_OVERRIDE = 7;

2.实现分析:当屏幕由亮屏变成息屏
1)屏幕监听框架
屏幕状态监听方法:

mDisplayManager.registerDisplayListener(mDisplayListener, null);

Listener实现:
    private final DisplayManager.DisplayListener mDisplayListener
            = new DisplayManager.DisplayListener() {
        @Override public void onDisplayAdded(int displayId) {
        }

        @Override public void onDisplayRemoved(int displayId) {
        }

        @Override public void onDisplayChanged(int displayId) {
            if (displayId == Display.DEFAULT_DISPLAY) {
                synchronized (DeviceIdleController.this) {
                    updateDisplayLocked();
                }
            }
        }
    };

2)具体流程
a)updateDisplayLocked

    void updateDisplayLocked() {
        mCurDisplay = mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY);
        // We consider any situation where the display is showing something to be it on,
        // because if there is anything shown we are going to be updating it at some
        // frequency so can't be allowed to go into deep sleeps.
        boolean screenOn = mCurDisplay.getState() == Display.STATE_ON;
        if (DEBUG) Slog.d(TAG, "updateDisplayLocked: screenOn=" + screenOn);
        if (!screenOn && mScreenOn) {//mScreenOn为上一次的状态,screenOn为这一次的状态
            mScreenOn = false;
            if (!mForceIdle) {//mForceIdle默认false。除非执行:adb shell dumpsys deviceidle light
                becomeInactiveIfAppropriateLocked();
            }
        } else if (screenOn) {
            mScreenOn = true;
            if (!mForceIdle) {
                becomeActiveLocked("screen", Process.myUid());
            }
        }
    }

初始化的mLightState的状态:mLightState = LIGHT_STATE_ACTIVE

b)becomeInactiveIfAppropriateLocked

    void becomeInactiveIfAppropriateLocked() {
        if (DEBUG) Slog.d(TAG, "becomeInactiveIfAppropriateLocked()");
        if ((!mScreenOn && !mCharging) || mForceIdle) {
            // Screen has turned off; we are now going to become inactive and start
            // waiting to see if we will ultimately go idle.
            if (mState == STATE_ACTIVE && mDeepEnabled) {//DeepDoze模式进入
                mState = STATE_INACTIVE;
                resetIdleManagementLocked();
                scheduleAlarmLocked(mInactiveTimeout, false);
                EventLogTags.writeDeviceIdle(mState, "no activity");
            }
            if (mLightState == LIGHT_STATE_ACTIVE && mLightEnabled) {//LightDoze模式进入
                mLightState = LIGHT_STATE_INACTIVE;//状态更新
                resetLightIdleManagementLocked();//重置LightDoze管理
                scheduleLightAlarmLocked(mConstants.LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT);//5分钟后进行状态更新
                EventLogTags.writeDeviceIdleLight(mLightState, "no activity");
            }
        }
    }
    
    void scheduleLightAlarmLocked(long delay) {
        if (DEBUG) Slog.d(TAG, "scheduleLightAlarmLocked(" + delay + ")");
        mNextLightAlarmTime = SystemClock.elapsedRealtime() + delay;
        mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
                mNextLightAlarmTime, "DeviceIdleController.light", mLightAlarmListener, mHandler);
    }

mLightState的状态更新:mLightState = LIGHT_STATE_INACTIVE

c)5分钟后执行scheduleLightAlarmLocked的alarm:mLightAlarmListener

    private final AlarmManager.OnAlarmListener mLightAlarmListener
            = new AlarmManager.OnAlarmListener() {
        @Override
        public void onAlarm() {
            synchronized (DeviceIdleController.this) {
                stepLightIdleStateLocked("s:alarm");
            }
        }
    };
    
    void stepLightIdleStateLocked(String reason) {
        if (mLightState == LIGHT_STATE_OVERRIDE) {
            return;
        }

        EventLogTags.writeDeviceIdleLightStep();

        switch (mLightState) {
            case LIGHT_STATE_INACTIVE:
                mCurIdleBudget = mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET;
                // Reset the upcoming idle delays.
                mNextLightIdleDelay = mConstants.LIGHT_IDLE_TIMEOUT;
                mMaintenanceStartTime = 0;
                if (!isOpsInactiveLocked()) {
                    
                    mLightState = LIGHT_STATE_PRE_IDLE;
                    EventLogTags.writeDeviceIdleLight(mLightState, reason);
                    scheduleLightAlarmLocked(mConstants.LIGHT_PRE_IDLE_TIMEOUT);
                    break;
                }
                // Nothing active, fall through to immediately idle.
            case LIGHT_STATE_PRE_IDLE:
            case LIGHT_STATE_IDLE_MAINTENANCE:
                ···
                mMaintenanceStartTime = 0;
                scheduleLightAlarmLocked(mNextLightIdleDelay);
                ···
                mLightState = LIGHT_STATE_IDLE;
                EventLogTags.writeDeviceIdleLight(mLightState, reason);
                addEvent(EVENT_LIGHT_IDLE);
                mGoingIdleWakeLock.acquire();
                mHandler.sendEmptyMessage(MSG_REPORT_IDLE_ON_LIGHT);
                break;
            case LIGHT_STATE_IDLE:
            case LIGHT_STATE_WAITING_FOR_NETWORK:
                if (mNetworkConnected || mLightState == LIGHT_STATE_WAITING_FOR_NETWORK) {
                    ···
                    scheduleLightAlarmLocked(mCurIdleBudget);
                    
                    mLightState = LIGHT_STATE_IDLE_MAINTENANCE;
                    ···
                    mHandler.sendEmptyMessage(MSG_REPORT_IDLE_OFF);
                } else {
                    ···
                    scheduleLightAlarmLocked(mNextLightIdleDelay);
                    
                    mLightState = LIGHT_STATE_WAITING_FOR_NETWORK;
                    EventLogTags.writeDeviceIdleLight(mLightState, reason);
                }
                break;
        }
    }

过程梳理
1.LIGHT_STATE_INACTIVE --> LIGHT_STATE_IDLE : 执行MSG_REPORT_IDLE_ON_LIGHT,关闭网络:mNetworkPolicyManager.setDeviceIdleMode(true);

2.LIGHT_STATE_INACTIVE --> LIGHT_STATE_PRE_IDLE -> LIGHT_STATE_IDLE :
执行MSG_REPORT_IDLE_ON_LIGHT,业务处理如下:
mLocalPowerManager.setDeviceIdleMode(false)
mLocalPowerManager.setLightDeviceIdleMode(true)
mNetworkPolicyManager.setDeviceIdleMode(true);
mBatteryStats.noteDeviceIdleMode(BatteryStats.DEVICE_IDLE_MODE_LIGHT, null, Process.myUid());


3.LIGHT_STATE_IDLE --无网络-->  LIGHT_STATE_WAITING_FOR_NETWORK --> LIGHT_STATE_IDLE_MAINTENANCE :
执行MSG_REPORT_IDLE_OFF,业务处理如下:
mLocalPowerManager.setDeviceIdleMode(false)
mLocalPowerManager.setLightDeviceIdleMode(false)
mNetworkPolicyManager.setDeviceIdleMode(false);
mBatteryStats.noteDeviceIdleMode(BatteryStats.DEVICE_IDLE_MODE_OFF,
                                null, Process.myUid());

4.LIGHT_STATE_IDLE <--有网络--> LIGHT_STATE_IDLE_MAINTENANCE :
执行MSG_REPORT_IDLE_OFF,业务处理如下:
mLocalPowerManager.setDeviceIdleMode(false)
mLocalPowerManager.setLightDeviceIdleMode(false)
mNetworkPolicyManager.setDeviceIdleMode(false);
mBatteryStats.noteDeviceIdleMode(BatteryStats.DEVICE_IDLE_MODE_OFF,
                                null, Process.myUid());

DeepDoze模式
1.状态介绍

//当前系统处于active状态
STATE_ACTIVE = 0;

//当前系统处于inactive状态,也就是灭屏且未充电状态,这个时候系统等待进入deepIdle
STATE_INACTIVE = 1;

//当前系统刚结束inactive状态,准备进入deepidle状态
STATE_IDLE_PENDING = 2;

//当前系统正在感应设备是否被移动
STATE_SENSING = 3;

//当前系统正在定位,并获取当前定位精度
STATE_LOCATING = 4;

//当前系统处于deepidle状态
STATE_IDLE = 5;

//当前系统处于维护状态
STATE_IDLE_MAINTENANCE = 6;

2.实现分析:当屏幕由亮屏变成息屏
1)参考LightDoze模式分析
2)具体流程
a)updateDisplayLocked -- LightDoze模式分析
初始化的mState的状态:mState = STATE_ACTIVE

b)becomeInactiveIfAppropriateLocked -- LightDoze模式分析
mState的状态更新:mState = STATE_INACTIVE

c)15分钟后执行scheduleAlarmLocked的alarm:mDeepAlarmListener

    private final AlarmManager.OnAlarmListener mDeepAlarmListener
            = new AlarmManager.OnAlarmListener() {
        @Override
        public void onAlarm() {
            synchronized (DeviceIdleController.this) {
                stepIdleStateLocked("s:alarm");
            }
        }
    };
    
    void stepIdleStateLocked(String reason) {
        if (DEBUG) Slog.d(TAG, "stepIdleStateLocked: mState=" + mState);
        EventLogTags.writeDeviceIdleStep();

        final long now = SystemClock.elapsedRealtime();
        if ((now+mConstants.MIN_TIME_TO_ALARM) > mAlarmManager.getNextWakeFromIdleTime()) {
            // Whoops, there is an upcoming alarm.  We don't actually want to go idle.
            if (mState != STATE_ACTIVE) {
                becomeActiveLocked("alarm", Process.myUid());
                becomeInactiveIfAppropriateLocked();
            }
            return;
        }

        switch (mState) {
            case STATE_INACTIVE:
                // We have now been inactive long enough, it is time to start looking
                // for motion and sleep some more while doing so.
                startMonitoringMotionLocked();
                scheduleAlarmLocked(mConstants.IDLE_AFTER_INACTIVE_TIMEOUT, false);
                // Reset the upcoming idle delays.
                mNextIdlePendingDelay = mConstants.IDLE_PENDING_TIMEOUT;
                mNextIdleDelay = mConstants.IDLE_TIMEOUT;
                mState = STATE_IDLE_PENDING;
                if (DEBUG) Slog.d(TAG, "Moved from STATE_INACTIVE to STATE_IDLE_PENDING.");
                EventLogTags.writeDeviceIdle(mState, reason);
                break;
            case STATE_IDLE_PENDING:
                mState = STATE_SENSING;
                if (DEBUG) Slog.d(TAG, "Moved from STATE_IDLE_PENDING to STATE_SENSING.");
                EventLogTags.writeDeviceIdle(mState, reason);
                scheduleSensingTimeoutAlarmLocked(mConstants.SENSING_TIMEOUT);
                cancelLocatingLocked();
                mNotMoving = false;
                mLocated = false;
                mLastGenericLocation = null;
                mLastGpsLocation = null;
                mAnyMotionDetector.checkForAnyMotion();
                break;
            case STATE_SENSING:
                cancelSensingTimeoutAlarmLocked();
                mState = STATE_LOCATING;
                if (DEBUG) Slog.d(TAG, "Moved from STATE_SENSING to STATE_LOCATING.");
                EventLogTags.writeDeviceIdle(mState, reason);
                scheduleAlarmLocked(mConstants.LOCATING_TIMEOUT, false);
                if (mLocationManager != null
                        && mLocationManager.getProvider(LocationManager.NETWORK_PROVIDER) != null) {
                    mLocationManager.requestLocationUpdates(mLocationRequest,
                            mGenericLocationListener, mHandler.getLooper());
                    mLocating = true;
                } else {
                    mHasNetworkLocation = false;
                }
                if (mLocationManager != null
                        && mLocationManager.getProvider(LocationManager.GPS_PROVIDER) != null) {
                    mHasGps = true;
                    mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 5,
                            mGpsLocationListener, mHandler.getLooper());
                    mLocating = true;
                } else {
                    mHasGps = false;
                }
                // If we have a location provider, we're all set, the listeners will move state
                // forward.
                if (mLocating) {
                    break;
                }

                // Otherwise, we have to move from locating into idle maintenance.
            case STATE_LOCATING:
                cancelAlarmLocked();
                cancelLocatingLocked();
                mAnyMotionDetector.stop();

            case STATE_IDLE_MAINTENANCE:
                scheduleAlarmLocked(mNextIdleDelay, true);
                if (DEBUG) Slog.d(TAG, "Moved to STATE_IDLE. Next alarm in " + mNextIdleDelay +
                        " ms.");
                mNextIdleDelay = (long)(mNextIdleDelay * mConstants.IDLE_FACTOR);
                if (DEBUG) Slog.d(TAG, "Setting mNextIdleDelay = " + mNextIdleDelay);
                mNextIdleDelay = Math.min(mNextIdleDelay, mConstants.MAX_IDLE_TIMEOUT);
                if (mNextIdleDelay < mConstants.IDLE_TIMEOUT) {
                    mNextIdleDelay = mConstants.IDLE_TIMEOUT;
                }
                mState = STATE_IDLE;
                if (mLightState != LIGHT_STATE_OVERRIDE) {
                    mLightState = LIGHT_STATE_OVERRIDE;
                    cancelLightAlarmLocked();
                }
                EventLogTags.writeDeviceIdle(mState, reason);
                addEvent(EVENT_DEEP_IDLE);
                mGoingIdleWakeLock.acquire();
                mHandler.sendEmptyMessage(MSG_REPORT_IDLE_ON);
                break;
            case STATE_IDLE:
                // We have been idling long enough, now it is time to do some work.
                mActiveIdleOpCount = 1;
                mActiveIdleWakeLock.acquire();
                scheduleAlarmLocked(mNextIdlePendingDelay, false);
                if (DEBUG) Slog.d(TAG, "Moved from STATE_IDLE to STATE_IDLE_MAINTENANCE. " +
                        "Next alarm in " + mNextIdlePendingDelay + " ms.");
                mMaintenanceStartTime = SystemClock.elapsedRealtime();
                mNextIdlePendingDelay = Math.min(mConstants.MAX_IDLE_PENDING_TIMEOUT,
                        (long)(mNextIdlePendingDelay * mConstants.IDLE_PENDING_FACTOR));
                if (mNextIdlePendingDelay < mConstants.IDLE_PENDING_TIMEOUT) {
                    mNextIdlePendingDelay = mConstants.IDLE_PENDING_TIMEOUT;
                }
                mState = STATE_IDLE_MAINTENANCE;
                EventLogTags.writeDeviceIdle(mState, reason);
                addEvent(EVENT_DEEP_MAINTENANCE);
                mHandler.sendEmptyMessage(MSG_REPORT_IDLE_OFF);
                break;
        }
    }
    
过程梳理:
1.STATE_INACTIVE --> STATE_IDLE_PENDING --> STATE_SENSING --sensor未动 --> STATE_LOCATING --location未动 --> STATE_IDLE :
执行MSG_REPORT_IDLE_ON,业务处理如下:
mLocalPowerManager.setDeviceIdleMode(true);
mLocalPowerManager.setLightDeviceIdleMode(false);
mNetworkPolicyManager.setDeviceIdleMode(true)
mBatteryStats.noteDeviceIdleMode(BatteryStats.DEVICE_IDLE_MODE_DEEP, null, Process.myUid());
注:
切换成STATE_IDLE,如果mLightState != LIGHT_STATE_OVERRIDE,则mLightState = LIGHT_STATE_OVERRIDE

2.STATE_IDLE <--> STATE_IDLE_MAINTENANCE:
执行MSG_REPORT_IDLE_OFF,业务处理如下:
mLocalPowerManager.setDeviceIdleMode(false)
mLocalPowerManager.setLightDeviceIdleMode(false)
mNetworkPolicyManager.setDeviceIdleMode(false);
mBatteryStats.noteDeviceIdleMode(BatteryStats.DEVICE_IDLE_MODE_OFF,
                                null, Process.myUid());

总结

1.LightDoze比DeepDoze各种状态的消化时间都短
2.LightDoze和DeepDoze都对网络都进行了限制,但是DeepDoze对PMS强化了状态
等等

参考学习

https://developer.android.com/training/monitoring-device-state/doze-standby
https://blog.csdn.net/gaugamela/article/details/52981984
https://juejin.cn/post/6844904008151203847

相关文章

网友评论

    本文标题:Android之Doze分析

    本文链接:https://www.haomeiwen.com/subject/zcathrtx.html