(原创)android6.0系统 PowerManager深入分析


概述

一直以来,电源管理是电子产品设计中非常重要的环节,也是任何电子设备中最为重要的系统模块之一,优秀的电源管理方案,能够提供持久的续航能力,良好的用户体验,更能提升电子产品的竞争力。

移动设备的电量主要由两种元件消耗:CPU和显示屏,因此设法降低这两种元件的耗电量就是电源管理的关键,为移动设备设计的CPU大多有两种工作频率,为了省电,大部分时间内cpu都工作在降低频率下,只有进行密集计算时,如视频解码才会切换到高频状态,而显示屏省电的方法是尽量减少亮屏时间,但是显示屏的开关和应用有很大的关系,因此系统中需要有一套机制来控制显示屏的开关和亮度,这也是电源管理的主要工作。

 

电源管理架构

Android的电源管理主要是通过wakelock机制管理系统的状态,整个android电源管理,可以分为四个层次:应用接口层(PowerManager.java),Framework层(PowerManagerService.java),HAL层(Power.c),和内核层(kernel/Power)。

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

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

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

 

Kernel层:内核层实现电源管理的方案主要包含三个部分:

1、Kernel/power/:实现了系统电源管理框架机制。

2、Arch/arm(ormips or powerpc)/mach-XXX/pm.c:实现对特定板的处理器电源管理。

3、drivers/power:是设备电源管理的基础框架,为驱动提供了电源管理接口。

 

Android电源管理框架如下图

 


 

电源管理服务——PowerManagerService

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

 

启动过程

 

SystemServer在系统启动的时候会启动三类服务:引导关键服务,核心服务,其他服务;PowerManagerService是在SystemServer中创建的,并将其作为一个系统服务加入到ServiceManager中:

mPowerManagerService = mSystemServiceManager.startService(PowerManagerService.class);

 

在启动引导关键服务调用startBootstrapServices(),其中各种服务都是通过SystemServiceManager中的startService()函数来启动:

public <T extends SystemService> T startService(Class<T> serviceClass) {

final String name = serviceClass.getName();

 final T service;

            Constructor<T> constructor = serviceClass.getConstructor(Context.class);

            service = constructor.newInstance(mContext);

  mServices.add(service);//注册服务到服务列表中去

 

 service.onStart();//启动服务

}

在启动PowerManagerService时,传入的参数类是PowerManagerService,在startService()中首先调用PowerManagerService的构造函数,然后调用其onStart()函数

PowerManagerServcie的构造函数:

mHandler = new PowerManagerHandler(mHandlerThread.getLooper());

synchronized (mLock) {
mWakeLockSuspendBlocker = createSuspendBlockerLocked("PowerManagerService.WakeLocks");
mDisplaySuspendBlocker = createSuspendBlockerLocked("PowerManagerService.Display");
mDisplaySuspendBlocker.acquire();

mWakefulness = WAKEFULNESS_AWAKE;


nativeInit();

创建一个处理消息和发送消息的线程mHandler,并且两种标志flag的wakelock锁PowerManagerService.WakeLocksPowerManagerService.Display,前者是传入到底层是控制cpu唤醒状态,后者则是控制屏幕亮灭。在构造函数最后调用nativeInit();在native层初始化相关资源。将mWakefulness 置成WAKEFULNESS_AWAKE状态,mWakefulness 标识系统当前状态共有四种定义:

WAKEFULNESS_ASLEEP:表示系统当前处于休眠状态,只能被wakeUp()调用唤醒。

WAKEFULNESS_AWAKE:表示系统目前处于正常运行状态。

WAKEFULNESS_DREAMING:表示系统当前正处于屏保的状态。

WAKEFULNESS_DOZING:表示系统正处于“doze”状态。这种状态下只有低耗电的“屏保”可以运行,其他应用进程都被挂起。

 

在SystemServer中startService中调用到PowerManagerService构造函数做完初始化操作之后便会调用PowerManagerService的onStart()函数:

publishBinderService(Context.POWER_SERVICE, new BinderService());

publishLocalService(PowerManagerInternal.classnew LocalService());

        Watchdog.getInstance().addMonitor(this);

        Watchdog.getInstance().addThread(mHandler);

 

Onstart完成的工作就是将POWER_SERVICE作为Binder的服务端,注册到SystemService中去;将PowerManagerInternal注册到本地服务中,将自己加到watchdog的监控队列中去;将之前在构造函数中创建的mHandler对象加入到watchdog的中,用于监视mHandler的looper是否空闲;

系统准备工作

SystemServer在调用PowerManagerService之后还会调用其SystemReady相当于在系统准备就绪后对PowerManagerService再进行一些初始化工作。SystemReady()方法代码如下:

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();

 

获取与PowerManager相关的本地服务,比如屏保(mDreamManager),屏幕显示(mDisplayManagerInternal),窗口策略(mPolicy),电池电量(mBatteryManagerInternal)等服务,然后初始化屏幕最大亮度,最小亮度,和默认亮度;

 

SensorManager sensorManager = new SystemSensorManager(mContextmHandler.getLooper());

mBatteryStats = BatteryStatsService.getService();

mNotifier new Notifier(Looper.getMainLooper(), mContextmBatteryStats,
        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);

创建sensorManager 对象,用于与sensor交互,比如距离传感器,光线传感器,加速度传感器(doze上使用)。获取电池状态服务,和背光服务;

创建mNotifier 对象,在通过mNotifier 发送通知时候,会传入底层申请PowerManagerService.Broadcasts的wakelock锁。

创建mSettingsObserver 监听系统设置变化,比如亮屏时间,自动背光,屏幕亮度,屏保,低电模式等等

 

总而言之在SystemReady方法中完成的主要工作如下:

获取与PowerManagerServcie相关的系统服务以及本地服务;

获取屏幕最大,最小以及默认亮度值;

创建SensorManager 对象,用于和SensorService交互;

创建Notifier对象,用于通知系统中电源状态的改变;

创建WirelessChargerDetector对象,用于检测无线充电的传感器(市面上支持的手机较少)

调用DisplayManagerService的initPowerManagement()方法来初始化Power显示模块。

注册SettingsObserver监听系统设置的变化

 

PowerManagerServcie的启动初始化过程如下:

 

 

相关接口

PowerManager向应用提供了相应的接口,以供应用程序调用,来改变系统待机状态,屏幕状态,屏幕亮度等,PowerManager是PowerManagerService的代理类,PowerManager向上层应用提供交互的接口,具体的处理工作在PowerManagerService中完成。下面介绍PowerManager中提供的相应接口作用:

Wakeup():强制系统从睡眠状态唤醒,此接口对应用是不开放的,应用想唤醒系统必须通过设置亮屏标志(后面即将讲到);

gotoSleep():强制系统进入到睡眠状态,此接口也是应用不开放。

userActivity():向PowerManagerService报告影响系统休眠的用户活动,重计算灭屏时间,背光亮度等,例如触屏,划屏,power键等用户活动;

Wakelock:wakelock是PowerManager的一个内部类,提供了相关的接口来操作wakelock锁,比如newWakeLock()方法来创建wakelock锁,acquire()和release()方法来申请和释放锁。

isDeviceIdleMode():返回设备当前的状态,如果处于Idle状态,则返回true,Idle状态是在手机长时间没有被使用以及没有运动的情况下,手机进入到一种Doze低功耗的模式下,这种状态下手机可能会关掉网络数据访问,可以通过监视DEVICE_IDLE_MODE_CHANGED这个广播信息,来监控手机状态的改变

唤醒——wakeup

PowerManager的wakeup接口属性是@hide的,所以对于上层应用是不可见的,上层应用要唤醒系统大都依靠两种方式:1.在应用启动Activity时候设置相应的window的flags,通过WMS来唤醒系统;2.在应用申请wakelock锁时附带ACQUIRE_CAUSES_WAKEUP标志;

Wakeup流程如下图所示

 

PowerManager的wakeup接口,可供应用程序调用,来强制唤醒系统,如果该设备处于睡眠状态,调用该接口会立即唤醒系统,比如按Power键,来电,闹钟等场景都会调用该接口。唤醒系统需要android.Manifest.permission#DEVICE_POWER的权限;

我们来看看PowerManagerServcie中wakeup接口的代码:

mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWERnull

  • 19
    点赞
  • 64
    收藏
    觉得还不错? 一键收藏
  • 20
    评论
要在Android 6.0上自定义屏保,你可以按照以下步骤进行操作: 1. 首先,在你的应用程序中创建一个自定义屏保活动(Activity)。 2. 在该活动中,你可以使用自定义的布局文件来显示你想要的屏保内容,例如图片、文字、动画等。 3. 创建一个广播接收器(BroadcastReceiver),用于监听屏幕锁定和解锁事件。 4. 在广播接收器中,注册相应的Intent过滤器以侦听SCREEN_OFF和SCREEN_ON动作。当屏幕关闭时,你可以启动你的自定义屏保活动。当屏幕开启时,你可以结束自定义屏保活动。 5. 在AndroidManifest.xml文件中,声明你的自定义屏保活动和广播接收器。 6. 在设置中,找到“安全”或“屏幕保护程序”选项,选择你的应用程序作为默认的屏幕保护程序。 7. 现在,当设备屏幕超过一段时间无操作后,你的自定义屏保活动将会显示。 需要注意的是,Android 6.0及以上版本对屏保权限有一些限制。如果你的应用程序没有获取屏保权限,它将无法成为默认的屏保程序。要获得此权限,你需要在AndroidManifest.xml文件中添加以下代码: ``` <uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" /> ``` 然后,需要在代码中使用以下方法请求允许忽略电池优化: ``` Intent intent = new Intent(); String packageName = getPackageName(); PowerManager pm = (PowerManager) getSystemService(POWER_SERVICE); if (!pm.isIgnoringBatteryOptimizations(packageName)) { intent.setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS); intent.setData(Uri.parse("package:" + packageName)); startActivity(intent); } ``` 这样,你的应用程序将获得屏保权限并成为默认的屏保程序。现在,你可以根据上述步骤自定义屏保并在Android 6.0设备上使用它。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 20
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值