Android 8.1 Doze模式分析(五) Doze白名单及Debug方式

1.Doze模式下豁免的应用和白名单列表

1.什么是白名单列表?

一系列应用包名的集合。

2.有什么作用?

处于白名单列表中的应用,不受Doze的影响,即Doze不会对该应用进行限制,如该应用的Job、Alarm、网络等不会进行限制。

3.DeviceIdleController中对白名单的读取

Doze白名单有两类来源:

  • 1.用户设置
  • 2.预置到配置文件中。

用户设置的将最终写到/data/system/deviceidle.xml文件中。
来看下可以预值的配置文件有哪些?以及是如何读取的。在onStart()方法中,通过SystemConfig类读取了两类配置文件:

    @Override
    public void onStart() {
        synchronized (this) {

            SystemConfig sysConfig = SystemConfig.getInstance();
            //得到允许在省电模式豁免但不允许IDLE状态豁免的应用列表,读取的是/etc/permissions/platform.xml中
            //的元素的应用包名
            ArraySet<String> allowPowerExceptIdle = sysConfig.getAllowInPowerSaveExceptIdle();
            for (int i=0; i<allowPowerExceptIdle.size(); i++) {
                String pkg = allowPowerExceptIdle.valueAt(i);
                try {
                    //过滤只得到系统应用,并加入mPowerSaveWhitelistAppsExceptIdle中
                    ApplicationInfo ai = pm.getApplicationInfo(pkg,
                            PackageManager.MATCH_SYSTEM_ONLY);
                    int appid = UserHandle.getAppId(ai.uid);
                    mPowerSaveWhitelistAppsExceptIdle.put(ai.packageName, appid);
                    mPowerSaveWhitelistSystemAppIdsExceptIdle.put(appid, true);
                } catch (PackageManager.NameNotFoundException e) {
                }
            }
            //得到允许在省电模式和IDLE状态都豁免的应用列表,读取的是/etc/permissions/platform.xml中
            //的元素的应用包名
            ArraySet<String> allowPower = sysConfig.getAllowInPowerSave();
            for (int i=0; i<allowPower.size(); i++) {
                String pkg = allowPower.valueAt(i);
                try {
                    //过滤只得到系统应用,加入mPowerSaveWhitelistAppsExceptIdle和mPowerSaveWhitelistApps中
                    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) {
                }
            }
            //读取/data/system/deviceidle.xml中的配置应用到mPowerSaveWhitelistUserApps中
            readConfigFileLocked();
            //更新所有的白名单列表
            updateWhitelistAppIdsLocked();
        }

因此,对于系统应用,可以在/etc/permissions/platform.xml中预设,如果是三方应用,目前还没有可预置的,只能手动添加。或者可以自定义一个xml文件,在DeviceIdleController中进行读取。

注:/data/system分区下的数据一旦恢复出厂设置,就会被擦除,因此不能预置到/data/system/deviceidle.xml中。

4.如何添加应用到白名单列表?

  • 1.通过“设置”>“应用和通知”>“特殊应用权限”>“电池优化”中添加或移除;
  • 2.对于系统应用,预值到/etc/permissions/platform.xml中。

5.如何实现对白名单应用不受限?

在代码中看到,DeviceIdleController中只会收集白名单应用列表,然后将这个列表传递给对应模块做具体的限制工作:

//将白名单列表传递给AMS
mLocalActivityManager.setDeviceIdleWhitelist(mPowerSaveWhitelistAllAppIdArray);
//将白名单列表传递给PMS,申请wakelock时将会判断是否忽略
mLocalPowerManager.setDeviceIdleWhitelist(mPowerSaveWhitelistAllAppIdArray);
//将白名单列表传递给Alarm,设置Alarm时将会判断是否忽略
mLocalAlarmManager.setDeviceIdleUserWhitelist(mPowerSaveWhitelistUserAppIdArray);

此外,DIC还提供了用于获取白名单列表的接口,其他模块通过LocalService从DeviceIdleController中获取这个列表:

int[] getPowerSaveWhitelistUserAppIds() {
    synchronized (this) {
        return mPowerSaveWhitelistUserAppIdArray;
    }
}

如在DeviceIdleJobController中:

mDeviceIdleWhitelistAppIds =
        mLocalDeviceIdleController.getPowerSaveWhitelistUserAppIds();

NOTE:使用 setAndAllowWhileIdle()setExactAndAllowWhileIdle()设置的闹钟将不会被Doze限制。

2.Debug Doze

可以在adb shell环境下通过dumpsys命令来DebugDoze,不过首先必须将电池充电状态置为未充电状态:

adb shell dumpsys battery unplug   # 将电池充电状态设置为unplug

然后通过adb shell dumpsys deviceidle命令就可以进行Debug了,通过adb shell dumpsys deviceidle help来查看所有参数:

@ubuntu:~$ adb shell dumpsys deviceidle help
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.
  except-idle-whitelist [package ...|reset]
    Prefix the package with '+' to add it to whitelist or '=' to check if it is already whitelisted
    [reset] will reset the whitelist to it's original state
    Note that unlike  cmd, changes made using this won't be persisted across boots
  tempwhitelist
    Print packages that are temporarily whitelisted.
  tempwhitelist [-u USER] [-d DURATION] [package ..]
    Temporarily place packages in whitelist for DURATION milliseconds.
    If no DURATION is specified, 10 seconds is used

如:

adb shell dumpsys deviceidle enable light    # 开启LightDoze功能
adb shell dumpsys deviceidle step light     #每执行一次,将会进入到LightDoze下一状态
adb shell dumpsys deviceidle whitelist   # 查看当前Doze白名单
adb shell dumpsys deviceidle whitelist +com.android.settings     #将Settings加入白名单

掌握DIC的dumpsys命令,对于平时调试很有帮助。

至此,Doze模式的分析就告一段落了。

你可能感兴趣的:(Android系统开发)