前言:手机电池的电量主要由两种元件消耗:CPU和显示屏,因此设法降低这两种元件的耗电量就是电源管理的关键; 针对CPU和显示屏,分别有两种节约能源的方案:
(1)CPU:CPU大多有低频率和高频率两种工作频率,为了省电,大部分时间内cpu都工作在降低频率下,只有进行密集计算时,如视频解码才会切换到高频状态;
(2)显示屏:显示屏省电的方法是尽量减少亮屏时间,但是显示屏的开关和应用有很大的关系,因此系统中需要有一套机制来控制显示屏的开关和亮度;
所以,今天分析的PowerManagerService就是管理显示屏的开关和亮度。
先来看下PowerManagerService启动和初始化
首先,我们知道,SystemServer在启动的时候,也就是run()方法中,会启动三类服务:引导服务、核心服务和其他服务,其中引导服务中启动的是一些依赖性比较强的服务,其中就包括了PMS,PMS由SystemServer通过反射的方式启动:
SystemServer.java
private PowerManagerService mPowerManagerService;
private void startBootstrapServices() {
.........
mPowerManagerService = mSystemServiceManager.startService(PowerManagerService.class);
.........
try {
// TODO: use boot phase
mPowerManagerService.systemReady(mActivityManagerService.getAppOpsService());
} catch (Throwable e) {
reportWtf("making Power Manager Service ready", e);
}
.........
}
看下mSystemServiceManager.startService():
SystemServiceManager.java
public <T extends SystemService> T startService(Class<T> serviceClass) {
try {
final String name = serviceClass.getName();
Slog.i(TAG, "Starting " + name);
Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartService " + name);
// Create the service.
if (!SystemService.class.isAssignableFrom(serviceClass)) {
throw new RuntimeException("Failed to create " + name
+ ": service must extend " + SystemService.class.getName());
}
final T service;
try {
//通过反射的方式创建PowerManagerService
Constructor<T> constructor = serviceClass.getConstructor(Context.class);
service = constructor.newInstance(mContext);
} catch (InstantiationException ex) {
......
}
//开启服务
startService(service);
return service;
} finally {
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
}
public void startService(@NonNull final SystemService service) {
//注册服务到服务列表中,进行生命周期管理
mServices.add(service);
// Start it.
long time = SystemClock.elapsedRealtime();
try {
//启动服务
service.onStart();
} catch (RuntimeException ex) {
throw new RuntimeException("Failed to start service " + service.getClass().getName()
+ ": onStart threw an exception", ex);
}
warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onStart");
}
从上面可以看出,先调用PowerManagerServcie的构造函数,再调用其onStart()函数,也就是PowerManagerService的初始化:
public PowerManagerService(Context context) {
super(context);
mContext = context;
//创建一个系统级别的HandlerThread,继承于Thread
mHandlerThread = new ServiceThread(TAG,
Process.THREAD_PRIORITY_DISPLAY, false /*allowIo*/);
mHandlerThread.start();//线程开启
//创建一个处理消息和发送消息的线程mHandler
//根据HandlerThread中的Looper,在HandlerThread中进行异步的操作
mHandler = new PowerManagerHandler(mHandlerThread.getLooper());
mConstants = new Constants(mHandler);
mAmbientDisplayConfiguration = new AmbientDisplayConfiguration(mContext);
mBatterySaverPolicy = new BatterySaverPolicy(mHandler);
qcNsrmPowExt = new QCNsrmPowerExtension(this);
synchronized (mLock) {
//获取当应用申请wakelock后让CUP保持激活状态的Suspendlocker实例,它会传入到底层,,控制cpu唤醒状态
mWakeLockSuspendBlocker = createSuspendBlockerLocked("PowerManagerService.WakeLocks");
//获取当显示屏开启、显示屏准备就绪或者有用户活动后让CPU保持激活状态的Suspendlocker,传入到底层,控制屏幕亮灭
mDisplaySuspendBlocker = createSuspendBlockerLocked("PowerManagerService.Display");
//申请PowerManagerService.Display类型的suspendBloker锁
mDisplaySuspendBlocker.acquire();
//持有Display锁的bool值
mHoldingDisplaySuspendBlocker = true;
//AutoSuspend模式是否开启
mHalAutoSuspendModeEnabled = false;
//是否处于交互模式
mHalInteractiveModeEnabled = true;
/*mWakefulness 标识系统当前状态共有四种定义:
WAKEFULNESS_ASLEEP:表示系统当前处于休眠状态,只能被wakeUp()调用唤醒。
WAKEFULNESS_AWAKE:表示系统目前处于正常运行状态。
WAKEFULNESS_DREAMING:表示系统当前正处于屏保的状态。
WAKEFULNESS_DOZING:表示系统正处于“doze”状态。这种状态下只有低耗电的“屏保”可以运行,其他应用进程都被挂起。*/
//将mWakefulness置成WAKEFULNESS_AWAKE状态
mWakefulness = WAKEFULNESS_AWAKE;
sQuiescent = SystemProperties.get(SYSTEM_PROPERTY_QUIESCENT, "0").equals("1");
//初始化相关资源
nativeInit();
nativeSetAutoSuspend(false);//设置是否开启anto suspend模式
nativeSetInteractive(true);//设置是否处于交互模式
nativeSetFeature(POWER_FEATURE_DOUBLE_TAP_TO_WAKE, 0);
}
}
public void onStart() {
//将POWER_SERVICE作为Binder的服务端,注册到SystemService中去,以后通过Context.POWER_SERVICE获取的服务,其实就是PowerManagerService的内部类BinderService();
publishBinderService(Context.POWER_SERVICE, new BinderService());
//将PowerManagerInternal注册到本地服务中
publishLocalService(PowerManagerInternal.class, new LocalService());
//将自己加到watchdog的监控队列中去
Watchdog.getInstance().addMonitor(this);
//将之前在构造函数中创建的mHandler对象加入到watchdog的中,用于监视mHandler的looper是否空闲;
Watchdog.getInstance().addThread(mHandler);
}
//系统启动的不同阶段都会调用onBootPhase()
public void onBootPhase(int phase) {
synchronized (mLock) {
if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
//统计启动的apk个数
incrementBootCount();
} else if (phase == PHASE_BOOT_COMPLETED) {//系统启动完成
final long now = SystemClock.uptimeMillis();
mBootCompleted = true;
//启动完成,需要更新
mDirty |= DIRTY_BOOT_COMPLETED;
//更新用户活动时间
userActivityNoUpdateLocked(
now, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID);
//更新电源状态信息
updatePowerStateLocked();
if (!ArrayUtils.isEmpty(mBootCompletedRunnables)) {
Slog.d(TAG, "Posting " + mBootCompletedRunnables.length + " delayed runnables");
for (Runnable r : mBootCompletedRunnables) {
BackgroundThread.getHandler().post(r);
}
}
mBootCompletedRunnables = null;
}
}
}
public void systemReady(IAppOpsService appOps) {
synchronized (mLock) {
mSystemReady = true;
mAppOps = appOps;
//屏保管理,和DreamManagerService交互
mDreamManager = getLocalService(DreamManagerInternal.class);
//屏幕显示管理,和DisplayManagerService交互
mDisplayManagerInternal = getLocalService(DisplayManagerInternal.class);
//窗口策略,和WindowManagerService交互
mPolicy = getLocalService(WindowManagerPolicy.class);
//电池电量管理,和BatteryService交互
mBatteryManagerInternal = getLocalService(BatteryManagerInternal.class);
PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
//获取屏幕最大亮度,最小亮度,和默认亮度;
mScreenBrightnessSettingMinimum = pm.getMinimumScreenBrightnessSetting();
mScreenBrightnessSettingMaximum = pm.getMaximumScreenBrightnessSetting();
mScreenBrightnessSettingDefault = pm.getDefaultScreenBrightnessSetting();
mScreenBrightnessForVrSettingDefault = pm.getDefaultScreenBrightnessForVrSetting();
//创建sensorManager对象,用于与sensor交互,比如距离传感器,光线传感器,加速度传感器(doze上使用)等
SensorManager sensorManager = new SystemSensorManager(mContext, mHandler.getLooper());
//获取BatteryStatsService,电池状态服务和背光服务
mBatteryStats = BatteryStatsService.getService();
//创建mNotifier对象,用于PMS和其他系统服务间的交互,以及广播的发送
//它会通知系统中电源状态的改变,在通过mNotifier发送通知时候,会传入底层申请PowerManagerService.Broadcasts的wakelock锁。
mNotifier = new Notifier(Looper.getMainLooper(), mContext, mBatteryStats,
mAppOps, createSuspendBlockerLocked("PowerManagerService.Broadcasts"),
mPolicy);
//用于检测无线充电的传感器(市面上支持的手机较少)
mWirelessChargerDetector = new WirelessChargerDetector(sensorManager,
createSuspendBlockerLocked("PowerManagerService.WirelessChargerDetector"),
mHandler);
//监听系统设置变化,比如亮屏时间,自动背光,屏幕亮度,屏保,低电模式等等
mSettingsObserver = new SettingsObserver(mHandler);
//指示灯管理,和LightsManager交互
mLightsManager = getLocalService(LightsManager.class);
mAttentionLight = mLightsManager.getLight(LightsManager.LIGHT_ID_ATTENTION);
//初始化Power显示模块
//mDisplayPowerCallbacks提供PMS和Display的接口,当DisplayPowerController发生改变,通过该接口回调PMS中的实现
//initPowerManagement()方法中实例化了DisplayPowerController,
//mDisplayPowerCallbacks是和显示有关,如亮灭屏、背光调节
mDisplayManagerInternal.initPowerManagement(
mDisplayPowerCallbacks, mHandler, sensorManager);
// Go.
readConfigurationLocked();
updateSettingsLocked();
mDirty |= DIRTY_BATTERY_STATE;
updatePowerStateLocked();
}
final ContentResolver resolver = mContext.getContentResolver();
mConstants.start(resolver);
mBatterySaverPolicy.start(resolver);
//以下是监听系统设置变化
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.Global.getUriFor(
Settings.Global.STAY_ON_WHILE_PLUGGED_IN),
false, mSettingsObserver, UserHandle.USER_ALL);
resolver.registerContentObserver(Settings.System.getUriFor(
Settings.System.SCREEN_BRIGHTNESS),
false, mSettingsObserver, UserHandle.USER_ALL);
resolver.registerContentObserver(Settings.System.getUriFor(
Settings.System.SCREEN_BRIGHTNESS_FOR_VR),
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.LOW_POWER_MODE),
false, mSettingsObserver, UserHandle.USER_ALL);
resolver.registerContentObserver(Settings.Global.getUriFor(
Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL),
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);
IVrManager vrManager = (IVrManager) getBinderService(Context.VR_SERVICE);
if (vrManager != null) {
try {
vrManager.registerListener(mVrStateCallbacks);
} catch (RemoteException e) {
Slog.e(TAG, "Failed to register VR mode state listener: " + e);
}
}
//以下是监听系统其他应用发来的广播
//注册BatteryService中ACTION_BATTERY_CHANGED广播
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_BATTERY_CHANGED);
filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
mContext.registerReceiver(new BatteryReceiver(), filter, null, mHandler);
Dream相关
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);
}
private void readConfigurationLocked() {
final Resources resources = mContext.getResources();
/**
* auto_suspend模式是否和display分离
* 如果为false,则在亮屏前调用autosuspend_disable(),灭屏后调用
* autosuspend_enable();
* 如果为ture,则调用autosuspend_display()和autosuspend_enable()独立于display
* on/off.
*/
mDecoupleHalAutoSuspendModeFromDisplayConfig = resources.getBoolean(
com.android.internal.R.bool.
config_powerDecoupleAutoSuspendModeFromDisplay);
/**
* interactive模式是否和display分离
* 如果为false,则在亮屏前调用setInteractive(..., true),灭屏后调用
* setInteractive(...,false);
* 如果为ture,则调用setInteractive(...)独立于display on/off.
*/
mDecoupleHalInteractiveModeFromDisplayConfig = resources.getBoolean(
com.android.internal.R.bool
.config_powerDecoupleInteractiveModeFromDisplay);
//插拔USB是否亮屏
mWakeUpWhenPluggedOrUnpluggedConfig = resources.getBoolean(
com.android.internal.R.bool.config_unplugTurnsOnScreen);
//设备处于剧院模式时,插拔USB是否亮屏
mWakeUpWhenPluggedOrUnpluggedInTheaterModeConfig = resources.getBoolean(
com.android.internal.R.bool.config_allowTheaterModeWakeFromUnplug);
//是否允许设备由于接近传感器而关闭屏幕时CPU挂起,进入suspend状态
mSuspendWhenScreenOffDueToProximityConfig = resources.getBoolean(
com.android.internal.R.bool.
config_suspendWhenScreenOffDueToProximity);
//是否支持屏保
mDreamsSupportedConfig = resources.getBoolean(
com.android.internal.R.bool.config_dreamsSupported);
//是否屏保默认打开--false
mDreamsEnabledByDefaultConfig = resources.getBoolean(
com.android.internal.R.bool.config_dreamsEnabledByDefault);
//充电和睡眠时屏保是否激活
mDreamsActivatedOnSleepByDefaultConfig = resources.getBoolean(
com.android.internal.R.bool.config_dreamsActivatedOnSleepByDefault);
//Dock时屏保是否激活
mDreamsActivatedOnDockByDefaultConfig = resources.getBoolean(
com.android.internal.R.bool.config_dreamsActivatedOnDockByDefault);
//放电时是否允许进入屏保
mDreamsEnabledOnBatteryConfig = resources.getBoolean(
com.android.internal.R.bool.config_dreamsEnabledOnBattery);
//充电时允许屏保的最低电量,使用-1禁用此功能
mDreamsBatteryLevelMinimumWhenPoweredConfig = resources.getInteger(
com.android.internal.R.integer.
config_dreamsBatteryLevelMinimumWhenPowered);
//放电时允许屏保的最低电量,使用-1禁用此功能,默认15
mDreamsBatteryLevelMinimumWhenNotPoweredConfig = resources.getInteger(
com.android.internal.R.integer.
config_dreamsBatteryLevelMinimumWhenNotPowered);
//电亮下降到该百分点,当用户活动超时后不进入屏保,默认5
mDreamsBatteryLevelDrainCutoffConfig = resources.getInteger(
com.android.internal.R.integer.config_dreamsBatteryLevelDrainCutoff);
//如果为true,则直到关闭屏幕并执行屏幕关闭动画之后,才开始Doze,默认false
mDozeAfterScreenOffConfig = resources.getBoolean(
com.android.internal.R.bool.config_dozeAfterScreenOff);
//用户活动超时的最小时间,默认10000ms,必须大于0
mMinimumScreenOffTimeoutConfig = resources.getInteger(
com.android.internal.R.integer.config_minimumScreenOffTimeout);
//用户活动超时进入且关闭屏幕前屏幕变暗的最大时间,默认7000ms,必须大于0
mMaximumScreenDimDurationConfig = resources.getInteger(
com.android.internal.R.integer.config_maximumScreenDimDuration);
//屏幕变暗的时长比例,如果用于超时时间过短,则在7000ms的基础上按还比例减少,默认20%
mMaximumScreenDimRatioConfig = resources.getFraction(
com.android.internal.R.fraction.config_maximumScreenDimRatio, 1, 1);
//是否支持双击唤醒屏幕
mSupportsDoubleTapWakeConfig = resources.getBoolean(
com.android.internal.R.bool.config_supportDoubleTapWake);
}
点评:(1)SuspendBlocker是一种锁机制,只用于系统内部,上层申请的wakelock锁在PMS中都会反映为SuspendBlocker锁。这里获取的两个Suspend锁在申请wakelock时会用到,这块在wakelock申请时会进行详细分析;
(2)首先对该服务进行Binder注册和本地注册,当进行Binder注册后,在其他模块中就可以通过Binder机制获取其实例,也就是PMS.BinderService,同理,当进行本地注册后,只有在System进程才能获取到其实例,也就是PMS.LocalService;
(3)在SystemServiceManager的startBootPhase()中,调用SystemService的onBootPhase(int)方法,此时每个SystemService都会执行其对应的onBootPhase()方法。通过在SystemServiceManager中传入不同的形参,回调所有SystemService的onBootPhase(),根据形参的不同,在方法实现中完成不同的工作,在SystemService中定义了六个阶段:
SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY:这是一个依赖 项,只有DisplayManagerService中进行了对应处理;
SystemService.PHASE_LOCK_SETTINGS_READY:经过这个引导阶段后,服务才可以接收到wakelock相关设置数据;
SystemService.PHASE_SYSTEM_SERVICES_READY:经过这个引导阶段 后,服务才可以安全地使用核心系统服务
SystemService.PHASE_ACTIVITY_MANAGER_READY:经过这个引导阶 段后,服务可以发送广播
SystemService.PHASE_THIRD_PARTY_APPS_CAN_START:经过这个引 导阶段后,服务可以启动第三方应用,第三方应用也可以通过Binder来调 用服务。
SystemService.PHASE_BOOT_COMPLETED:经过这个引导阶段后,说明服务启动完成,这时用户就可以和设备进行交互。
只要在其他模块中调用了SystemServiceManager.startBootPhase(),都会触发各自的onBootPhase()。PMS的onBootPhase()方法只对引导阶段的2个阶段做了处理;
(4)mDirty是一个二进制的标记位,用来表示电源状态哪一部分发生了改变;
(5)PMS在初始化时,依次执行的函数是:构造方法、onStart()、onBootPhase()(会调用多次)方法,systemReady()方法;
PowerManagerService管理的功能很多,如亮屏,暗屏,系统睡眠,唤醒等,主要分析它的唤醒机制;
2.提供给应用端使用的api
我们知道,通过Context.POWER_SERVICE获取的服务,其实就是PowerManagerService的内部类BinderService(),我们来看下BinderService():
private final class BinderService extends IPowerManager.Stub {
@Override
public void onShellCommand(FileDescriptor in, FileDescriptor out,
FileDescriptor err, String[] args, ShellCallback callback,
ResultReceiver resultReceiver) {
(new PowerManagerShellCommand(this)).exec(
this, in, out, err, args, callback, resultReceiver);
}
@Override // Binder call
public void acquireWakeLockWithUid(IBinder lock, int flags, String tag,
......
}
@Override // Binder call
public void powerHint(int hintId, int data) {
......
}
@Override // Binder call
public void acquireWakeLock(IBinder lock, int flags, String tag, String packageName,
WorkSource ws, String historyTag) {
......
}
@Override // Binder call
public void releaseWakeLock(IBinder lock, int flags) {
......
}
@Override // Binder call
public void updateWakeLockUids(IBinder lock, int[] uids) {
......
}
@Override // Binder call
public void updateWakeLockWorkSource(IBinder lock, WorkSource ws, String historyTag) {
......
}
@Override // Binder call
public boolean isWakeLockLevelSupported(int level) {
......
}
@Override // Binder call
//用户活动
public void userActivity(long eventTime, int event, int flags) {
......
}
@Override // Binder call
public void wakeUp(long eventTime, String reason, String opPackageName) {
......
}
@Override // Binder call
public void goToSleep(long eventTime, int reason, int flags) {
......
}
@Override // Binder call
public void nap(long eventTime) {
......
}
@Override // Binder call
public boolean isInteractive() {
......
}
@Override // Binder call
public boolean isPowerSaveMode() {
......
}
// Binder call
public PowerSaveState getPowerSaveState(@ServiceType int serviceType) {
......
}
@Override // Binder call
public boolean setPowerSaveMode(boolean mode) {
......
}
@Override // Binder call
public boolean isDeviceIdleMode() {
......
}
@Override // Binder call
public boolean isLightDeviceIdleMode() {
......
}
@Override // Binder call
public int getLastShutdownReason() {
......
}
@Override // Binder call
public void reboot(boolean confirm, String reason, boolean wait) {
......
}
@Override // Binder call
public void rebootSafeMode(boolean confirm, boolean wait) {
......
}
@Override // Binder call
public void shutdown(boolean confirm, String reason, boolean wait) {
......
}
@Override // Binder call
public void crash(String message) {
......
}
@Override // Binder call
public void setStayOnSetting(int val) {
......
}
@Override // Binder call
public void setTemporaryScreenBrightnessSettingOverride(int brightness) {
......
}
@Override // Binder call
public void setTemporaryScreenAutoBrightnessAdjustmentSettingOverride(float adj) {
......
}
@Override // Binder call
public void setAttentionLight(boolean on, int color) {
......
}
@Override // Binder call
public void boostScreenBrightness(long eventTime) {
......
}
@Override // Binder call
public boolean isScreenBrightnessBoosted() {
......
}
@Override // Binder call
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
......
}
@Override
public void updateBlockedUids(int uid, boolean isBlocked) {
......
}
}
PowerManagerService给我们提供了如此多的API,那我们就以分析这些api来窥探PowerManagerService的原理;
1.用户活动 userActivity()
userActivity()接口用于用户进程向PowerManagerService报告用户影响系统休眠的活动。例如, 用户点击屏幕时,系统会调用该方法来告诉PowerManagerService用户点击的时间,这样PowerManagerService将更新内部保存的时间值,从而推迟系统休眠的时间;
//eventTime表示用户活动产生的时间戳
public void userActivity(long eventTime, int event, int flags) {
final long now = SystemClock.uptimeMillis();
//查看是否有android.Manifest.permission.DEVICE_POWER以及android.Manifest.permission.USER_ACTIVITY权限
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER)
!= PackageManager.PERMISSION_GRANTED
&& mContext.checkCallingOrSelfPermission(
android.Manifest.permission.USER_ACTIVITY)
!= PackageManager.PERMISSION_GRANTED) {
synchronized (mLock) {
if (now >= mLastWarningAboutUserActivityPermission + (5 * 60 * 1000)) {
mLastWarningAboutUserActivityPermission = now;
Slog.w(TAG, "Ignoring call to PowerManager.userActivity() because the "
+ "caller does not have DEVICE_POWER or USER_ACTIVITY "
+ "permission. Please fix your app! "
+ " pid=" + Binder.getCallingPid()
+ " uid=" + Binder.getCallingUid());
}
}
return;
}
if (eventTime > now) {
throw new IllegalArgumentException("event time must not be in the future");
}
final int uid = Binder.getCallingUid();
final long ident = Binder.clearCallingIdentity();
try {
//调用userActivityInternal()
userActivityInternal(eventTime, event, flags, uid);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
private void userActivityInternal(long eventTime, int event, int flags, int uid) {
synchronized (mLock) {
//判断该用户活动是否需要更新电源状态
if (userActivityNoUpdateLocked(eventTime, event, flags, uid)) {
//调用updatePowerStateLocked(),后面会分析
updatePowerStateLocked();
}
}
}
private boolean userActivityNoUpdateLocked(long eventTime, int event, int flags, int uid) {
if (DEBUG_SPEW) {
Slog.d(TAG, "userActivityNoUpdateLocked: eventTime=" + eventTime
+ ", event=" + event + ", flags=0x" + Integer.toHexString(flags)
+ ", uid=" + uid);
}
if (eventTime < mLastSleepTime || eventTime < mLastWakeTime
|| !mBootCompleted || !mSystemReady) {
return false;
}
Trace.traceBegin(Trace.TRACE_TAG_POWER, "userActivity");
try {
//
if (eventTime > mLastInteractivePowerHintTime) {
powerHintInternal(PowerHint.INTERACTION, 0);
mLastInteractivePowerHintTime = eventTime;
}
//向系统通知,有用户活动
mNotifier.onUserActivity(event, uid);
if (mUserInactiveOverrideFromWindowManager) {
mUserInactiveOverrideFromWindowManager = false;
mOverriddenTimeout = -1;
}
//如果当前是休眠状态,或者正处于“doze”状态,或者传递进来了PowerManager.USER_ACTIVITY_FLAG_INDIRECT标签,此时的用户活动无效;
//比如,此时用户点击了屏幕,但是它不想让此次点击延迟电源休眠的时间
if (mWakefulness == WAKEFULNESS_ASLEEP
|| mWakefulness == WAKEFULNESS_DOZING
|| (flags & PowerManager.USER_ACTIVITY_FLAG_INDIRECT) != 0) {
return false;
}
//含有USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS标签
if ((flags & PowerManager.USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS) != 0) {
if (eventTime > mLastUserActivityTimeNoChangeLights
&& eventTime > mLastUserActivityTime) {
mLastUserActivityTimeNoChangeLights = eventTime;
mDirty |= DIRTY_USER_ACTIVITY;
if (event == PowerManager.USER_ACTIVITY_EVENT_BUTTON) {
mDirty |= DIRTY_QUIESCENT;
}
return true;
}
} else {
if (eventTime > mLastUserActivityTime) {
//设置最新的mLastUserActivityTime
mLastUserActivityTime = eventTime;
//保存DIRTY_USER_ACTIVITY
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;
}
2.唤醒 wakeUp()
为什么要唤醒或者休眠系统呢?因为系统在休眠状态下更省电,当没有任务时就进入休眠状态,当有任务来临时候,就唤醒系统,执行相应的任务;
PowerManager的wakeup接口属性是@hide的,对于上层应用是不可见的;
上层应用要唤醒系统大都依靠两种方式:1.在应用启动Activity时候设置相应的window的flags,通过WMS来唤醒系统;2.在应用申请wakelock锁时附带ACQUIRE_CAUSES_WAKEUP标志;
来看下wakeUp()函数:
//强制唤醒系统,如果该设备处于睡眠状态,调用该接口会立即唤醒系统,比如按Power键,来电,闹钟等场景都会调用该接口;
public void wakeUp(long eventTime, String reason, String opPackageName) {
//调用wakeUp()函数的时间不能发生在未来
if (eventTime > SystemClock.uptimeMillis()) {
throw new IllegalArgumentException("event time must not be in the future");
}
//唤醒系统需要android.Manifest.permission#DEVICE_POWER的权限
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.DEVICE_POWER, null);
final int uid = Binder.getCallingUid();
final long ident = Binder.clearCallingIdentity();
try {
//调用wakeUpInternal()
wakeUpInternal(eventTime, reason, uid, opPackageName, uid);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
private void wakeUpInternal(long eventTime, String reason, int uid, String opPackageName,
int opUid) {
synchronized (mLock) {
//判断是否要唤醒系统,如果要唤醒,就设置当前的状态为系统状态
if (wakeUpNoUpdateLocked(eventTime, reason, uid, opPackageName, opUid)) {
//调用updatePowerStateLocked(),后面分析
updatePowerStateLocked();
}
}
}
先看下wakeUpNoUpdateLocked()函数:
private boolean wakeUpNoUpdateLocked(long eventTime, String reason, int reasonUid,
String opPackageName, int opUid) {
if (DEBUG_SPEW) {
Slog.d(TAG, "wakeUpNoUpdateLocked: eventTime=" + eventTime + ", uid=" + reasonUid);
}
//当此时已经是唤醒状态,或者开机未完成,或者systemReady()函数还未调用(也就是初始化未完成)时,不执行唤醒系统操作
if (eventTime < mLastSleepTime || mWakefulness == WAKEFULNESS_AWAKE
|| !mBootCompleted || !mSystemReady) {
return false;
}
Trace.asyncTraceBegin(Trace.TRACE_TAG_POWER, TRACE_SCREEN_ON, 0);
Trace.traceBegin(Trace.TRACE_TAG_POWER, "wakeUp");
try {
switch (mWakefulness) {
case WAKEFULNESS_ASLEEP:
Slog.i(TAG, "Waking up from sleep (uid=" + reasonUid + " reason=" + reason
+ ")...");
break;
case WAKEFULNESS_DREAMING:
Slog.i(TAG, "Waking up from dream (uid=" + reasonUid + " reason=" + reason
+ ")...");
break;
case WAKEFULNESS_DOZING:
Slog.i(TAG, "Waking up from dozing (uid=" + reasonUid + " reason=" + reason
+ ")...");
break;
}
//保存当前的唤醒时间
mLastWakeTime = eventTime;
//设置当前的状态为唤醒状态
setWakefulnessLocked(WAKEFULNESS_AWAKE, 0);
//调用mNotifier向系统通知,系统被唤醒,后面会详述该函数
mNotifier.onWakeUp(reason, reasonUid, opPackageName, opUid);
//更新用户活动,将mDirty |= DIRTY_USER_ACTIVITY置位,来重新计算亮屏时间,后面会详述该函数
userActivityNoUpdateLocked(
eventTime, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, reasonUid);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
return true;
}
void setWakefulnessLocked(int wakefulness, int reason) {
if (mWakefulness != wakefulness) {
//设置mWakefulness
mWakefulness = wakefulness;
mWakefulnessChanging = true;
//设置mDirty
mDirty |= DIRTY_WAKEFULNESS;
if (mNotifier != null) {
//通知到PhoneWindowManager屏幕开始启动;
mNotifier.onWakefulnessChangeStarted(wakefulness, reason);
}
}
}
3.休眠 goToSleep()
唤醒系统执行任务,那也要休眠系统保持低耗电;
PowerManager的goToSleep()接口属性也是@hide的,对于上层应用是不可见的;
设备强制进入睡眠状态,在处理一些灭屏按键事件时,会通过WMS来调用PowerManager的gotoSleep接口;当然,当系统一段时间没有被操作时,系统将会自动调用gotoSleep函数,让其进入到睡眠模式:
public void goToSleep(long eventTime, int reason, int flags) {
if (eventTime > SystemClock.uptimeMillis()) {
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 {
//调用goToSleepInternal()
goToSleepInternal(eventTime, reason, flags, uid);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
private void goToSleepInternal(long eventTime, int reason, int flags, int uid) {
synchronized (mLock) {
//是否要休眠
if (goToSleepNoUpdateLocked(eventTime, reason, flags, uid)) {
//调用updatePowerStateLocked(),后面分析
updatePowerStateLocked();
}
}
}
private boolean goToSleepNoUpdateLocked(long eventTime, int reason, int flags, int uid) {
if (DEBUG_SPEW) {
Slog.d(TAG, "goToSleepNoUpdateLocked: eventTime=" + eventTime
+ ", reason=" + reason + ", flags=" + flags + ", uid=" + uid);
}
if (eventTime < mLastWakeTime
|| mWakefulness == WAKEFULNESS_ASLEEP
|| mWakefulness == WAKEFULNESS_DOZING
|| !mBootCompleted || !mSystemReady) {
return false;
}
Trace.traceBegin(Trace.TRACE_TAG_POWER, "goToSleep");
try {
//休眠原因
switch (reason) {
case PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN:
Slog.i(TAG, "Going to sleep due to device administration policy "
+ "(uid " + uid +")...");
break;
case PowerManager.GO_TO_SLEEP_REASON_TIMEOUT:
Slog.i(TAG, "Going to sleep due to screen timeout (uid " + uid +")...");
break;
case PowerManager.GO_TO_SLEEP_REASON_LID_SWITCH:
Slog.i(TAG, "Going to sleep due to lid switch (uid " + uid +")...");
break;
case PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON:
Slog.i(TAG, "Going to sleep due to power button (uid " + uid +")...");
break;
case PowerManager.GO_TO_SLEEP_REASON_SLEEP_BUTTON:
Slog.i(TAG, "Going to sleep due to sleep button (uid " + uid +")...");
break;
case PowerManager.GO_TO_SLEEP_REASON_HDMI:
Slog.i(TAG, "Going to sleep due to HDMI standby (uid " + uid +")...");
break;
default:
Slog.i(TAG, "Going to sleep by application request (uid " + uid +")...");
reason = PowerManager.GO_TO_SLEEP_REASON_APPLICATION;
break;
}
//记录休眠时间
mLastSleepTime = eventTime;
mSandmanSummoned = true;
//设置电源状态
setWakefulnessLocked(WAKEFULNESS_DOZING, reason);
// Report the number of wake locks that will be cleared by going to sleep.
int numWakeLocksCleared = 0;
//关于WakeLock,等会解释
final int numWakeLocks = mWakeLocks.size();
for (int i = 0; i < numWakeLocks; i++) {
final WakeLock wakeLock = mWakeLocks.get(i);
switch (wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK) {
case PowerManager.FULL_WAKE_LOCK:
case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
case PowerManager.SCREEN_DIM_WAKE_LOCK:
numWakeLocksCleared += 1;
break;
}
}
EventLog.writeEvent(EventLogTags.POWER_SLEEP_REQUESTED, numWakeLocksCleared);
// Skip dozing if requested.
//跳过电源的dozing状态
if ((flags & PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE) != 0) {
reallyGoToSleepNoUpdateLocked(eventTime, uid);
}
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
return true;
}
private boolean reallyGoToSleepNoUpdateLocked(long eventTime, int uid) {
if (DEBUG_SPEW) {
Slog.d(TAG, "reallyGoToSleepNoUpdateLocked: eventTime=" + eventTime
+ ", uid=" + uid);
}
if (eventTime < mLastWakeTime || mWakefulness == WAKEFULNESS_ASLEEP
|| !mBootCompleted || !mSystemReady) {
return false;
}
Trace.traceBegin(Trace.TRACE_TAG_POWER, "reallyGoToSleep");
try {
Slog.i(TAG, "Sleeping (uid " + uid +")...");
//设置系统的状态为休眠状态
setWakefulnessLocked(WAKEFULNESS_ASLEEP, PowerManager.GO_TO_SLEEP_REASON_TIMEOUT);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
return true;
}
4.申请锁 acquireWakeLock()
我们知道,手机待机一段时间之后,便会进入休眠状态,一旦进入休眠状态后,自定义的Timer、Handler、Thread、Service等都会暂停,这种机制会影响到我们程序的正常运行,那如何避免系统休眠对我们程序的影响呢?
答案就是申请WakeLock锁;
Android设备的休眠和唤醒主要基于WakeLock机制。WakeLock是一种上锁机制,只要有进程获得了WakeLock锁系统就不会进 入休眠。例如,在下载文件或播放音乐时,即使休眠时间到了,系统也不能进行休眠。WakeLock可以设置超时,超时后会自动解锁。
那应用如何获取WakeLock锁呢?写个例子:
public WakeLock wakeLock = null;
PowerManager pm = (PowerManager) myActivity.getSystemService(Context.POWER_SERVICE);
//创建一个WakeLock类对象
wakeLock = pm.newWakeLock(PowerManager.ON_AFTER_RELEASE | PowerManager.PARTIAL_WAKE_LOCK, "wakeLockUtil");
if (null != wakeLock){
wakeLock.acquire(); // 立即获取WakeLock锁,禁止系统休眠
// wakeLock.acquire(2000); // 2秒后获取WakeLock锁
}
if (null != wakeLock){
//释放WakeLock锁,恢复休眠机制,否则系统将无法休眠,直到耗光所有电量
wakeLock.release();
wakeLock = null;
}
先来理解下这个WakeLock:
Wakelock是android系统上特有的电源管理机制,只要有应用拿着这个锁,系统就不能进入睡眠状态,在上层不同的应用程序可以持有多个不同的wakelock锁,但是反映到底层就只有三种:控制系统休眠PowerManagerService.WakeLock,控制屏幕显示的PowerManagerService.Display和控制电源状态改变通知的PowerManagerService.Broadcasts。
PowerManagerService有加锁和解锁两种状态,加锁有两种方式:
第一种是永久的锁住,即acquire(),这样的锁除非显式的放开,即release(),否则是不会解锁的;
第二种锁是超时锁,即acquire(long timeout),这种锁会在锁住后一段时间解锁,timeout为设置的超时时间,超时自动release掉该wakelock;
看下WakeLock的源码,简单的介绍下它,WakeLock定义在PowerManager中:
public final class WakeLock {
private int mFlags;
private String mTag;
private final String mPackageName;
private final IBinder mToken;
private int mInternalCount;
private int mExternalCount;
private boolean mRefCounted = true;
private boolean mHeld;
private WorkSource mWorkSource;
private String mHistoryTag;
private final String mTraceName;
private final Runnable mReleaser = new Runnable() {
public void run() {
release(RELEASE_FLAG_TIMEOUT);
}
};
WakeLock(int flags, String tag, String packageName) {
mFlags = flags;
mTag = tag;
mPackageName = packageName;
mToken = new Binder();
mTraceName = "WakeLock (" + mTag + ")";
}
@Override
protected void finalize() throws Throwable {
synchronized (mToken) {
if (mHeld) {
Log.wtf(TAG, "WakeLock finalized while still held: " + mTag);
Trace.asyncTraceEnd(Trace.TRACE_TAG_POWER, mTraceName, 0);
try {
mService.releaseWakeLock(mToken, 0);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
}
}
//设置计数锁和非计数锁;
//wakelock分为计数锁和非计数锁两种:
//计数锁是应用调用一次acquire申请必定会对应一个release来释放;非计数锁应用调用多次acquire,调用一次release就可释放前面acquire的锁。
//在申请wakelock时默认申请的是计数锁。
public void setReferenceCounted(boolean value) {
synchronized (mToken) {
mRefCounted = value;
}
}
//申请wakelock永久锁(默认),需要手动release
public void acquire() {
synchronized (mToken) {
acquireLocked();
}
}
//申请wakelock超时锁,timeout为设置的超时时间,超时自动release掉该wakelock。
public void acquire(long timeout) {
synchronized (mToken) {
acquireLocked();
mHandler.postDelayed(mReleaser, timeout);
}
}
private void acquireLocked() {
mInternalCount++;
mExternalCount++;
if (!mRefCounted || mInternalCount == 1) {
mHandler.removeCallbacks(mReleaser);
Trace.asyncTraceBegin(Trace.TRACE_TAG_POWER, mTraceName, 0);
try {
mService.acquireWakeLock(mToken, mFlags, mTag, mPackageName, mWorkSource,
mHistoryTag);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
mHeld = true;
}
}
public void release() {
release(0);
}
public void release(int flags) {
synchronized (mToken) {
mInternalCount--;
if ((flags & RELEASE_FLAG_TIMEOUT) == 0) {
mExternalCount--;
}
if (!mRefCounted || mInternalCount == 0) {
mHandler.removeCallbacks(mReleaser);
if (mHeld) {
Trace.asyncTraceEnd(Trace.TRACE_TAG_POWER, mTraceName, 0);
try {
mService.releaseWakeLock(mToken, flags);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
mHeld = false;
}
}
if (mRefCounted && mExternalCount < 0) {
throw new RuntimeException("WakeLock under-locked " + mTag);
}
}
}
//判断一个wakelock锁是否acquire申请了,但是没有release释放;
public boolean isHeld() {
synchronized (mToken) {
return mHeld;
}
}
public void setWorkSource(WorkSource ws) {
synchronized (mToken) {
if (ws != null && ws.size() == 0) {
ws = null;
}
final boolean changed;
if (ws == null) {
changed = mWorkSource != null;
mWorkSource = null;
} else if (mWorkSource == null) {
changed = true;
mWorkSource = new WorkSource(ws);
} else {
changed = mWorkSource.diff(ws);
if (changed) {
mWorkSource.set(ws);
}
}
if (changed && mHeld) {
try {
mService.updateWakeLockWorkSource(mToken, mWorkSource, mHistoryTag);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
}
}
......
}
我们使用PowerManager.newWakeLock()方法来创建wakelock锁;
public WakeLock newWakeLock(int levelAndFlags, String tag) {
//检查传递进来的WakeLock类型和tag是否可用
validateWakeLockParameters(levelAndFlags, tag);
return new WakeLock(levelAndFlags, tag, mContext.getOpPackageName());
}
public static void validateWakeLockParameters(int levelAndFlags, String tag) {
switch (levelAndFlags & WAKE_LOCK_LEVEL_MASK) {
//保持CPU运转,屏幕和键盘灯允许关闭,不受电源键影响,应用场景:听音乐,后台下载等 -- 最常用
case PARTIAL_WAKE_LOCK:
//保持CPU 运转,允许保持屏幕显示但有可能是灰的,允许关闭键盘灯,受电源键影响,应用场景:即将进入灭屏休眠状态时
case SCREEN_DIM_WAKE_LOCK:
//保持CPU 运转,允许保持屏幕高亮显示,允许关闭键盘灯,受电源键影响,应用场景:看电子书,看视频,操作屏幕没有操作到键盘等
case SCREEN_BRIGHT_WAKE_LOCK:
//保持CPU 运转,保持屏幕高亮显示,键盘灯也保持亮度,受电源键影响,应用场景:来电话,闹钟触发等
case FULL_WAKE_LOCK:
//CPU不运转,保持屏幕高亮或者关闭,没有置灰,允许关闭键盘灯,受电源键影响,应用场景:
//打电话靠近或远离手机时,需要设备支持距离传感器
case PROXIMITY_SCREEN_OFF_WAKE_LOCK:
//CPU不运转,保持屏幕关闭,允许关闭键盘灯,受电源键影响,应用场景:低电状态,doze模式下,允许cpu进入suspend状态,(系统支持doze)
case DOZE_WAKE_LOCK:
//保持CPU 运转,保持屏幕关闭,允许关闭键盘灯,不受电源键影响,应用场景:保持设备唤醒,能正常进行绘图(windowManager允许应用在dozing状态绘制屏幕)
case DRAW_WAKE_LOCK:
break;
default:
throw new IllegalArgumentException("Must specify a valid wake lock level.");
}
if (tag == null) {
throw new IllegalArgumentException("The tag must not be null.");
}
}
validateWakeLockParameters()函数中规定了WakeLock的类型,除了上面的几种类型,还有以下两种:
ACQUIRE_CAUSES_WAKEUP = 0x10000000//正常情况下,获取wakelock是不会唤醒设备的,加上该标志之后,acquire wakelock也会唤醒设备,该标志常用于闹钟触发,蓝牙链接提醒等场景。
ON_AFTER_RELEASE = 0x20000000//和用户体验有关,当wakelock释放后如果没有该标志,屏幕会立即黑屏,如果有该标志,屏幕会亮一小会然后在黑屏。
ACQUIRE_CAUSES_WAKEUP和ON_AFTER_RELEASE不能和PARTIAL_WAKE_LOCK 一起用。
注意:SCREEN_DIM_WAKE_LOCK,SCREEN_BRIGHT_WAKE_LOCK和FULL_WAKE_LOCK这三种类型的锁,在6.0以后版本会逐渐被抛弃使用,改用WindowManager. LayoutParams 的一个参数FLAG_KEEP_SCREEN_ON 来替换上述三种类型的锁,因为它将由平台被准确地管理用户应用程序之间的动作,并且不需要特殊的权限。
总结:Andoid的控制系统休眠是用wakelock机制,应用程序在使用wakelock前,必须在其manifest.xml文件中注册android.permission.WAKE_LOCK权限,应用要使用wakelock,需先调用newWakeLock()创建wakelock,然后acquire()申请该锁,从而阻止系统休眠,在处理完事物之后要及时调用release()来释放wakelock,否则系统始终无法进入睡眠状态,直到电量耗光。应用创建锁之后,必须通过acquire申请锁才能持有wakelock锁,才能保证系统处于唤醒状态来使用电力资源,接下来就看PowerManagerService的acquireWakeLock()方法:
public void acquireWakeLock(IBinder lock, int flags, String tag, String packageName,
WorkSource ws, String historyTag) {
if (lock == null) {
throw new IllegalArgumentException("lock must not be null");
}
if (packageName == null) {
throw new IllegalArgumentException("packageName must not be null");
}
//验证flags
PowerManager.validateWakeLockParameters(flags, tag);
//检查权限
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
if ((flags & PowerManager.DOZE_WAKE_LOCK) != 0) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.DEVICE_POWER, null);
}
if (ws != null && ws.size() != 0) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.UPDATE_DEVICE_STATS, null);
} else {
ws = null;
}
final int uid = Binder.getCallingUid();
final int pid = Binder.getCallingPid();
final long ident = Binder.clearCallingIdentity();
try {
//调用acquireWakeLockInternal()
acquireWakeLockInternal(lock, flags, tag, packageName, ws, historyTag, uid, pid);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
private void acquireWakeLockInternal(IBinder lock, int flags, String tag, String packageName,
WorkSource ws, String historyTag, int uid, int pid) {
synchronized (mLock) {
if (DEBUG_SPEW) {
Slog.d(TAG, "acquireWakeLockInternal: lock=" + Objects.hashCode(lock)
+ ", flags=0x" + Integer.toHexString(flags)
+ ", tag=\"" + tag + "\", ws=" + ws + ", uid=" + uid + ", pid=" + pid);
}
WakeLock wakeLock;
//检查mWakeLock列表中是否已经存在有相同的wakelock,
int index = findWakeLockIndexLocked(lock);
boolean notifyAcquire;
if (index >= 0) {//如果存在那么调用wakeLock.updateProperties()
wakeLock = mWakeLocks.get(index);
if (!wakeLock.hasSameProperties(flags, tag, ws, uid, pid)) {
// Update existing wake lock. This shouldn't happen but is harmless.
notifyWakeLockChangingLocked(wakeLock, flags, tag, packageName,
uid, pid, ws, historyTag);
//更新该wakelock的属性值
wakeLock.updateProperties(flags, tag, packageName, ws, historyTag, uid, pid);
}
notifyAcquire = false;
} else {//如果不存在,
UidState state = mUidState.get(uid);
if (state == null) {
state = new UidState(uid);
state.mProcState = ActivityManager.PROCESS_STATE_NONEXISTENT;
mUidState.put(uid, state);
}
state.mNumWakeLocks++;
//那么创建wakelock锁,
wakeLock = new WakeLock(lock, flags, tag, packageName, ws, historyTag, uid, pid,
state);
try {
lock.linkToDeath(wakeLock, 0);
} catch (RemoteException ex) {
throw new IllegalArgumentException("Wake lock is already dead.");
}
mWakeLocks.add(wakeLock);
setWakeLockDisabledStateLocked(wakeLock);
qcNsrmPowExt.checkPmsBlockedWakelocks(uid, pid, flags, tag, wakeLock);
notifyAcquire = true;
}
//检查申请锁是否带有ACQUIRE_CAUSES_WAKEUP标志,
//若带有该标志,则则会直接调用到wakeup调用线程上,执行唤醒操作,该标志在闹钟,蓝牙链接,来电以及短信窗口提醒等功能中有应用
applyWakeLockFlagsOnAcquireLocked(wakeLock, uid);
//记录申请锁的操作
mDirty |= DIRTY_WAKE_LOCKS;
//更新电源状态
updatePowerStateLocked();
if (notifyAcquire) {
// This needs to be done last so we are sure we have acquired the
// kernel wake lock. Otherwise we have a race where the system may
// go to sleep between the time we start the accounting in battery
// stats and when we actually get around to telling the kernel to
// stay awake.
notifyWakeLockAcquiredLocked(wakeLock);
}
}
}
5.释放锁 releaseWakeLock()
正常情况下,每个wakelock的acquire都应该对应一个release操作,release操作和acquire流程相似。
public void releaseWakeLock(IBinder lock, int flags) {
if (lock == null) {
throw new IllegalArgumentException("lock must not be null");
}
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
final long ident = Binder.clearCallingIdentity();
try {
//调用releaseWakeLockInternal()
releaseWakeLockInternal(lock, flags);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
private void releaseWakeLockInternal(IBinder lock, int flags) {
synchronized (mLock) {
int index = findWakeLockIndexLocked(lock);
if (index < 0) {
if (DEBUG_SPEW) {
Slog.d(TAG, "releaseWakeLockInternal: lock=" + Objects.hashCode(lock)
+ " [not found], flags=0x" + Integer.toHexString(flags));
}
return;
}
//获取要释放的wakelock在mWakeLocks列表中的下标值
WakeLock wakeLock = mWakeLocks.get(index);
if (DEBUG_SPEW) {
Slog.d(TAG, "releaseWakeLockInternal: lock=" + Objects.hashCode(lock)
+ " [" + wakeLock.mTag + "], flags=0x" + Integer.toHexString(flags));
}
if ((flags & PowerManager.RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY) != 0) {
mRequestWaitForNegativeProximity = true;
}
wakeLock.mLock.unlinkToDeath(wakeLock, 0);
//删除该wakelock
removeWakeLockLocked(wakeLock, index);
}
}
private void removeWakeLockLocked(WakeLock wakeLock, int index) {
//mWakeLocks列表中将该wakelock删除
mWakeLocks.remove(index);
UidState state = wakeLock.mUidState;
state.mNumWakeLocks--;
if (state.mNumWakeLocks <= 0 &&
state.mProcState == ActivityManager.PROCESS_STATE_NONEXISTENT) {
mUidState.remove(state.mUid);
}
//通知系统该wakelock已经被删除
notifyWakeLockReleasedLocked(wakeLock);
//判断该wakelock是否有ON_AFTER_RELEASE标志,
//如果带有这个标志释放wakelock锁后系统不会立即进入黑屏状态,而是屏幕继续亮一小会再灭屏,在蓝牙连接,小区广播,来电等功能场景下有应用
applyWakeLockFlagsOnReleaseLocked(wakeLock);
//由于wakelock被释放了,所以mDirty置为DIRTY_WAKE_LOCKS
mDirty |= DIRTY_WAKE_LOCKS;
//更新电源状态
updatePowerStateLocked();
}
6.上面的函数,最终都调用到了updatePowerStateLocked()函数,接下来就看核心函数updatePowerStateLocked():
它用来更新整个电源状态的改变,并进行重新计算:
protected void updatePowerStateLocked() {
if (!mSystemReady || mDirty == 0) {
return;
}
if (!Thread.holdsLock(mLock)) {
Slog.wtf(TAG, "Power manager lock was not held when calling updatePowerStateLocked");
}
Trace.traceBegin(Trace.TRACE_TAG_POWER, "updatePowerState");
try {
/*电源状态更新,最重要的标志变量为mDirty,当与电源相关的状态改变,都会通过置位的方法反映在mDirty集合变量中,
比如充电状态,屏幕亮度,电源设置,唤醒状态等发生改变都会在mDirty中反映出来*/
//代码1
//调用BatteryService更新电池状态,包括电池充电,电量等级等状态。
updateIsPoweredLocked(mDirty);
//代码2
//更新变量mStayOn的值,如果mStayOn如果为true,则屏幕长亮,
//在Setting中可以设置充电时候屏幕长亮,如果Setting中设置了该选项,updateIsPoweredLocked检查到正在充电,会将mStayOn置为true。
updateStayOnLocked(mDirty);
//代码3
//更新屏幕亮度增强
updateScreenBrightnessBoostLocked(mDirty);
// Phase 1: Update wakefulness.
// Loop because the wake lock and user activity computations are influenced
// by changes in wakefulness.
final long now = SystemClock.uptimeMillis();
int dirtyPhase2 = 0;
//这是无限循环,但是这个循环最多执行两次便退出了
for (;;) {
int dirtyPhase1 = mDirty;
dirtyPhase2 |= dirtyPhase1;
mDirty = 0;
//代码4
//将系统中所有的wakelock锁更新到一个集合变量mWakeLockSummary中,也就是不管系统中创建了多少个wakelock,一个便足以阻止系统进入睡眠状态,
// 因此这里将所有的wakelock总结后通过置位的方法保存到一个变量中,应用创建wakelock时会指定wakelock的类型,不同的wakelock类型置于不同的位。
updateWakeLockSummaryLocked(dirtyPhase1);
//代码5
//更新统计userActivity的标记值mUserActivitySummary和休眠到达时间;
//根据系统最后一次调用userActivity()方法的时间计算现在
//是否可以将屏幕状态的变量mUserActivitySummary置成USER_ACTIVITY_SCREEN_BRIGHT(亮屏)还是USER_ACTIVITY_SCREEN_DIM(暗屏)等
updateUserActivitySummaryLocked(now, dirtyPhase1);
//代码6
//用来更新屏幕唤醒状态,状态改变返回true;
//updateWakefulnessLocked(),如果它的返回值为true,则表示wakefulness的状态发生改变了,
//将继续循环重新调用前面两个方法更新userActivity和Wakelock集合变量。
//如果能第二次调用updateWakefulnessLocked()一定会返回false,继而跳出循环
if (!updateWakefulnessLocked(dirtyPhase1)) {
break;
}
}
//代码1--代码6都是在收集属性,接下来就要根据属性来进行操作了
//代码7
// Phase 2: Update display power state.
//和Display交互,请求Display状态;
//更新屏幕显示,当前面如果申请了亮屏锁和更新userActivity时,mUserActivitySummary带有USER_ACTIVITY_SCREEN_BRIGHT标志,则会将mDisplayPowerRequest.policy置为POLICY_BRIGHT,
//这个标志在DisplayPowerController中会将屏幕从灭屏状态下唤醒。
boolean displayBecameReady = updateDisplayPowerStateLocked(dirtyPhase2);
//代码8
// Phase 3: Update dream state (depends on display ready signal).
//更新屏保模式
updateDreamLocked(dirtyPhase2, displayBecameReady);
//代码9
// Phase 4: Send notifications, if needed.
//通知系统mWakefulness改变更新已经完成
finishWakefulnessChangeIfNeededLocked();
//代码10
// Phase 5: Update suspend blocker.
// Because we might release the last suspend blocker here, we need to make sure
// we finished everything else first!
//更新Suspend锁
//由于系统中可能需要释放最后一个维持CPU唤醒或者维持屏幕亮灭的Blocker,所以必须将所有事物处理完成,再执行该操作
//该函数是由PowerManagerService调用到底层的唯一入口
updateSuspendBlockerLocked();
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
}
详细分析:
(1)updateIsPoweredLocked(),更新电池状态:
这个方法主要功能有两个:USB插拔亮屏入口点和更新低电量模式;
前面说过,PowerManagerService在初始化的时候会注册了Intent.ACTION_BATTERY_CHANGED的广播,这个广播由BatteryService发出来的,所以,当电池的状态发生变化时:
private final class BatteryReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
synchronized (mLock) {
handleBatteryStateChangedLocked();
}
}
}
private void handleBatteryStateChangedLocked() {
//将DIRTY_BATTERY_STATE添加到mDirty
mDirty |= DIRTY_BATTERY_STATE;
//调用updatePowerStateLocked()
updatePowerStateLocked();
}
可以看到,当电池的状态发生变化时,会调用updatePowerStateLocked()函数,来看下updateIsPoweredLocked()函数:
private void updateIsPoweredLocked(int dirty) {
if ((dirty & DIRTY_BATTERY_STATE) != 0) {
//是否充电
final boolean wasPowered = mIsPowered;
//充电类型
final int oldPlugType = mPlugType;
//是否低电量
final boolean oldLevelLow = mBatteryLevelLow;
//BatteryManagerInternal的实现类被定义在BatteryService的LocalService中
//mIsPowered表示是否在充电
mIsPowered = mBatteryManagerInternal.isPowered(BatteryManager.BATTERY_PLUGGED_ANY);
//mPlugType 表示充电类型
mPlugType = mBatteryManagerInternal.getPlugType();
//mBatteryLevel 表示当前电量等级
mBatteryLevel = mBatteryManagerInternal.getBatteryLevel();
//mBatteryLevelLow 表示是否为低电;
mBatteryLevelLow = mBatteryManagerInternal.getBatteryLevelLow();
//充电状态发生改变,或者充电方式发生了改变,如USB充电变成了充电器充电
if (wasPowered != mIsPowered || oldPlugType != mPlugType) {
//添加DIRTY_IS_POWERED到mDirty中
mDirty |= DIRTY_IS_POWERED;
//是否是无线充电
final boolean dockedOnWirelessCharger = mWirelessChargerDetector.update(
mIsPowered, mPlugType, mBatteryLevel);
final long now = SystemClock.uptimeMillis();
//插拔充电线是否唤醒屏幕
//充电状态发生改变时,即拔下电池器或者插入充电器,此时需要唤醒系统,进行提醒
if (shouldWakeUpWhenPluggedOrUnpluggedLocked(wasPowered, oldPlugType,
dockedOnWirelessCharger)) {
//屏幕唤醒
wakeUpNoUpdateLocked(now, "android.server.power:POWER", Process.SYSTEM_UID,
mContext.getOpPackageName(), Process.SYSTEM_UID);
}
//用户活动,拔下电池器或者插入充电器也是用户活动的一部分,那就延迟休眠时间
userActivityNoUpdateLocked(
now, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID);
if (dockedOnWirelessCharger) {
mNotifier.onWirelessChargingStarted();
}
}
//充电状态发生改变,或者低电量状态发生变化
if (wasPowered != mIsPowered || oldLevelLow != mBatteryLevelLow) {
if (oldLevelLow != mBatteryLevelLow && !mBatteryLevelLow) {//由低电量状态,进入非低电量状态
if (DEBUG_SPEW) {
Slog.d(TAG, "updateIsPoweredLocked: resetting low power snooze");
}
mAutoLowPowerModeSnoozing = false;
}
//更新低电量的模式
updateLowPowerModeLocked();
}
}
}
再看updateLowPowerModeLocked()函数:
private void updateLowPowerModeLocked() {
if ((mIsPowered || !mBatteryLevelLow && !mBootCompleted) && mLowPowerModeSetting) {
if (DEBUG_SPEW) {
Slog.d(TAG, "updateLowPowerModeLocked: powered or booting with sufficient battery,"
+ " turning setting off");
}
// Turn setting off if powered
//如果正在充电,关闭低电量模式
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.LOW_POWER_MODE, 0);
mLowPowerModeSetting = false;
}
final boolean autoLowPowerModeEnabled = !mIsPowered && mAutoLowPowerModeConfigured
&& !mAutoLowPowerModeSnoozing && mBatteryLevelLow;
final boolean lowPowerModeEnabled = mLowPowerModeSetting || autoLowPowerModeEnabled;
//低电量模式的改变后,发送通知
if (mLowPowerModeEnabled != lowPowerModeEnabled) {
mLowPowerModeEnabled = lowPowerModeEnabled;
//低电量提示
powerHintInternal(PowerHint.LOW_POWER, lowPowerModeEnabled ? 1 : 0);
postAfterBootCompleted(new Runnable() {
@Override
public void run() {
//通知低电量模式的改变
Intent intent = new Intent(PowerManager.ACTION_POWER_SAVE_MODE_CHANGING)
.putExtra(PowerManager.EXTRA_POWER_SAVE_MODE, mLowPowerModeEnabled)
.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
mContext.sendBroadcast(intent);
ArrayList<PowerManagerInternal.LowPowerModeListener> listeners;
synchronized (mLock) {
listeners = new ArrayList<PowerManagerInternal.LowPowerModeListener>(
mLowPowerModeListeners);
}
for (int i = 0; i < listeners.size(); i++) {
final PowerManagerInternal.LowPowerModeListener listener = listeners.get(i);
final PowerSaveState result =
mBatterySaverPolicy.getBatterySaverPolicy(
listener.getServiceType(), lowPowerModeEnabled);
listener.onLowPowerModeChanged(result);
}
intent = new Intent(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
// Send internal version that requires signature permission.
intent = new Intent(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED_INTERNAL);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
Manifest.permission.DEVICE_POWER);
}
});
}
}
点评:只要电池状态发生变化,就能够调用执行到updateIsPoweredLocked()方法进行操作。
在这个方法中,通过BatteryService的本地服务BatteryManagerInternal,和BatteryService进行交互,刷新电池信息,并记录上次的电池数据;然后判断是插拔USB是否需要唤醒屏幕。我们在插拔USB时,可以唤醒屏幕就是从这里为入口进行唤醒的。然后更新用户活动事件;之后会处理低电量时的操作,在if语句中,如果插拔充电线,此时满足条件wasPowered != mIsPowered;或者上次和本次有一次处于低电量,则进入if语句;如果在当前电量未达到低电量值,并且之前处于低电量状态下,此时满足if语句中的if语句,说明此时电量大于低电量值,将mAutoLowPowerModeSnoozing 置为false.于是更新低电量相关的设置。
(2)updateStayOnLocked(),更新变量mStayOn的值,即屏幕是否常亮
方法主要用于判断系统是否在Settings中设置了充电时保持屏幕亮屏后,根据是否充电来决定亮屏与否;
PowerManagerService在初始化的时候,监听了系统设置的变化,当系统设置发生变化时:
private final class SettingsObserver extends ContentObserver {
public SettingsObserver(Handler handler) {
super(handler);
}
@Override
public void onChange(boolean selfChange, Uri uri) {
synchronized (mLock) {
//调用handleSettingsChangedLocked()
handleSettingsChangedLocked();
}
}
}
private void handleSettingsChangedLocked() {
//根据系统中的值,更新相关属性
updateSettingsLocked();
//调用updatePowerStateLocked()
updatePowerStateLocked();
}
private void updateSettingsLocked() {
final ContentResolver resolver = mContext.getContentResolver();
//获取系统中的相关属性值
//屏保是否支持
mDreamsEnabledSetting = (Settings.Secure.getIntForUser(resolver,
Settings.Secure.SCREENSAVER_ENABLED,
mDreamsEnabledByDefaultConfig ? 1 : 0,
UserHandle.USER_CURRENT) != 0);
//休眠时是否启用屏保
mDreamsActivateOnSleepSetting = (Settings.Secure.getIntForUser(resolver,
Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP,
mDreamsActivatedOnSleepByDefaultConfig ? 1 : 0,
UserHandle.USER_CURRENT) != 0);
//插入基座时屏保是否激活
mDreamsActivateOnDockSetting = (Settings.Secure.getIntForUser(resolver,
Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK,
mDreamsActivatedOnDockByDefaultConfig ? 1 : 0,
UserHandle.USER_CURRENT) != 0);
//设备在一段时间不活动后进入休眠或者屏保状态的时间,15*1000ms
mScreenOffTimeoutSetting = Settings.System.getIntForUser(resolver,
Settings.System.SCREEN_OFF_TIMEOUT, DEFAULT_SCREEN_OFF_TIMEOUT,
UserHandle.USER_CURRENT);
/*设备在一段时间不活动后完全进入休眠状态之前的超时时间,
该值必须大于SCREEN_OFF_TIMEOUT,否则设置了屏保后来不及显示屏保就sleep*/
mSleepTimeoutSetting = Settings.Secure.getIntForUser(resolver,
Settings.Secure.SLEEP_TIMEOUT, DEFAULT_SLEEP_TIMEOUT,
UserHandle.USER_CURRENT);
//充电时屏幕一直开启
mStayOnWhilePluggedInSetting = Settings.Global.getInt(resolver,
Settings.Global.STAY_ON_WHILE_PLUGGED_IN, BatteryManager.BATTERY_PLUGGED_USB);
//是否支持剧院模式
mTheaterModeEnabled = Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.THEATER_MODE_ON, 0) == 1;
//屏幕保持常亮
mAlwaysOnEnabled = mAmbientDisplayConfiguration.alwaysOnEnabled(UserHandle.USER_CURRENT);
//双击唤醒屏幕设置
if (mSupportsDoubleTapWakeConfig) {
boolean doubleTapWakeEnabled = Settings.Secure.getIntForUser(resolver,
Settings.Secure.DOUBLE_TAP_TO_WAKE, DEFAULT_DOUBLE_TAP_TO_WAKE,
UserHandle.USER_CURRENT) != 0;
if (doubleTapWakeEnabled != mDoubleTapWakeEnabled) {
mDoubleTapWakeEnabled = doubleTapWakeEnabled;
nativeSetFeature(POWER_FEATURE_DOUBLE_TAP_TO_WAKE, mDoubleTapWakeEnabled ? 1 : 0);
}
}
final String retailDemoValue = UserManager.isDeviceInDemoMode(mContext) ? "1" : "0";
if (!retailDemoValue.equals(SystemProperties.get(SYSTEM_PROPERTY_RETAIL_DEMO_ENABLED))) {
SystemProperties.set(SYSTEM_PROPERTY_RETAIL_DEMO_ENABLED, retailDemoValue);
}
final int oldScreenBrightnessSetting = getCurrentBrightnessSettingLocked();
//VR时的屏幕家亮度
mScreenBrightnessForVrSetting = Settings.System.getIntForUser(resolver,
Settings.System.SCREEN_BRIGHTNESS_FOR_VR, mScreenBrightnessForVrSettingDefault,
UserHandle.USER_CURRENT);
//屏幕亮度
mScreenBrightnessSetting = Settings.System.getIntForUser(resolver,
Settings.System.SCREEN_BRIGHTNESS, mScreenBrightnessSettingDefault,
UserHandle.USER_CURRENT);
//重置临时亮度值
if (oldScreenBrightnessSetting != getCurrentBrightnessSettingLocked()) {
mTemporaryScreenBrightnessSettingOverride = -1;
}
//自动调节亮度值(>0.0 <1.0)
final float oldScreenAutoBrightnessAdjustmentSetting =
mScreenAutoBrightnessAdjustmentSetting;
mScreenAutoBrightnessAdjustmentSetting = Settings.System.getFloatForUser(resolver,
Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, 0.0f,
UserHandle.USER_CURRENT);
if (oldScreenAutoBrightnessAdjustmentSetting != mScreenAutoBrightnessAdjustmentSetting) {
mTemporaryScreenAutoBrightnessAdjustmentSettingOverride = Float.NaN;
}
//亮度调节模式,自动1,正常0
mScreenBrightnessModeSetting = Settings.System.getIntForUser(resolver,
Settings.System.SCREEN_BRIGHTNESS_MODE,
Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL, UserHandle.USER_CURRENT);
//低电量模式是否可用,1表示true
final boolean lowPowerModeEnabled = Settings.Global.getInt(resolver,
Settings.Global.LOW_POWER_MODE, 0) != 0;
final boolean autoLowPowerModeConfigured = Settings.Global.getInt(resolver,
Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0) != 0;
if (lowPowerModeEnabled != mLowPowerModeSetting
|| autoLowPowerModeConfigured != mAutoLowPowerModeConfigured) {
mLowPowerModeSetting = lowPowerModeEnabled;
mAutoLowPowerModeConfigured = autoLowPowerModeConfigured;
//更新低电量模式
updateLowPowerModeLocked();
}
//这个很重要,表示设置中的值发生了变化
mDirty |= DIRTY_SETTINGS;
}
private void updateStayOnLocked(int dirty) {
//电池属性发生了变化并且系统的中值发生了变化
if ((dirty & (DIRTY_BATTERY_STATE | DIRTY_SETTINGS)) != 0) {
final boolean wasStayOn = mStayOn;
//充电时亮屏 && DevicePolicyManager中未设置最大关闭时间;
//mStayOnWhilePluggedInSetting != 0表示插上电源时,屏幕应该常量;
//mMaximumScreenOffTimeoutFromDeviceAdmin表示设备允许的最大屏幕关闭超时时间,
//如果!isMaximumScreenOffTimeoutFromDeviceAdminEnforcedLocked()成立,就表示没有设置屏幕休眠的最大超时时间
if (mStayOnWhilePluggedInSetting != 0
&& !isMaximumScreenOffTimeoutFromDeviceAdminEnforcedLocked()) {
//保持亮屏取决于是否充电
//如果当前正在充电,mStayOn为true,即屏幕常量
mStayOn = mBatteryManagerInternal.isPowered(mStayOnWhilePluggedInSetting);
} else {
mStayOn = false;
}
if (mStayOn != wasStayOn) {
//表示屏幕要常量
mDirty |= DIRTY_STAY_ON;
}
}
}
点评:mStayOnWhilePluggedInSetting是从SettingsProvider中读取的值,表示是否设置了充电时保持屏幕常亮,若要使mStayOn为true,其先决条件是mStayOnWhilePluggedInSetting为true,同时DevicePolicyManager没有进行最大超时时间的约束,如果符合这个条件,则当设备在充电时mStayOn为true.其他情况下都为false.mStayOn在进入Dream相关从操作时作为判断条件用到。
注意:调用PowerWindowService.setDozeOverrideFromDreamManager()也是可以设置屏幕是否要常亮,这个函数具体就不分析了;
(3)updateScreenBrightnessBoostLocked(mDirty),更新屏幕亮度增强
调用PowerManager.boostScreenBrightness()的函数,继而调用PowerWindowService.boostScreenBrightness():
public void boostScreenBrightness(long eventTime) {
if (eventTime > SystemClock.uptimeMillis()) {
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 {
//调用boostScreenBrightnessInternal()
boostScreenBrightnessInternal(eventTime, uid);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
private void boostScreenBrightnessInternal(long eventTime, int uid) {
synchronized (mLock) {
if (!mSystemReady || mWakefulness == WAKEFULNESS_ASLEEP
|| eventTime < mLastScreenBrightnessBoostTime) {
return;
}
Slog.i(TAG, "Brightness boost activated (uid " + uid +")...");
mLastScreenBrightnessBoostTime = eventTime;
//将mScreenBrightnessBoostInProgress置为true
if (!mScreenBrightnessBoostInProgress) {
mScreenBrightnessBoostInProgress = true;
//通知亮度增强
mNotifier.onScreenBrightnessBoostChanged();
}
//亮度增强
mDirty |= DIRTY_SCREEN_BRIGHTNESS_BOOST;
//此动作为用户活动
userActivityNoUpdateLocked(eventTime,
PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, uid);
//更新电源状态
updatePowerStateLocked();
}
}
继而进入updateScreenBrightnessBoostLocked()函数:
private void updateScreenBrightnessBoostLocked(int dirty) {
if ((dirty & DIRTY_SCREEN_BRIGHTNESS_BOOST) != 0) {
//boostScreenBrightnessInternal()中已经将mScreenBrightnessBoostInProgress置为了true
if (mScreenBrightnessBoostInProgress) {
final long now = SystemClock.uptimeMillis();
mHandler.removeMessages(MSG_SCREEN_BRIGHTNESS_BOOST_TIMEOUT);
if (mLastScreenBrightnessBoostTime > mLastSleepTime) {
final long boostTimeout = mLastScreenBrightnessBoostTime +
SCREEN_BRIGHTNESS_BOOST_TIMEOUT;
if (boostTimeout > now) {
Message msg = mHandler.obtainMessage(MSG_SCREEN_BRIGHTNESS_BOOST_TIMEOUT);
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, boostTimeout);
return;
}
}
mScreenBrightnessBoostInProgress = false;
//通知屏幕亮度增强
mNotifier.onScreenBrightnessBoostChanged();
//用户活动
userActivityNoUpdateLocked(now,
PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID);
}
}
}
(4)updateWakeLockSummaryLocked(dirtyPhase1)
在这个方法中,会对当前所有的WakeLock锁进行统计,过滤所有的wakelock锁状态(wakelock锁机制在后续进行分析),并更新mWakeLockSummary的值以汇总所有活动的唤醒锁的状态。
mWakeLockSummary是一个用来记录所有WakeLock锁状态的标识值,该值在请求Display状时会用到。当系统处于睡眠状态时,大多数唤醒锁都将被忽略,比如系统在处于唤醒状态(awake)时,会忽略PowerManager.DOZE_WAKE_LOCK类型的唤醒锁,系统在处于睡眠状态(asleep)或者Doze状态时,会忽略PowerManager.SCREEN_BRIGHT类型的锁等等。
将系统中所有的wakelock锁更新到集合变量mWakeLockSummary中:
private void updateWakeLockSummaryLocked(int dirty) {
//申请锁和释放锁,都会导致DIRTY_WAKE_LOCKS;
//DIRTY_WAKEFULNESS便是电源的唤醒状态发生改变
if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_WAKEFULNESS)) != 0) {
//将系统中所有的wakelock锁更新到集合变量mWakeLockSummary中
mWakeLockSummary = 0;
//当前系统中WakeLock锁的数量
final int numWakeLocks = mWakeLocks.size();
//遍历系统中的WakeLock锁
for (int i = 0; i < numWakeLocks; i++) {
final WakeLock wakeLock = mWakeLocks.get(i);
//分析WakeLock锁的类型
switch (wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK) {
case PowerManager.PARTIAL_WAKE_LOCK:
if (!wakeLock.mDisabled) {
// We only respect this if the wake lock is not disabled.
//如果存在PARTIAL_WAKE_LOCK并且该wakelock可用,
//通过置位进行记录,下同
mWakeLockSummary |= WAKE_LOCK_CPU;
}
break;
case PowerManager.FULL_WAKE_LOCK:
mWakeLockSummary |= WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_BUTTON_BRIGHT;
break;
case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
mWakeLockSummary |= WAKE_LOCK_SCREEN_BRIGHT;
break;
case PowerManager.SCREEN_DIM_WAKE_LOCK:
mWakeLockSummary |= WAKE_LOCK_SCREEN_DIM;
break;
case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK:
mWakeLockSummary |= WAKE_LOCK_PROXIMITY_SCREEN_OFF;
break;
case PowerManager.DOZE_WAKE_LOCK:
mWakeLockSummary |= WAKE_LOCK_DOZE;
break;
case PowerManager.DRAW_WAKE_LOCK:
mWakeLockSummary |= WAKE_LOCK_DRAW;
break;
}
}
// Cancel wake locks that make no sense based on the current state.
/**
* 设备不处于DOZE状态时,通过置位操作忽略相关类型wakelock
* PowerManager.DOZE_WAKE_LOCK和WAKE_LOCK_DRAW锁仅仅
* 在Doze状态下有效
*/
if (mWakefulness != WAKEFULNESS_DOZING) {
mWakeLockSummary &= ~(WAKE_LOCK_DOZE | WAKE_LOCK_DRAW);
}
/**
* 如果处于Doze状态,忽略三类Wakelock.
* 如果处于睡眠状态,忽略四类wakelock.
*/
if (mWakefulness == WAKEFULNESS_ASLEEP
|| (mWakeLockSummary & WAKE_LOCK_DOZE) != 0) {
mWakeLockSummary &= ~(WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_SCREEN_DIM
| WAKE_LOCK_BUTTON_BRIGHT);
if (mWakefulness == WAKEFULNESS_ASLEEP) {
mWakeLockSummary &= ~WAKE_LOCK_PROXIMITY_SCREEN_OFF;
}
}
// Infer implied wake locks where necessary based on the current state.
//根据当前状态推断必要的wakelock
//处于awake或dream(不处于asleep/doze)
if ((mWakeLockSummary & (WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_SCREEN_DIM)) != 0) {
//处于awake状态,WAKE_LOCK_STAY_AWAKE只用于awake状态时
if (mWakefulness == WAKEFULNESS_AWAKE) {
mWakeLockSummary |= WAKE_LOCK_CPU | WAKE_LOCK_STAY_AWAKE;
} else if (mWakefulness == WAKEFULNESS_DREAMING) {//处于屏保状态(dream)
mWakeLockSummary |= WAKE_LOCK_CPU;
}
}
if ((mWakeLockSummary & WAKE_LOCK_DRAW) != 0) {
mWakeLockSummary |= WAKE_LOCK_CPU;
}
if (DEBUG_SPEW) {
Slog.d(TAG, "updateWakeLockSummaryLocked: mWakefulness="
+ PowerManagerInternal.wakefulnessToString(mWakefulness)
+ ", mWakeLockSummary=0x" + Integer.toHexString(mWakeLockSummary));
}
}
}
(5)updateUserActivitySummaryLocked(now, dirtyPhase1)
该方法用来更新用户活动时间,当设备和用户有交互时,都会根据当前时间和休眠时长、Dim时长、所处状态而计算下次休眠的时间,从而完成用户活动超时时的操作。如由亮屏进入Dim的时长、Dim到灭屏的时长、亮屏到屏保的时长,就是在这里计算的。
private void updateUserActivitySummaryLocked(long now, int dirty) {
// Update the status of the user activity timeout timer.
//WAKE_LOCKS的申请和释放,用户活动,电源唤醒状态的改变,系统属性的改变,只要有一个发生,下面这个判断都成立
if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY
| DIRTY_WAKEFULNESS | DIRTY_SETTINGS)) != 0) {
mHandler.removeMessages(MSG_USER_ACTIVITY_TIMEOUT);
//以下代码是设置屏幕状态的变量mUserActivitySummary的值,这个值表示当前是要亮屏还是暗屏等
long nextTimeout = 0;
//如果处于休眠状态,则不会执行该方法
if (mWakefulness == WAKEFULNESS_AWAKE
|| mWakefulness == WAKEFULNESS_DREAMING
|| mWakefulness == WAKEFULNESS_DOZING) {
//设备完全进入休眠所需时间,该值为-1表示禁用此值,默认-1
final int sleepTimeout = getSleepTimeoutLocked();
//用户超时时间,既经过一段时间不活动进入休眠或屏保的时间,特殊情况外,该值为Settings中的休眠时长
final int screenOffTimeout = getScreenOffTimeoutLocked(sleepTimeout);
//Dim时长,即亮屏不操作,变暗多久休眠
final int screenDimDuration = getScreenDimDurationLocked(screenOffTimeout);
//通过WindowManager的用户交互
final boolean userInactiveOverride = mUserInactiveOverrideFromWindowManager;
mUserActivitySummary = 0;
//1.亮屏;2.亮屏后进行用户活动
if (mLastUserActivityTime >= mLastWakeTime) {
//下次睡眠时间=上次用户活动时间+休眠时间-Dim时间
nextTimeout = mLastUserActivityTime
+ screenOffTimeout - screenDimDuration;
//如果满足当前时间<下次屏幕超时时间,说明此时设备为亮屏状态,则将用户活动状态置为表示亮屏的USER_ACTIVITY_SCREEN_BRIGHT
if (now < nextTimeout) {
mUserActivitySummary = USER_ACTIVITY_SCREEN_BRIGHT;
} else {
//如果当前时间>下次活动时间,此时应有两种情况:已经休眠和Dim
nextTimeout = mLastUserActivityTime + screenOffTimeout;
//如果当前时间<上次活动时间+屏幕超时时间,这个值约为3s,说明此时设备为Dim状态,则将用户活动状态置为表示Dim的USER_ACTIVITY_SCREEN_DIM
if (now < nextTimeout) {
mUserActivitySummary = USER_ACTIVITY_SCREEN_DIM;
}
}
}
if (mUserActivitySummary == 0
&& mLastUserActivityTimeNoChangeLights >= mLastWakeTime) {
nextTimeout = mLastUserActivityTimeNoChangeLights + screenOffTimeout;
if (now < nextTimeout) {
if (mDisplayPowerRequest.policy == DisplayPowerRequest.POLICY_BRIGHT
|| mDisplayPowerRequest.policy == DisplayPowerRequest.POLICY_VR) {
mUserActivitySummary = USER_ACTIVITY_SCREEN_BRIGHT;
} else if (mDisplayPowerRequest.policy == DisplayPowerRequest.POLICY_DIM) {
mUserActivitySummary = USER_ACTIVITY_SCREEN_DIM;
}
}
}
if (mUserActivitySummary == 0) {
if (sleepTimeout >= 0) {
final long anyUserActivity = Math.max(mLastUserActivityTime,
mLastUserActivityTimeNoChangeLights);
if (anyUserActivity >= mLastWakeTime) {
nextTimeout = anyUserActivity + sleepTimeout;
if (now < nextTimeout) {
mUserActivitySummary = USER_ACTIVITY_SCREEN_DREAM;
}
}
} else {
mUserActivitySummary = USER_ACTIVITY_SCREEN_DREAM;
nextTimeout = -1;
}
}
if (mUserActivitySummary != USER_ACTIVITY_SCREEN_DREAM && userInactiveOverride) {
if ((mUserActivitySummary &
(USER_ACTIVITY_SCREEN_BRIGHT | USER_ACTIVITY_SCREEN_DIM)) != 0) {
// Device is being kept awake by recent user activity
if (nextTimeout >= now && mOverriddenTimeout == -1) {
// Save when the next timeout would have occurred
mOverriddenTimeout = nextTimeout;
}
}
mUserActivitySummary = USER_ACTIVITY_SCREEN_DREAM;
nextTimeout = -1;
}
//发送定时Handler,到达时间后再次进行updatePowerStateLocked()
if (mUserActivitySummary != 0 && nextTimeout >= 0) {
Message msg = mHandler.obtainMessage(MSG_USER_ACTIVITY_TIMEOUT);
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, nextTimeout);
}
} else {
mUserActivitySummary = 0;
}
if (DEBUG_SPEW) {
Slog.d(TAG, "updateUserActivitySummaryLocked: mWakefulness="
+ PowerManagerInternal.wakefulnessToString(mWakefulness)
+ ", mUserActivitySummary=0x" + Integer.toHexString(mUserActivitySummary)
+ ", nextTimeout=" + TimeUtils.formatUptime(nextTimeout));
}
}
}
点评:在获取用户活动超时时长时,不仅仅是由用户在设置中设置的休眠时长所决定,还有比如带有PowerManager.ON_AFTER_RELEASE
标记的wakelock锁在释放时也会影响用户超时时间。
举个例子:用户亮屏到到达时间休眠,假设设备设定休眠时间为15s,Dim时长为3s,我在9:20:01时按power键唤醒设备,因此,执行到该方法时有:
mLastUserActivity=mLastWakeTime=9:20:01,now=9:20:01+0.02ms,screenOffTimeout=15s,screenDimDuration=3s,所以nextTimeout为9:20:01+15s-3s=9:20:13
因此会通过Handler发送一个定时消息,13秒后会进入Dim…
现在时间到9:20:13,执行Handler中的消息,这个消息中又调用了一次updatePowerState()方法,所以又会执行到这个方法,此时:只有now发生改变为9:20:13+0.02ms(调用方法消耗的时间),因此now>nextTimeout,进入else语句,进入else后:
nextTimeout = mLastUserActivity + screenOffTimeout =9:20:01+15s=9:20:16 > now
因此判断当前因为Dim状态,同时nextTimeout发生改变,并且再次通过Handler设置定时消息,…,3s后,又回到了该方法中进行了处理,这次处理,会通过判断将nextTimeout设为-1,从而不再发送Handler,通过updatePowerStateLocked()中的其他方法进行休眠。
在计算完成nextTimeout后,会通过Handler发送一个延时消息,到达nextTimeout后,再次更新整个电源状态:
private final class PowerManagerHandler extends Handler {
public PowerManagerHandler(Looper looper) {
super(looper, null, true /*async*/);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_USER_ACTIVITY_TIMEOUT:
handleUserActivityTimeout();
break;
......
private void handleUserActivityTimeout() { // runs on handler thread
synchronized (mLock) {
if (DEBUG_SPEW) {
Slog.d(TAG, "handleUserActivityTimeout");
}
mDirty |= DIRTY_USER_ACTIVITY;
updatePowerStateLocked();
}
}
此外,这里还有一点需要注意的地方,在计算灭屏超时时间时,有两个值:
final int sleepTimeout = getSleepTimeoutLocked();
final int screenOffTimeout = getScreenOffTimeoutLocked(sleepTimeout);
这两个方法和休眠时间相关,在PMS中,定义了两个相关值:
mSleepTimeoutSetting = Settings.Secure.getIntForUser(resolver,
Settings.Secure.SLEEP_TIMEOUT, DEFAULT_SLEEP_TIMEOUT,
UserHandle.USER_CURRENT);
mScreenOffTimeoutSetting = Settings.System.getIntForUser(resolver,
Settings.System.SCREEN_OFF_TIMEOUT, DEFAULT_SCREEN_OFF_TIMEOUT,
UserHandle.USER_CURRENT);
其中Settings.Secure.SLEEP_TIMEOUT表示设备在经过一段不活动后完全进入睡眠后屏保的时间,该值可以理解为保持唤醒或屏保的最大值或上限,并且该值要大于Settings.System.SCREEN_OFF_TIMEOUT,默认为-1,表示禁用此项功能。
Settings.System.SCREEN_OFF_TIMEOUT表示设备在经过一段不活动后进入睡眠或屏保的时间,也称为用户活动超时时间,但屏幕到期时不一定关闭。该值可以在设置-休眠中设置。
(6)updateWakefulnessLocked()
这个方法是退出循环的关键。如果这个方法返回false,则循环结束,如果返回true,则进行下一次循环:
private boolean updateWakefulnessLocked(int dirty) {
boolean changed = false;
if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY | DIRTY_BOOT_COMPLETED
| DIRTY_WAKEFULNESS | DIRTY_STAY_ON | DIRTY_PROXIMITY_POSITIVE
| DIRTY_DOCK_STATE)) != 0) {
//当前屏幕保持唤醒&&设备将要退出唤醒状态(睡眠or屏保)
//isItBedTimeYetLocked(),当系统马上要进入睡眠状态时会返回true,也就是当系统一直处于活跃状态,则其返回false;
//所以,updateWakefulnessLocked()方法返回值为false,那么这个死循环只用执行一次就跳出了;
//这里假定系统一段时间未被操作,即将接下来就要调用进入睡眠状态,则isItBedTimeYetLocked()函数返回true
if (mWakefulness == WAKEFULNESS_AWAKE && isItBedTimeYetLocked()) {
if (DEBUG_SPEW) {
Slog.d(TAG, "updateWakefulnessLocked: Bed time...");
}
final long time = SystemClock.uptimeMillis();
//是否在休眠时启用屏保
//检查有没有设置睡眠之前启动动态屏保或者插在座充上启动屏保
if (shouldNapAtBedTimeLocked()) {//设置了
//进入屏保,返回true
changed = napNoUpdateLocked(time, Process.SYSTEM_UID);
} else {//未设置
//进入睡眠,返回true
changed = goToSleepNoUpdateLocked(time,
PowerManager.GO_TO_SLEEP_REASON_TIMEOUT, 0, Process.SYSTEM_UID);
}
}
}
return changed;
}
private boolean napNoUpdateLocked(long eventTime, int uid) {
if (DEBUG_SPEW) {
Slog.d(TAG, "napNoUpdateLocked: eventTime=" + eventTime + ", uid=" + uid);
}
//如果if语句中有一项成立则返回false,则跳出死循环,当时如果第一次调用该方法,正常情况下当为false,
// 如果第二次调用到此肯定会返回false,因为第二次调用时mWakefulness 为,WAKEFULNESS_DREAMING。
if (eventTime < mLastWakeTime || mWakefulness != WAKEFULNESS_AWAKE
|| !mBootCompleted || !mSystemReady) {
return false;
}
Trace.traceBegin(Trace.TRACE_TAG_POWER, "nap");
try {
Slog.i(TAG, "Nap time (uid " + uid +")...");
mSandmanSummoned = true;
setWakefulnessLocked(WAKEFULNESS_DREAMING, 0);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
return true;
}
这个方法用于更新设备的wakefulness,同时,这个方法是亮屏->屏保/睡眠的决策点。wakefulness是用来表示当前设备状态的一个值,系统定义的wakefulness值共有四种,分别表示不同的状态:
//睡眠状态,此时灭屏
public static final int WAKEFULNESS_ASLEEP = 0;
//屏幕亮
public static final int WAKEFULNESS_AWAKE = 1;
//屏保
public static final int WAKEFULNESS_DREAMING = 2;
//处于DOZE模式时
public static final int WAKEFULNESS_DOZING = 3;
如果当前设备处于唤醒状态(awake),并且将要退出唤醒状态,也就是进入睡眠状态(sleep)或者屏保状态(dreaming),如果设备开启了屏保,进入屏保状态,否则直接进入睡眠状态。这种情况下,wakefulness发生改变,因此返回值为true,需要通过下一次循环重新统计wakelockSummary和userActivitySummary。如果不是以上情况,则不会进入if语句,说明不需要改变wakefulness值,返回false,则循环体只执行一次便退出。因此,该循环只有在一段时间不活动到达用户超时时间后进入屏保或者进入睡眠时,会执行两次,其他情况下只执行一次便退出,比如按power键灭屏等只会执行一次,因为当power键灭屏时,wakefulness值已经由唤醒状态变为SLEEP状态,因此不满足执行条件。
知道updatefulnessLocked()方法的主要功能后,现在来看看其中和休眠、屏保相关的方法。首先来看isItBedTimeYetLocked()方法,该方法判断当前设备是否将要进入睡眠状态,返回值为对isBeKeptAwakeLocke()方法返回值取反,由mStayOn(是否屏幕常亮)、wakelockSummary、userActivitySummary、mProximityPositive等决定,只要满足其中之一为ture,则说明无法进入睡眠,也就说,要满足进入睡眠,相关属性值都为false。isBeKeptAwakeLocke()如下:
private boolean isBeingKeptAwakeLocked() {
return mStayOn//屏幕是否保持常亮
|| mProximityPositive//接近传感器接近屏幕时为true
//处于awake状态
|| (mWakeLockSummary & WAKE_LOCK_STAY_AWAKE) != 0
//屏幕处于亮屏或者dim状态
|| (mUserActivitySummary & (USER_ACTIVITY_SCREEN_BRIGHT
| USER_ACTIVITY_SCREEN_DIM)) != 0
|| mScreenBrightnessBoostInProgress;//处于亮度增强中
}
接下来看看shoudNapAtBedTimeLocked()方法。这个方法用来判断设备是否进入屏保模式:
private boolean shouldNapAtBedTimeLocked() {
//屏保是否开启
return mDreamsActivateOnSleepSetting
|| (mDreamsActivateOnDockSetting //插入基座时是否开启屏保
&& mDockState != Intent.EXTRA_DOCK_STATE_UNDOCKED);
}
除了以上方法外,还有napNoUpdateLocked()和goToSleepNoUpdateLocked()方法,这两个方法分别用于控制设备进入屏保或者休眠,将在特定场景下进行分析。
结合上述三个方法的分析,之所以把updateWakeLockSummaryLocked()、updateUserActivitySummaryLocked()、updateWakefulnessLocked()这三个方法放在for(;;)循环中调用,是因为它们共同决定了设备的状态,前两个方法是汇总状态,后一个方法是根据前两个方法汇总的值而进行判断是否要改变当前的设备唤醒状态,汇总状态会受mWakefulness的影响,因此会进行循环处理。同时,也仅仅会在超时灭屏进入睡眠或屏保时,for循环会执行两次,其他情况下,只会执行一次。
(7)updateDisplayPowerStateLocked()
该方法用于更新设备显示状态,在这个方法中,会计算出最终需要显示的亮度值和其他值,然后将这些值封装到DisplayPowerRequest对象中,向DisplayMangerService请求Display状态,完成屏幕亮度显示等。
首先看一下亮度值,系统的亮度值并不是简单的在Settings中设置了就可以了,决定亮度值的一些相关值如下:
//WindowManager覆盖的亮度值,如播放视频时调节亮度
//-1表示禁止使用(未发现使用到)
private int mScreenBrightnessOverrideFromWindowManager = -1;
//SystemUI中设置的临时亮度值,自动亮度时无效
//该值之所以是临时的,是因为当调节亮度进度条时,会调用到updateDisplayPowerLocked(),这里给它赋值;
// 当手指放开时,调用updateSettingLocked(),这里又将它置为-1
private int mTemporaryScreenBrightnessSettingOverride = -1;
//Settings.System.SCREEN_BRIGHTNESS中的值,即反映给用户的值
private int mScreenBrightnessSetting;
//限定值,config.xml中配置
private int mScreenBrightnessSettingMinimum;//0
private int mScreenBrightnessSettingMaximum;//255
private int mScreenBrightnessSettingDefault;//102
private int mScreenBrightnessForVrSettingDefault;//86
//自动调节亮度调整值,-1~1
private float mScreenAutoBrightnessAdjustmentSetting;
//Settings中的默认值,一般和config.xml中的默认值相同,也可能不同
Settings.System.SCREEN_BRIGHTNESS
最终显示的亮度值和不同的状态有关,如在自动亮度调节打开时、VR模式时、或者从一个视频播放窗口中调节亮度时,都对应有不同的值。
在这个方法中,用到了一个DisplayPowerRequest类的对象,这个类是DisplayManageInternal类中的一个内部类,专门用于PowerManagerService和DisplayPowerController交互。PMS中会将当前亮度、屏幕状态等多个值封装在这个对象中,然后调用requestPowerState()请求DisplayPowerController,从而完成显示更新。
// 可以理解为Display的‘策略‘,该值非常重要,决定了请求后屏幕的状态,有四个值:off,doze,dim,bright.
public int policy;
// 如果为true,则PSensor会覆盖屏幕状态,当物体靠近时将其临时关闭直到物体移开。
public boolean useProximitySensor;
// 屏幕亮度
public int screenBrightness;
// 自动调节亮度值,-1(dimmer)至1(brighter)之间
public float screenAutoBrightnessAdjustment;
// 如果screenBrightness和screenAutoBrightnessAdjustment 由用户设置,则为true
public boolean brightnessSetByUser;
// 是否使用了自动调节亮度
public boolean useAutoBrightness;
// 是否使用了低电量模式,该模式下亮度会减半
public boolean lowPowerMode;
// 在低电量模式下调整屏幕亮度的系数,0(screen off)至1(no change)之间
public float screenLowPowerBrightnessFactor;
// 是否启动了亮度增强
public boolean boostScreenBrightness;
// 如果为true,则会在屏幕亮起时阻止屏幕完全亮起,窗口管理器策略在准备键盘保护程// 时阻止屏幕,以防止用户看到中间更新。
public boolean blockScreenOn;
// 设备处于Doze状态下时覆盖的屏幕亮度和屏幕状态
public int dozeScreenBrightness;
public int dozeScreenState;
至于详细的DisplayPowerRequest,在Display分析时进行,这里只需要知道亮屏灭屏、亮度调节时会进行请求,交给DisplayManagerService去处理。由于亮度调节这块涉及到的模块有WindowManager、DisplayManagerService等模块,和这个方法一起分析内容略显臃肿,因此这里仅仅总结该方法主要逻辑,具体亮度调整流程做了单独分析。
接下来就看updateDisplayPowerStateLocked()函数:
private boolean updateDisplayPowerStateLocked(int dirty) {
final boolean oldDisplayReady = mDisplayReady;
if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY | DIRTY_WAKEFULNESS
| DIRTY_ACTUAL_DISPLAY_POWER_STATE_UPDATED | DIRTY_BOOT_COMPLETED
| DIRTY_SETTINGS | DIRTY_SCREEN_BRIGHTNESS_BOOST | DIRTY_VR_MODE_CHANGED |
DIRTY_QUIESCENT)) != 0) {
//获取mDisplayPowerRequest.policy,如DisplayPowerRequest.POLICY_BRIGHT,这个标志在DisplayPowerController中会将屏幕从灭屏状态下唤醒
mDisplayPowerRequest.policy = getDesiredScreenPolicyLocked();
// Determine appropriate screen brightness and auto-brightness adjustments.
//是否是用户手动设置的亮度
boolean brightnessSetByUser = true;
//屏幕亮度值
int screenBrightness = mScreenBrightnessSettingDefault;
float screenAutoBrightnessAdjustment = 0.0f;
//是否是自动调节亮度
boolean autoBrightness = (mScreenBrightnessModeSetting ==
Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC);
if (!mBootCompleted) {
// Keep the brightness steady during boot. This requires the
// bootloader brightness and the default brightness to be identical.
autoBrightness = false;
brightnessSetByUser = false;
} else if (mIsVrModeEnabled) {
screenBrightness = mScreenBrightnessForVrSetting;
autoBrightness = false;
} else if (isValidBrightness(mScreenBrightnessOverrideFromWindowManager)) {
screenBrightness = mScreenBrightnessOverrideFromWindowManager;
autoBrightness = false;
brightnessSetByUser = false;
} else if (isValidBrightness(mTemporaryScreenBrightnessSettingOverride)) {
screenBrightness = mTemporaryScreenBrightnessSettingOverride;
} else if (isValidBrightness(mScreenBrightnessSetting)) {
screenBrightness = mScreenBrightnessSetting;
}
if (autoBrightness) {
screenBrightness = mScreenBrightnessSettingDefault;
if (isValidAutoBrightnessAdjustment(
mTemporaryScreenAutoBrightnessAdjustmentSettingOverride)) {
screenAutoBrightnessAdjustment =
mTemporaryScreenAutoBrightnessAdjustmentSettingOverride;
} else if (isValidAutoBrightnessAdjustment(
mScreenAutoBrightnessAdjustmentSetting)) {
screenAutoBrightnessAdjustment = mScreenAutoBrightnessAdjustmentSetting;
}
}
screenBrightness = Math.max(Math.min(screenBrightness,
mScreenBrightnessSettingMaximum), mScreenBrightnessSettingMinimum);
screenAutoBrightnessAdjustment = Math.max(Math.min(
screenAutoBrightnessAdjustment, 1.0f), -1.0f);
// Update display power request.
//将屏幕亮度值,自动调节亮度等属性,保存到mDisplayPowerRequest中
mDisplayPowerRequest.screenBrightness = screenBrightness;
mDisplayPowerRequest.screenAutoBrightnessAdjustment =
screenAutoBrightnessAdjustment;
mDisplayPowerRequest.brightnessSetByUser = brightnessSetByUser;
mDisplayPowerRequest.useAutoBrightness = autoBrightness;
mDisplayPowerRequest.useProximitySensor = shouldUseProximitySensorLocked();
mDisplayPowerRequest.boostScreenBrightness = shouldBoostScreenBrightness();
updatePowerRequestFromBatterySaverPolicy(mDisplayPowerRequest);
if (mDisplayPowerRequest.policy == DisplayPowerRequest.POLICY_DOZE) {
mDisplayPowerRequest.dozeScreenState = mDozeScreenStateOverrideFromDreamManager;
if (mDisplayPowerRequest.dozeScreenState == Display.STATE_DOZE_SUSPEND
&& (mWakeLockSummary & WAKE_LOCK_DRAW) != 0) {
mDisplayPowerRequest.dozeScreenState = Display.STATE_DOZE;
}
mDisplayPowerRequest.dozeScreenBrightness =
mDozeScreenBrightnessOverrideFromDreamManager;
} else {
mDisplayPowerRequest.dozeScreenState = Display.STATE_UNKNOWN;
mDisplayPowerRequest.dozeScreenBrightness = PowerManager.BRIGHTNESS_DEFAULT;
}
//收集完了mDisplayPowerRequest的信息,接下来就是将它传递给mDisplayManagerInternal的requestPowerState()函数处理;
//requestPowerState()是一个抽象方法,由DisplayPowerController实现
mDisplayReady = mDisplayManagerInternal.requestPowerState(mDisplayPowerRequest,
mRequestWaitForNegativeProximity);
mRequestWaitForNegativeProximity = false;
if ((dirty & DIRTY_QUIESCENT) != 0) {
sQuiescent = false;
}
if (DEBUG_SPEW) {
Slog.d(TAG, "updateDisplayPowerStateLocked: mDisplayReady=" + mDisplayReady
+ ", policy=" + mDisplayPowerRequest.policy
+ ", mWakefulness=" + mWakefulness
+ ", mWakeLockSummary=0x" + Integer.toHexString(mWakeLockSummary)
+ ", mUserActivitySummary=0x" + Integer.toHexString(mUserActivitySummary)
+ ", mBootCompleted=" + mBootCompleted
+ ", mScreenBrightnessBoostInProgress=" + mScreenBrightnessBoostInProgress
+ ", mIsVrModeEnabled= " + mIsVrModeEnabled
+ ", sQuiescent=" + sQuiescent);
}
}
return mDisplayReady && !oldDisplayReady;
}
在请求DisplayManagerService时,会将所有的信息封装到DisplayPowerRequest对象中,其中需要注意policy值。policy作为DisplayPowerRequset的属性,有四种值,分别为off、doze、dim、bright、vr。在向DisplayManagerService请求时,会根据当前PMS中的唤醒状态和统计的wakelock来决定要请求的Display状态,这部分源码如下:
@VisibleForTesting
int getDesiredScreenPolicyLocked() {
//asleep时,policy值为0
if (mWakefulness == WAKEFULNESS_ASLEEP || sQuiescent) {
return DisplayPowerRequest.POLICY_OFF;//0
}
if (mWakefulness == WAKEFULNESS_DOZING) {
if ((mWakeLockSummary & WAKE_LOCK_DOZE) != 0) {
return DisplayPowerRequest.POLICY_DOZE;//1
}
if (mDozeAfterScreenOffConfig) {
return DisplayPowerRequest.POLICY_OFF;
}
}
if ((mWakeLockSummary & WAKE_LOCK_SCREEN_BRIGHT) != 0
|| (mUserActivitySummary & USER_ACTIVITY_SCREEN_BRIGHT) != 0
|| !mBootCompleted
|| mScreenBrightnessBoostInProgress) {
return DisplayPowerRequest.POLICY_BRIGHT;//3
}
return DisplayPowerRequest.POLICY_DIM;
}
比如,如果当前mWakefulness为ASLEEP,则表示要进入睡眠状态,去请求Display。最终会在DisplayPowerController中处理这次请求,如果发现请求时携带的DisplayPowerRequest对象和上一次请求时相同,则直接返回true,表示Display已经准备就绪了,如果请求时携带的DisplayPowerRequest对象和上一次请求时的不同,说明状态有所改变,此时会返回false,表示Display状态未准备就绪,同时异步请求新的状态。
这里再次总结下这个方法,首先封装一个DisplayPowerRequest对象,并且请求DisplayPowerController,交给DisplayPowerController去完成剩余任务。该方法有个返回值,表示Display是否准备就绪,并且接下来的屏保也依赖于这个返回值。
(8)updateDreamLocked(dirtyPhase2, displayBecameReady);
该方法用来更新设备Dream状态,比如是否继续屏保、Doze或者开始休眠,这个方法中异步处理该过程(因此,这里在唤醒或休眠时有风险):
/**
* Determines whether to post a message to the sandman to update the dream state.
*/
private void updateDreamLocked(int dirty, boolean displayBecameReady) {
if ((dirty & (DIRTY_WAKEFULNESS
| DIRTY_USER_ACTIVITY
| DIRTY_WAKE_LOCKS
| DIRTY_BOOT_COMPLETED
| DIRTY_SETTINGS
| DIRTY_IS_POWERED
| DIRTY_STAY_ON
| DIRTY_PROXIMITY_POSITIVE
| DIRTY_BATTERY_STATE)) != 0 || displayBecameReady) {
if (mDisplayReady) {
//通过Handler异步发送一个消息
scheduleSandmanLocked();
}
}
}
从这里可以看到,该方法依赖于mDisplayReady值,这个值是上个方法在请求Display时的返回值,表示Display是否准备就绪,因此,只有在准备就绪的情况下才会进一步调用该方法的方法体。在scheduleSandmanLocked()方法中,通过Handler发送了一个异步消息,代码如下:
private void scheduleSandmanLocked() {
if (!mSandmanScheduled) {
//由于是异步处理,因此表示是否已经调用该方法且没有被handler处理
//,如果为true就不会进入该方法了
mSandmanScheduled = true;
Message msg = mHandler.obtainMessage(MSG_SANDMAN);
msg.setAsynchronous(true);
mHandler.sendMessage(msg);
}
}
再来看看handleMessage()中对接受消息的处理:
case MSG_SANDMAN:
handleSandman();
break;
因此,当updateDreamLocked()方法调用后,最终会异步执行这个方法,在这个方法中进行屏保相关处理,继续看看这个方法:
private void handleSandman() { // runs on handler thread
// Handle preconditions.
//是否开始进入屏保
final boolean startDreaming;
final int wakefulness;
synchronized (mLock) {
//为false后下次updateDreamLocked()可处理
mSandmanScheduled = false;
wakefulness = mWakefulness;
//在进入asleep状态后该值为true,用于判断是否处于Dream状态;
//更新变量startDreaming,当前状态如果可以进入屏保或者Dozing状态,则置为true,否则置为false;
//如果设置了屏保,则灭屏之后会进入一段时间屏保,然后灭屏;如果没有设置屏保则默认进入dozing(打盹)状态。
if (mSandmanSummoned && mDisplayReady) {
//当前状态能否进入Dream || 当前wakefulness状态为Doze
startDreaming = canDreamLocked() || canDozeLocked();
mSandmanSummoned = false;
} else {
startDreaming = false;
}
}
//表示是否正在屏保
//isDreaming是用来判断屏保服务是否启动了
final boolean isDreaming;
if (mDreamManager != null) {
// Restart the dream whenever the sandman is summoned.
//重启屏保
//在屏保服务实在系统启动时在StartOtherService中随系统启动,再次重启屏保服务
if (startDreaming) {
mDreamManager.stopDream(false /*immediate*/);
mDreamManager.startDream(wakefulness == WAKEFULNESS_DOZING);
}
isDreaming = mDreamManager.isDreaming();
} else {
isDreaming = false;
}
//下面代码表示:如果屏保结束,判断是进入唤醒状态还是进入睡眠状态,然后更新电源状态。
//若是还为到时,且wakefulness为WAKEFULNESS_DOZING则返回,继续处于dozing状态。
// Update dream state.
synchronized (mLock) {
// Remember the initial battery level when the dream started.
//记录进入屏保时的电池电量
if (startDreaming && isDreaming) {
mBatteryLevelWhenDreamStarted = mBatteryLevel;
if (wakefulness == WAKEFULNESS_DOZING) {
Slog.i(TAG, "Dozing...");
} else {
Slog.i(TAG, "Dreaming...");
}
}
// If preconditions changed, wait for the next iteration to determine
// whether the dream should continue (or be restarted).
//如果mSandmanSummoned改变或者wakefulness状态改变,则return等待下次处理
if (mSandmanSummoned || mWakefulness != wakefulness) {
return; // wait for next cycle
}
// Determine whether the dream should continue.
//决定是否继续Dream
if (wakefulness == WAKEFULNESS_DREAMING) {
if (isDreaming && canDreamLocked()) {
//表示从开启屏保开始电池电量下降这个值就退出屏保,-1表示禁用该值
if (mDreamsBatteryLevelDrainCutoffConfig >= 0
&& mBatteryLevel < mBatteryLevelWhenDreamStarted
- mDreamsBatteryLevelDrainCutoffConfig
&& !isBeingKeptAwakeLocked()) {
// If the user activity timeout expired and the battery appears
// to be draining faster than it is charging then stop dreaming
// and go to sleep.
Slog.i(TAG, "Stopping dream because the battery appears to "
+ "be draining faster than it is charging. "
+ "Battery level when dream started: "
+ mBatteryLevelWhenDreamStarted + "%. "
+ "Battery level now: " + mBatteryLevel + "%.");
} else {
return; // continue dreaming
}
}
// Dream has ended or will be stopped. Update the power state.
//退出屏保,进入Doze状态
if (isItBedTimeYetLocked()) {
goToSleepNoUpdateLocked(SystemClock.uptimeMillis(),
PowerManager.GO_TO_SLEEP_REASON_TIMEOUT, 0, Process.SYSTEM_UID);
updatePowerStateLocked();
} else {
//唤醒设备,reason为android.server.power:DREAM
wakeUpNoUpdateLocked(SystemClock.uptimeMillis(), "android.server.power:DREAM",
Process.SYSTEM_UID, mContext.getOpPackageName(), Process.SYSTEM_UID);
updatePowerStateLocked();
}
//如果处于Doze状态,在power键灭屏时,首次会将wakefulness设置为该值
} else if (wakefulness == WAKEFULNESS_DOZING) {
if (isDreaming) {
return; // continue dozing
}
// Doze has ended or will be stopped. Update the power state.
//进入asleep状态
//真正进入睡眠状态调用reallyGoToSleepNoUpdateLocked,
//将mWakefulness置为WAKEFULNESS_ASLEEP,再次更新电源状态时将wakelock锁尽数释放,屏幕完全灭屏,进入睡眠状态。
reallyGoToSleepNoUpdateLocked(SystemClock.uptimeMillis(), Process.SYSTEM_UID);
updatePowerStateLocked();
}
}
//如果正处在Dream,则只要触发updatePowerStateLocked(),立即退出Dream
// Stop dream.
if (isDreaming) {
mDreamManager.stopDream(false /*immediate*/);
}
}
在PMS中,进入或退出屏保是通过DreamManager进行的,在PMS中相当于给DMS下达命令,具体的实现在DreamManagerService中。
这里还需要注意,一般在灭屏时,会首先进入Doze状态随后立即进入Sleep状态,但是如果在config.xml文件中配置了config_dozeComponent值,则会进入Doze状态,该值表示当系统进入休眠状态时所启动的组件名称,在该组件中调用startDozing()进入Doze Dream状态。如:
<string name="config_dozeComponent" translatable="false">com.android.systemui/com.android.systemui.doze.DozeService</string>
则在灭屏后,首先会进入Doze状态,DozeService会申请一个PowerManager.DOZE_WAKE_LOCK类型的锁,直到DOZE状态退出后才会进入Sleep状态。
(9)finishWakefulnessChangeIfNeededLocked():
该方法主要做updateWakefulnessLocked()方法的结束工作,可以说updateWakefulnessLocked()方法中做了屏幕改变的前半部分工作,而这个方法中做后半部分工作。当屏幕状态改变后,才会执行该方法。我们已经分析了,屏幕状态有四种:唤醒状态(awake)、休眠状态(asleep)、屏保状态(dream)、打盹状态(doze),当前屏幕状态由wakefulness表示,当wakefulness发生改变,布尔值mWakefulnessChanging变为true。该方法涉及wakefulness收尾相关内容,用来处理wakefulness改变完成后的工作,相关部分如下:
private void finishWakefulnessChangeIfNeededLocked() {
if (mWakefulnessChanging && mDisplayReady) {
//如果当前处于Doze状态,不进行处理
if (mWakefulness == WAKEFULNESS_DOZING
&& (mWakeLockSummary & WAKE_LOCK_DOZE) == 0) {
return; // wait until dream has enabled dozing
}
if (mWakefulness == WAKEFULNESS_DOZING || mWakefulness == WAKEFULNESS_ASLEEP) {
logSleepTimeoutRecapturedLocked();
}
if (mWakefulness == WAKEFULNESS_AWAKE) {
logScreenOn();
}
mWakefulnessChanging = false;
//通过Notifier进行wakefulness改变后的处理
mNotifier.onWakefulnessChangeFinished();
}
}
可以看到,如果当前屏幕状态处于Doze模式,则不作处理直接return。如果是其他模式,则通过调用Notifier的方法去处理了,Notifier好比PMS的一个喇叭,用来发送广播,和其他组件交互等,都是通过Notifier进行处理的,这个类也会进行单独的分析。
此外,该方法中的logScreenOn()方法将打印出整个亮屏流程的耗时,在平时处理问题时也很有帮助。
(10)updateSuspendBlockerLocked():
在分析这个方法前,先来了解下什么是Suspend锁。Suspend锁机制是Android电源管理框架中的一种机制,在前面还提到的wakelock锁也是,不过wakelock锁是上层向framwork层申请,而Suspend锁是framework层中对wakelock锁的表现,也就是说,上层应用申请了wakelock锁后,在PMS中最终都会表现为Suspend锁,通过Suspend锁向Hal层写入节点,Kernal层会读取节点,从而进入唤醒或者休眠。
该函数是由PowerManagerService调用到底层的唯一入口:
private void updateSuspendBlockerLocked() {
//根据wakelock是否带有WAKE_LOCK_CPU标志来决定是否为需要保持CPU唤醒
//其中能维持CPU唤醒的wakelock类型有:PARTIAL_WAKE_LOCK,FULL_WAKE_LOCK,SCREEN_BRIGHT_WAKE_LOCK,SCREEN_DIM_WAKE_LOCK,DRAW_WAKE_LOCK
final boolean needWakeLockSuspendBlocker = ((mWakeLockSummary & WAKE_LOCK_CPU) != 0);
//表示是否维持屏幕亮灭的变量,true表示维持屏幕亮,false表示可以关闭屏幕。
final boolean needDisplaySuspendBlocker = needDisplaySuspendBlockerLocked();
final boolean autoSuspend = !needDisplaySuspendBlocker;
final boolean interactive = mDisplayPowerRequest.isBrightOrDim();
// Disable auto-suspend if needed.
// FIXME We should consider just leaving auto-suspend enabled forever since
// we already hold the necessary wakelocks.
if (!autoSuspend && mDecoupleHalAutoSuspendModeFromDisplayConfig) {
setHalAutoSuspendModeLocked(false);
}
//向下申请PowerManagerService.WakeLocks和PowerManagerService.Display类型的wakelock锁的入口
// First acquire suspend blockers if needed.
if (needWakeLockSuspendBlocker && !mHoldingWakeLockSuspendBlocker) {
mWakeLockSuspendBlocker.acquire();
//mHoldingWakeLockSuspendBlocker表示当前是否持有cpu唤醒锁,如果持有则不必向下继续申请锁,如果维持有,且需要维持CPU唤醒则需要,申请CPU唤醒锁
mHoldingWakeLockSuspendBlocker = true;
}
if (needDisplaySuspendBlocker && !mHoldingDisplaySuspendBlocker) {
mDisplaySuspendBlocker.acquire();
//mHoldingDisplaySuspendBlocker逻辑与mHoldingWakeLockSuspendBlocker相似
mHoldingDisplaySuspendBlocker = true;
}
// Inform the power HAL about interactive mode.
// Although we could set interactive strictly based on the wakefulness
// as reported by isInteractive(), it is actually more desirable to track
// the display policy state instead so that the interactive state observed
// by the HAL more accurately tracks transitions between AWAKE and DOZING.
// Refer to getDesiredScreenPolicyLocked() for details.
if (mDecoupleHalInteractiveModeFromDisplayConfig) {
// When becoming non-interactive, we want to defer sending this signal
// until the display is actually ready so that all transitions have
// completed. This is probably a good sign that things have gotten
// too tangled over here...
if (interactive || mDisplayReady) {
setHalInteractiveModeLocked(interactive);
}
}
// Then release suspend blockers if needed.
if (!needWakeLockSuspendBlocker && mHoldingWakeLockSuspendBlocker) {
mWakeLockSuspendBlocker.release();
mHoldingWakeLockSuspendBlocker = false;
}
if (!needDisplaySuspendBlocker && mHoldingDisplaySuspendBlocker) {
mDisplaySuspendBlocker.release();
mHoldingDisplaySuspendBlocker = false;
}
// Enable auto-suspend if needed.
if (autoSuspend && mDecoupleHalAutoSuspendModeFromDisplayConfig) {
setHalAutoSuspendModeLocked(true);
}
}
上面代码中有mWakeLockSuspendBlocker.acquire()和mDisplaySuspendBlocker.acquire()这两个函数,mWakeLockSuspendBlocker和mDisplaySuspendBlocker的实现类都是SuspendBlockerImpl,SuspendBlockerImpl是PowerManagerService的内部类,看下这个函数:
public void acquire() {
synchronized (this) {
//前面已经说过SuspendBlockerImpl维持了一个计数标志mReferenceCount 当为1的时候申请锁,为0时释放锁。
mReferenceCount += 1;
if (mReferenceCount == 1) {
if (DEBUG_SPEW) {
Slog.d(TAG, "Acquiring suspend blocker \"" + mName + "\".");
}
Trace.asyncTraceBegin(Trace.TRACE_TAG_POWER, mTraceName, 0);
//通过JNI调用到, native层的com_android_server_power_PowerManagerService.cpp文件的nativeAcquireSuspendBlocker函数
nativeAcquireSuspendBlocker(mName);
}
}
}
就这样,我们就把PowerManagerService的架构分析完了,从下个章节开始,深入研究关于电源管理的每个功能的实现,比如亮度调节,比如WackLock锁的机制等;