电量优化一直是Android
开发中的头等问题。本篇将分析一下Android M
以上电量优化措施电量优化相关的部分知识点。
注:文章参考MTK手机解决方案文档
通过本篇文章阅读,你将收获以下知识点:
1.Doze 模式
Doze 模式涉及的类如下:
Doze 模式状态
Doze 模式测试方法
开启Doze dubug 调试开关
欢迎关注微信公众号:程序员Android
微信公众号:ProgramAndroid
我们不是牛逼的程序员,我们只是程序开发中的垫脚石。
1.Doze 模式
当设备处于非充电、灭屏状态下静止一段时间,设备将进入睡眠状态,进入Doze
模式,延长电池使用时间。Doze
模式下系统会定期恢复正常操作,异步执行ap
p的一些同步数据等操作。比如很长时间不使用,系统会允许设备一天访问一次网络等。当设备处于充电状态下,系统将进入标准模式,app
执行操作将不被限制。
2.空闲状态下,优化app耗电
在用户没有使用app
的情况下,系统会使app
处于idle
状态,app
网络访问以及数据同步
3.Doze 模式下的限制措施
1.禁止网络访问Wake lock
Alarms(setAlarmClock() 、AlarmManager.setAndAllowwhileIdle()
这两个方法除外)WIFI
扫描
4.Doze 模式概要
Doze模式概要
5.Doze 模式涉及的类如下:
frameworks/base/services/core/java/com/android/server/DeviceIdleController.java
/**
* Keeps track of device idleness and drives low power mode based on that.
*/
public class DeviceIdleController extends SystemService
implements AnyMotionDetector.DeviceIdleCallback {
6. Doze 模式状态
ACTIVE:手机设备处于激活活动状态
INACTIVE:屏幕关闭进入非活动状态
IDLE_PENDING:每隔30分钟让App进入等待空闲预备状态
IDLE:空闲状态
IDLE_MAINTENANCE:处理挂起任务
Doze 模式状态
对应的 Doze 模式状态如下:
Doze模式状态图
active---> inactive ---> idle_pending
运动模式检测
void handleMotionDetectedLocked(long timeout, String type) { // The device is not yet active, so we want to go back to the pending idle
// state to wait again for no motion. Note that we only monitor for motion
// after moving out of the inactive state, so no need to worry about that.
boolean becomeInactive = false; if (mState != STATE_ACTIVE) {
scheduleReportActiveLocked(type, Process.myUid());
mState = STATE_ACTIVE;
mInactiveTimeout = timeout;
mCurIdleBudget = 0;
mMaintenanceStartTime = 0;
EventLogTags.writeDeviceIdle(mState, type);
addEvent(EVENT_NORMAL);
becomeInactive = true;
} if (mLightState == LIGHT_STATE_OVERRIDE) { // We went out of light idle mode because we had started deep idle mode... let's
// now go back and reset things so we resume light idling if appropriate.
mLightState = STATE_ACTIVE;
EventLogTags.writeDeviceIdleLight(mLightState, type);
becomeInactive = true;
} if (becomeInactive) {
becomeInactiveIfAppropriateLocked();
}
}
idle_pending ————>sensing
@Override
public void onAnyMotionResult(int result) { if (DEBUG) Slog.d(TAG, "onAnyMotionResult(" + result + ")"); if (result != AnyMotionDetector.RESULT_UNKNOWN) { synchronized (this) {
cancelSensingTimeoutAlarmLocked();
}
} if (result == AnyMotionDetector.RESULT_MOVED) { if (DEBUG) Slog.d(TAG, "RESULT_MOVED received."); synchronized (this) {
handleMotionDetectedLocked(mConstants.INACTIVE_TIMEOUT, "sense_motion");
}
} else if (result == AnyMotionDetector.RESULT_STATIONARY) { if (DEBUG) Slog.d(TAG, "RESULT_STATIONARY received."); if (mState == STATE_SENSING) { // If we are currently sensing, it is time to move to locating.
synchronized (this) {
mNotMoving = true;
stepIdleStateLocked("s:stationary");
}
} else if (mState == STATE_LOCATING) { // If we are currently locating, note that we are not moving and step
// if we have located the position.
synchronized (this) {
mNotMoving = true; if (mLocated) {
stepIdleStateLocked("s:stationary");
}
}
}
}
}
7.Doze 白名单
电量优化白名单deviceidle.xml)
//主要存放app包名adb shell dumpsys deviceidle whitelist
白名单代码保存部分代码如下
/**
* Package names the system has white-listed to opt out of power save restrictions,
* except for device idle mode.
*/
private final ArrayMap<String, Integer> mPowerSaveWhitelistAppsExceptIdle = new ArrayMap<>(); /**
* Package names the system has white-listed to opt out of power save restrictions for
* all modes.
*/
private final ArrayMap<String, Integer> mPowerSaveWhitelistApps = new ArrayMap<>(); /**
* Package names the user has white-listed to opt out of power save restrictions.
*/
private final ArrayMap<String, Integer> mPowerSaveWhitelistUserApps = new ArrayMap<>(); /**
* App IDs of built-in system apps that have been white-listed except for idle modes.
*/
private final SparseBooleanArray mPowerSaveWhitelistSystemAppIdsExceptIdle
= new SparseBooleanArray(); /**
* App IDs of built-in system apps that have been white-listed.
*/
private final SparseBooleanArray mPowerSaveWhitelistSystemAppIds = new SparseBooleanArray(); /**
* App IDs that have been white-listed to opt out of power save restrictions, except
* for device idle modes.
*/
private final SparseBooleanArray mPowerSaveWhitelistExceptIdleAppIds = new SparseBooleanArray(); /**
* Current app IDs that are in the complete power save white list, but shouldn't be
* excluded from idle modes. This array can be shared with others because it will not be
* modified once set.
*/
private int[] mPowerSaveWhitelistExceptIdleAppIdArray = new int[0]; /**
* App IDs that have been white-listed to opt out of power save restrictions.
*/
private final SparseBooleanArray mPowerSaveWhitelistAllAppIds = new SparseBooleanArray(); /**
* Current app IDs that are in the complete power save white list. This array can
* be shared with others because it will not be modified once set.
*/
private int[] mPowerSaveWhitelistAllAppIdArray = new int[0]; /**
* App IDs that have been white-listed by the user to opt out of power save restrictions.
*/
private final SparseBooleanArray mPowerSaveWhitelistUserAppIds = new SparseBooleanArray(); /**
* Current app IDs that are in the user power save white list. This array can
* be shared with others because it will not be modified once set.
*/
private int[] mPowerSaveWhitelistUserAppIdArray = new int[0];
8. Doze 模式测试方法
1.开启Dozeadb shell dumpsys deviceidle enable
// or MTK addadb shell setprop persist.config.AutoPowerModes 1
adb shell dumpsys battery unplug
Active ---idle_pending---sensing--location---idle --idle_mantenance
adb shell dumpsys deviceidle step
Doze
模式下的信息,包括电池电量优化白名单等adb shell dumpsys deviceidle
9. 开启Doze dubug 调试开关
默认false
关闭,设置为true
开启DeviceIdleController.java
private static final boolean DEBUG = false;
感谢您的阅读,谢谢!
欢迎关注微信公众号:程序员Android
微信公众号:ProgramAndroid
我们不是牛逼的程序员,我们只是程序开发中的垫脚石。
点击阅读原文,获取更多福利