PowerManagerService流程分析
一、PowerManagerService簡介
PowerManagerService主要服務Android系統電源管理工作,這樣講比較籠統,就具體細節上大致可以認為PowerManagerService集中處理用戶活動(如點擊屏幕,按電源鍵等)、電量變化、用戶設置(如在Setting中設置省電模式,飛行模式)、插拔充電器(無線沖,有線沖)等。當發生以上事件時,PowerManagerService都要進行各種狀態的更新,以下把PMS作為PowerManagerService的簡稱
二、PowerManagerService啟動流程
2.1、PMS啟動
// Power manager needs to be started early because other services need it.// Native daemons may be watching for it to be registered so it must be ready // to handle incoming binder calls immediately (including being able to verify // the permissions for those calls). mPowerManagerService = mSystemServiceManager.startService(PowerManagerService.class); . . .try { // TODO: use boot phase mPowerManagerService.systemReady(mActivityManagerService.getAppOpsService()); } catch (Throwable e) { reportWtf("making Power Manager Service ready", e); }
2.2、SystemServiceManager.startService()
1 public <T extendsSystemService> T startService(Class<T> serviceClass) { 2 final String name = serviceClass.getName(); 3 Slog.i(TAG, "Starting " + name); 4 5 // Create the service. 6 if (!SystemService.class.isAssignableFrom(serviceClass)) { 7 throw new RuntimeException("Failed to create " + name 8 + ": service must extend " + SystemService.class.getName()); 9 } 10 final T service; 11 try { 12 Constructor<T> constructor = serviceClass.getConstructor(Context.class); 13 service = constructor.newInstance(mContext); 14 } catch (InstantiationException ex) { 15 throw new RuntimeException("Failed to create service " + name 16 + ": service could not be instantiated", ex); 17 } catch (IllegalAccessException ex) { 18 throw new RuntimeException("Failed to create service " + name 19 + ": service must have a public constructor with a Context argument", ex); 20 } catch (NoSuchMethodException ex) { 21 throw new RuntimeException("Failed to create service " + name 22 + ": service must have a public constructor with a Context argument", ex); 23 } catch (InvocationTargetException ex) { 24 throw new RuntimeException("Failed to create service " + name 25 + ": service constructor threw an exception", ex); 26 } 27 28 // Register it. 29 mServices.add(service); 30 31 // Start it. 32 try { 33 service.onStart(); 34 } catch (RuntimeException ex) { 35 throw new RuntimeException("Failed to start service " + name 36 + ": onStart threw an exception", ex); 37 } 38 return service; 39 }
在Android5.0以後SystemServer啟動服務的方式發生了改變,在Android4.4以前SystemServer通過new方法創建服務的對象,並把服務註冊到SystemManager中;Android5.0以後SystemServer通過SystemServiceManager.startService來啟動服務,主要通過反射的方式獲取服務的構造方法,並創建服務對象;最後調用服務重寫的onStart()方法。
說明:Android5.0以後所有服務都實現SystemService接口,這樣方法服務的統一管理。
2.3 、PMS構造方法
public PowerManagerService(Context context) { super(context); mContext = context; //啟動一個線程,創建一個handler,handler發送的消息由該線程來處理 mHandlerThread = new ServiceThread(TAG, Process.THREAD_PRIORITY_DISPLAY, false /*allowIo*/); mHandlerThread.start(); mHandler = new PowerManagerHandler(mHandlerThread.getLooper()); synchronized (mLock) { //創建兩個suspendBlocker對象,獲取suspendblocker防止cpu進去休眠 mWakeLockSuspendBlocker = createSuspendBlockerLocked("PowerManagerService.WakeLocks"); mDisplaySuspendBlocker = createSuspendBlockerLocked("PowerManagerService.Display"); mDisplaySuspendBlocker.acquire(); mHoldingDisplaySuspendBlocker = true; mHalAutoSuspendModeEnabled = false; mHalInteractiveModeEnabled = true; mWakefulness = WAKEFULNESS_AWAKE; //初始化電源相關設置,這些方法通過jni調動native方法 nativeInit(); nativeSetAutoSuspend(false); nativeSetInteractive(true); nativeSetFeature(POWER_FEATURE_DOUBLE_TAP_TO_WAKE, 0); } }
2.4、OnStart()方法
1 @Override 2 public void onStart() { 3 //BinderService繼承IPowerManager.Stub,其實就是PowerManager的服務端 4 //這裏其實就是把BinderService對象註冊到ServiceManager中 5 publishBinderService(Context.POWER_SERVICE, new BinderService()); 6 publishLocalService(PowerManagerInternal.class, new LocalService()); 7 8 //加入Watchdog監聽 9 Watchdog.getInstance().addMonitor(this); 10 Watchdog.getInstance().addThread(mHandler); 11 }
2.5、systemReady()方法
public void systemReady(IAppOpsService appOps) { synchronized (mLock) { mSystemReady = true; mAppOps = appOps; mDreamManager = getLocalService(DreamManagerInternal.class); mDisplayManagerInternal = getLocalService(DisplayManagerInternal.class); mPolicy = getLocalService(WindowManagerPolicy.class); mBatteryManagerInternal = getLocalService(BatteryManagerInternal.class); PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); //最大、最小、默認的屏幕亮超時時間 mScreenBrightnessSettingMinimum = pm.getMinimumScreenBrightnessSetting(); mScreenBrightnessSettingMaximum = pm.getMaximumScreenBrightnessSetting(); mScreenBrightnessSettingDefault = pm.getDefaultScreenBrightnessSetting(); //傳感器相關,傳感器檢查到外部事件可以通過發送消息到mHandler的消息隊列中處理 SensorManager sensorManager = new SystemSensorManager(mContext, mHandler.getLooper()); // The notifier runs on the system server‘s main looper so as not to interfere // with the animations and other critical functions of the power manager. mBatteryStats = BatteryStatsService.getService(); //註意上面的註釋,notifier運行在system server的主線程中,並且參數中傳入了一個SuspendBlocker對象,應該發送通知的時候需要點亮屏幕 mNotifier = new Notifier(Looper.getMainLooper(), mContext, mBatteryStats, mAppOps, createSuspendBlockerLocked("PowerManagerService.Broadcasts"), mPolicy); //無線充電器相關,參數中傳入了sensorManager,並且參數中傳入了一個SuspendBlocker對象,也是為了有外部事件發生時點亮屏幕 mWirelessChargerDetector = new WirelessChargerDetector(sensorManager, createSuspendBlockerLocked("PowerManagerService.WirelessChargerDetector"), mHandler); //ContentObserver對象,用來監聽電源相關設置的改變 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 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); // Register for settings changes. //監聽系統中對電源的設置,如開啟省電模式、默認休眠超時時間、屏幕亮度、充電是否亮屏等等 final ContentResolver resolver = mContext.getContentResolver(); resolver.registerContentObserver(Settings.Secure.getUriFor( Settings.Secure.SCREENSAVER_ENABLED), false, mSettingsObserver, UserHandle.USER_ALL); ....... ....... ....... // Go. //讀取資源文件中電源相關設置 readConfigurationLocked(); //更新設置中對電源的相關設置 updateSettingsLocked(); mDirty |= DIRTY_BATTERY_STATE; //更新電源狀態,這裏統一處理了所有的狀態更新,該方法會被頻繁調用 updatePowerStateLocked(); } }
2.6、updatePowerStateLocked()方法
三、PowerManager用法
PowerManager的用法很簡單,我們主要看下PowerManager創建鎖這部分:
newWakeLock(int levelAndFlags, String tag)
levelAndFlags: 就是上邊表格中的幾個flag,可以看到不同的flag對系統的影響並不一樣
PARTIAL_WAKE_LOCK: 保持cpu運轉狀態,屏幕鍵盤滅,按power鍵該鎖不會被系統自動釋放,所以系統無法進去待機休眠
SCREEN_DIM_WAKE_LOCK: 保持cpu處於運行狀態,屏幕微亮、鍵盤滅,但是按power鍵進入待機休眠時會自動釋放
SCREEN_BRIGHT_WAKE_LOCK: 保持cpu處於運行狀態,屏幕亮、鍵盤滅,但是按power鍵進入待機休眠時會自動釋放
FULL_WAKE_LOCK: 保持cpu處於運行狀態,屏幕、鍵盤亮,但是按power鍵進入待機休眠時會自動釋放
註意:官方的文檔介紹盡量不要使用WAKE_LOCK,用FLAG_KEEP_SCREEN_ON標誌位代替WAKE_LOCK,用如下方式:
1 getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
當然該方法只是針對當前Activity,如果要整個應用都保持屏幕亮,則可以寫了BaseActivity並設置該標誌位,其他Activity繼承BaseActivity即可。
四、PowerManagerService調試
PMS中最容易出現的問題就是待機待不下去,原因很可能就是獲取的WAKE_LOCK沒有及時釋放,如果待機時有如下的鎖的話是沒法正真進去待機的,如果出現這種情況,按理說是應該在應用在進去待機時釋放鎖的
五、總結
總的來說PMS的流程並不復雜,不過需要靜下心來分析代碼仍然不是一件很容易的事情,關於updatePowerStateLocked()方法暫時還沒寫上去,感覺東西挺多的一下子寫上去會顯得很長,但是不仔細分析又感覺沒必要寫,所以就先空著,過兩天再補上吧。本人水平有限,有不足之處請指出,後續我會持續更新修改。
PowerManagerService流程分析