Doze中的白名单
预备知识:
Doze机制是Google为了提升设备续航时间设计的一套方案,设备处在idle下,通过限制非白名单应用的网络、job执行时间、调整alarm触发时间、禁止wifi扫描、丢弃部分wakelock等行为,可以有效的降低设备在doze状态下的功耗。
而对于白名单应用,上述行为在设备进入到idle状态时,均不会进行限制。light idle和deep idle共用一套白名单。
doze白名单分类
doze中白名单有5个列表:
名称 | 含义 | doze中对应的数据结构 |
---|---|---|
system whitelist | 系统白名单 | mPowerSaveWhitelistApps |
system-except-idle | 系统except-idle白名单 | mPowerSaveWhitelistAppsExceptIdle |
user whitelist | 用户白白名单 | mPowerSaveWhitelistUserApps |
user-except-idle | 用户添加的ecept-idle白名单 | mPowerSaveWhitelistUserAppsExceptIdle |
temp whitelist | 临时白名单 | mTempWhitelistAppIdEndTimes |
(1)一般来说,手机厂商都会针对于user whitelist进行定制,根据业务需求添加不同应用进去。
(2)通过adb shell dumpsys deviceidle whitelist +/- pkgName也是在user whitelist中进行更改。
(3)temp whitelist属于临时白名单应用,比如后台应用想要拉起服务时,会将自身加入到临时doze白名单中,不受doze和power等模块的约束,时间到时后,会从名单中删除该应用。
(4)idle状态下,处在system whitelist、user whitelist和temp whitelist中的应用是不受任何限制的。
(5)只在系统except-idle白名单中的应用,在idle状态下仍然会被限制,但是在省电模式下会被豁免。
(6)mPowerSaveWhitelistAppsExceptIdle名单范围 = mPowerSaveWhitelistUserAppsExceptIdle + mPowerSaveWhitelistApps + 初始化时的mPowerSaveWhitelistAppsExceptIdle
system whitelist和system-except-idle whitelist:
初始化
这两个名单在DeviceidleController初始化的时候填充。
从代码中发现,mPowerSaveWhitelistApps中的应用包含在了mPowerSaveWhitelistAppsExceptIdle中。而mPowerSaveWhitelistApps中的应用一般都是带android、Qualcomm字段的应用。
public void onStart() {
final PackageManager pm = getContext().getPackageManager();
synchronized (this) {
mLightEnabled = mDeepEnabled = getContext().getResources().getBoolean(
com.android.internal.R.bool.config_enableAutoPowerModes);
SystemConfig sysConfig = SystemConfig.getInstance();
//从AOSP配置文件中读取以allow-in-power-save-except-idle开头的except-idle名单
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中
mPowerSaveWhitelistAppsExceptIdle.put(ai.packageName, appid);
mPowerSaveWhitelistSystemAppIdsExceptIdle.put(appid, true);
} catch (PackageManager.NameNotFoundException e) {
}
}
//从系统配置文件中读取以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中
mPowerSaveWhitelistAppsExceptIdle.put(ai.packageName, appid);
mPowerSaveWhitelistSystemAppIdsExceptIdle.put(appid, true);
//放入到mPowerSaveWhitelistApps中
mPowerSaveWhitelistApps.put(ai.packageName, appid);
mPowerSaveWhitelistSystemAppIds.put(appid, true);
} catch (PackageManager.NameNotFoundException e) {
}
}
.......
}
system whitelist 的adb命令操作内容:
通过adb命令操作system whitelist中的内容时:
命令 | 含义 |
---|---|
dumpsys deviceidle sys-whitelist -pkgName | 调用removeSystemPowerWhitelistAppInternal函数删除白名单应用 |
dumpsys deviceidle sys-whitelist +pkgName | 调用restoreSystemPowerWhitelistAppInternal函数添加白名单 |
系统白名单应用变化涉及到的结构:
名称 | 含义 |
---|---|
mPowerSaveWhitelistApps | 系统doze白名单应用 |
mRemovedFromSystemWhitelistApps | 从系统doze白名单应用中暂时移除的应用 |
removeSystemPowerWhitelistAppInternal函数:
1、应用从mPowerSaveWhitelistApps中移除;
2、将被移除的应用添加到mRemovedFromSystemWhitelistApps。
3、发送名单变化的广播:androod.os.action.POWER_SAVE_WHITELIST_CHANGED
4、新名单同步到AMS、power、和AppStateTracker模块
5、存到data/system/deviceilde.xml文件中
public boolean removeSystemPowerWhitelistAppInternal(String name) {
synchronized (this) {
//移除的应用必须是白名单的应用
if (!mPowerSaveWhitelistApps.containsKey(name)) {
return false;
}
// 添加到mRemovedFromSystemWhitelistApps中
mRemovedFromSystemWhitelistApps.put(name, mPowerSaveWhitelistApps.remove(name));
//发送名单变化的广播
reportPowerSaveWhitelistChangedLocked();
//向ams等其他模块通知名单变化,并将最新的名单发送过去
updateWhitelistAppIdsLocked();
//写入到文件中
writeConfigFileLocked();
return true;
}
}
restoreSystemPowerWhitelistAppInternal:
1、从mRemovedFromSystemWhitelistApps中获取之前被移除的应用;
2、重新添加到mPowerSaveWhitelistApps中;
3、发送名单变化的广播:androod.os.action.POWER_SAVE_WHITELIST_CHANGED
4、新名单同步到AMS、power、和AppStatsTrackerImpl模块
5、存到data/system/deviceilde.xml文件中
public boolean restoreSystemPowerWhitelistAppInternal(String name) {
synchronized (this) {
//如果mRemovedFromSystemWhitelistApps中不包含该应用,那么直接退出;
if (!mRemovedFromSystemWhitelistApps.containsKey(name)) {
return false;
}
//添加到mPowerSaveWhitelistApps中
mPowerSaveWhitelistApps.put(name, mRemovedFromSystemWhitelistApps.remove(name));
//发送名单变化的广播
reportPowerSaveWhitelistChangedLocked();
//向ams等其他模块通知名单变化,并将最新的名单发送过去
updateWhitelistAppIdsLocked();
//写入到文件中
writeConfigFileLocked();
return true;
}
}
mRemovedFromSystemWhitelistApps的作用:保证system 白名单的不变性。删除系统白名单时,将应用添加进去;添加系统白名单时,如果被添加的应用不在mRemovedFromSystemWhitelistApps中,那么就不是最开始初始化时的白名单应用,那么不准添加到system 白名单中。
system-except-idle whitelist的adb命令操作内容
dumpsys deviceidle except-idle-whitelist +pkgName | 调用addPowerSaveWhitelistExceptIdleInternal添加except idle白名单 |
dumpsys deviceidle except-idle-whitelist reset | 调用resetPowerSaveWhitelistExceptIdleInternal恢复初始化时的except-idle白名单 |
except-idle名单变化涉及到的数据结构:
mPowerSaveWhitelistAppsExceptIdle | 存储except-idle白名单 |
mPowerSaveWhitelistUserAppsExceptIdle | 存储新增加的except-idle白名单 |
mPowerSaveWhitelistUserAppsExceptIdle的作用和前文的mRemovedFromSystemWhitelistApps类似,reset时保持初始化时的except-idle名单。
addPowerSaveWhitelistExceptIdleInternal:
1、将应用加入到mPowerSaveWhitelistAppsExceptIdle和mPowerSaveWhitelistUserAppsExceptIdle中。
2、发送名单变化的广播:androod.os.action.POWER_SAVE_WHITELIST_CHANGED
3、新名单同步到AppStatsTrackerImpl模块
public boolean addPowerSaveWhitelistExceptIdleInternal(String name) {
synchronized (this) {
try {
final ApplicationInfo ai = getContext().getPackageManager().getApplicationInfo(name,
PackageManager.MATCH_ANY_USER);
//将应用加入到mPowerSaveWhitelistAppsExceptIdle
if (mPowerSaveWhitelistAppsExceptIdle.put(name, UserHandle.getAppId(ai.uid))
== null) {
//将应用加入到mPowerSaveWhitelistUserAppsExceptIdle
mPowerSaveWhitelistUserAppsExceptIdle.add(name);
//发送白名单变化的广播
reportPowerSaveWhitelistChangedLocked();
mPowerSaveWhitelistExceptIdleAppIdArray = buildAppIdArray(
mPowerSaveWhitelistAppsExceptIdle, mPowerSaveWhitelistUserApps,
mPowerSaveWhitelistExceptIdleAppIds);
passWhiteListsToForceAppStandbyTrackerLocked();//通知到AppStatsTrackerImpl
}
return true;
} catch (PackageManager.NameNotFoundException e) {
return false;
}
}
}
resetPowerSaveWhitelistExceptIdleInternal:
1、将之前添加的except-idle名单全部从mPowerSaveWhitelistAppsExceptIdle中移除
2、发送名单变化的广播:androod.os.action.POWER_SAVE_WHITELIST_CHANGED
3、新名单同步到AppStatsTrackerImpl模块
public void resetPowerSaveWhitelistExceptIdleInternal() {
synchronized (this) {
//将之前添加的except-idle名单全部从mPowerSaveWhitelistAppsExceptIdle中移除
if (mPowerSaveWhitelistAppsExceptIdle.removeAll(
mPowerSaveWhitelistUserAppsExceptIdle)) {
reportPowerSaveWhitelistChangedLocked();
mPowerSaveWhitelistExceptIdleAppIdArray = buildAppIdArray(
mPowerSaveWhitelistAppsExceptIdle, mPowerSaveWhitelistUserApps,
mPowerSaveWhitelistExceptIdleAppIds);
mPowerSaveWhitelistUserAppsExceptIdle.clear();
passWhiteListsToForceAppStandbyTrackerLocked();
}
}
}
user whitelist
各大手机厂商定制的名单均在这个列表中。通过adb shell dumpsys deviceidle whitelist相关的命令操作名单变化会改变mPowerSaveWhitelistUserApps中的内容,并且会通知到其他模块。
DeviceidleController中也有向外提供的方法,将应用加入到mPowerSaveWhitelistUserApps中,但是所需要的权限较高,一般systemServer进程和uid=1000的应用可以调用。
mPowerSaveWhitelistUserApps中的内容只能被addPowerSaveWhitelistAppsInternal和removePowerSaveWhitelistAppInternal改变,下面总结DeviceidleController中可能改变user名单的原因。
addPowerSaveWhitelistAppsInternal:
dumpsys deviceidle whitelist +pkgName | adb命令本地调试 |
addPowerSaveWhitelistApps | binder调用到该函数添加白名单应用(如电池应用) |
removePowerSaveWhitelistAppInternal:
dumpsys deviceidle whitelist -pkgName | adb命令本地调试 |
removePowerSaveWhitelistApp函数 | binder调用到该函数移除白名单应用(如电池应用) |
Intent.ACTION_PACKAGE_REMOVED | 应用被卸载 |
addPowerSaveWhitelistAppsInternal:
1、mPowerSaveWhitelistUserApps添加内容;
2、发送名单变化的广播:androod.os.action.POWER_SAVE_WHITELIST_CHANGED
3、新名单同步到AMS、power、和AppStatsTrackerImpl模块
4、存到data/system/deviceilde.xml文件中
private int addPowerSaveWhitelistAppsInternal(List<String> pkgNames) {
int numAdded = 0;
int numErrors = 0;
synchronized (this) {
for (int i = pkgNames.size() - 1; i >= 0; --i) {
final String name = pkgNames.get(i);
.....
try {
ApplicationInfo ai = getContext().getPackageManager().getApplicationInfo(name,
PackageManager.MATCH_ANY_USER);
//向mPowerSaveWhitelistUserApps添加内容
if (mPowerSaveWhitelistUserApps.put(name, UserHandle.getAppId(ai.uid))
== null) {
numAdded++;
}
} catch (PackageManager.NameNotFoundException e) {
}
}
if (numAdded > 0) {
//发送名单变化的广播
reportPowerSaveWhitelistChangedLocked();
//更新到power等模块
updateWhitelistAppIdsLocked();
//写到文件中
writeConfigFileLocked();
}
}
return pkgNames.size() - numErrors;
}
removePowerSaveWhitelistAppInternal:
1、mPowerSaveWhitelistUserApps
2、发送名单变化的广播:androod.os.action.POWER_SAVE_WHITELIST_CHANGED
3、新名单同步到AMS、power、和AppStatsTrackerImpl模块
4、存到data/system/deviceilde.xml文件中
public boolean removePowerSaveWhitelistAppInternal(String name) {
synchronized (this) {
if (mPowerSaveWhitelistUserApps.remove(name) != null) {
reportPowerSaveWhitelistChangedLocked();
updateWhitelistAppIdsLocked();
writeConfigFileLocked();
Counter.logIncrement(USER_ALLOWLIST_REMOVAL_METRIC_ID);
return true;
}
}
return false;
}
updateWhitelistAppIdsLocked:
新名单同步到AMS、power、和AppStatsTrackerImpl模块
private void updateWhitelistAppIdsLocked() {
mPowerSaveWhitelistExceptIdleAppIdArray = buildAppIdArray(mPowerSaveWhitelistAppsExceptIdle,
mPowerSaveWhitelistUserApps, mPowerSaveWhitelistExceptIdleAppIds);
mPowerSaveWhitelistAllAppIdArray = buildAppIdArray(mPowerSaveWhitelistApps,
mPowerSaveWhitelistUserApps, mPowerSaveWhitelistAllAppIds);
mPowerSaveWhitelistUserAppIdArray = buildAppIdArray(null,
mPowerSaveWhitelistUserApps, mPowerSaveWhitelistUserAppIds);
if (mLocalActivityManager != null) {//AMS
mLocalActivityManager.setDeviceIdleAllowlist(
mPowerSaveWhitelistAllAppIdArray, mPowerSaveWhitelistExceptIdleAppIdArray);
}
if (mLocalPowerManager != null) {//Power
mLocalPowerManager.setDeviceIdleWhitelist(mPowerSaveWhitelistAllAppIdArray);
}
passWhiteListsToForceAppStandbyTrackerLocked();//AppStatsTrackerImpl
}
总结:
本文总结了DeviceidController模块中不同类型白名单的作用,对名单变化的流程做了详细的分析。
后续会继续更新ams、power等模块如何处理doze白名单应用;以及在idle状态下是怎样限制应用的行为…