【android睡眠唤醒 三】PowerManagerService框架解析

一、电源管理框架
  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流程

2、系统睡眠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);
        }

下面继续看goToSleepInternal,在goToSleepNoUpdateLocked()中完成发送了将要休眠的通知,然后修改了Wakefulness,将其置成WAKEFULNESS_DOZING,将mDirty |= DIRTY_WAKEFULNESS置位,更多的实际工作在updatePowerStateLocked()中完成。在updateDreamLocked中完成真正进入睡眠的过程:

    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()来更新电源状态。

未完待续…

作者:frank_zyp
您的支持是对博主最大的鼓励,感谢您的认真阅读。
本文无所谓版权,欢迎转载。

猜你喜欢

转载自blog.csdn.net/frank_zyp/article/details/77965214