目录
6.1.2 userActivityNoUpdateLocked
一、功能介绍
PMS作用:
1)向上提供给应用程序接口,例如音频场景中保持系统唤醒、消息通知中唤醒手机屏幕场景;
2)向下决策HAL层以及Kernel层来控制设备待机状态,控制显示屏、背光灯、距离传感器、光线传感器等硬件设备的状态;
二、电源管理架构
三、UML
1)PMS服务继承SystemService类,说明是系统服务;实现了Watchdog.Monitor接口,重写其方法,将PMS服务纳入Watchdog监听
2)Constants、DisplayGroupPowerChangeListener、DreamManagerStateListener、PowerGroupWakefulnessChangeListener、static Injector、static NativeWrapper、static final ProfilePowerState、ForegroundProfileObserver、DeviceStateListener、LocalService、BinderService、SuspendBlockImpl、WakeLock、PowerManagerHandlerCallback、SettingsObserver、DockReceiver、BatteryReceiver 、UserSwitchedReceiver为PMS服务的内部类,Clock为内部接口
类名 | 作用 |
Constants | 设置系统Settings global power相关的属性值 |
DisplayGroupPowerChangeListener | 监听显示组(屏幕、显示器)电源状态发生变化 |
DreamManagerStateListener | 监听屏保状态的变化 |
PowerGroupWakefulnessChangeListener | 监听电源组(display、audio、sendor group等)休眠唤醒状态状态监听 |
static NativeWrapper | NativeWrapper对象封装相关native接口 |
static final ProfilePowerState | 记录用户的状态信息 |
ForegroundProfileObserver | 监听用户切换和前台配置文件切换事件 |
DeviceStateListener | 监听设备状态变化 |
LocalService | 提供进程内其它模块的API |
BinderService | 提供Binder Call API |
SuspendBlockImpl | 对wakelock管理实现,调用native方法 |
WakeLock | Wakelock类 |
PowerManagerHandlerCallback | power相关的一些callback回调实现 |
SettingsObserver | 监听系统设置发生变化状态 |
DockReceiver | 监听设备电源底座连接或断开状态,并当地更新电源状态 |
BatteryReceiver | 监听电池状态发生变化广播 |
UserSwitchedReceiver | 监听用户切换广播 |
Clock | 封装获取uptimeMillis和elapsedRealtime的接口 |
四、PMS模块解析
根据PMS对外提供的功能、内部的模块划分,解析各功能或模块的代码实现。
4.1 PMS启动初始化
public PowerManagerService(Context context) {
this(context, new Injector());
}
@VisibleForTesting
PowerManagerService(Context context, Injector injector) {
super(context);
mContext = context;
mBinderService = new BinderService(mContext); // 用于注册服务
mLocalService = new LocalService(); // 获取LocalService对象,注册服务到本地
mNativeWrapper = injector.createNativeWrapper(); // 调用native方法的对象
mSystemProperties = injector.createSystemPropertiesWrapper(); // systemproperity封装
mClock = injector.createClock(); // systemclock封装
mInjector = injector;
mHandlerThread = new ServiceThread(TAG,
Process.THREAD_PRIORITY_DISPLAY, /* allowIo= */ false); // THREAD_PRIORITY_DISPLAY是最高的优先级之一
mHandlerThread.start();
mHandler = injector.createHandler(mHandlerThread.getLooper(), // 创建handler,实现消息异步处理
new PowerManagerHandlerCallback());
mConstants = new Constants(mHandler); // 监听系统设置的变化,并根据设置项的值来更新Constants中的常量,以便在电源管理服务中使用这些常量来控制相关的行为
mAmbientDisplayConfiguration = mInjector.createAmbientDisplayConfiguration(context); // 获取环境显示的配置信息
mAmbientDisplaySuppressionController =
mInjector.createAmbientDisplaySuppressionController(
mAmbientSuppressionChangedCallback); // 环境显示是指设备或屏幕在休眠或关闭状态下,以一种低功耗的方式显示有限的信息
mAttentionDetector = new AttentionDetector(this::onUserAttention, mLock); // 检测用户当前是否注意手机并通知PowerManagerService更新用户活动
mFaceDownDetector = new FaceDownDetector(this::onFlip); // 检测手机是否放置于屏幕向下
mScreenUndimDetector = new ScreenUndimDetector(); // 检测用户手动取消屏幕变暗并且获取唤醒锁以暂时保持屏幕常亮
mBatterySavingStats = new BatterySavingStats(mLock); // 用于跟踪电池耗电速率,监测电池的电量变化和时间来计算电池的耗电速率
mBatterySaverPolicy =
mInjector.createBatterySaverPolicy(mLock, mContext, mBatterySavingStats); // 用于决定是否启用省电模式
mBatterySaverController = mInjector.createBatterySaverController(mLock, mContext,
mBatterySaverPolicy, mBatterySavingStats); // 负责省电模式转换逻辑
mBatterySaverStateMachine = mInjector.createBatterySaverStateMachine(mLock, mContext,
mBatterySaverController); // 用于决定何时启用/禁用省电模式
mLowPowerStandbyController = mInjector.createLowPowerStandbyController(mContext,
Looper.getMainLooper()); // 控制低功耗待机状态
mInattentiveSleepWarningOverlayController =
mInjector.createInattentiveSleepWarningController(); // 与系统UI通信,用于显示/隐藏非用户活动警告覆盖层(如低电量提示)
mPermissionCheckerWrapper = mInjector.createPermissionCheckerWrapper(); // 用于检测app的执行权限
mPowerPropertiesWrapper = mInjector.createPowerPropertiesWrapper(); // power属性
mDeviceConfigProvider = mInjector.createDeviceConfigParameterProvider(); // 访问和处理与 display相关的设备配置参数
mPowerGroupWakefulnessChangeListener = new PowerGroupWakefulnessChangeListener(); // 监听唤醒状态的变化,并根据需要更新相关的状态和执行相应的操作
// Save brightness values:
// Get float values from config.
// Store float if valid
// Otherwise, get int values and convert to float and then store.
final float min = mContext.getResources().getFloat(com.android.internal.R.dimen
.config_screenBrightnessSettingMinimumFloat); // 从资源文件中获取的屏幕亮度设置的最小值
final float max = mContext.getResources().getFloat(com.android.internal.R.dimen
.config_screenBrightnessSettingMaximumFloat); // 从资源文件中获取的屏幕亮度设置的最大值
final float def = mContext.getResources().getFloat(com.android.internal.R.dimen
.config_screenBrightnessSettingDefaultFloat); // 从资源文件中获取的屏幕亮度默认值
final float doze = mContext.getResources().getFloat(com.android.internal.R.dimen
.config_screenBrightnessDozeFloat);
final float dim = mContext.getResources().getFloat(com.android.internal.R.dimen
.config_screenBrightnessDimFloat);
if (min == INVALID_BRIGHTNESS_IN_CONFIG || max == INVALID_BRIGHTNESS_IN_CONFIG
|| def == INVALID_BRIGHTNESS_IN_CONFIG) {
mScreenBrightnessMinimum = BrightnessSynchronizer.brightnessIntToFloat(
mContext.getResources().getInteger(com.android.internal.R.integer
.config_screenBrightnessSettingMinimum));
mScreenBrightnessMaximum = BrightnessSynchronizer.brightnessIntToFloat(
mContext.getResources().getInteger(com.android.internal.R.integer
.config_screenBrightnessSettingMaximum));
mScreenBrightnessDefault = BrightnessSynchronizer.brightnessIntToFloat(
mContext.getResources().getInteger(com.android.internal.R.integer
.config_screenBrightnessSettingDefault));
} else {
mScreenBrightnessMinimum = min;
mScreenBrightnessMaximum = max;
mScreenBrightnessDefault = def;
}
if (doze == INVALID_BRIGHTNESS_IN_CONFIG) {
mScreenBrightnessDoze = BrightnessSynchronizer.brightnessIntToFloat(
mContext.getResources().getInteger(com.android.internal.R.integer
.config_screenBrightnessDoze));
} else {
mScreenBrightnessDoze = doze;
}
if (dim == INVALID_BRIGHTNESS_IN_CONFIG) {
mScreenBrightnessDim = BrightnessSynchronizer.brightnessIntToFloat(
mContext.getResources().getInteger(com.android.internal.R.integer
.config_screenBrightnessDim));
} else {
mScreenBrightnessDim = dim;
}
synchronized (mLock) {
// 系统启动阶段,获取保持cpu唤醒状态的wakelock
mBootingSuspendBlocker =
mInjector.createSuspendBlocker(this, "PowerManagerService.Booting");
// 在特定情况下,如app需要保持cpu运行,获取保持cpu唤醒状态的wakelock
mWakeLockSuspendBlocker =
mInjector.createSuspendBlocker(this, "PowerManagerService.WakeLocks");
// 保持亮屏,获取保持cpu唤醒状态的wakelock
mDisplaySuspendBlocker =
mInjector.createSuspendBlocker(this, "PowerManagerService.Display");
if (mBootingSuspendBlocker != null) {
mBootingSuspendBlocker.acquire();
mHoldingBootingSuspendBlocker = true;
}
if (mDisplaySuspendBlocker != null) {
mDisplaySuspendBlocker.acquire(HOLDING_DISPLAY_SUSPEND_BLOCKER);
mHoldingDisplaySuspendBlocker = true;
}
mHalAutoSuspendModeEnabled = false;
mHalInteractiveModeEnabled = true;
mWakefulnessRaw = WAKEFULNESS_AWAKE;
sQuiescent = mSystemProperties.get(SYSTEM_PROPERTY_QUIESCENT, "0").equals("1")
|| InitProperties.userspace_reboot_in_progress().orElse(false);
mNativeWrapper.nativeInit(this);
mNativeWrapper.nativeSetAutoSuspend(false);
mNativeWrapper.nativeSetPowerMode(Mode.INTERACTIVE, true);
mNativeWrapper.nativeSetPowerMode(Mode.DOUBLE_TAP_TO_WAKE, false);
mInjector.invalidateIsInteractiveCaches();
}
}
@Override
public void onStart() {
// 注册服务到Service Manager
publishBinderService(Context.POWER_SERVICE, mBinderService, /* allowIsolated= */ false,
DUMP_FLAG_PRIORITY_DEFAULT | DUMP_FLAG_PRIORITY_CRITICAL);
// 注册服务到logcal service,便于system_server进程内部其他模块获取
publishLocalService(PowerManagerInternal.class, mLocalService);
// 加入watchdog监听
Watchdog.getInstance().addMonitor(this);
Watchdog.getInstance().addThread(mHandler);
}
@Override
public void onBootPhase(int phase) {
if (phase == PHASE_SYSTEM_SERVICES_READY) {
systemReady();
} else if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
incrementBootCount();
} else if (phase == PHASE_BOOT_COMPLETED) {
synchronized (mLock) {
final long now = mClock.uptimeMillis();
mBootCompleted = true;
mDirty |= DIRTY_BOOT_COMPLETED;
mBatterySaverStateMachine.onBootCompleted();
userActivityNoUpdateLocked(
now, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID);
updatePowerStateLocked();
if (sQuiescent) {
sleepPowerGroupLocked(mPowerGroups.get(Display.DEFAULT_DISPLAY_GROUP),
mClock.uptimeMillis(),
PowerManager.GO_TO_SLEEP_REASON_QUIESCENT,
Process.SYSTEM_UID);
}
mContext.getSystemService(DeviceStateManager.class).registerCallback(
new HandlerExecutor(mHandler), new DeviceStateListener());
}
}
}
private void systemReady() {
synchronized (mLock) {
mSystemReady = true;
mDreamManager = getLocalService(DreamManagerInternal.class);
mDisplayManagerInternal = getLocalService(DisplayManagerInternal.class);
mPolicy = getLocalService(WindowManagerPolicy.class);
mBatteryManagerInternal = getLocalService(BatteryManagerInternal.class);
mAttentionDetector.systemReady(mContext);
// 用于无线充电检测
SensorManager sensorManager = new SystemSensorManager(mContext, mHandler.getLooper());
// The notifier runs on the system server's main looper so as not to interfere
// with the animations and other critical functions of the power manager.
mBatteryStats = BatteryStatsService.getService();
mNotifier = mInjector.createNotifier(Looper.getMainLooper(), mContext, mBatteryStats,
mInjector.createSuspendBlocker(this, "PowerManagerService.Broadcasts"),
mPolicy, mFaceDownDetector, mScreenUndimDetector,
BackgroundThread.getExecutor());
mPowerGroups.append(Display.DEFAULT_DISPLAY_GROUP,
new PowerGroup(WAKEFULNESS_AWAKE, mPowerGroupWakefulnessChangeListener,
mNotifier, mDisplayManagerInternal, mClock.uptimeMillis()));
DisplayGroupPowerChangeListener displayGroupPowerChangeListener =
new DisplayGroupPowerChangeListener();
mDisplayManagerInternal.registerDisplayGroupListener(displayGroupPowerChangeListener);
// This DreamManager method does not acquire a lock, so it should be safe to call.
mDreamManager.registerDreamManagerStateListener(new DreamManagerStateListener());
mWirelessChargerDetector = mInjector.createWirelessChargerDetector(sensorManager,
mInjector.createSuspendBlocker(
this, "PowerManagerService.WirelessChargerDetector"),
mHandler);
mSettingsObserver = new SettingsObserver(mHandler);
mLightsManager = getLocalService(LightsManager.class);
mAttentionLight = mLightsManager.getLight(LightsManager.LIGHT_ID_ATTENTION);
updateDeviceConfigLocked();
mDeviceConfigProvider.addOnPropertiesChangedListener(BackgroundThread.getExecutor(),
properties -> {
synchronized (mLock) {
updateDeviceConfigLocked();
updateWakeLockDisabledStatesLocked();
}
});
// Initialize display power management.
mDisplayManagerInternal.initPowerManagement(
mDisplayPowerCallbacks, mHandler, sensorManager);
// Create power groups for display groups other than DEFAULT_DISPLAY_GROUP.
addPowerGroupsForNonDefaultDisplayGroupLocked();
try {
final ForegroundProfileObserver observer = new ForegroundProfileObserver();
ActivityManager.getService().registerUserSwitchObserver(observer, TAG);
} catch (RemoteException e) {
// Shouldn't happen since in-process.
}
mLowPowerStandbyController.systemReady();
// Go.
readConfigurationLocked();
updateSettingsLocked();
mDirty |= DIRTY_BATTERY_STATE; // 电源状态发生变化
updatePowerStateLocked(); // 更新电源状态
}
final ContentResolver resolver = mContext.getContentResolver();
mConstants.start(resolver);
mBatterySaverController.systemReady();
mBatterySaverPolicy.systemReady();
mFaceDownDetector.systemReady(mContext);
mScreenUndimDetector.systemReady(mContext);
// Register for settings changes.
// 注册settings变化的监听,当发生变化时会回调Constants的onChange方法
resolver.registerContentObserver(Settings.Secure.getUriFor(
Settings.Secure.SCREENSAVER_ENABLED),
false, mSettingsObserver, UserHandle.USER_ALL);
resolver.registerContentObserver(Settings.Secure.getUriFor(
Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP),
false, mSettingsObserver, UserHandle.USER_ALL);
resolver.registerContentObserver(Settings.Secure.getUriFor(
Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK),
false, mSettingsObserver, UserHandle.USER_ALL);
resolver.registerContentObserver(Settings.System.getUriFor(
Settings.System.SCREEN_OFF_TIMEOUT),
false, mSettingsObserver, UserHandle.USER_ALL);
resolver.registerContentObserver(Settings.Secure.getUriFor(
Settings.Secure.SLEEP_TIMEOUT),
false, mSettingsObserver, UserHandle.USER_ALL);
resolver.registerContentObserver(Settings.Secure.getUriFor(
Settings.Secure.ATTENTIVE_TIMEOUT),
false, mSettingsObserver, UserHandle.USER_ALL);
resolver.registerContentObserver(Settings.Global.getUriFor(
Settings.Global.STAY_ON_WHILE_PLUGGED_IN),
false, mSettingsObserver, UserHandle.USER_ALL);
resolver.registerContentObserver(Settings.System.getUriFor(
Settings.System.SCREEN_BRIGHTNESS_MODE),
false, mSettingsObserver, UserHandle.USER_ALL);
resolver.registerContentObserver(Settings.System.getUriFor(
Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ),
false, mSettingsObserver, UserHandle.USER_ALL);
resolver.registerContentObserver(Settings.Global.getUriFor(
Settings.Global.THEATER_MODE_ON),
false, mSettingsObserver, UserHandle.USER_ALL);
resolver.registerContentObserver(Settings.Secure.getUriFor(
Settings.Secure.DOZE_ALWAYS_ON),
false, mSettingsObserver, UserHandle.USER_ALL);
resolver.registerContentObserver(Settings.Secure.getUriFor(
Settings.Secure.DOUBLE_TAP_TO_WAKE),
false, mSettingsObserver, UserHandle.USER_ALL);
resolver.registerContentObserver(Settings.Global.getUriFor(
Settings.Global.DEVICE_DEMO_MODE),
false, mSettingsObserver, UserHandle.USER_SYSTEM);
// Register for broadcasts from other components of the system.
// 注册电源变化的广播,接收电源变化的信息,并做相应的处理
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_BATTERY_CHANGED);
filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
mContext.registerReceiver(new BatteryReceiver(), filter, null, mHandler);
// 屏保发生变化的广播
filter = new IntentFilter();
filter.addAction(Intent.ACTION_DREAMING_STARTED);
filter.addAction(Intent.ACTION_DREAMING_STOPPED);
mContext.registerReceiver(new DreamReceiver(), filter, null, mHandler);
// 系统设置发生变化的广播
filter = new IntentFilter();
filter.addAction(Intent.ACTION_USER_SWITCHED);
mContext.registerReceiver(new UserSwitchedReceiver(), filter, null, mHandler);
// 设备的对接状态发生变化时(例如连接或断开手机底座等),系统会发送此广播消息
filter = new IntentFilter();
filter.addAction(Intent.ACTION_DOCK_EVENT);
mContext.registerReceiver(new DockReceiver(), filter, null, mHandler);
}
systemReady完成的工作主要如下:
1)获取与PowerManangerService相关的系统服务以及本地服务
2)获取屏幕最大、最小以及默认亮度值
3)创建SensorManager对象用于与WirelessChargerDetector交互
4)创建Notifier对象,用户通知系统电源状态的改变
5)调用DisplayManagerInternal的initPowerMannagerMent()方法来初始化Power显示模块
6)注册SettingsObserver监听系统设置的变化
7)注册一些广播接收器,如电池状态变化、Settings变化等
4.2 wakelock管理
Android Wakelock管理【app至kernel】-CSDN博客
4.3 亮灭屏管理
基本流程:
这里只列举了亮灭屏管理中PMS的代码。
1)灭屏休眠
@Override // Binder call
@RequiresPermission(android.Manifest.permission.DEVICE_POWER)
public void goToSleep(long eventTime, int reason, int flags) {
goToSleepInternal(DEFAULT_DISPLAY_GROUP_IDS, eventTime, reason, flags);
}
@RequiresPermission(android.Manifest.permission.DEVICE_POWER)
private void goToSleepInternal(IntArray groupIds, long eventTime, int reason, int flags) {
final long now = mClock.uptimeMillis();
if (eventTime > now) {
Slog.e(TAG, "Event time " + eventTime + " cannot be newer than " + now);
throw new IllegalArgumentException("event time must not be in the future");
}
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER,
/* message= */ null);
boolean isNoDoze = (flags & PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE) != 0;
int uid = Binder.getCallingUid();
final long ident = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
for (int i = 0; i < groupIds.size(); i++) {
int groupId = groupIds.get(i);
PowerGroup powerGroup = mPowerGroups.get(groupId);
if (powerGroup == null) {
throw new IllegalArgumentException("power group(" + groupId
+ ") doesn't exist");
}
if ((flags & PowerManager.GO_TO_SLEEP_FLAG_SOFT_SLEEP) != 0) {
if (powerGroup.hasWakeLockKeepingScreenOnLocked()) {
continue;
}
}
if (isNoDoze) {
sleepPowerGroupLocked(powerGroup, eventTime, reason, uid);
} else {
dozePowerGroupLocked(powerGroup, eventTime, reason, uid);
}
}
}
} finally {
Binder.restoreCallingIdentity(ident);
}
}
@GuardedBy("mLock")
private boolean sleepPowerGroupLocked(final PowerGroup powerGroup, long eventTime,
@GoToSleepReason int reason, int uid) {
if (DEBUG_SPEW) {
Slog.d(TAG, "sleepPowerGroup: eventTime=" + eventTime
+ ", groupId=" + powerGroup.getGroupId()
+ ", reason=" + PowerManager.sleepReasonToString(reason) + ", uid=" + uid);
}
if (!mBootCompleted || !mSystemReady) {
return false;
}
return powerGroup.sleepLocked(eventTime, uid, reason);
}
// PowerGroup.java
boolean sleepLocked(long eventTime, int uid, @PowerManager.GoToSleepReason int reason) {
if (eventTime < mLastWakeTime || getWakefulnessLocked() == WAKEFULNESS_ASLEEP) {
return false;
}
Trace.traceBegin(Trace.TRACE_TAG_POWER, "sleepPowerGroup");
try {
Slog.i(TAG,
"Sleeping power group (groupId=" + getGroupId() + ", uid=" + uid + ", reason="
+ PowerManager.sleepReasonToString(reason) + ")...");
setSandmanSummonedLocked(/* isSandmanSummoned= */ true);
setWakefulnessLocked(WAKEFULNESS_ASLEEP, eventTime, uid, reason, /* opUid= */0,
/* opPackageName= */ null, /* details= */ null);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
return true;
}
/**
* Sets the {@code wakefulness} value for this {@link PowerGroup}.
*
* @return {@code true} if the wakefulness value was changed; {@code false} otherwise.
*/
boolean setWakefulnessLocked(int newWakefulness, long eventTime, int uid, int reason, int opUid,
String opPackageName, String details) {
if (mWakefulness != newWakefulness) {
if (newWakefulness == WAKEFULNESS_AWAKE) {
setLastPowerOnTimeLocked(eventTime);
setIsPoweringOnLocked(true);
mLastWakeTime = eventTime;
} else if (isInteractive(mWakefulness) && !isInteractive(newWakefulness)) {
mLastSleepTime = eventTime;
}
mWakefulness = newWakefulness;
mWakefulnessListener.onWakefulnessChangedLocked(mGroupId, mWakefulness, eventTime,
reason, uid, opUid, opPackageName, details);
return true;
}
return false;
}
// PowerManagerService.java
private final class PowerGroupWakefulnessChangeListener implements
PowerGroup.PowerGroupListener {
@GuardedBy("mLock")
@Override
public void onWakefulnessChangedLocked(int groupId, int wakefulness, long eventTime,
int reason, int uid, int opUid, String opPackageName, String details) {
mWakefulnessChanging = true;
mDirty |= DIRTY_WAKEFULNESS;
if (wakefulness == WAKEFULNESS_AWAKE) {
// Kick user activity to prevent newly awake group from timing out instantly.
// The dream may end without user activity if the dream app crashes / is updated,
// don't poke the user activity timer for these wakes.
int flags = reason == PowerManager.WAKE_REASON_DREAM_FINISHED
? PowerManager.USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS : 0;
userActivityNoUpdateLocked(mPowerGroups.get(groupId), eventTime,
PowerManager.USER_ACTIVITY_EVENT_OTHER, flags, uid);
}
mDirty |= DIRTY_DISPLAY_GROUP_WAKEFULNESS;
mNotifier.onGroupWakefulnessChangeStarted(groupId, wakefulness, reason, eventTime);
updateGlobalWakefulnessLocked(eventTime, reason, uid, opUid, opPackageName, details);
updatePowerStateLocked();
}
}
// Notifier.java
public void onGroupWakefulnessChangeStarted(int groupId, int wakefulness, int changeReason,
long eventTime) {
final boolean isInteractive = PowerManagerInternal.isInteractive(wakefulness);
boolean isNewGroup = false;
Interactivity interactivity = mInteractivityByGroupId.get(groupId);
if (interactivity == null) {
isNewGroup = true;
interactivity = new Interactivity();
mInteractivityByGroupId.put(groupId, interactivity);
}
if (isNewGroup || interactivity.isInteractive != isInteractive) {
// Finish up late behaviors if needed.
if (interactivity.isChanging) {
handleLateInteractiveChange(groupId);
}
// Handle early behaviors.
interactivity.isInteractive = isInteractive;
interactivity.changeReason = changeReason;
interactivity.changeStartTime = eventTime;
interactivity.isChanging = true;
handleEarlyInteractiveChange(groupId);
}
}
private void handleEarlyInteractiveChange(int groupId) {
synchronized (mLock) {
Interactivity interactivity = mInteractivityByGroupId.get(groupId);
if (interactivity == null) {
Slog.e(TAG, "no Interactivity entry for groupId:" + groupId);
return;
}
final int changeReason = interactivity.changeReason;
if (interactivity.isInteractive) {
// 最终通知PowerManagerService模块处理
mHandler.post(() -> mPolicy.startedWakingUp(groupId, changeReason));
} else {
mHandler.post(() -> mPolicy.startedGoingToSleep(groupId, changeReason));
}
}
}
2)亮屏
@Override // Binder call
public void wakeUp(long eventTime, @WakeReason int reason, String details,
String opPackageName) {
final long now = mClock.uptimeMillis();
if (eventTime > now) {
Slog.e(TAG, "Event time " + eventTime + " cannot be newer than " + now);
throw new IllegalArgumentException("event time must not be in the future");
}
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.DEVICE_POWER, null);
final int uid = Binder.getCallingUid();
final long ident = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
if (!mBootCompleted && sQuiescent) {
mDirty |= DIRTY_QUIESCENT;
updatePowerStateLocked();
return;
}
wakePowerGroupLocked(mPowerGroups.get(Display.DEFAULT_DISPLAY_GROUP), eventTime,
reason, details, uid, opPackageName, uid);
}
} finally {
Binder.restoreCallingIdentity(ident);
}
}
@GuardedBy("mLock")
private void wakePowerGroupLocked(final PowerGroup powerGroup, long eventTime,
@WakeReason int reason, String details, int uid, String opPackageName, int opUid) {
if (DEBUG_SPEW) {
Slog.d(TAG, "wakePowerGroupLocked: eventTime=" + eventTime
+ ", groupId=" + powerGroup.getGroupId()
+ ", reason=" + PowerManager.wakeReasonToString(reason) + ", uid=" + uid);
}
if (mForceSuspendActive || !mSystemReady) {
return;
}
powerGroup.wakeUpLocked(eventTime, reason, details, uid, opPackageName, opUid,
LatencyTracker.getInstance(mContext));
}
void wakeUpLocked(long eventTime, @PowerManager.WakeReason int reason, String details, int uid,
String opPackageName, int opUid, LatencyTracker latencyTracker) {
if (eventTime < mLastSleepTime || mWakefulness == WAKEFULNESS_AWAKE) {
return;
}
Trace.traceBegin(Trace.TRACE_TAG_POWER, "wakePowerGroup" + mGroupId);
try {
Slog.i(TAG, "Waking up power group from "
+ PowerManagerInternal.wakefulnessToString(mWakefulness)
+ " (groupId=" + mGroupId
+ ", uid=" + uid
+ ", reason=" + PowerManager.wakeReasonToString(reason)
+ ", details=" + details
+ ")...");
Trace.asyncTraceBegin(Trace.TRACE_TAG_POWER, TRACE_SCREEN_ON, mGroupId);
// The instrument will be timed out automatically after 2 seconds.
latencyTracker.onActionStart(ACTION_TURN_ON_SCREEN, String.valueOf(mGroupId));
setWakefulnessLocked(WAKEFULNESS_AWAKE, eventTime, uid, reason, opUid,
opPackageName, details);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
}
boolean setWakefulnessLocked(int newWakefulness, long eventTime, int uid, int reason, int opUid,
String opPackageName, String details) {
if (mWakefulness != newWakefulness) {
if (newWakefulness == WAKEFULNESS_AWAKE) {
setLastPowerOnTimeLocked(eventTime);
setIsPoweringOnLocked(true);
mLastWakeTime = eventTime;
} else if (isInteractive(mWakefulness) && !isInteractive(newWakefulness)) {
mLastSleepTime = eventTime;
}
mWakefulness = newWakefulness;
mWakefulnessListener.onWakefulnessChangedLocked(mGroupId, mWakefulness, eventTime,
reason, uid, opUid, opPackageName, details);
return true;
}
return false;
}
private final class PowerGroupWakefulnessChangeListener implementsPowerGroup.PowerGroupListener {
@GuardedBy("mLock")
@Override
public void onWakefulnessChangedLocked(int groupId, int wakefulness, long eventTime, int reason, int uid, int opUid, String opPackageName, String details) {
mWakefulnessChanging = true;
mDirty |= DIRTY_WAKEFULNESS;
if (wakefulness == WAKEFULNESS_AWAKE) {
// Kick user activity to prevent newly awake group from timing out instantly.// The dream may end without user activity if the dream app crashes / is updated,// don't poke the user activity timer for these wakes.int flags = reason == PowerManager.WAKE_REASON_DREAM_FINISHED
? PowerManager.USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS : 0;
userActivityNoUpdateLocked(mPowerGroups.get(groupId), eventTime,
PowerManager.USER_ACTIVITY_EVENT_OTHER, flags, uid);
}
mDirty |= DIRTY_DISPLAY_GROUP_WAKEFULNESS;
mNotifier.onGroupWakefulnessChangeStarted(groupId, wakefulness, reason, eventTime);
updateGlobalWakefulnessLocked(eventTime, reason, uid, opUid, opPackageName, details);
updatePowerStateLocked();
}
}
4.4 Watchdog监听
用于检测PMS服务中是否存在死锁,超过5s,就认为PMS服务卡死,watch dog会将相关日志信息会写入dropbox和kmsg,kill system_server进程等操作。
// PowerManagerService.java
@Override
public void onStart() {
// 加入watchdog监听
Watchdog.getInstance().addMonitor(this);
Watchdog.getInstance().addThread(mHandler);
}
// 在watch dog中调用,用于检测PMS服务中是否存在死锁
@Override // Watchdog.Monitor implementation
public void monitor() {
// Grab and release lock for watchdog monitor to detect deadlocks.
synchronized (mLock) {
}
}
----------------------------------------------------------------------------
// Watchdog.java
public class Watchdog implements Dumpable {
......
public final class HandlerChecker implements Runnable {
......
@Override
public void run() {
// Once we get here, we ensure that mMonitors does not change even if we call
// #addMonitorLocked because we first add the new monitors to mMonitorQueue and
// move them to mMonitors on the next schedule when mCompleted is true, at which
// point we have completed execution of this method.
final int size = mMonitors.size();
for (int i = 0 ; i < size ; i++) {
synchronized (mLock) {
mCurrentMonitor = mMonitors.get(i);
}
mCurrentMonitor.monitor();
}
synchronized (mLock) {
mCompleted = true;
mCurrentMonitor = null;
}
}
......
}
......
private void run() {
boolean waitedHalf = false;
while (true) {
List<HandlerChecker> blockedCheckers = Collections.emptyList();
String subject = "";
boolean allowRestart = true;
int debuggerWasConnected = 0;
boolean doWaitedHalfDump = false;
// The value of mWatchdogTimeoutMillis might change while we are executing the loop.
// We store the current value to use a consistent value for all handlers.
final long watchdogTimeoutMillis = mWatchdogTimeoutMillis;
final long checkIntervalMillis = watchdogTimeoutMillis / 2; // 5s
final ArrayList<Integer> pids;
synchronized (mLock) {
long timeout = checkIntervalMillis;
// Make sure we (re)spin the checkers that have become idle within
// this wait-and-check interval
// 1.启动HandlerChecker线程对PMS服务的监听
for (int i=0; i<mHandlerCheckers.size(); i++) {
HandlerCheckerAndTimeout hc = mHandlerCheckers.get(i);
// We pick the watchdog to apply every time we reschedule the checkers. The
// default timeout might have changed since the last run.
hc.checker().scheduleCheckLocked(hc.customTimeoutMillis()
.orElse(watchdogTimeoutMillis * Build.HW_TIMEOUT_MULTIPLIER));
}
if (debuggerWasConnected > 0) {
debuggerWasConnected--;
}
// NOTE: We use uptimeMillis() here because we do not want to increment the time we
// wait while asleep. If the device is asleep then the thing that we are waiting
// to timeout on is asleep as well and won't have a chance to run, causing a false
// positive on when to kill things.
long start = SystemClock.uptimeMillis();
while (timeout > 0) {
if (Debug.isDebuggerConnected()) {
debuggerWasConnected = 2;
}
try {
mLock.wait(timeout);
// Note: mHandlerCheckers and mMonitorChecker may have changed after waiting
} catch (InterruptedException e) {
Log.wtf(TAG, e);
}
if (Debug.isDebuggerConnected()) {
debuggerWasConnected = 2;
}
timeout = checkIntervalMillis - (SystemClock.uptimeMillis() - start);
}
final int waitState = evaluateCheckerCompletionLocked();
if (waitState == COMPLETED) {
// The monitors have returned; reset
waitedHalf = false;
continue;
} else if (waitState == WAITING) {
// still waiting but within their configured intervals; back off and recheck
continue;
} else if (waitState == WAITED_HALF) {
if (!waitedHalf) {
Slog.i(TAG, "WAITED_HALF");
waitedHalf = true;
// We've waited half, but we'd need to do the stack trace dump w/o the lock.
blockedCheckers = getCheckersWithStateLocked(WAITED_HALF);
subject = describeCheckersLocked(blockedCheckers);
pids = new ArrayList<>(mInterestingJavaPids);
doWaitedHalfDump = true;
} else {
continue;
}
} else {
// something is overdue!
blockedCheckers = getCheckersWithStateLocked(OVERDUE);
subject = describeCheckersLocked(blockedCheckers);
allowRestart = mAllowRestart;
pids = new ArrayList<>(mInterestingJavaPids);
}
} // END synchronized (mLock)
// If we got here, that means that the system is most likely hung.
//
// First collect stack traces from all threads of the system process.
//
// Then, if we reached the full timeout, kill this process so that the system will
// restart. If we reached half of the timeout, just log some information and continue.
// 2.创建dropbox线程,日志信息(当前/proc/pressure/io memory cpu信息、函数调用栈信息)写入dropbox
logWatchog(doWaitedHalfDump, subject, pids);
if (doWaitedHalfDump) {
// We have waited for only half of the timeout, we continue to wait for the duration
// of the full timeout before killing the process.
continue;
}
IActivityController controller;
synchronized (mLock) {
controller = mController;
}
if (controller != null) {
Slog.i(TAG, "Reporting stuck state to activity controller");
try {
Binder.setDumpDisabled("Service dumps disabled due to hung system process.");
// 1 = keep waiting, -1 = kill system
int res = controller.systemNotResponding(subject);
if (res >= 0) {
Slog.i(TAG, "Activity controller requested to coninue to wait");
waitedHalf = false;
continue;
}
} catch (RemoteException e) {
}
}
// Only kill the process if the debugger is not attached.
if (Debug.isDebuggerConnected()) {
debuggerWasConnected = 2;
}
if (debuggerWasConnected >= 2) {
Slog.w(TAG, "Debugger connected: Watchdog is *not* killing the system process");
} else if (debuggerWasConnected > 0) {
Slog.w(TAG, "Debugger was connected: Watchdog is *not* killing the system process");
} else if (!allowRestart) {
Slog.w(TAG, "Restart not allowed: Watchdog is *not* killing the system process");
} else {
Slog.w(TAG, "*** WATCHDOG KILLING SYSTEM PROCESS: " + subject);
WatchdogDiagnostics.diagnoseCheckers(blockedCheckers);
Slog.w(TAG, "*** GOODBYE!");
if (!Build.IS_USER && isCrashLoopFound()
&& !WatchdogProperties.should_ignore_fatal_count().orElse(false)) {
// 3."Fatal reset to escape the system_server crashing loop\n"字符串
// 写入/dev/kmsg_debug
breakCrashLoop();
}
// 4.kill system_server进程
Process.killProcess(Process.myPid());
System.exit(10);
}
waitedHalf = false;
}
}
......
}
总结---
Watch dog工作原理:
1)启动HandlerChecker线程对PMS服务的监听(默认超过5s认为是死锁)
2)PMS服务出现死锁,创建dropbox线程,日志信息(当前/proc/pressure/io memory cpu信息、函数调用栈信息)写入dropbox
3)"Fatal reset to escape the system_server crashing loop\n"字符串写入/dev/kmsg_debug
4)kill system_server进程
4.5 关机流程
其它模块调用reboot binder api,执行ShutdownThread线程的reboot或shutdown接口,做重启或关机操作。
@Override // Binder call
public void reboot(boolean confirm, @Nullable String reason, boolean wait) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.REBOOT, null);
if (PowerManager.REBOOT_RECOVERY.equals(reason)
|| PowerManager.REBOOT_RECOVERY_UPDATE.equals(reason)) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null);
}
ShutdownCheckPoints.recordCheckPoint(Binder.getCallingPid(), reason);
final long ident = Binder.clearCallingIdentity();
try {
shutdownOrRebootInternal(HALT_MODE_REBOOT, confirm, reason, wait);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
private void shutdownOrRebootInternal(final @HaltMode int haltMode, final boolean confirm,
@Nullable final String reason, boolean wait) {
if (PowerManager.REBOOT_USERSPACE.equals(reason)) {
if (!PowerManager.isRebootingUserspaceSupportedImpl()) {
throw new UnsupportedOperationException(
"Attempted userspace reboot on a device that doesn't support it");
}
UserspaceRebootLogger.noteUserspaceRebootWasRequested();
}
if (mHandler == null || !mSystemReady) {
if (RescueParty.isAttemptingFactoryReset()) {
// If we're stuck in a really low-level reboot loop, and a
// rescue party is trying to prompt the user for a factory data
// reset, we must GET TO DA CHOPPA!
// No check point from ShutdownCheckPoints will be dumped at this state.
PowerManagerService.lowLevelReboot(reason);
} else {
throw new IllegalStateException("Too early to call shutdown() or reboot()");
}
}
Runnable runnable = new Runnable() {
@Override
public void run() {
synchronized (this) {
if (haltMode == HALT_MODE_REBOOT_SAFE_MODE) {
ShutdownThread.rebootSafeMode(getUiContext(), confirm);
} else if (haltMode == HALT_MODE_REBOOT) {
ShutdownThread.reboot(getUiContext(), reason, confirm);
} else {
ShutdownThread.shutdown(getUiContext(), reason, confirm);
}
}
}
};
// ShutdownThread must run on a looper capable of displaying the UI.
// 关机操作必须在一个看得见的UI线程上执行
Message msg = Message.obtain(UiThread.getHandler(), runnable);
msg.setAsynchronous(true);
UiThread.getHandler().sendMessage(msg);
// PowerManager.reboot() is documented not to return so just wait for the inevitable.
if (wait) {
synchronized (runnable) {
while (true) {
try {
runnable.wait();
} catch (InterruptedException e) {
}
}
}
}
}
4.6 Device Doze or Idle mode
1)涉及device doze机制相关的代码
将Android Doze调用该API,将Doze白名单传给PMS,当设备处于device idle或standby模式下,将非Doze或非Standby白名单中的app的wakelock进行disable处理。
@Override
public void setDeviceIdleWhitelist(int[] appids) {
setDeviceIdleWhitelistInternal(appids);
}
void setDeviceIdleWhitelistInternal(int[] appids) {
synchronized (mLock) {
mDeviceIdleWhitelist = appids;
if (mDeviceIdleMode) {
updateWakeLockDisabledStatesLocked();
}
}
}
// 更新wakelock disable状态
@GuardedBy("mLock")
private void updateWakeLockDisabledStatesLocked() {
boolean changed = false;
final int numWakeLocks = mWakeLocks.size();
for (int i = 0; i < numWakeLocks; i++) {
final WakeLock wakeLock = mWakeLocks.get(i);
// 判断是否为PARTIAL_WAKE_LOCK或亮屏锁
if ((wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK)
== PowerManager.PARTIAL_WAKE_LOCK || isScreenLock(wakeLock)) {
// 将wakelock状态设置为disable
if (setWakeLockDisabledStateLocked(wakeLock)) {
changed = true;
if (wakeLock.mDisabled) {
// This wake lock is no longer being respected.
notifyWakeLockReleasedLocked(wakeLock);
} else {
notifyWakeLockAcquiredLocked(wakeLock);
}
}
}
}
if (changed) {
mDirty |= DIRTY_WAKE_LOCKS;
updatePowerStateLocked();
}
}
// 根据当前设备所处的模式,将非Doze或非Standby白名单中的app的wakelock进行disable处理
@GuardedBy("mLock")
private boolean setWakeLockDisabledStateLocked(WakeLock wakeLock) {
if ((wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK)
== PowerManager.PARTIAL_WAKE_LOCK) {
boolean disabled = false;
final int appid = UserHandle.getAppId(wakeLock.mOwnerUid);
// FIRST_APPLICATION_UID为10000,> 10000的分配给app进程
if (appid >= Process.FIRST_APPLICATION_UID) {
// Cached inactive processes are never allowed to hold wake locks.
// 禁止非活跃状态的cache进程持有唤醒锁
if (mConstants.NO_CACHED_WAKE_LOCKS) {
disabled = mForceSuspendActive
|| (!wakeLock.mUidState.mActive && wakeLock.mUidState.mProcState
!= ActivityManager.PROCESS_STATE_NONEXISTENT &&
wakeLock.mUidState.mProcState > ActivityManager.PROCESS_STATE_RECEIVER);
}
// 如果设备处于device idle模式,忽略非Doze白名单中的app的wakelock
if (mDeviceIdleMode) {
// If we are in idle mode, we will also ignore all partial wake locks that are
// for application uids that are not allowlisted.
final UidState state = wakeLock.mUidState;
if (Arrays.binarySearch(mDeviceIdleWhitelist, appid) < 0 &&
Arrays.binarySearch(mDeviceIdleTempWhitelist, appid) < 0 &&
state.mProcState != ActivityManager.PROCESS_STATE_NONEXISTENT &&
state.mProcState >
ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE) {
disabled = true;
}
}
// 如果设备处于LowPowerStandbyActive模式,忽略非Standby白名单中的app的wakelock
if (mLowPowerStandbyActive) {
final UidState state = wakeLock.mUidState;
if (Arrays.binarySearch(mLowPowerStandbyAllowlist, wakeLock.mOwnerUid) < 0
&& state.mProcState != ActivityManager.PROCESS_STATE_NONEXISTENT
&& state.mProcState > ActivityManager.PROCESS_STATE_BOUND_TOP) {
disabled = true;
}
}
}
return wakeLock.setDisabled(disabled);
} else if (mDisableScreenWakeLocksWhileCached && isScreenLock(wakeLock)) {
boolean disabled = false;
final int appid = UserHandle.getAppId(wakeLock.mOwnerUid);
final UidState state = wakeLock.mUidState;
// Cached inactive processes are never allowed to hold wake locks.
if (mConstants.NO_CACHED_WAKE_LOCKS
&& appid >= Process.FIRST_APPLICATION_UID
&& !state.mActive
&& state.mProcState != ActivityManager.PROCESS_STATE_NONEXISTENT
&& state.mProcState >= ActivityManager.PROCESS_STATE_TOP_SLEEPING) {
if (DEBUG_SPEW) {
Slog.d(TAG, "disabling full wakelock " + wakeLock);
}
disabled = true;
}
return wakeLock.setDisabled(disabled);
}
return false;
}
2)设置device idle模式
PMS提供设置device idle mode的接口,然后通过power hal将该模式写入"/power/mode"节点,device idle模式下,设备频率电压会降低或关闭设备,达到节省功耗的目的。
@Override
public boolean setDeviceIdleMode(boolean enabled) {
return setDeviceIdleModeInternal(enabled);
}
boolean setDeviceIdleModeInternal(boolean enabled) {
synchronized (mLock) {
if (mDeviceIdleMode == enabled) {
return false;
}
mDeviceIdleMode = enabled;
updateWakeLockDisabledStatesLocked();
setPowerModeInternal(MODE_DEVICE_IDLE, mDeviceIdleMode || mLightDeviceIdleMode);
}
if (enabled) {
EventLogTags.writeDeviceIdleOnPhase("power");
} else {
EventLogTags.writeDeviceIdleOffPhase("power");
}
return true;
}
private boolean setPowerModeInternal(int mode, boolean enabled) {
// Maybe filter the event.
if (mode == Mode.LAUNCH && enabled && mBatterySaverController.isLaunchBoostDisabled()) {
return false;
}
return mNativeWrapper.nativeSetPowerMode(mode, enabled);
}
// /com_android_server_power_PowerManagerService.cpp
static power::PowerHalController gPowerHalController;
static jboolean nativeSetPowerMode(JNIEnv* /* env */, jclass /* clazz */, jint mode,
jboolean enabled) {
return setPowerMode(static_cast<Mode>(mode), enabled);
}
static bool setPowerMode(Mode mode, bool enabled) {
android::base::Timer t;
auto result = gPowerHalController.setMode(mode, enabled);
if (mode == Mode::INTERACTIVE && t.duration() > 20ms) {
ALOGD("Excessive delay in setting interactive mode to %s while turning screen %s",
enabled ? "true" : "false", enabled ? "on" : "off");
}
return result.isOk();
}
// power hal
ndk::ScopedAStatus Power::setMode(Mode type, bool enabled) {
LOG(VERBOSE) << "Power setMode: " << static_cast<int32_t>(type) << " to: " << enabled;
int32_t param = 1;
int32_t hint = static_cast<int32_t>(type);
if (type == Mode::INTERACTIVE) {
if (mModule->setInteractive)
mModule->setInteractive(mModule, enabled ? 1 : 0);
return ndk::ScopedAStatus::ok();
}
if (hint < VENDOR_PERF_ID_BASE) {
hint = hint + MODE_PERF_ID_MAPPING;
}
if (mModule->powerHint) {
if (enabled)
mModule->powerHint(mModule, static_cast<power_hint_t>(hint), ¶m);
else
mModule->powerHint(mModule, static_cast<power_hint_t>(hint), NULL);
}
return ndk::ScopedAStatus::ok();
}
static void xxx_power_hint(struct xxx_power_module *module, power_hint_t hint,
void *data)
{
struct xxx_power_module *pm = (struct xxx_power_module *)module;
static bool is_launching = false;
if (CC_UNLIKELY(power_hint_enable == 0)) return;
ALOGD_IF(DEBUG_V, "Enter %s:(%d:%d)", __func__, hint, ((data!=NULL)?(*(int*)data):0));
pthread_mutex_lock(&pm->lock);
if (CC_UNLIKELY(!pm->init_done)) {
pthread_mutex_unlock(&pm->lock);
ALOGE("%s: power hint is not inited", __func__);
return;
}
int duration = 0;
if (data != NULL) {
duration = *((int*)data) & 0xffff;
if (duration == 1 || duration == 0) {
duration = 0;
} else if (duration < BOOST_DURATION_DEFAULT || duration > BOOST_DURATION_MAX) {
duration = BOOST_DURATION_DEFAULT;
}
}
// 最后写入 "/power/mode"节点
boost(hint, 0, ((data != NULL)? 1: 0), duration);
pthread_mutex_unlock(&pm->lock);
ALOGD_IF(DEBUG_V, "Exit %s:(%d:%d)", __func__, hint, ((data!=NULL)?(*(int*)data):0));
}
4.7 监控长时间持锁行为
PMS监控应用或模块长时间持锁行为,
void checkForLongWakeLocks() {
synchronized (mLock) {
final long now = mClock.uptimeMillis();
mNotifyLongDispatched = now;
final long when = now - MIN_LONG_WAKE_CHECK_INTERVAL;
long nextCheckTime = Long.MAX_VALUE;
final int numWakeLocks = mWakeLocks.size();
// 遍历wakelock列表,如果wakelock超过持锁时间60s,则notify。否则,找到最小的nextCheckTime,
// 如,wakelock1持锁40s,wakelock2持锁50s,
// 则下一次检测持锁时间nextCheckTime为wakelock2开始持锁时间点+ 60s
for (int i = 0; i < numWakeLocks; i++) {
final WakeLock wakeLock = mWakeLocks.get(i);
if ((wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK)
== PowerManager.PARTIAL_WAKE_LOCK) {
if (wakeLock.mNotifiedAcquired && !wakeLock.mNotifiedLong) {
// 持锁时间超过MIN_LONG_WAKE_CHECK_INTERVAL (60s),notify
if (wakeLock.mAcquireTime < when) {
// This wake lock has exceeded the long acquire time, report!
notifyWakeLockLongStartedLocked(wakeLock);
} else {
// This wake lock could still become a long one, at this time.
// 更新下一次检测wakelock持锁时长
long checkTime = wakeLock.mAcquireTime + MIN_LONG_WAKE_CHECK_INTERVAL;
if (checkTime < nextCheckTime) {
nextCheckTime = checkTime;
}
}
}
}
}
mNotifyLongScheduled = 0;
// 从handler消息队列中删除MSG_CHECK_FOR_LONG_WAKELOCKS,然后重新加入
mHandler.removeMessages(MSG_CHECK_FOR_LONG_WAKELOCKS);
if (nextCheckTime != Long.MAX_VALUE) {
mNotifyLongNextCheck = nextCheckTime;
enqueueNotifyLongMsgLocked(nextCheckTime);
} else {
mNotifyLongNextCheck = 0;
}
}
}
// MSG_CHECK_FOR_LONG_WAKELOCKS时间加入handler消息队列,并在nextCheckTime后出发
@GuardedBy("mLock")
private void enqueueNotifyLongMsgLocked(long time) {
mNotifyLongScheduled = time;
Message msg = mHandler.obtainMessage(MSG_CHECK_FOR_LONG_WAKELOCKS);
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, time);
}
// nextCheckTime后,取出并处理消息队列中的MSG_CHECK_FOR_LONG_WAKELOCKS信息,执行checkForLongWakeLocks方法
private final class PowerManagerHandlerCallback implements Handler.Callback {
@Override
public boolean handleMessage(Message msg) {
switch (msg.what) {
case MSG_USER_ACTIVITY_TIMEOUT:
handleUserActivityTimeout();
break;
case MSG_SANDMAN:
handleSandman(msg.arg1);
break;
case MSG_SCREEN_BRIGHTNESS_BOOST_TIMEOUT:
handleScreenBrightnessBoostTimeout();
break;
case MSG_CHECK_FOR_LONG_WAKELOCKS:
checkForLongWakeLocks();
break;
case MSG_ATTENTIVE_TIMEOUT:
handleAttentiveTimeout();
break;
}
return true;
}
}
待改进点:
1)下一次检测持锁时间:当前是nextCheckTime为wakelock开始持锁时间点+ 60s,可以改成nextCheckTime为60s - 当前的时间点。如,某个wakelock持锁时长为40s,还未超过60s,则下一次检测持锁时间为20s后。
2)可以增加对模块长时间持锁是否为异常行为的判断机制,如audio app长时间持锁,但不持有Audio focus、没有对应可执行的struct task等为异常行为,对异常持锁行为进行管理与优化
五、PMS服务核心参数
// 1.电源状态发生变化的参数
// Dirty bit: mWakeLocks changed
private static final int DIRTY_WAKE_LOCKS = 1 << 0;
// Dirty bit: mWakefulness changed
private static final int DIRTY_WAKEFULNESS = 1 << 1;
// Dirty bit: user activity was poked or may have timed out
private static final int DIRTY_USER_ACTIVITY = 1 << 2;
// Dirty bit: actual display power state was updated asynchronously
private static final int DIRTY_ACTUAL_DISPLAY_POWER_STATE_UPDATED = 1 << 3;
// Dirty bit: mBootCompleted changed
private static final int DIRTY_BOOT_COMPLETED = 1 << 4;
// Dirty bit: settings changed
private static final int DIRTY_SETTINGS = 1 << 5;
// Dirty bit: mIsPowered changed
private static final int DIRTY_IS_POWERED = 1 << 6;
// Dirty bit: mStayOn changed
private static final int DIRTY_STAY_ON = 1 << 7;
// Dirty bit: battery state changed
private static final int DIRTY_BATTERY_STATE = 1 << 8;
// Dirty bit: proximity state changed
private static final int DIRTY_PROXIMITY_POSITIVE = 1 << 9;
// Dirty bit: dock state changed
private static final int DIRTY_DOCK_STATE = 1 << 10;
// Dirty bit: brightness boost changed
private static final int DIRTY_SCREEN_BRIGHTNESS_BOOST = 1 << 11;
// Dirty bit: sQuiescent changed
private static final int DIRTY_QUIESCENT = 1 << 12;
// Dirty bit: attentive timer may have timed out
private static final int DIRTY_ATTENTIVE = 1 << 14;
// Dirty bit: display group wakefulness has changed
private static final int DIRTY_DISPLAY_GROUP_WAKEFULNESS = 1 << 16;
// 2.wakelock类型
// Summarizes the state of all active wakelocks.
static final int WAKE_LOCK_CPU = 1 << 0;
static final int WAKE_LOCK_SCREEN_BRIGHT = 1 << 1;
static final int WAKE_LOCK_SCREEN_DIM = 1 << 2;
static final int WAKE_LOCK_BUTTON_BRIGHT = 1 << 3;
static final int WAKE_LOCK_PROXIMITY_SCREEN_OFF = 1 << 4;
static final int WAKE_LOCK_STAY_AWAKE = 1 << 5; // only set if already awake
static final int WAKE_LOCK_DOZE = 1 << 6;
static final int WAKE_LOCK_DRAW = 1 << 7;
// 3.用户活动状态参数
// Summarizes the user activity state.
static final int USER_ACTIVITY_SCREEN_BRIGHT = 1 << 0; // 屏幕高亮
static final int USER_ACTIVITY_SCREEN_DIM = 1 << 1; // 屏幕昏暗
static final int USER_ACTIVITY_SCREEN_DREAM = 1 << 2; // 屏幕进入屏保
// 4.设备关机原生的参数
// Possible reasons for shutting down or reboot for use in
// SYSTEM_PROPERTY_REBOOT_REASON(sys.boot.reason) which is set by bootstatprivate static final String REASON_SHUTDOWN = "shutdown";
private static final String REASON_REBOOT = "reboot";
private static final String REASON_USERREQUESTED = "shutdown,userrequested";
private static final String REASON_THERMAL_SHUTDOWN = "shutdown,thermal";
private static final String REASON_LOW_BATTERY = "shutdown,battery";
private static final String REASON_BATTERY_THERMAL_STATE = "shutdown,thermal,
六、核心API
6.1 核心private API
6.1.1 updatePowerStateLocked
updatePowerStateLocked接口基于mDirty状态值更新电源状态。
电源状态更新的场景:
1)设备唤醒状态发生变化---onWakefulnessChangedLocked
2)完成开机---onBootPhase
3)systemReady初始化阶段---systemReady
4)系统设置发生变化---handleSettingsChangedLocked
5)申请wakelock---acquireWakeLockInternal
6)释放wakelock---removeWakeLockLocked
7)用户活动状态发生变化---userActivityInternal
8)display发生变化
9)电池状态发生变化---handleBatteryStateChangedLocked
10)屏幕亮度状态发生变化
11)屏保状态发生变化
12)wakelock状态发生变化---updateWakeLockDisabledStatesLocked
13)dock状态发生变化
14)设备唤醒状态发生变化---wakeUp
/**
* Updates the global power state based on dirty bits recorded in mDirty.
*
* This is the main function that performs power state transitions.
* We centralize them here so that we can recompute the power state completely
* each time something important changes, and ensure that we do it the same
* way each time. The point is to gather all of the transition logic here.
*/
@GuardedBy("mLock")
private void updatePowerStateLocked() {
// mDirty状态值为0,无需更新电源状态
if (!mSystemReady || mDirty == 0 || mUpdatePowerStateInProgress) {
return;
}
if (!Thread.holdsLock(mLock)) {
Slog.wtf(TAG, "Power manager lock was not held when calling updatePowerStateLocked");
}
Trace.traceBegin(Trace.TRACE_TAG_POWER, "updatePowerState");
mUpdatePowerStateInProgress = true;
try {
// Phase 0: Basic state updates.
// 基础状态更新
updateIsPoweredLocked(mDirty); // 更新电池状态、充电器类型、电池电量等信息
updateStayOnLocked(mDirty); // 更新设备的待机状态
updateScreenBrightnessBoostLocked(mDirty); // 更新屏幕亮度增强状态
// Phase 1: Update wakefulness.
// Loop because the wake lock and user activity computations are influenced
// by changes in wakefulness.
// 更新设备休眠唤醒状态
final long now = mClock.uptimeMillis();
int dirtyPhase2 = 0;
for (;;) {
int dirtyPhase1 = mDirty;
dirtyPhase2 |= dirtyPhase1;
mDirty = 0;
updateWakeLockSummaryLocked(dirtyPhase1); // 更新所有活动唤醒锁的状态
updateUserActivitySummaryLocked(now, dirtyPhase1); // 更新用户活动状态
updateAttentiveStateLocked(now, dirtyPhase1); // 更新用户提示状态,如低电量
// 更新设备休眠唤醒状态
if (!updateWakefulnessLocked(dirtyPhase1)) {
break;
}
}
// Phase 2: Lock profiles that became inactive/not kept awake.
// 更新User ID、屏幕关闭超时时间和当前时间
updateProfilesLocked(now);
// Phase 3: Update power state of all PowerGroups.
final boolean powerGroupsBecameReady = updatePowerGroupsLocked(dirtyPhase2);
// Phase 4: Update dream state (depends on power group ready signal).
// 更新屏保状态
updateDreamLocked(dirtyPhase2, powerGroupsBecameReady);
// Phase 5: Send notifications, if needed.
// 向其他组件发出设备休眠与唤醒状态切换的通知
finishWakefulnessChangeIfNeededLocked();
// Phase 6: Update suspend blocker.
// Because we might release the last suspend blocker here, we need to make sure
// we finished everything else first!
// 更新系统的wakelock
updateSuspendBlockerLocked();
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
mUpdatePowerStateInProgress = false;
}
}
6.1.2 userActivityNoUpdateLocked
处理用户活动事件,如屏幕触摸、按键等。根据条件判断确定能否处理用户活动,然后根据事件时间、事件类型等信息更新相应的状态。
private boolean userActivityNoUpdateLocked(final PowerGroup powerGroup, long eventTime,
@PowerManager.UserActivityEvent int event, int flags, int uid) {
final int groupId = powerGroup.getGroupId();
if (DEBUG_SPEW) {
Slog.d(TAG, "userActivityNoUpdateLocked: groupId=" + groupId
+ ", eventTime=" + eventTime
+ ", event=" + PowerManager.userActivityEventToString(event)
+ ", flags=0x" + Integer.toHexString(flags) + ", uid=" + uid);
}
if (eventTime < powerGroup.getLastSleepTimeLocked()
|| eventTime < powerGroup.getLastWakeTimeLocked() || !mSystemReady) {
return false;
}
Trace.traceBegin(Trace.TRACE_TAG_POWER, "userActivity");
try {
if (eventTime > mLastInteractivePowerHintTime) {
setPowerBoostInternal(Boost.INTERACTION, 0);
mLastInteractivePowerHintTime = eventTime;
}
mNotifier.onUserActivity(powerGroup.getGroupId(), event, uid);
mAttentionDetector.onUserActivity(eventTime, event);
if (mUserInactiveOverrideFromWindowManager) {
mUserInactiveOverrideFromWindowManager = false;
mOverriddenTimeout = -1;
}
final int wakefulness = powerGroup.getWakefulnessLocked();
if (wakefulness == WAKEFULNESS_ASLEEP
|| wakefulness == WAKEFULNESS_DOZING
|| (flags & PowerManager.USER_ACTIVITY_FLAG_INDIRECT) != 0) {
return false;
}
maybeUpdateForegroundProfileLastActivityLocked(eventTime);
if ((flags & PowerManager.USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS) != 0) {
if (eventTime > powerGroup.getLastUserActivityTimeNoChangeLightsLocked()
&& eventTime > powerGroup.getLastUserActivityTimeLocked()) {
powerGroup.setLastUserActivityTimeNoChangeLightsLocked(eventTime, event);
mDirty |= DIRTY_USER_ACTIVITY;
if (event == PowerManager.USER_ACTIVITY_EVENT_BUTTON) {
mDirty |= DIRTY_QUIESCENT;
}
return true;
}
} else {
if (eventTime > powerGroup.getLastUserActivityTimeLocked()) {
powerGroup.setLastUserActivityTimeLocked(eventTime, event);
mDirty |= DIRTY_USER_ACTIVITY;
if (event == PowerManager.USER_ACTIVITY_EVENT_BUTTON) {
mDirty |= DIRTY_QUIESCENT;
}
return true;
}
}
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
return false;
}
6.2 Binder API
BinderService继承IPowerManager.Stub(由IPowerManager.aidl编译生成的binder框架代码),提供Binder API.
其它模块可以通过PowerManager mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);获取PowerManager对象,然后通过该对象获取PMS中的Binder API.
Binder接口 | 作用 | |
1 | acquireWakeLockWithUid | 申请wakelock,需传入app的uid,其uid封装到wakesource对象 |
2 | setPowerBoost | cpu提频 |
3 | setPowerMode | 设置设备模式,如device idle、performance等 |
4 | setPowerModeChecked | 设置设备模式,如device idle、performance等,且当PMS服务还未system ready,返回false |
5 | acquireWakeLock | 申请wakelock |
6 | acquireWakeLockAsync | 异步方式申请wakelock |
7 | releaseWakeLock | 释放wakelock |
8 | releaseWakeLockAsync | 异步方式释放wakelock |
9 | updateWakeLockUids | 更新某应用的wakelock |
10 | updateWakeLockUidsAsync | 异步方式申请wakelock |
11 | updateWakeLockWorkSource | 更新某个wakelock的WorkSource |
12 | updateWakeLockCallback | 更新某个wakelock的Callback对象 |
13 | isWakeLockLevelSupported | 判断申请的wakelock类型是否可用 |
14 | userActivity | 当设备接收到用户活动事件,例如按下按钮、触摸屏幕或使用键盘时,该方法会根据用户的操作来更新相关的电源状态 |
15 | wakeUp | 唤醒系统 |
16 | goToSleep | 系统进入休眠 |
17 | goToSleepWithDisplayId | 系统进入休眠,并传入DisplayId信息 |
18 | nap | 屏幕进入屏保状态 |
19 | isInteractive | 判断设备是否处于用户活动状态,如用户触摸屏幕、按键事件等 |
20 | isDisplayInteractive | 根据特定显示和给定的用户 ID 来判断是否处于互动状态 |
21 | areAutoPowerSaveModesEnabled | 在配置文件中获取省电模式是否默认使能 |
22 | isPowerSaveMode | 判断省电模式得功能是否使能 |
23 | getPowerSaveState | 获取不同场景下的省电策略,如app standby场景下,所有app进入standby模式 |
24 | setPowerSaveModeEnabled | 省电策略使能 |
25 | getFullPowerSavePolicy | 获取所有的电池节能策略 |
26 | setFullPowerSavePolicy | 设置整个电池节能策略 |
27 | setDynamicPowerSaveHint | 设置动态地调整电池的使用策略。根据设备的使用情况动态地调整电池的使用策略,以实现更有效的电池管理和延长电池寿命。 |
28 | setAdaptivePowerSavePolicy | 设置自适应省电策略。可以根据设备的使用情况和用户习惯动态地调整电池的使用策略 |
29 | setAdaptivePowerSaveEnabled | 用于设置是否启用自适应省电模式 |
30 | getPowerSaveModeTrigger | 从settings中获取触发省电模式开关的值 |
31 | setBatteryDischargePrediction | 不充电环境下,设置对设备的电池消耗预测 |
32 | getBatteryDischargePrediction | 不充电环境下,获取对设备的电池消耗预测 |
33 | isBatteryDischargePredictionPersonalized | 电池放电预测个性化功能是否打开。在电池放电预测个性化,是针对每个用户的独特使用模式和习惯进行定制化的预测 |
34 | isDeviceIdleMode | 判断设备是否进入device idle模式 |
35 | isLightDeviceIdleMode | 同上 |
36 | isLowPowerStandbySupported | 判断是否支持standby省电模式 |
37 | isLowPowerStandbyEnabled | 判断standby省电模式功能开关是否打开 |
38 | setLowPowerStandbyEnabled | 设置standby省电模式功能使能 |
39 | setLowPowerStandbyActiveDuringMaintenance | 在Maintenance阶段,设置standby省电模式功能使能 |
40 | forceLowPowerStandbyActive | 强制进入standby省电模式 |
41 | setLowPowerStandbyPolicy | 设置standby模式的省电策略 |
42 | getLowPowerStandbyPolicy | 获取standby模式的省电策略 |
43 | isExemptFromLowPowerStandby | 判断该app是否免除进入低功耗待机模式 |
44 | isReasonAllowedInLowPowerStandby | 检测在低功耗待机模式中是否被允许执行 |
45 | isFeatureAllowedInLowPowerStandby | 检查给定特性是否在低功耗待机模式下被允许 |
46 | acquireLowPowerStandbyPorts | 低功耗待机(standby)模式下的端口用于在设备进入低功耗待机模式时保持一些特定服务或功能的连接或开放。在低功耗待机模式下,设备会关闭或限制某些后台操作。然而,有一些服务或功能可能仍然需要保持活动状态,以便能够及时提供必要的功能或服务。 |
47 | releaseLowPowerStandbyPorts | 释放低功耗待机模式下的端口 |
48 | getActiveLowPowerStandbyPorts | 获取低功耗待机模式下的端口 |
49 | getLastShutdownReason | 获取上次进入系统关机的原因 |
50 | getLastSleepReason | 获取上次进入系统睡眠的原因 |
51 | reboot | 系统重启。系统重启是指将设备重新启动,关闭当前的运行进程和服务,然后重新启动整个系统。这通常会导致设备重新加载所有组件并恢复到初始状态。 |
52 | rebootSafeMode | 系统在安全模式下重启。安全模式下,设备会以最小化的配置和功能启动,只加载必需的系统组件和驱动程序,并禁用所有第三方应用和扩展。它的目的是让用户在安全模式下排除可能导致设备问题的第三方应用或驱动程序,以便诊断和修复系统故障。 |
53 | shutdown | 系统关机 |
54 | crash | 调用该接口,会使整个system_server进程crash,然后重启system_server |
55 | setStayOnSetting | 插入特定电源充电(如USB)时,即使用户没有进行操作,设备仍然保持亮屏状态,不自动进入休眠或待机模式。这通常用于特定的应用场景,如在展示设备、信息显示屏等需要持续工作的环境中。 |
56 | setAttentionLight | 当来电话时,设置LED灯闪烁功能开关设置 |
57 | setDozeAfterScreenOff | 灭屏后进入Doze状态的功能开关设置 |
58 | isAmbientDisplayAvailable | 用于检查Ambient Display功能是否可用 |
59 | suppressAmbientDisplay | 控制Ambient Display功能使能 |
60 | isAmbientDisplaySuppressedForToken | 检查Ambient Display功能的是否使能 |
61 | isAmbientDisplaySuppressedForTokenByApp | 同上 |
62 | isAmbientDisplaySuppressed | 同上 |
63 | boostScreenBrightness | 增加屏幕亮度 |
64 | isScreenBrightnessBoosted | 判断是否正处于屏幕亮度增强阶段 |
65 | forceSuspend | 强制进入系统休眠,忽略系统中的保持cpu唤醒的wakelock |
66 | dump | dump进程的调用接口,可以set\get操作 |
6.3 Local API
PMS提供给System_server进程中其它服务或组件的进程内部API.
其它模块可以通过PowerManagerInternal mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);获取PowerManagerInternal 对象,通过该对象获取到Local API.
本地接口 | 作用 | |
1 | setScreenBrightnessOverrideFromWindowManager | 设置屏幕亮度值 |
2 | setDozeOverrideFromDreamManager | 设置Display状态(包括ON\OFF\DOZE\DOZE_SUPEND\ON_SUSPEND)及屏幕亮度值 |
3 | setUserInactiveOverrideFromWindowManager | 设置用户为非活动状态 |
4 | setUserActivityTimeoutOverrideFromWindowManager | 设置foreground activity覆盖用户活动超时时间的功能,前台应用需要保持屏幕保持唤醒状态,以便持续显示内容或响应用户的操作 |
5 | setDrawWakeLockOverrideFromSidekick | 控制设备在doze(设备休眠)状态下是否保持屏幕的显示状态 |
6 | setMaximumScreenOffTimeoutFromDeviceAdmin | 设置屏幕关闭的最大超时时间 |
7 | getLowPowerState | 根据场景,获取该场景下的省电策略参数,封装到PowerSaveState对象返回。如app standby场景下,所有app进入standby模式 |
8 | registerLowPowerModeObserver | 注册低电量模式监听广播 |
9 | setDeviceIdleMode | 设置设备为device idle模式,通过power hal向"/power/mode"写节点 |
10 | setLightDeviceIdleMode | 同上 |
11 | setDeviceIdleWhitelist | Doze模块向PMS传递xml默认Doze白名单 |
12 | setDeviceIdleTempWhitelist | Doze模块向PMS传递用户设置Doze白名单 |
13 | setLowPowerStandbyAllowlist | 设置app standby模式下的白名单 |
14 | setLowPowerStandbyActive | 设置app standby模式状态 |
15 | startUidChanges | 开始更改用户ID |
16 | finishUidChanges | 结束更改用户ID |
17 | updateUidProcState | 更新某个UID下的进程状态 |
18 | uidGone | 某个app或其它模块被卸载,从mUidState列表中移除该UID号 |
19 | uidActive | 某个app或其它模块被安装,从mUidState列表中加入该UID号 |
20 | uidIdle | 某个app或其它模块进入idle状态,对其state更新为Active为false状态 |
21 | setPowerBoost | cpu提频 |
22 | setPowerMode | 设置设备模式,如device idle、performance等 |
23 | wasDeviceIdleFor | 判断设备是否在指定的时间段内处于空闲状态 |
24 | getLastWakeup | 获取上一次设备被唤醒的原因及时间点 |
25 | getLastGoToSleep | 获取上一次设备进入睡眠的原因及时间点 |
26 | interceptPowerKeyDown | 如果侦测到屏幕关闭时启用的接近传感器(proximity sensor),则告诉显示管理器忽略接近传感器,从而重新打开屏幕 |
27 | nap | 屏幕进入屏保状态 |
28 | isAmbientDisplaySuppressed | 该方法用于检测该功能被关闭。Ambient Display可以在Android设备的待机状态下,通过点亮部分屏幕或显示简洁的信息来提醒用户有新的通知或消息。它提供了一种无需解锁手机即可查看最新通知的便捷方式。 |