美文网首页
电源 | PowerManagerService框架解析

电源 | PowerManagerService框架解析

作者: 力卉编程 | 来源:发表于2019-12-28 16:34 被阅读0次

    一、电源管理框架

    PowerManagerServcie是android系统电源管理的核心服务,它在Framework层建立起一个策略控制方案,向下决策HAL层以及kernel层来控制设备待机状态,控制显示屏,背光灯,距离传感器,光线传感器等硬件设备的状态。向上提供给应用程序相应的操作接口,比如听音乐时持续保持系统唤醒,应用通知来临唤醒手机屏幕等场景等,PMS也是系统的核心服务,Android的电源管理主要是通过wakelock机制来管理系统的状态,整个android电源管理,可以分为如下四个层次:

    1. 应用接口层(PowerManager.java)
        PowerManager中开放给应用一系列接口,应用可以调用PM的接口申请wakelock,唤醒系统,或使系统进入睡眠等操作;

    2. Framework层(PowerManagerService.java)
        应用调用PowerManager开放的接口,来对系统进行一些列的操作是在PowerManagerService中完成的,PowerManagerService计算系统中和Power 相关的计算,是整个电源管理的决策系统。同时协调Power如何与系统其 它模块的交互,比如亮屏,暗屏,系统睡眠,唤醒等等;

    3. HAL层(Power.c)
        该层只有一个power.c文件,该文件通过上层传下来的参数,向/sys/power/wake_lock 或者/sys/power/wake_unlock文件节点写数据来与kernel进行通信,主要功能是申请/释放锁,维持屏幕亮灭;

    4. 内核层(kernel/Power)
        内核层实现电源管理的方案主要包含三个部分:
        (1)Kernel/power/:实现了系统电源管理框架机制;
        (2)Arch/arm(ormips or powerpc)/mach-XXX/pm.c:实现对特定板的处理器电源管理;
        (3)drivers/power:是设备电源管理的基础框架,为驱动提供了电源管理接口。

    电源管理的框架

    二、电源管理服务PowerManagerService

    1. PowerServiceManager启动流程
        PowerManagerService是在SystemServer中创建的,其中在SystemServer在系统启动的时候会启动三类服务:引导关键服务、核心服务和其他服务,PowerManagerService是作为一个核心服务加入到ServiceManager中,启动服务的方式如下:
        startBootstrapServices(); //启动引导服务
        startCoreServices();//启动核心服务
        startOtherServices();//其他服务
      (1)核心服务创建以后,PowerServiceManager的服务随之创建(SystemServer.java):
        mPowerManagerService =
              mSystemServiceManager.startService(PowerManagerService.class);
              
      (2)startService方法(SystemServiceManager.java ):
        public T startService(Class serviceClass) {
        mServices.add(service); //注册服务到服务列表中去
         ervice.onStart();//启动服务
         return service;//返回启动的服务
        }
        在startService方法中,利用反射方法构造PowerManagerService的对象,将它添加到本地service变量中,然后调用了PowerManagerService的onStart方法。

    (3)PowerManagerService构造方法(PowerManagerService.java)

        public PowerManagerService(Context context) {
          //创建一个HandlerThread,并启动  
            mHandlerThread = new ServiceThread(TAG,
                    Process.THREAD_PRIORITY_DISPLAY, false /*allowIo*/);
            mHandlerThread.start();
            //基于这个HandlerThread创建相关的Handler对象,用于向handlerThread中发送消息
            mHandler = new PowerManagerHandler(mHandlerThread.getLooper());
            synchronized (mLock) {
                mWakeLockSuspendBlocker = 
                    createSuspendBlockerLocked("PowerManagerService.WakeLocks");
                mDisplaySuspendBlocker = 
                    createSuspendBlockerLocked("PowerManagerService.Display");
                mDisplaySuspendBlocker.acquire();
                //调用native层初始化  
                nativeInit();
                nativeSetAutoSuspend(false);
                nativeSetInteractive(true);
                nativeSetFeature(POWER_FEATURE_DOUBLE_TAP_TO_WAKE, 0);
            }
       }
    

    在PowerManagerService的构造函数创建了一个消息发送和处理的Handler和两种WakeLock锁:
        a、PowerManagerService.WakeLocks,主要用于控制CPU的唤醒;
        b、PowerManagerService.Display 主要用于控制屏幕的点亮和熄灭;
    (4)PowerManagerService的Onstart方法:
      在PowerManagerService的Onstart方法中:

        public void onStart() {
            publishBinderService(Context.POWER_SERVICE, new BinderService());
            publishLocalService(PowerManagerInternal.class, new LocalService());
    
            Watchdog.getInstance().addMonitor(this);
            Watchdog.getInstance().addThread(mHandler);
        }
    

    Onstart完成的工作就是将POWER_SERVICE作为Binder的服务端,注册到SystemService中去;将PowerManagerInternal注册到本地服务中,将自己加到watchdog的监控队列中去;将之前在构造函数中创建的mHandler对象加入到watchdog的中,用于监视mHandler的looper是否空闲。
    (4)系统准备工作:
      在PowerManagerService创建之后会调用systemReady做一些初始化相关的操作,获取与PowerManager相关的本地服务:

    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();  
                //获取屏幕的亮度值,最大亮度,最小亮度,默认亮度  
                SensorManager sensorManager = new SystemSensorManager
                                (mContext, mHandler.getLooper());  
                //获取传感器管理服务  
                mBatteryStats = BatteryStatsService.getService();  
                //初始化电量统计服务  
                mNotifier = new Notifier(
                    Looper.getMainLooper(), 
                    mBatteryStats,mAppOps, 
                    createSuspendBlockerLocked("PowerManagerService.Broadcasts"),  
                    mPolicy);  
      
                mWirelessChargerDetector = new WirelessChargerDetector(sensorManager,  
                createSuspendBlockerLocked
                            ("PowerManagerService.WirelessChargerDetector"),mHandler);  
                mSettingsObserver = new SettingsObserver(mHandler);  
                //settings的监听器  
                mLightsManager = getLocalService(LightsManager.class);  
                //LED指示灯管理服务  
                mAttentionLight = 
                    mLightsManager.getLight(LightsManager.LIGHT_ID_ATTENTION);  
      
                // 初始化屏幕显示服务  
                mDisplayManagerInternal.initPowerManagement(  
                        mDisplayPowerCallbacks, mHandler, sensorManager);  
                //第二步:注册相关的BroadCastReceiver  
                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);  
                  
                //第三步.注册设置变化的监听器  
                final ContentResolver resolver = mContext.getContentResolver();  
                resolver.registerContentObserver(Settings.Secure.getUriFor(  
                        Settings.Secure.SCREENSAVER_ENABLED),  
                        false, mSettingsObserver, UserHandle.USER_ALL);  
                  
                ……  
                resolver.registerContentObserver(Settings.Secure.getUriFor(  
                        Settings.Secure.DOUBLE_TAP_TO_WAKE),  
                        false, mSettingsObserver, UserHandle.USER_ALL);  
                //双击唤醒屏幕  
                // 第四步: 从文件读取默认的配置信息  
                readConfigurationLocked();  
                //读取设置信息,并更新相关的变量  
                updateSettingsLocked();  
                // 第五步  
                mDirty |= DIRTY_BATTERY_STATE;  
                //更新电源的相关信息  
                updatePowerStateLocked();  
            }  
        }  
    

    SystemReady所完成的工作如下:
      -获取与PowerManagerServcie相关的系统服务以及本地服务;
      -获取屏幕最大,最小以及默认亮度值;
      -创建SensorManager 对象,用于和SensorService交互;
      -创建Notifier对象,用于通知系统中电源状态的改变;
      -调用DisplayManagerService的initPowerManagement()方法来初始化Power显示模块。
      -注册SettingsObserver监听系统设置的变化。
    整体框架流程图如下:


    流程图

    (5)PowerManager相关接口:
      PowerManager向应用提供了相应的接口,以供应用程序调用,来改变系统待机状态,屏幕状态,屏幕亮度等,PowerManager是PowerManagerService的代理类,PowerManager向上层应用提供交互的接口,具体的处理工作在PowerManagerService中完成。下面介绍PowerManager中提供的相应接口作用:
    a、Wakeup():
      强制系统从睡眠状态唤醒,此接口对应用是不开放的,应用想唤醒系统必须通过设置亮屏标志;
    b、gotoSleep():
      强制系统进入到睡眠状态,此接口也是应用不开放;
    c、userActivity():
      向PowerManagerService报告影响系统休眠的用户活动,重计算灭屏时间,背光亮度等,例如触屏,划屏,power键等用户活动;
    d、Wakelock:
      wakelock是PowerManager的一个内部类,提供了相关的接口来操作wakelock锁,比如newWakeLock()方法来创建wakelock锁,acquire()和release()方法来申请和释放锁;
    e、isDeviceIdleMode():
      返回设备当前的状态,如果处于Idle状态,则返回true,Idle状态是在手机长时间没有被使用以及没有运动的情况下,手机进入到一种Doze低功耗的模式下,这种状态下手机可能会关掉网络数据访问,可以通过监视DEVICE_IDLE_MODE_CHANGED这个广播信息,来监控手机状态的改变。

    三、系统唤醒wakeup/睡眠goToSleep
    1、PowerManager的wakeup接口,可供应用程序调用,来强制唤醒系统,如果该设备处于睡眠状态,调用该接口会立即唤醒系统,比如按Power键,来电,闹钟等场景都会调用该接口。PowerManager的wakeup接口属性是@hide的,所以对于上层应用是不可见的,上层应用要唤醒系统大都依靠两种方式:
      (1)在应用启动Activity时候设置相应的window的flags,通过WMS来唤醒系统;
      (2)在应用申请wakelock锁时附带ACQUIRE_CAUSES_WAKEUP标志。

     /**
         * @hide
         */
        public void wakeUp(long time, String reason) {
            try {
                mService.wakeUp(time, reason, mContext.getOpPackageName());
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }
    

    在wakeUp中调用PowerManagerService的wakeUp方法如下:

    public void wakeUp(long eventTime, String reason, String opPackageName) {
                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);
                }
            }
    

    在wakeUpInternal中,通过wakeUpNoUpdateLocked来做唤醒系统的相关通知工作,最后调用PowerManagerService的核心接口updatePowerStateLocked来更新电源状态,从而完成亮屏前的图形绘制工作及亮屏动作。

        private void wakeUpInternal(long eventTime, String reason, int uid, String opPackageName,
                int opUid) {
            synchronized (mLock) {
                if (mIPOShutdown && reason != PowerManager.WAKE_UP_REASON_SHUTDOWN)
                    return;
                if (wakeUpNoUpdateLocked(eventTime, reason, uid, opPackageName, opUid)) {
                    updatePowerStateLocked();
                }
            }
        }
    

    wakeup调用流程

    调用流程

    系统睡眠goToSleep
      PowerManager的gotoSleep()接口是@hide属性,因此对于上层应用是不开放的,设备强制进入睡眠状态,在处理一些灭屏按键事件时,会通过WMS来调用PowerManager的gotoSleep接口,一般在系统一段时间没有被操作时,系统将会自动调用gotoSleep函数,让其进入到睡眠模式;与wakeup唤醒一样,PowerManager的gotoSleep()在PowerManagerService中处理,PMS中的gotoSleep()首先检查调用者是否拥有android.Manifest.permission.DEVICE_POWER权限。然后调用到goToSleepInternal()中处理:

    /**
         * @hide Requires signature permission.
         */
        public void goToSleep(long time, int reason, int flags) {
            try {
               //调用PMS的goToSleep方法
                mService.goToSleep(time, reason, flags);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }
    
      public void goToSleep(long eventTime, int reason, int flags) {
                //检测权限android.Manifest.permission.DEVICE_POWER的权限
                ...
                goToSleepInternal(eventTime, reason, flags, uid);
            }
      private void goToSleepInternal(long eventTime, int reason, int flags, int uid) {
            synchronized (mLock) {
                if (mProximityPositive && reason ==
                     PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON) {
                    mDirty |= DIRTY_WAKEFULNESS;
                    mWakefulness = WAKEFULNESS_ASLEEP;
                    updatePowerStateLocked();
                    return;
                }
    
                if (goToSleepNoUpdateLocked(eventTime, reason, flags, uid)) {
                    updatePowerStateLocked();//PMS核心
                }
            }
        }
    

    系统睡眠唤醒策略wakelock
      Android设备的休眠和唤醒主要基于WakeLock机制。WakeLock是一种上锁机制,只要有进程获得了WakeLock锁系统就不会进 入休眠。例如,在下载文件或播放音乐时,即使休眠时间到了,系统也不能进行休眠。WakeLock可以设置超时,超时后会自动解锁。
      应用使用WakeLock功能前,需要先使用new WakeLock()接口创建一个WakeLock类对象,然后调用它的acquire()方法禁止系统休眠,应用完成工作后调用release()方法来恢复休眠机制,否则系统将无法休眠,直到耗光所有电量。WakeLock类中实现acquire()和release()方法实际上是调用了PowerManagerService的acquireWakeLock()和releaseWakeLock()方法。updatePowerStateLocked为PowerManagerService的核心函数;在执行完申请锁,释放锁,用户事件,强制唤醒/睡眠等操作都需要调用updatePowerStateLocked()来更新电源状态。

    文 |力卉编程

    相关文章

      网友评论

          本文标题:电源 | PowerManagerService框架解析

          本文链接:https://www.haomeiwen.com/subject/hxusoctx.html