1. 程式人生 > >PowerManagerService流程分析

PowerManagerService流程分析

other nes func 靜下心來 沒有 light 事情 統一管理 mon

一、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 extends
SystemService> 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流程分析