簡述
PowerManagerServcie
是android系統電源管理的核心服務,它在Framework層建立起一個策略控制方案,向下決策HAL層以及kernel層來控制設備待機狀態,主要功能是控制系統待機狀態,屏幕顯示,亮度調節,光線/距離傳感器的控制等。
除了與應用程序交互之外,還要與系統中其它模塊配合,在提供良好的能源管理同時提供友好的用戶體驗。比如聽音樂時持續保持系統喚醒,應用通知來臨喚醒手機屏幕等場景
分析一個服務,首先要從它對應用層提供的api PowerManager
入手,觀察提供了哪些接口調用;
-
Wakeup()
:強制系統從睡眠狀態喚醒,此接口對應用是不開放的,應用想喚醒系統必須通過設置亮屏標志(后面即將講到); -
gotoSleep()
:強制系統進入到睡眠狀態,此接口也是應用不開放。 -
userActivity()
:向PowerManagerService報告影響系統休眠的用戶活動,重計算滅屏時間,背光亮度等,例如觸屏,劃屏,power鍵等用戶活動; -
Wakelock
:wakelock是PowerManager的一個內部類,提供了相關的接口來操作wakelock鎖,比如newWakeLock()方法來創建wakelock鎖,acquire()和release()方法來申請和釋放鎖。下面例子有介紹! -
isDeviceIdleMode()
:返回設備當前的狀態,如果處于Idle狀態,則返回true,Idle狀態是在手機長時間沒有被使用以及沒有運動的情況下,手機進入到一種Doze低功耗的模式下,這種狀態下手機可能會關掉網絡數據訪問,可以通過監視DEVICE_IDLE_MODE_CHANGED這個廣播信息,來監控手機狀態的改變
系統層級圖
電源管理架構
主要分為四個層次:
- 應用接口層:
PowerManager.java
中開放給應用一系列接口,應用可以調用PM的接口申請wakelock,喚醒系統,使系統進入睡眠等操作; - Framework層:
PowerManagerService.java
計算系統中和Power相關的計算,是整個電源管理的決策系; - HAL層:該層只有一個
power.c
文件,該文件通過上層傳下來的參數,向/sys/power/wake_lock
或者/sys/power/wake_unlock
文件節點寫數據來與kernel進行通信,主要功能是申請/釋放鎖,維持屏幕亮滅。 - Kernel層:內核層實現電源管理的方案主要包含三個部分:
Kernel/power/
:實現了系統電源管理框架機制。
Arch/arm(ormips or powerpc)/mach-XXX/pm.c
:實現對特定板的處理器電源管理。
drivers/power
:是設備電源管理的基礎框架,為驅動提供了電源管理接口。
一、 初始化
跟其他系統服務一樣,PowerManagerService也是繼承于SystemService并通過SystemServer啟動。
SystemServer啟動PowerManagerService服務
frameworks/base/services/java/com/android/server/SystemServer.java
private void startBootstrapServices() {
......
mPowerManagerService = mSystemServiceManager.startService(PowerManagerService.class);
......
}
PowerManagerService構造
frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
public final class PowerManagerService extends SystemService
implements Watchdog.Monitor {
public PowerManagerService(Context context) {
super(context);
mContext = context;
//創建消息處理線程,并啟動
mHandlerThread = new ServiceThread(TAG,
Process.THREAD_PRIORITY_DISPLAY, false /*allowIo*/);
mHandlerThread.start();
//創建Hanlder對象處理消息
mHandler = new PowerManagerHandler(mHandlerThread.getLooper());
mConstants = new Constants(mHandler);
mAmbientDisplayConfiguration = new AmbientDisplayConfiguration(mContext);
mBatterySaverPolicy = new BatterySaverPolicy(mHandler);
synchronized (mLock) {
//創建"PowerManagerService.WakeLocks"的SuspendBlocker
mWakeLockSuspendBlocker = createSuspendBlockerLocked("PowerManagerService.WakeLocks");
// 創建"PowerManagerService.Display"的SuspendBlocker
mDisplaySuspendBlocker = createSuspendBlockerLocked("PowerManagerService.Display");
// 請求DisplaySuspendBlocker,禁止系統進入休眠
mDisplaySuspendBlocker.acquire();
mHoldingDisplaySuspendBlocker = true;
mHalAutoSuspendModeEnabled = false;
mHalInteractiveModeEnabled = true;
// 設置mWakefulness為喚醒狀態
mWakefulness = WAKEFULNESS_AWAKE;
sQuiescent = SystemProperties.get(SYSTEM_PROPERTY_QUIESCENT, "0").equals("1");
// 進入到native層初始化
nativeInit();
nativeSetAutoSuspend(false);
nativeSetInteractive(true);
nativeSetFeature(POWER_FEATURE_DOUBLE_TAP_TO_WAKE, 0);
}
}
......
}
PowerManagerService構造函數中首先創建了處理消息的進程及對應的handler對象以進行消息處理,然后創建SuspendBlocker對象,用于WakeLocks與Display,并設置mWakefulness的初始狀態為WAKEFULNESS_AWAKE,最后進入到native層初始化。下面先看一下關于mWakefulness的定義。
frameworks/base/core/java/android/os/PowerManagerInternal.java
/**
* 設備處于休眠狀態,只能被wakeUp()喚醒.
*/
public static final int WAKEFULNESS_ASLEEP = 0;
/**
* 設備處于正常工作(fully awake)狀態.
*/
public static final int WAKEFULNESS_AWAKE = 1;
/**
* 設備處于播放屏保狀態.
*/
public static final int WAKEFULNESS_DREAMING = 2;
/**
* 設備處于doze狀態,只有低耗電的屏保可以運行,其他應用被掛起.
*/
public static final int WAKEFULNESS_DOZING = 3;
繼續回到PowerManagerService構造函數的native初始化中,首先來看nativeInit的實現。
frameworks/base/services/core/jni/com_android_server_power_PowerManagerService.cpp
static void nativeInit(JNIEnv* env, jobject obj) {
// 創建一個全局對象,引用PMS
gPowerManagerServiceObj = env->NewGlobalRef(obj);
// 利用hw_get_module加載power模塊
status_t err = hw_get_module(POWER_HARDWARE_MODULE_ID,
(hw_module_t const**)&gPowerModule);
if (!err) {
gPowerModule->init(gPowerModule);
} else {
ALOGE("Couldn't load %s module (%s)", POWER_HARDWARE_MODULE_ID, strerror(-err));
}
}
nativeInit的主要任務時裝載power模塊,該模塊由廠商實現,以高通為例,如下。
device/qcom/common/power/power.c
tatic struct hw_module_methods_t power_module_methods = {
.open = NULL,
};
struct power_module HAL_MODULE_INFO_SYM = {
.common = {
.tag = HARDWARE_MODULE_TAG,
.module_api_version = POWER_MODULE_API_VERSION_0_2,
.hal_api_version = HARDWARE_HAL_API_VERSION,
.id = POWER_HARDWARE_MODULE_ID,
.name = "QCOM Power HAL",
.author = "Qualcomm",
.methods = &power_module_methods,
},
.init = power_init,
.powerHint = power_hint,
.setInteractive = set_interactive,
};
power_module中實現了init,powerHint,setInteractive,nativeInit最終調用到HAL power模塊的power_init具體實現中。接著看native初始化nativeSetAutoSuspend的實現。
frameworks/base/services/core/jni/com_android_server_power_PowerManagerService.cpp
static void nativeSetAutoSuspend(JNIEnv* /* env */, jclass /* clazz */, jboolean enable) {
if (enable) {
ALOGD_IF_SLOW(100, "Excessive delay in autosuspend_enable() while turning screen off");
autosuspend_enable();
} else {
ALOGD_IF_SLOW(100, "Excessive delay in autosuspend_disable() while turning screen on");
autosuspend_disable();
}
}
static void nativeSetInteractive(JNIEnv* /* env */, jclass /* clazz */, jboolean enable) {
if (gPowerModule) {
if (enable) {
ALOGD_IF_SLOW(20, "Excessive delay in setInteractive(true) while turning screen on");
gPowerModule->setInteractive(gPowerModule, true);
} else {
ALOGD_IF_SLOW(20, "Excessive delay in setInteractive(false) while turning screen off");
gPowerModule->setInteractive(gPowerModule, false);
}
}
}
static void nativeSetFeature(JNIEnv *env, jclass clazz, jint featureId, jint data) {
int data_param = data;
if (gPowerModule && gPowerModule->setFeature) {
gPowerModule->setFeature(gPowerModule, (feature_t)featureId, data_param);
}
}
system/core/libsuspend/autosuspend.c
int autosuspend_disable(void)
{
int ret;
ret = autosuspend_init();
if (ret) {
return ret;
}
ALOGV("autosuspend_disable\n");
if (!autosuspend_enabled) {
return 0;
}
ret = autosuspend_ops->disable();
if (ret) {
return ret;
}
autosuspend_enabled = false;
return 0;
}
同nativeInit一樣,最終都是調用到HAL power模塊的具體實現中。
二、 啟動
下面繼續看PowerManagerService在系統啟動過程中回調onStart(),onBootPhase(),systemReady()的實現。
啟動服務SystemServiceManager.onStart
frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
public void onStart() {
publishBinderService(Context.POWER_SERVICE, new BinderService());
publishLocalService(PowerManagerInternal.class, new LocalService());
Watchdog.getInstance().addMonitor(this);
Watchdog.getInstance().addThread(mHandler);
}
private final class BinderService extends IPowerManager.Stub {
......
}
private final class LocalService extends PowerManagerInternal {
......
}
onStart()
中發布了BinderService
,LocalService
分別供其他進程,進程內其他服務調用,并將PowerManagerService
加入到Watchdog
監控中。
啟動服務SystemServiceManager.onBootPhase
public void onBootPhase(int phase) {
synchronized (mLock) {
if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
......
} else if (phase == PHASE_BOOT_COMPLETED) {
final long now = SystemClock.uptimeMillis();
// 設置mBootCompleted狀態
mBootCompleted = true;
mDirty |= DIRTY_BOOT_COMPLETED;
// 更新userActivity及PowerState,后面分析
userActivityNoUpdateLocked(
now, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID);
updatePowerStateLocked();
// 執行mBootCompletedRunnables中的runnable方法
if (!ArrayUtils.isEmpty(mBootCompletedRunnables)) {
Slog.d(TAG, "Posting " + mBootCompletedRunnables.length + " delayed runnables");
for (Runnable r : mBootCompletedRunnables) {
BackgroundThread.getHandler().post(r);
}
}
mBootCompletedRunnables = null;
}
}
}
onBootPhase()
中主要設置mBootCompleted
狀態,更新PowerState
狀態,并執行mBootCompletedRunnables
中的runnables
方法(低電量模式會設置)。
啟動服務SystemServiceManager.systemReady
public void systemReady(IAppOpsService appOps) {
synchronized (mLock) {
mSystemReady = true;
// 獲取AppOpsService
mAppOps = appOps;
// 獲取DreamManager 屏保
mDreamManager = getLocalService(DreamManagerInternal.class);
// 獲取DisplayManagerService 屏幕顯示
mDisplayManagerInternal = getLocalService(DisplayManagerInternal.class);
//窗口策略
mPolicy = getLocalService(WindowManagerPolicy.class);
// 獲取mBatteryService 電池電量
mBatteryManagerInternal = getLocalService(BatteryManagerInternal.class);
PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
// 獲取屏幕默認,最大,最小亮度
mScreenBrightnessSettingMinimum = pm.getMinimumScreenBrightnessSetting();
mScreenBrightnessSettingMaximum = pm.getMaximumScreenBrightnessSetting();
mScreenBrightnessSettingDefault = pm.getDefaultScreenBrightnessSetting();
// 獲取SensorManager
SensorManager sensorManager = new SystemSensorManager(mContext, mHandler.getLooper());
mBatteryStats = BatteryStatsService.getService();
// 創建Notifier對象,用于廣播power state的變化
mNotifier = new Notifier(Looper.getMainLooper(), mContext, mBatteryStats,
mAppOps, createSuspendBlockerLocked("PowerManagerService.Broadcasts"),
mPolicy);
// 無線充電檢測
mWirelessChargerDetector = new WirelessChargerDetector(sensorManager,
createSuspendBlockerLocked("PowerManagerService.WirelessChargerDetector"),
mHandler);
// 監聽設置的變化
mSettingsObserver = new SettingsObserver(mHandler);
mLightsManager = getLocalService(LightsManager.class);
mAttentionLight = mLightsManager.getLight(LightsManager.LIGHT_ID_ATTENTION);
// Initialize display power management.
mDisplayManagerInternal.initPowerManagement(
mDisplayPowerCallbacks, mHandler, sensorManager);
// Register for settings changes.
final ContentResolver resolver = mContext.getContentResolver();
resolver.registerContentObserver(Settings.Secure.getUriFor(
Settings.Secure.SCREENSAVER_ENABLED),
......
IVrManager vrManager =
(IVrManager) getBinderService(VrManagerService.VR_MANAGER_BINDER_SERVICE);
try {
vrManager.registerListener(mVrStateCallbacks);
} catch (RemoteException e) {
Slog.e(TAG, "Failed to register VR mode state listener: " + e);
}
// 讀取配置
readConfigurationLocked();
updateSettingsLocked();
mDirty |= DIRTY_BATTERY_STATE;
updatePowerStateLocked();
}
// 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.獲取與PowerManagerServcie相關的系統服務以及本地服務;
獲取屏幕最大,最小以及默認亮度值; - 2.創建SensorManager 對象,用于和SensorService交互;
- 3.創建Notifier對象,用于通知系統中電源狀態的改變;
- 4.創建WirelessChargerDetector對象,用于檢測無線充電的傳感器(市面上支持的手機較少)
- 5.調用DisplayManagerService的initPowerManagement()方法來初始化Power顯示模塊。
- 6.注冊SettingsObserver監聽系統設置的變化
userActivity
userActivity是定義在PowerManager中的SystemApi,用戶向PowerManagerService報告用戶活動,以更新PowerManagerService內部時間/狀態值,推遲系統休眠的時間。
PowerManager中userActivity請求調用服務端PowerManagerService BinderService的userActivity
,即調用內部方法userActivityNoUpdateLocked
。
private boolean userActivityNoUpdateLocked(long eventTime, int event, int flags, int uid) {
// 如果發生時間是上一次休眠或喚醒前,或當前沒有開機完成到systemReady,不采取操作直接返回
if (eventTime < mLastSleepTime || eventTime < mLastWakeTime
|| !mBootCompleted || !mSystemReady) {
return false;
}
try {
// 更新mLastInteractivePowerHintTime時間
if (eventTime > mLastInteractivePowerHintTime) {
powerHintInternal(POWER_HINT_INTERACTION, 0);
mLastInteractivePowerHintTime = eventTime;
}
// 通過mNotifier通知BatteryStats UserActivity事件
mNotifier.onUserActivity(event, uid);
if (mUserInactiveOverrideFromWindowManager) {
mUserInactiveOverrideFromWindowManager = false;
mOverriddenTimeout = -1;
}
// 如果系統處于休眠狀態,不進行處理
if (mWakefulness == WAKEFULNESS_ASLEEP
|| mWakefulness == WAKEFULNESS_DOZING
|| (flags & PowerManager.USER_ACTIVITY_FLAG_INDIRECT) != 0) {
return false;
}
// 根據flag是否在已變暗的情況下是否重啟活動超時更新mLastUserActivityTimeNoChangeLights或mLastUserActivityTime
// 并且設置mDirty DIRTY_USER_ACTIVITY
if ((flags & PowerManager.USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS) != 0) {
if (eventTime > mLastUserActivityTimeNoChangeLights
&& eventTime > mLastUserActivityTime) {
mLastUserActivityTimeNoChangeLights = eventTime;
mDirty |= DIRTY_USER_ACTIVITY;
return true;
}
} else {
if (eventTime > mLastUserActivityTime) {
mLastUserActivityTime = eventTime;
mDirty |= DIRTY_USER_ACTIVITY;
return true;
}
}
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
return false;
}
三、 應用場景
例如:長連接需要在后臺服務需要持續在線;安卓系統底層優化策略會在系統休眠這段時間調整CPU的運作,我們需要將應用保持CPU一直運轉。
mqtt或者websocket等長連接框架就需要如此!
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock w1 = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "MyTag");
w1.acquire();
//在這個過程,屏幕會保持光亮!
//或者網絡協議執行心跳包
w1.release();
上述newWakeLock( )的第一個flag標記,這些標記不同程度的影響系統電源.
這些標記都是獨占的,并且每次只能指定其中一個。
-
PARTIAL_WAKE_LOCK
:保持CPU 運轉,屏幕和鍵盤燈有可能是關閉的。 -
SCREEN_DIM_WAKE_LOCK
:保持CPU 運轉,允許保持屏幕顯示但有可能是灰的,允許關閉鍵盤燈 -
SCREEN_BRIGHT_WAKE_LOCK
:保持CPU 運轉,允許保持屏幕高亮顯示,允許關閉鍵盤燈 -
FULL_WAKE_LOCK
:保持CPU 運轉,保持屏幕高亮顯示,鍵盤燈也保持亮度
四、 控制系統休眠
Android設備的休眠和喚醒主要基于WakeLock機制。WakeLock是一種上鎖機制,只要有進程獲得了WakeLock鎖系統就不會進 入休眠。例如,在下載文件或播放音樂時,即使休眠時間到了,系統也不能進行休眠。WakeLock可以設置超時,超時后會自動解鎖。
應用使用WakeLock功能前,需要先使用new WakeLock()
接口創建一個WakeLock
類對象,然后調用它的acquire()
方法禁止系統休眠,應用完成工作后調用release()
方法來恢復休眠機制,否則系統將無法休眠,直到耗光所有電量。
WakeLock
類中實現acquire()
和release()
方法實際上是調用了PowerManagerService
的acquireWakeLock()
和releaseWakeLock()
方法。
updatePowerStateLocked()
為PowerManagerService
的核心函數;在執行完申請鎖,釋放鎖,用戶事件,強制喚醒/睡眠等操作都需要調用updatePowerStateLocked()
來更新電源狀態
wakelock
Wakelock是android系統上特有的電源管理機制,只要有應用拿著這個鎖,系統就不能進入睡眠狀態,在上層不同的應用程序可以持有多個不同的wakelock鎖,但是反映到底層就只有三種:控制系統休眠PowerManagerService.WakeLock
,控制屏幕顯示的PowerManagerService.Display
和控制電源狀態改變通知的PowerManagerService.Broadcasts
。
PowerManagerService
有acquire()加鎖和
release()解鎖`兩種狀態,加鎖有兩種方式:
- 第一種是永久的鎖住,這樣的鎖除非顯式的放開,否則是不會解鎖的,所以這種鎖用起來要非常的小心(默認)。
acquire()
:申請wakelock永久鎖(默認),需要手動release - 第二種鎖是超時鎖,這種鎖會在鎖住后一段時間解鎖。
acquire(long timeout)
:申請wakelock超時鎖,timeout為設置的超時時間,超時自動release掉該wakelock。
應用程序在使用wakelock前,必須在其manifest.xml
文件中注冊android.permission.WAKE_LOCK
權限;