您的位置:首页 > 移动开发 > Android开发

Android6.0中Doze模式实现原理的源码分析

2016-11-19 15:27 453 查看
Doze模式是Android6.0上新出的一种模式,是一种全新的、低能耗的状态,在后台只有部分任务允许运行,其他都被强制停止。当用户一段时间内没有使用手机时,Doze模式通过延缓APP后台的CPU和网络活动来减少电量的消耗。

如果用户断开了充电连接,灭屏不动手机一段时间后会进入Doze模式。在Doze模式中系统尝试去通过减少应用的网络访问和CPU敏感的服务来保护电池。它也阻止应用访问网络、延迟应用的任务、同步和alarm。

系统定期退出Doze模式(maintenance window)去让app完成它们被延迟的动作,在maintenance window期间,系统运行所有挂起的任务、同步、alarm以及访问网络。如下图所示:



Doze模式的限制:

1.网络访问被暂停

2.忽略wakelock

3.alarm被延迟到下一个maintenance window执行

4.如果需要在Doze状态下启动设置的alarm,可以使用setAndAllowWhileIdle()或者setExactAndAllowWhileIdle()

5.当有setAlarmClock()的alarm启动时,系统会短暂退出Doze模式

6.系统不会扫描WiFi热点

7.系统不允许sync adapter运行

8.系统不允许JobScheduler运行

Doze模式在系统中主要是DeviceIdleController类来驱动,下面来分析下它:

DeviceIdleController的启动和初始化和之前分析的AlarmManagerService、JobSchedulerService等一样也是在SystemServer的startOtherServices()方法中启动的:

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

SystemServiceManager类的startService方法之前已经分析过,这里贴下代码:
private final ArrayList<SystemService> mServices = new ArrayList<SystemService>();

/**
* 创建并启动一个继承自SystemService类的系统服务。
*
* @param 一个继承自SystemService类的服务类
* @return 服务类的实例
* @throws 如果服务启动失败则抛RuntimeException异常
*/
@SuppressWarnings("unchecked")
public <T extends SystemService> T startService(Class<T> serviceClass) {
// 获取服务类的类名
final String name = serviceClass.getName();
Slog.i(TAG, "Starting " + name);

// 判断服务类是否是SystemService的子类
if (!SystemService.class.isAssignableFrom(serviceClass)) {
throw new RuntimeException("Failed to create " + name
+ ": service must extend " + SystemService.class.getName());
}
final T service;
try {
// 获取服务类包含一个Context参数的构造方法
Constructor<T> constructor = serviceClass.getConstructor(Context.class);
// 创建这个服务类的实例
service = constructor.newInstance(mContext);
} catch (InstantiationException ex) {
throw new RuntimeException("Failed to create service " + name
+ ": service could not be instantiated", ex);
} catch (IllegalAccessException ex) {
throw new RuntimeException("Failed to create service " + name
+ ": service must have a public constructor with a Context argument", ex);
} catch (NoSuchMethodException ex) {
throw new RuntimeException("Failed to create service " + name
+ ": service must have a public constructor with a Context argument", ex);
} catch (InvocationTargetException ex) {
throw new RuntimeException("Failed to create service " + name
+ ": service constructor threw an exception", ex);
}

// 把服务添加到mServices列表中,方便后续使用时取出
mServices.add(service);

try {
// 回调服务的onStart方法
service.onStart();
} catch (RuntimeException ex) {
throw new RuntimeException("Failed to start service " + name
+ ": onStart threw an exception", ex);
}
return service;
}

DeviceIdleController类的构造方法:
public final AtomicFile mConfigFile;
final MyHandler mHandler;

public DeviceIdleController(Context context) {
super(context);
// 创建原子操作文件deviceidle.xml
mConfigFile = new AtomicFile(new File(getSystemDir(), "deviceidle.xml"));
// 创建处理消息的handler,BackgroundThread是HandlerThread的子类
mHandler = new MyHandler(BackgroundThread.getHandler().getLooper());
}

// 获取data/system目录
private static File getSystemDir() {
return new File(Environment.getDataDirectory(), "system");
}

mHandler处理消息的代码后面再分析,先看onStart()方法:
/**
* 省电模式下能在后台运行的白名单,idle模式除外
*/
private final ArrayMap<String, Integer> mPowerSaveWhitelistAppsExceptIdle = new ArrayMap<>();

/**
* 所有省电模式下的白名单
*/
private final ArrayMap<String, Integer> mPowerSaveWhitelistApps = new ArrayMap<>();

/**
* APPID是否在idle模式外的白名单中
*/
private final SparseBooleanArray mPowerSaveWhitelistSystemAppIdsExceptIdle
= new SparseBooleanArray();

/**
* APPID是否在全模式的白名单中
*/
private final SparseBooleanArray mPowerSaveWhitelistSystemAppIds = new SparseBooleanArray();

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

synchronized (this) {
// 获取Doze模式是否开启的默认值,该参数在frameworks/base/core/res/res/values/config.xml文件中设置,默认值为false
mEnabled = getContext().getResources().getBoolean(
com.android.internal.R.bool.config_enableAutoPowerModes);
/// M: Config Doze and App Standby { MTK做的修改,可以直接修改这里的默认值来打开或关闭Doze模式
if (SystemProperties.get(CONFIG_AUTO_POWER, "0").equals("-1")) {
mEnabled = false;
} else if (SystemProperties.get(CONFIG_AUTO_POWER, "0").equals("1")) {
mEnabled = true;
}
/// Config Doze and App Standby }
// 从SystemConfig中获取默认系统应用白名单,该类之前在分析apk的安装过程时分析过,
// 主要是解析system/etc/sysconfig、system/etc/permissions目录下的各xml文件
SystemConfig sysConfig = SystemConfig.getInstance();
// 从系统配置文件中读取省电模式下能在后台运行的白名单(除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, 0);
if ((ai.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
int appid = UserHandle.getAppId(ai.uid);
mPowerSaveWhitelistAppsExceptIdle.put(ai.packageName, appid);
mPowerSaveWhitelistSystemAppIdsExceptIdle.put(appid, true);
}
} catch (PackageManager.NameNotFoundException e) {
}
}
// 从系统配置文件中读取省电模式下能在后台运行的白名单,包括Idle模式
ArraySet<String> allowPower = sysConfig.getAllowInPowerSave();
for (int i=0; i<allowPower.size(); i++) {
String pkg = allowPower.valueAt(i);
try {
ApplicationInfo ai = pm.getApplicationInfo(pkg, 0);
if ((ai.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
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) {
}
}

// 初始化常量类,后面有详细分析
mConstants = new Constants(mHandler, getContext().getContentResolver());

// 读取deviceidle.xml文件,解析该文件并将用户应用的白名单保存在map中
readConfigFileLocked();
// 将系统应用白名单和用户应用白名单合并
updateWhitelistAppIdsLocked();

// 初始化变量:屏幕为开启、充电状态为true、Doze模式为ACTIVE状态等
mScreenOn = true;
mCharging = true;
mState = STATE_ACTIVE;
mInactiveTimeout = mConstants.INACTIVE_TIMEOUT;
}

// 发布服务到ServiceManager和LocalService中
publishBinderService(Context.DEVICE_IDLE_CONTROLLER, new BinderService());
// LocalService后续用到时再分析
publishLocalService(LocalService.class, new LocalService());
}

onStart()方法中的初始化常量类操作:
/**
* 该类中所有的时间单位都是ms,这些常量跟settings数据库中的值保持一致。所有访问该常量类的类或方法都
* 必须持有DeviceIdleController对象锁
*/
private final class Constants extends ContentObserver {
// Key names stored in the settings value.
private static final String KEY_INACTIVE_TIMEOUT = "inactive_to";
private static final String KEY_SENSING_TIMEOUT = "sensing_to";
private static final String KEY_LOCATING_TIMEOUT = "locating_to";
private static final String KEY_LOCATION_ACCURACY = "location_accuracy";
private static final String KEY_MOTION_INACTIVE_TIMEOUT = "motion_inactive_to";
private static final String KEY_IDLE_AFTER_INACTIVE_TIMEOUT = "idle_after_inactive_to";
private static final String KEY_IDLE_PENDING_TIMEOUT = "idle_pending_to";
private static final String KEY_MAX_IDLE_PENDING_TIMEOUT = "max_idle_pending_to";
private static final String KEY_IDLE_PENDING_FACTOR = "idle_pending_factor";
private static final String KEY_IDLE_TIMEOUT = "idle_to";
private static final String KEY_MAX_IDLE_TIMEOUT = "max_idle_to";
private static final String KEY_IDLE_FACTOR = "idle_factor";
private static final String KEY_MIN_TIME_TO_ALARM = "min_time_to_alarm";
private static final String KEY_MAX_TEMP_APP_WHITELIST_DURATION =
"max_temp_app_whitelist_duration";
private static final String KEY_MMS_TEMP_APP_WHITELIST_DURATION =
"mms_temp_app_whitelist_duration";
private static final String KEY_SMS_TEMP_APP_WHITELIST_DURATION =
"sms_temp_app_whitelist_duration";

/**
* 切换到inactive状态后,INACTIVE_TIMEOUT时间后开始检测运动传感器以确定设备是否是静止状态。
* 因为在屏幕关闭时切换到inactive状态后我们不想连续运行重要的运动传感器
*/
public long INACTIVE_TIMEOUT;

/**
* Sensing状态的超时时间
*/
public long SENSING_TIMEOUT;

/**
* 进入空闲模式之前等待尝试修复位置信息的时间
*/
public long LOCATING_TIMEOUT;

/**
* 满足位置信息最大精度(单位:米)的要求以确保能够进入Idle模式。
* 会尝试修复位置信息或直到LOCATING_TIMEOUT时间到期
*/
public float LOCATION_ACCURACY;

/**
* 操作手机后,从切换到inactive状态后,下次检测操作手机需要等待的时间
*/
public long MOTION_INACTIVE_TIMEOUT;

/**
* 在inactive超时之后,等待监测重大操作的时间,以便让手机进入Idle状态
*/
public long IDLE_AFTER_INACTIVE_TIMEOUT;

/**
* 切换到Idle状态时的初始化时间,此时允许回到IDLE_PENDING(空闲延迟)状态允许系统正常运行直到回到Idle状态
*/
public long IDLE_PENDING_TIMEOUT;

/**
*进入到Idle模式后,系统能正常运行的最大时间段
*/
public long MAX_IDLE_PENDING_TIMEOUT;

/**
* 空闲延迟缩放因子
*/
public float IDLE_PENDING_FACTOR;

/**
* 在再次唤醒手机以便回到待机空闲并允许正常工作运行之前,想要处于空闲状态的时间
* 即:空闲持续时间
*/
public long IDLE_TIMEOUT;

/**
* 最大空闲持续时间
*/
public long MAX_IDLE_TIMEOUT;

/**
* 空闲持续缩放因子
*/
public float IDLE_FACTOR;

/**
* 进入空闲模式后,到下一次执行alarm的最小时间
*/
public long MIN_TIME_TO_ALARM;

/**
* 当一个应用接收到高优先级事件时,将其加入到临时白名单的最长时间
*/
public long MAX_TEMP_APP_WHITELIST_DURATION;

/**
* 将正在接收彩信的应用加入临时白名单的时间
*/
public long MMS_TEMP_APP_WHITELIST_DURATION;

/**
* 将正在接收短信的应用加入临时白名单的时间
*/
public long SMS_TEMP_APP_WHITELIST_DURATION;

private final ContentResolver mResolver;
// 创建','分割的键值对列表解析器,下面会分析该解析器
private final KeyValueListParser mParser = new KeyValueListParser(',');
private static final boolean DEBUG = false;
// 压缩时间的标记
private static final boolean COMPRESS_TIME = false;

public Constants(Handler handler, ContentResolver resolver) {
super(handler);
mResolver = resolver;
// 注册数据库变化监听
mResolver.registerContentObserver(
Settings.Global.getUriFor(Settings.Global.DEVICE_IDLE_CONSTANTS), false, this);
updateConstants();
}

@Override
public void onChange(boolean selfChange, Uri uri) {
updateConstants();
}

// 更新常量
private void updateConstants() {
synchronized (DeviceIdleController.this) {
try {
// 解析字符串
mParser.setString(Settings.Global.getString(mResolver,
Settings.Global.DEVICE_IDLE_CONSTANTS));
} catch (IllegalArgumentException e) {
// Failed to parse the settings string, log this and move on
// with defaults.
Slog.e(TAG, "Bad device idle settings", e);
}

INACTIVE_TIMEOUT = mParser.getLong(KEY_INACTIVE_TIMEOUT,
!COMPRESS_TIME ? 30 * 60 * 1000L : 3 * 60 * 1000L);
SENSING_TIMEOUT = mParser.getLong(KEY_SENSING_TIMEOUT,
!DEBUG ? 4 * 60 * 1000L : 60 * 1000L);
LOCATING_TIMEOUT = mParser.getLong(KEY_LOCATING_TIMEOUT,
!DEBUG ? 30 * 1000L : 15 * 1000L);
LOCATION_ACCURACY = mParser.getFloat(KEY_LOCATION_ACCURACY, 20);
MOTION_INACTIVE_TIMEOUT = mParser.getLong(KEY_MOTION_INACTIVE_TIMEOUT,
!COMPRESS_TIME ? 10 * 60 * 1000L : 60 * 1000L);
IDLE_AFTER_INACTIVE_TIMEOUT = mParser.getLong(KEY_IDLE_AFTER_INACTIVE_TIMEOUT,
!COMPRESS_TIME ? 30 * 60 * 1000L : 3 * 60 * 1000L);
IDLE_PENDING_TIMEOUT = mParser.getLong(KEY_IDLE_PENDING_TIMEOUT,
!COMPRESS_TIME ? 5 * 60 * 1000L : 30 * 1000L);
MAX_IDLE_PENDING_TIMEOUT = mParser.getLong(KEY_MAX_IDLE_PENDING_TIMEOUT,
!COMPRESS_TIME ? 10 * 60 * 1000L : 60 * 1000L);
IDLE_PENDING_FACTOR = mParser.getFloat(KEY_IDLE_PENDING_FACTOR,
2f);
IDLE_TIMEOUT = mParser.getLong(KEY_IDLE_TIMEOUT,
!COMPRESS_TIME ? 60 * 60 * 1000L : 6 * 60 * 1000L);
MAX_IDLE_TIMEOUT = mParser.getLong(KEY_MAX_IDLE_TIMEOUT,
!COMPRESS_TIME ? 6 * 60 * 60 * 1000L : 30 * 60 * 1000L);
IDLE_FACTOR = mParser.getFloat(KEY_IDLE_FACTOR,
2f);
MIN_TIME_TO_ALARM = mParser.getLong(KEY_MIN_TIME_TO_ALARM,
!COMPRESS_TIME ? 60 * 60 * 1000L : 6 * 60 * 1000L);
MAX_TEMP_APP_WHITELIST_DURATION = mParser.getLong(
KEY_MAX_TEMP_APP_WHITELIST_DURATION, 5 * 60 * 1000L);
MMS_TEMP_APP_WHITELIST_DURATION = mParser.getLong(
KEY_MMS_TEMP_APP_WHITELIST_DURATION, 60 * 1000L);
SMS_TEMP_APP_WHITELIST_DURATION = mParser.getLong(
KEY_SMS_TEMP_APP_WHITELIST_DURATION, 20 * 1000L);
}
}

void dump(PrintWriter pw) {
. . .
}
}

分析下KeyValueListParser类:
/**
* 根据一些分隔符解析key=value的键值对列表,并保存到Map中。可以通过key查询value,未查询到则返回默认值
* @hide
*/
public class KeyValueListParser {
private final ArrayMap<String, String> mValues = new ArrayMap<>();
private final TextUtils.StringSplitter mSplitter;

/**
* 用分隔符构造键值对列表解析器,可以调用setString(String)方法解析不同的字符串
*/
public KeyValueListParser(char delim) {
mSplitter = new TextUtils.SimpleStringSplitter(delim);
}

/**
*设置要解析的字符串,字符串格式如下:
* <pre>key1=value,key2=value,key3=value</pre>
*/
public void setString(String str) throws IllegalArgumentException {
mValues.clear();
if (str != null) {
mSplitter.setString(str);
for (String pair : mSplitter) {
int sep = pair.indexOf('=');
if (sep < 0) {
mValues.clear();
throw new IllegalArgumentException(
"'" + pair + "' in '" + str + "' is not a valid key-value pair");
}
// 解析的结果以键值对的形式保存在map中
mValues.put(pair.substring(0, sep).trim(), pair.substring(sep + 1).trim());
}
}
}

/**
* 根据key获取long型的value
*/
public long getLong(String key, long def) {
String value = mValues.get(key);
if (value != null) {
try {
return Long.parseLong(value);
} catch (NumberFormatException e) {
// fallthrough
}
}
return def;
}

/**
* 根据key获取float类型的value
*/
public float getFloat(String key, float def) {
String value = mValues.get(key);
if (value != null) {
try {
return Float.parseFloat(value);
} catch (NumberFormatException e) {
// fallthrough
}
}
return def;
}

/**
* 根据key获取String类型的value
*/
public String getString(String key, String def) {
String value = mValues.get(key);
if (value != null) {
return value;
}
return def;
}
}

回到onStart()方法中的readConfigFileLocked方法:
/**
* 省电模式下应用白名单
*/
private final ArrayMap<String, Integer> mPowerSaveWhitelistUserApps = new ArrayMap<>();

// 读取配置文件
void readConfigFileLocked() {
if (DEBUG) Slog.d(TAG, "Reading config from " + mConfigFile.getBaseFile());
mPowerSaveWhitelistUserApps.clear();
FileInputStream stream;
try {
stream = mConfigFile.openRead();
} catch (FileNotFoundException e) {
return;
}
try {
XmlPullParser parser = Xml.newPullParser();
parser.setInput(stream, StandardCharsets.UTF_8.name());
readConfigFileLocked(parser);
} catch (XmlPullParserException e) {
} finally {
try {
stream.close();
} catch (IOException e) {
}
}

}

// 解析配置文件,并把应用包名加入到应用白名单
private void readConfigFileLocked(XmlPullParser parser) {
final PackageManager pm = getContext().getPackageManager();

try {
int type;
while ((type = parser.next()) != XmlPullParser.START_TAG
&& type != XmlPullParser.END_DOCUMENT) {
;
}

if (type != XmlPullParser.START_TAG) {
throw new IllegalStateException("no start tag found");
}

int outerDepth = parser.getDepth();
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
continue;
}

String tagName = parser.getName();
if (tagName.equals("wl")) { // wl是whitelist的缩写
String name = parser.getAttributeValue(null, "n");
if (name != null) {
try {
ApplicationInfo ai = pm.getApplicationInfo(name, 0);
// 把应用包名和appid保存在map中
mPowerSaveWhitelistUserApps.put(ai.packageName,
UserHandle.getAppId(ai.uid));
} catch (PackageManager.NameNotFoundException e) {
}
}
} else {
Slog.w(TAG, "Unknown element under <config>: "
+ parser.getName());
XmlUtils.skipCurrentTag(parser);
}
}

} catch (IllegalStateException e) {
Slog.w(TAG, "Failed parsing config " + e);
} catch (NullPointerException e) {
Slog.w(TAG, "Failed parsing config " + e);
} catch (NumberFormatException e) {
Slog.w(TAG, "Failed parsing config " + e);
} catch (XmlPullParserException e) {
Slog.w(TAG, "Failed parsing config " + e);
} catch (IOException e) {
Slog.w(TAG, "Failed parsing config " + e);
} catch (IndexOutOfBoundsException e) {
Slog.w(TAG, "Failed parsing config " + e);
}
}

回到onStart()方法中的updateWhitelistAppIdsLocked方法:
/**
*idle模式外的应用白名单,该数组可以共享,因为一旦设置就不会被修改
*/
private int[] mPowerSaveWhitelistExceptIdleAppIdArray = new int[0];

/**
* idle模式外的应用白名单
*/
private final SparseBooleanArray mPowerSaveWhitelistExceptIdleAppIds = new SparseBooleanArray();

/**
* 全模式下的应用白名单,该数组可以共享,因为一旦设置就不会被修改
*/
private int[] mPowerSaveWhitelistAllAppIdArray = new int[0];

/**
* 全模式下的应用白名单
*/
private final SparseBooleanArray mPowerSaveWhitelistAllAppIds = new SparseBooleanArray();

private PowerManagerInternal mLocalPowerManager;

private void updateWhitelistAppIdsLocked() {
// 合并idle模式外的应用白名单
mPowerSaveWhitelistExceptIdleAppIdArray = buildAppIdArray(mPowerSaveWhitelistAppsExceptIdle,
mPowerSaveWhitelistUserApps, mPowerSaveWhitelistExceptIdleAppIds);
// 合并全模式的应用白名单
mPowerSaveWhitelistAllAppIdArray = buildAppIdArray(mPowerSaveWhitelistApps,
mPowerSaveWhitelistUserApps, mPowerSaveWhitelistAllAppIds);
// mLocalPowerManager参数在开机阶段完成初始化
if (mLocalPowerManager != null) {
if (DEBUG) {
Slog.d(TAG, "Setting wakelock whitelist to "
+ Arrays.toString(mPowerSaveWhitelistAllAppIdArray));
}
// 将合并后的白名单设置到PowerManagerService中
mLocalPowerManager.setDeviceIdleWhitelist(mPowerSaveWhitelistAllAppIdArray);
}
}

// 合并systemApps和userApps参数中的应用
private static int[] buildAppIdArray(ArrayMap<String, Integer> systemApps,
ArrayMap<String, Integer> userApps, SparseBooleanArray outAppIds) {
outAppIds.clear();
for (int i=0; i<systemApps.size(); i++) {
outAppIds.put(systemApps.valueAt(i), true);
}
for (int i=0; i<userApps.size(); i++) {
outAppIds.put(userApps.valueAt(i), true);
}
int size = outAppIds.size();
int[] appids = new int[size];
for (int i = 0; i < size; i++) {
appids[i] = outAppIds.keyAt(i);
}
return appids;
}

当SystemService Ready后会回调onBootPhase方法:
private static final String ACTION_STEP_IDLE_STATE =
"com.android.server.device_idle.STEP_IDLE_STATE";

public void onBootPhase(int phase) {
if (phase == PHASE_SYSTEM_SERVICES_READY) {
synchronized (this) {
// 初始化一些服务管理器,后续有时间会专门分析各服务
mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
mBatteryStats = BatteryStatsService.getService();
mLocalPowerManager = getLocalService(PowerManagerInternal.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);
mSigMotionSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_SIGNIFICANT_MOTION);
mLocationManager = (LocationManager) getContext().getSystemService(
Context.LOCATION_SERVICE);
mLocationRequest = new LocationRequest()
.setQuality(LocationRequest.ACCURACY_FINE)
.setInterval(0)
.setFastestInterval(0)
.setNumUpdates(1);
// 设备是否静止探测器(重力感应加速度、屏幕旋转)
mAnyMotionDetector = new AnyMotionDetector(
(PowerManager) getContext().getSystemService(Context.POWER_SERVICE),
mHandler, mSensorManager, this);

Intent intent = new Intent(ACTION_STEP_IDLE_STATE)
.setPackage("android")
.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
mAlarmIntent = PendingIntent.getBroadcast(getContext(), 0, intent, 0);

Intent intentSensing = new Intent(ACTION_STEP_IDLE_STATE)
.setPackage("android")
.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
mSensingAlarmIntent = PendingIntent.getBroadcast(getContext(), 0, intentSensing, 0);

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

// 注册电池电量变化、空闲状态步骤变化的广播
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_BATTERY_CHANGED);
filter.addAction(ACTION_STEP_IDLE_STATE);
getContext().registerReceiver(mReceiver, filter);

// 设置全模式白名单
mLocalPowerManager.setDeviceIdleWhitelist(mPowerSaveWhitelistAllAppIdArray);

// 注册屏幕显示的回调方法,屏幕状态发生变化时会回调下面的updateDisplayLocked方法
mDisplayManager.registerDisplayListener(mDisplayListener, null);
// 更新屏幕显示状态
updateDisplayLocked();
}
}
}

// 接收到相关广播的处理
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override public void onReceive(Context context, Intent intent) {
// 电量变化广播的处理
if (Intent.ACTION_BATTERY_CHANGED.equals(intent.getAction())) {
int plugged = intent.getIntExtra("plugged", 0);
updateChargingLocked(plugged != 0);
} else if (ACTION_STEP_IDLE_STATE.equals(intent.getAction())) {
synchronized (DeviceIdleController.this) {
// 该广播是在进入Inactive状态后30min/3min后发出的
// 空闲状态步骤变化的处理
stepIdleStateLocked();
}
}
}
};

先看下电量变化广播的处理:
// 强制进入idle模式,应该是调试时候用的,正式版本该参数一直为false
private boolean mForceIdle;

// 更新充电状态的处理
void updateChargingLocked(boolean charging) {
if (DEBUG) Slog.i(TAG, "updateChargingLocked: charging=" + charging);
if (!charging && mCharging) { // 非充电状态
mCharging = false;
if (!mForceIdle) {
// 非充电状态下,合适时机时切换到Inactive状态
becomeInactiveIfAppropriateLocked();
}
} else if (charging) { // 充电状态
mCharging = charging;
if (!mForceIdle) {
// 充电状态下,切换到Active状态
becomeActiveLocked("charging", Process.myUid());
}
}
}

电量变化广播的处理包括非充电状态和充电状态两种情况,先看下非充电状态的处理:
// 合适时机时切换到Inactive状态
void becomeInactiveIfAppropriateLocked() {
if (DEBUG) Slog.d(TAG, "becomeInactiveIfAppropriateLocked()");
if (((!mScreenOn && !mCharging) || mForceIdle) && mEnabled && mState == STATE_ACTIVE) {
// 符合条件时切换到Inactive状态
mState = STATE_INACTIVE;
if (DEBUG) Slog.d(TAG, "Moved from STATE_ACTIVE to STATE_INACTIVE");
// 由于状态变化,故需要重置空闲管理器
resetIdleManagementLocked();
// 设置发送ACTION_STEP_IDLE_STATE广播的alarm,延迟时间为30min/3min
scheduleAlarmLocked(mInactiveTimeout, false);
// log相关
EventLogTags.writeDeviceIdle(mState, "no activity");
}
}

// 重置空闲管理器
void resetIdleManagementLocked() {
mNextIdlePendingDelay = 0;
mNextIdleDelay = 0;
// 重置下次执行alarm的时间
cancelAlarmLocked();
// 重置Sensing状态
cancelSensingAlarmLocked();
// 重置Locating状态
cancelLocatingLocked();
// 停止检测重要运动
stopMonitoringSignificantMotion();
// 暂停设置是否静止的探测器
mAnyMotionDetector.stop();
}

// 重置下次执行alarm的时间
void cancelAlarmLocked() {
if (mNextAlarmTime != 0) {
mNextAlarmTime = 0;
mAlarmManager.cancel(mAlarmIntent);
}
}

// 重置Sensing状态
void cancelSensingAlarmLocked() {
if (mSensing) {
if (DEBUG) Slog.d(TAG, "cancelSensingAlarmLocked()");
mAlarmManager.cancel(mSensingAlarmIntent);
mSensing = false;
}
}

// 重置Locating状态
void cancelLocatingLocked() {
if (mLocating) {
// 移除掉通用位置监听器和GPS位置监听器
mLocationManager.removeUpdates(mGenericLocationListener);
mLocationManager.removeUpdates(mGpsLocationListener);
mLocating = false;
}
}

// 停止检测重要运动
void stopMonitoringSignificantMotion() {
if (DEBUG) Slog.d(TAG, "stopMonitoringSignificantMotion()");
if (mSigMotionActive) {
// 取消重要运动监听器,初始化的地方再详细介绍
mSensorManager.cancelTriggerSensor(mSigMotionListener, mSigMotionSensor);
mSigMotionActive = false;
}
}

// 设置发送ACTION_STEP_IDLE_STATE广播的alarm
void scheduleAlarmLocked(long delay, boolean idleUntil) {
if (DEBUG) Slog.d(TAG, "scheduleAlarmLocked(" + delay + ", " + idleUntil + ")");
if (mSigMotionSensor == null) {
// 如果设备没有重要操作传感器,则不能设置alarm,因为无法得知设备是否移动。
return;
}
mNextAlarmTime = SystemClock.elapsedRealtime() + delay;
// 重新设置发送ACTION_STEP_IDLE_STATE广播的alarm
if (idleUntil) {
mAlarmManager.setIdleUntil(AlarmManager.ELAPSED_REALTIME_WAKEUP,
mNextAlarmTime, mAlarmIntent);
} else {
mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
mNextAlarmTime, mAlarmIntent);
}
}

上面是非充电状态时的处理情况,下面看充电状态时的处理:
// 切换到Active状态
void becomeActiveLocked(String activeReason, int activeUid) {
if (DEBUG) Slog.i(TAG, "becomeActiveLocked, reason = " + activeReason);
if (mState != STATE_ACTIVE) {
// log相关
EventLogTags.writeDeviceIdle(STATE_ACTIVE, activeReason);
// 上报要切换到Active状态的消息
scheduleReportActiveLocked(activeReason, activeUid);
// 设置当前状态为Active状态,并重置Inactive的超时时间
mState = STATE_ACTIVE;
mInactiveTimeout = mConstants.INACTIVE_TIMEOUT;
// 重置空闲管理器,前面刚分析过
resetIdleManagementLocked();
}
}

// 上报要切换到Active状态的消息
void scheduleReportActiveLocked(String activeReason, int activeUid) {
Message msg = mHandler.obtainMessage(MSG_REPORT_ACTIVE, activeUid,
mState == STATE_IDLE ? 1 : 0, activeReason);
mHandler.sendMessage(msg);
}

下面看切换到Active状态之前的具体操作,这里需要看mHandler的代码了:
static final int MSG_REPORT_ACTIVE = 4;

final class MyHandler extends Handler {
MyHandler(Looper looper) {
super(looper);
}

@Override public void handleMessage(Message msg) {
if (DEBUG) Slog.d(TAG, "handleMessage(" + msg.what + ")");
switch (msg.what) {
. . .
case MSG_REPORT_ACTIVE: {
String activeReason = (String)msg.obj;
int activeUid = msg.arg1;
// 空闲状态切换到Active状态时需要发广播
boolean needBroadcast = msg.arg2 != 0;
// log相关
EventLogTags.writeDeviceIdleOffStart(
activeReason != null ? activeReason : "unknown");
// 设置PowerManagerService退出Doze模式
mLocalPowerManager.setDeviceIdleMode(false);
try {
/// M: integrate Doze and App Standby @{
if(null != getDataShapingService()) {
mDataShapingManager.setDeviceIdleMode(false);
}
/// integrate Doze and App Standby @}
// 设置网络、电量统计退出Doze模式
mNetworkPolicyManager.setDeviceIdleMode(false);
mBatteryStats.noteDeviceIdleMode(false, activeReason, activeUid);
} catch (RemoteException e) {
}
if (needBroadcast) {
// 发送广播通知其他服务更新各自状态,如:GPS、JobSchedulerService、
// SyncManager、UsageStatsService、WiFiServiceImpl等
getContext().sendBroadcastAsUser(mIdleIntent, UserHandle.ALL);
}
EventLogTags.writeDeviceIdleOffComplete();
} break;
. . .
}
}
}

电量变化广播的处理已经分析完了,下面看下另一个广播 ACTION_STEP_IDLE_STATE ,该广播是在进入Inactive状态30min/3min后发出的,该广播的处理逻辑如下:
void stepIdleStateLocked() {
if (DEBUG) Slog.d(TAG, "stepIdleStateLocked: mState=" + mState);
EventLogTags.writeDeviceIdleStep();

final long now = SystemClock.elapsedRealtime();
// 判断进入空闲模式后,是否到下一次要执行alarm的时间
if ((now+mConstants.MIN_TIME_TO_ALARM) > mAlarmManager.getNextWakeFromIdleTime()) {
// alarm就要执行了,如果当前状态不是Active状态则切换到Active状态
if (mState != STATE_ACTIVE) {
becomeActiveLocked("alarm", Process.myUid());
}
return;
}

switch (mState) {
case STATE_INACTIVE:
// 该case是在进入Inactive状态后30min/3min后执行的,故此时该检测是否有重要运动了
// 注册SigMotion传感器,检测重要的运动事件
startMonitoringSignificantMotion();
// 设置30min/3min后发送 ACTION_STEP_IDLE_STATE 广播的alarm
scheduleAlarmLocked(mConstants.IDLE_AFTER_INACTIVE_TIMEOUT, false);
// 设置Idle_Pending的延迟时间为5min/30s
mNextIdlePendingDelay = mConstants.IDLE_PENDING_TIMEOUT;
// 设置Idle的持续时间为1h/6min
mNextIdleDelay = mConstants.IDLE_TIMEOUT;
// 设置当前状态为IDLE_PENDING
mState = STATE_IDLE_PENDING;
if (DEBUG) Slog.d(TAG, "Moved from STATE_INACTIVE to STATE_IDLE_PENDING.");
EventLogTags.writeDeviceIdle(mState, "step");
break;
. . .
}
}

// 注册SigMotion传感器,检测重要的运动事件
void startMonitoringSignificantMotion() {
if (DEBUG) Slog.d(TAG, "startMonitoringSignificantMotion()");
if (mSigMotionSensor != null && !mSigMotionActive) {
// 注册传感器,传感器被触发时会回调mSigMotionListener接口
mSensorManager.requestTriggerSensor(mSigMotionListener, mSigMotionSensor);
// 设置传感器激活状态为true
mSigMotionActive = true;
}
}

// 传感器触发监听器
private final TriggerEventListener mSigMotionListener = new TriggerEventListener() {
@Override public void onTrigger(TriggerEvent event) {
synchronized (DeviceIdleController.this) {
// 有重要的运动事件时触发传感器监听器,执行相应操作
significantMotionLocked();
}
}
};

// 执行有重要的运动事件时的操作:切回到Active状态
void significantMotionLocked() {
if (DEBUG) Slog.d(TAG, "significantMotionLocked()");
// 触发监听器后传感器会关闭
// 当传感器关闭时,其触发器将自动移除
mSigMotionActive = false;
// 处理重要运动发生的情况,传递超时时间为10min/1min
handleMotionDetectedLocked(mConstants.MOTION_INACTIVE_TIMEOUT, "motion");
}

// 处理Idle_Pending状态下发生重要运动的情况:由于发生了重要运动,故非Active状态时要切回到Active状态,
// 然后在合适的时机还需要切回到Inactive状态
void handleMotionDetectedLocked(long timeout, String type) {
// 设备当前没有处于Active状态,故我们需要切回到Idle_Pending状态等待没有重要运动发生。
if (mState != STATE_ACTIVE) {
// 上报要切换到Active状态的消息
scheduleReportActiveLocked(type, Process.myUid());
// 设置当前状态为Active状态
mState = STATE_ACTIVE;
// 设置Inactive状态超时时间
mInactiveTimeout = timeout;
EventLogTags.writeDeviceIdle(mState, type);
// 合适时机时切换到Inactive状态
becomeInactiveIfAppropriateLocked();
}
}

如果Idle_Pending状态下30min/3min内没有触发重要运动事件,则会执行alarm操作:发送ACTION_STEP_IDLE_STATE 广播,对该广播的处理:
void stepIdleStateLocked() {
if (DEBUG) Slog.d(TAG, "stepIdleStateLocked: mState=" + mState);
EventLogTags.writeDeviceIdleStep();

final long now = SystemClock.elapsedRealtime();
// 判断进入空闲模式后,是否到下一次要执行alarm的时间
if ((now+mConstants.MIN_TIME_TO_ALARM) > mAlarmManager.getNextWakeFromIdleTime()) {
// alarm就要执行了,如果当前状态不是Active状态则切换到Active状态
if (mState != STATE_ACTIVE) {
becomeActiveLocked("alarm", Process.myUid());
}
return;
}

switch (mState) {
case STATE_IDLE_PENDING:
// 从Idle_Pending状态切换到Sensing状态
mState = STATE_SENSING;
if (DEBUG) Slog.d(TAG, "Moved from STATE_IDLE_PENDING to STATE_SENSING.");
EventLogTags.writeDeviceIdle(mState, "step");
// 设置4min/1min后发送ACTION_STEP_IDLE_STATE广播的alarm
scheduleSensingAlarmLocked(mConstants.SENSING_TIMEOUT);
// 取消之前的相关alarm
cancelSensingAlarmLocked();
cancelLocatingLocked();
// 开启任何运动检测
mAnyMotionDetector.checkForAnyMotion();
mNotMoving = false;
mLocated = false;
mLastGenericLocation = null;
mLastGpsLocation = null;
break;
. . .
}
}

// 设置发送 ACTION_STEP_IDLE_STATE 广播的alarm
void scheduleSensingAlarmLocked(long delay) {
if (DEBUG) Slog.d(TAG, "scheduleSensingAlarmLocked(" + delay + ")");
cancelSensingAlarmLocked();
mNextAlarmTime = SystemClock.elapsedRealtime() + delay;
mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
mNextAlarmTime, mSensingAlarmIntent);
mSensing = true;
}

先看开启检测AnyMotion,再看对广播的处理。开启运动检测调用的是AnyMotionDetector类中的checkForAnyMotion方法:
/*
* 获取加速度数据,直到确定AnyMotion的状态
*/
public void checkForAnyMotion() {
if (DEBUG) Slog.d(TAG, "checkForAnyMotion(). mState = " + mState);
// mState是当前测量状态,如果是非测量状态则先设置它为测量状态再进行检测
if (mState != STATE_ACTIVE) {
mState = STATE_ACTIVE;
if (DEBUG) Slog.d(TAG, "Moved from STATE_INACTIVE to STATE_ACTIVE.");
mCurrentGravityVector = null;
mPreviousGravityVector = null;
// 开始方向测量
startOrientationMeasurement();
}
}

/** 是否正在进行方向测量的标志. */
private boolean mMeasurementInProgress;
/** 加速度计采样间隔 */
private static final int SAMPLING_INTERVAL_MILLIS = 40;
/** 收集加速度计数据的持续时间 */
private static final long ACCELEROMETER_DATA_TIMEOUT_MILLIS = 3000;
/** 两次采样之间的时间间隔 */
private static final long ORIENTATION_MEASUREMENT_INTERVAL_MILLIS = 5000;

// 开始方向测量
private void startOrientationMeasurement() {
if (DEBUG) Slog.d(TAG, "startOrientationMeasurement: mMeasurementInProgress=" +
mMeasurementInProgress + ", (mAccelSensor != null)=" + (mAccelSensor != null));

if (!mMeasurementInProgress && mAccelSensor != null) {
// 注册传感器
if (mSensorManager.registerListener(mListener, mAccelSensor,
SAMPLING_INTERVAL_MILLIS * 1000)) {
mWakeLock.acquire();
mMeasurementInProgress = true;
mRunningStats.reset();
}

Message msg = Message.obtain(mHandler, mMeasurementTimeout);
msg.setAsynchronous(true);
// 发送3s后开始执行mMeasurementTimeout的消息
mHandler.sendMessageDelayed(msg, ACCELEROMETER_DATA_TIMEOUT_MILLIS);
}
}

// 传感器监听器
private final SensorEventListener mListener = new SensorEventListener() {
@Override
public void onSensorChanged(SensorEvent event) {
int status = RESULT_UNKNOWN;
synchronized (mLock) {
// 传感器变化则开始加速度计的采样
Vector3 accelDatum = new Vector3(SystemClock.elapsedRealtime(), event.values[0],
event.values[1], event.values[2]);
mRunningStats.accumulate(accelDatum);

// If we have enough samples, stop accelerometer data acquisition.
if (mRunningStats.getSampleCount() >= mNumSufficientSamples) {
// 采样数据满足要求时则停止采样
status = stopOrientationMeasurementLocked();
}
}
if (status != RESULT_UNKNOWN) {
// 回调DeviceIdleController中的接口
mCallback.onAnyMotionResult(status);
}
}

@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
};

// 检测3s后的ruunable
private final Runnable mMeasurementTimeout = new Runnable() {
@Override
public void run() {
int status = RESULT_UNKNOWN;
synchronized (mLock) {
if (DEBUG) Slog.i(TAG, "mMeasurementTimeout. Failed to collect sufficient accel " +
"data within " + ACCELEROMETER_DATA_TIMEOUT_MILLIS + " ms. Stopping " +
"orientation measurement.");
// 3s钟内没有收集到有效加速数据,则停止采样
status = stopOrientationMeasurementLocked();
}
if (status != RESULT_UNKNOWN) {
mCallback.onAnyMotionResult(status);
}
}
};

// 停止采样
private int stopOrientationMeasurementLocked() {
if (DEBUG) Slog.d(TAG, "stopOrientationMeasurement. mMeasurementInProgress=" +
mMeasurementInProgress);
int status = RESULT_UNKNOWN;
if (mMeasurementInProgress) {
// 一些注销、释放操作
mSensorManager.unregisterListener(mListener);
mHandler.removeCallbacks(mMeasurementTimeout);
mWakeLock.release();
long detectionEndTime = SystemClock.elapsedRealtime();
mMeasurementInProgress = false;
mPreviousGravityVector = mCurrentGravityVector;
mCurrentGravityVector = mRunningStats.getRunningAverage();
if (DEBUG) {
Slog.d(TAG, "mRunningStats = " + mRunningStats.toString());
String currentGravityVectorString = (mCurrentGravityVector == null) ?
"null" : mCurrentGravityVector.toString();
String previousGravityVectorString = (mPreviousGravityVector == null) ?
"null" : mPreviousGravityVector.toString();
Slog.d(TAG, "mCurrentGravityVector = " + currentGravityVectorString);
Slog.d(TAG, "mPreviousGravityVector = " + previousGravityVectorString);
}
mRunningStats.reset();
// 获取当前AnyMotion的状态
status = getStationaryStatus();
if (DEBUG) Slog.d(TAG, "getStationaryStatus() returned " + status);
if (status != RESULT_UNKNOWN) {
if (DEBUG) Slog.d(TAG, "Moved from STATE_ACTIVE to STATE_INACTIVE. status = " +
status);
// 手机移动则改变测量状态
mState = STATE_INACTIVE;
} else {
/*
* 由于某种原因导致测量不足则安排另一次采样
*/
if (DEBUG) Slog.d(TAG, "stopOrientationMeasurementLocked(): another measurement" +
" scheduled in " + ORIENTATION_MEASUREMENT_INTERVAL_MILLIS +
" milliseconds.");
Message msg = Message.obtain(mHandler, mSensorRestart);
msg.setAsynchronous(true);
// 5s后进行下一次采样
mHandler.sendMessageDelayed(msg, ORIENTATION_MEASUREMENT_INTERVAL_MILLIS);
}
}
return status;
}

/** 如果手机改变角度超过2度,则认为手机被移动. */
private final float THRESHOLD_ANGLE = 2f;
/** Threshold energy above which the device is considered moving. */
private final float THRESHOLD_ENERGY = 5f;
/**
* 两次采样有效时间间隔,超过该时间则认为采样无效
*/
private static final int STALE_MEASUREMENT_TIMEOUT_MILLIS = 2 * 60 * 1000;

/*
* 获取当前AnyMotion的状态
*/
public int getStationaryStatus() {
// 如果先前的重力矢量或当前的重力矢量为null,则返回unknown状态
if ((mPreviousGravityVector == null) || (mCurrentGravityVector == null)) {
return RESULT_UNKNOWN;
}
Vector3 previousGravityVectorNormalized = mPreviousGravityVector.normalized();
Vector3 currentGravityVectorNormalized = mCurrentGravityVector.normalized();
float angle = previousGravityVectorNormalized.angleBetween(currentGravityVectorNormalized);
if (DEBUG) Slog.d(TAG, "getStationaryStatus: angle = " + angle);
// 根据角度判断是否有移动
if ((angle < THRESHOLD_ANGLE) && (mRunningStats.getEnergy() < THRESHOLD_ENERGY)) {
return RESULT_STATIONARY;
} else if (Float.isNaN(angle)) {
/**
* Floating point rounding errors have caused the angle calcuation's dot product to
* exceed 1.0. In such case, we report RESULT_MOVED to prevent devices from rapidly
* retrying this measurement.
*/
return RESULT_MOVED;
}
long diffTime = mCurrentGravityVector.timeMillisSinceBoot -
mPreviousGravityVector.timeMillisSinceBoot;
// 判断该次采样是否有效,无效则返回unknown
if (diffTime > STALE_MEASUREMENT_TIMEOUT_MILLIS) {
if (DEBUG) Slog.d(TAG, "getStationaryStatus: mPreviousGravityVector is too stale at " +
diffTime + " ms ago. Returning RESULT_UNKNOWN.");
return RESULT_UNKNOWN;
}
return RESULT_MOVED;
}

// 5s后执行下一次采样
private final Runnable mSensorRestart = new Runnable() {
@Override
public void run() {
synchronized (mLock) {
startOrientationMeasurement();
}
}
};

检测之后回调到DeviceIdleController类中的onAnyMotionResult接口:
public void onAnyMotionResult(int result) {
if (DEBUG) Slog.d(TAG, "onAnyMotionResult(" + result + ")");
if (result == AnyMotionDetector.RESULT_MOVED) {
// 如果手机有移动,则需要切回到Active状态,然后在合适的时机再切到Inactive状态
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.");
// 如果手机没有移动,则根据当前Doze模式的不同状态执行不同的操作
if (mState == STATE_SENSING) {
// 如果当前是Sensing状态,则切换到Locating状态
synchronized (this) {
mNotMoving = true;
stepIdleStateLocked();
}
} else if (mState == STATE_LOCATING) {
// 因为Sensing状态有4min/1min超时发广播机制,故如果超时此时可能已经切换到Locating状态
synchronized (this) {
mNotMoving = true;
if (mLocated) {
stepIdleStateLocked();
}
}
}
}
}

Sensing状态4min/1min之后广播或者有检测结果时的处理:
void stepIdleStateLocked() {
if (DEBUG) Slog.d(TAG, "stepIdleStateLocked: mState=" + mState);
EventLogTags.writeDeviceIdleStep();

final long now = SystemClock.elapsedRealtime();
// 判断进入空闲模式后,是否到下一次要执行alarm的时间
if ((now+mConstants.MIN_TIME_TO_ALARM) > mAlarmManager.getNextWakeFromIdleTime()) {
// alarm就要执行了,如果当前状态不是Active状态则切换到Active状态
if (mState != STATE_ACTIVE) {
becomeActiveLocked("alarm", Process.myUid());
}
return;
}

switch (mState) {
case STATE_SENSING:
// 从Sensing状态切换到Locating状态
mState = STATE_LOCATING;
if (DEBUG) Slog.d(TAG, "Moved from STATE_SENSING to STATE_LOCATING.");
EventLogTags.writeDeviceIdle(mState, "step");
cancelSensingAlarmLocked();
// 设置3min/15s后发送ACTION_STEP_IDLE_STATE广播的alarm
scheduleSensingAlarmLocked(mConstants.LOCATING_TIMEOUT);
mLocating = true;
// 注册定位传感器
mLocationManager.requestLocationUpdates(mLocationRequest, mGenericLocationListener,
mHandler.getLooper());
// 如果有GPS的话,使用GPS定位
if (mLocationManager.getProvider(LocationManager.GPS_PROVIDER) != null) {
mHaveGps = true;
mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 5,
mGpsLocationListener, mHandler.getLooper());
} else {
mHaveGps = false;
}
break;
case STATE_LOCATING:
// 取消各种检测
cancelSensingAlarmLocked();
cancelLocatingLocked();
mAnyMotionDetector.stop();// 该case后面是没有break的
case STATE_IDLE_MAINTENANCE:
// 设置1h/6min后发送ACTION_STEP_IDLE_STATE广播的alarm
scheduleAlarmLocked(mNextIdleDelay, true);
if (DEBUG) Slog.d(TAG, "Moved to STATE_IDLE. Next alarm in " + mNextIdleDelay +
" ms.");
// 重新赋值为2h/12min
mNextIdleDelay = (long)(mNextIdleDelay * mConstants.IDLE_FACTOR);
if (DEBUG) Slog.d(TAG, "Setting mNextIdleDelay = " + mNextIdleDelay);
// 2h/12min与6h/30min比较,取小的
mNextIdleDelay = Math.min(mNextIdleDelay, mConstants.MAX_IDLE_TIMEOUT);
// 修改当前状态为Idle
mState = STATE_IDLE;
EventLogTags.writeDeviceIdle(mState, "step");
// 上报切换到Idle状态的消息MSG_REPORT_IDLE_ON
mHandler.sendEmptyMessage(MSG_REPORT_IDLE_ON);
break;
. . .
}
}

// 普通定位回调
private final LocationListener mGenericLocationListener = new LocationListener() {
@Override
public void onLocationChanged(Location location) {
synchronized (DeviceIdleController.this) {
receivedGenericLocationLocked(location);
}
}

@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}

@Override
public void onProviderEnabled(String provider) {
}

@Override
public void onProviderDisabled(String provider) {
}
};

// 普通定位位置发生变化的回调
void receivedGenericLocationLocked(Location location) {
if (mState != STATE_LOCATING) {
cancelLocatingLocked();
return;
}
if (DEBUG) Slog.d(TAG, "Generic location: " + location);
mLastGenericLocation = new Location(location);
// 定位精度大于20米且手机又GPS的话直接返回
if (location.getAccuracy() > mConstants.LOCATION_ACCURACY && mHaveGps) {
return;
}
mLocated = true;
if (mNotMoving) {
// 如果手机没有有移动,执行状态变化
stepIdleStateLocked();
}
}

// GPS定位回调
private final LocationListener mGpsLocationListener = new LocationListener() {
@Override
public void onLocationChanged(Location location) {
synchronized (DeviceIdleController.this) {
receivedGpsLocationLocked(location);
}
}

@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}

@Override
public void onProviderEnabled(String provider) {
}

@Override
public void onProviderDisabled(String provider) {
}
};

// GPS定位位置发生变化的回调
void receivedGpsLocationLocked(Location location) {
if (mState != STATE_LOCATING) {
cancelLocatingLocked();
return;
}
if (DEBUG) Slog.d(TAG, "GPS location: " + location);
mLastGpsLocation = new Location(location);
if (location.getAccuracy() > mConstants.LOCATION_ACCURACY) {
return;
}
mLocated = true;
if (mNotMoving) {
stepIdleStateLocked();
}
}

先看上报切换到Idle状态的消息,再看Idle状态下1h/6min后发送的ACTION_STEP_IDLE_STATE广播:
static final int MSG_REPORT_IDLE_ON = 2;

final class MyHandler extends Handler {
MyHandler(Looper looper) {
super(looper);
}

@Override public void handleMessage(Message msg) {
if (DEBUG) Slog.d(TAG, "handleMessage(" + msg.what + ")");
switch (msg.what) {
. . .
case MSG_REPORT_IDLE_ON: {
EventLogTags.writeDeviceIdleOnStart();
// 设置各相关服务为Idle状态
mLocalPowerManager.setDeviceIdleMode(true);
try {
/// M: integrate Doze and App Standby @{
if(null != getDataShapingService()) {
mDataShapingManager.setDeviceIdleMode(true);
}
/// integrate Doze and App Standby @}
mNetworkPolicyManager.setDeviceIdleMode(true);
mBatteryStats.noteDeviceIdleMode(true, null, Process.myUid());
} catch (RemoteException e) {
}
// 发送广播通知其他服务更新各自状态,如:GPS、JobSchedulerService、
// SyncManager、UsageStatsService、WiFiServiceImpl等
getContext().sendBroadcastAsUser(mIdleIntent, UserHandle.ALL);
EventLogTags.writeDeviceIdleOnComplete();
} break;
. . .
}
}
}

Idle状态下1h/6min后发送广播的处理:
void stepIdleStateLocked() {
if (DEBUG) Slog.d(TAG, "stepIdleStateLocked: mState=" + mState);
EventLogTags.writeDeviceIdleStep();

final long now = SystemClock.elapsedRealtime();
// 判断进入空闲模式后,是否到下一次要执行alarm的时间
if ((now+mConstants.MIN_TIME_TO_ALARM) > mAlarmManager.getNextWakeFromIdleTime()) {
// alarm就要执行了,如果当前状态不是Active状态则切换到Active状态
if (mState != STATE_ACTIVE) {
becomeActiveLocked("alarm", Process.myUid());
}
return;
}

switch (mState) {
case STATE_IDLE:
// 处于Idle状态的时间已经足够长了,现在该执行一些工作了
// 设置5min/30s后发送ACTION_STEP_IDLE_STATE广播的alarm
scheduleAlarmLocked(mNextIdlePendingDelay, false);
if (DEBUG) Slog.d(TAG, "Moved from STATE_IDLE to STATE_IDLE_MAINTENANCE. " +
"Next alarm in " + mNextIdlePendingDelay + " ms.");
// 取10min/1min跟10min/1min的最小值
mNextIdlePendingDelay = Math.min(mConstants.MAX_IDLE_PENDING_TIMEOUT,
(long)(mNextIdlePendingDelay * mConstants.IDLE_PENDING_FACTOR));
// 从Idle状态切换到Idle_Maintenance状态
mState = STATE_IDLE_MAINTENANCE;
EventLogTags.writeDeviceIdle(mState, "step");
// 上报退出Idle状态的消息MSG_REPORT_IDLE_OFF
mHandler.sendEmptyMessage(MSG_REPORT_IDLE_OFF);
break;
. . .
}
}

static final int MSG_REPORT_IDLE_OFF = 3;

final class MyHandler extends Handler {
MyHandler(Looper looper) {
super(looper);
}

@Override public void handleMessage(Message msg) {
if (DEBUG) Slog.d(TAG, "handleMessage(" + msg.what + ")");
switch (msg.what) {
. . .
case MSG_REPORT_IDLE_OFF: {
// 设置各服务退出Idle模式
EventLogTags.writeDeviceIdleOffStart("unknown");
mLocalPowerManager.setDeviceIdleMode(false);
try {
mNetworkPolicyManager.setDeviceIdleMode(false);
mBatteryStats.noteDeviceIdleMode(false, null, Process.myUid());
} catch (RemoteException e) {
}
// 发送广播通知其他服务更新各自状态,如:GPS、JobSchedulerService、
// SyncManager、UsageStatsService、WiFiServiceImpl等
getContext().sendBroadcastAsUser(mIdleIntent, UserHandle.ALL);
EventLogTags.writeDeviceIdleOffComplete();
} break;
. . .
}
}
}

Idle_Maintenance状态下5min/30s之后广播的处理,再次进入Idle状态:
void stepIdleStateLocked() {
if (DEBUG) Slog.d(TAG, "stepIdleStateLocked: mState=" + mState);
EventLogTags.writeDeviceIdleStep();

final long now = SystemClock.elapsedRealtime();
// 判断进入空闲模式后,是否到下一次要执行alarm的时间
if ((now+mConstants.MIN_TIME_TO_ALARM) > mAlarmManager.getNextWakeFromIdleTime()) {
// alarm就要执行了,如果当前状态不是Active状态则切换到Active状态
if (mState != STATE_ACTIVE) {
becomeActiveLocked("alarm", Process.myUid());
}
return;
}

switch (mState) {
case STATE_IDLE_MAINTENANCE:
// 设置1h/6min后发送ACTION_STEP_IDLE_STATE广播的alarm
scheduleAlarmLocked(mNextIdleDelay, true);
if (DEBUG) Slog.d(TAG, "Moved to STATE_IDLE. Next alarm in " + mNextIdleDelay +
" ms.");
// 重新赋值为2h/12min
mNextIdleDelay = (long)(mNextIdleDelay * mConstants.IDLE_FACTOR);
if (DEBUG) Slog.d(TAG, "Setting mNextIdleDelay = " + mNextIdleDelay);
// 2h/12min与6h/30min比较,取小的
mNextIdleDelay = Math.min(mNextIdleDelay, mConstants.MAX_IDLE_TIMEOUT);
// 修改当前状态为Idle
mState = STATE_IDLE;
EventLogTags.writeDeviceIdle(mState, "step");
// 上报切换到Idle状态的消息MSG_REPORT_IDLE_ON
mHandler.sendEmptyMessage(MSG_REPORT_IDLE_ON);
break;
. . .
}
}

在onBootPhase方法中还设置了displayListener监听器,代码如下:
// 监听屏幕显示状态变化
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();
}
}
}
};

private Display mCurDisplay;

// 更新屏幕显示状态
void updateDisplayLocked() {
// 获取显示相关信息
mCurDisplay = mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY);
// 当前显示状态是否为亮屏
boolean screenOn = mCurDisplay.getState() == Display.STATE_ON;
if (DEBUG) Slog.d(TAG, "updateDisplayLocked: screenOn=" + screenOn);
if (!screenOn && mScreenOn) {
mScreenOn = false;
if (!mForceIdle) {
// 亮屏-->灭屏则切换到Inactive状态,该方法前面已经分析过
becomeInactiveIfAppropriateLocked();
}
} else if (screenOn) {
mScreenOn = true;
if (!mForceIdle) {
// 灭屏-->亮屏则切换回Active状态,该方法前面也已经分析过
becomeActiveLocked("screen", Process.myUid());
}
}
}

上面分析完了Doze的几个状态之间的转换,下面看它所控制的几个服务在Doze模式下的处理逻辑。
当Doze模式切换到Idle状态时,会通知各相关服务进入Idle状态,其中我们看下PowerManagerService的处理:

// 设置PowerManagerService的Idle状态
public void setDeviceIdleMode(boolean enabled) {
setDeviceIdleModeInternal(enabled);
}

void setDeviceIdleModeInternal(boolean enabled) {
synchronized (mLock) {
if (mDeviceIdleMode != enabled) {
mDeviceIdleMode = enabled;
// 更新wakelock的状态
updateWakeLockDisabledStatesLocked();
if (enabled) {
EventLogTags.writeDeviceIdleOnPhase("power");
} else {
EventLogTags.writeDeviceIdleOffPhase("power");
}
}
}
}

// 更新wakelock的状态
private void updateWakeLockDisabledStatesLocked() {
boolean changed = false;
final int numWakeLocks = mWakeLocks.size();
// 遍历所有wakelock
for (int i = 0; i < numWakeLocks; i++) {
final WakeLock wakeLock = mWakeLocks.get(i);
// 只处理 PARTIAL_WAKE_LOCK 类型的wakelock
if ((wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK)
== PowerManager.PARTIAL_WAKE_LOCK) {
// 判断wakelock的disable值是否变化
if (setWakeLockDisabledStateLocked(wakeLock)) {
changed = true;
if (wakeLock.mDisabled) {
// 如果wakelock的mDisabled为true,说明该wakelock不可用则释放掉该wakelock
notifyWakeLockReleasedLocked(wakeLock);
} else {
// 没有变化则继续执行该wakelock了
notifyWakeLockAcquiredLocked(wakeLock);
}
}
}
}
if (changed) {
mDirty |= DIRTY_WAKE_LOCKS;
updatePowerStateLocked();
}
}

// 判断wakelock的disable值是否变化
private boolean setWakeLockDisabledStateLocked(WakeLock wakeLock) {
// 再次确认该wakelock是 PARTIAL_WAKE_LOCK 类型的
if ((wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK)
== PowerManager.PARTIAL_WAKE_LOCK) {
boolean disabled = false;
if (mDeviceIdleMode) {
// 如果当前是Doze模式的Idle状态,则判断wakelock所属应用是否在白名单中
final int appid = UserHandle.getAppId(wakeLock.mOwnerUid);
if (appid >= Process.FIRST_APPLICATION_UID &&
Arrays.binarySearch(mDeviceIdleWhitelist, appid) < 0 &&
Arrays.binarySearch(mDeviceIdleTempWhitelist, appid) < 0 &&
mUidState.get(wakeLock.mOwnerUid,
ActivityManager.PROCESS_STATE_CACHED_EMPTY)
> ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) {
// 如果应用不在白名单中则设置该wakelock的disable为true
disabled = true;
}
}
// 如果wakelock的disable的值有变化则返回true
if (wakeLock.mDisabled != disabled) {
wakeLock.mDisabled = disabled;
return true;
}
}
return false;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: