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 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()方法暂时还没写上去,感觉东西挺多的一下子写上去会显得很长,但是不仔细分析又感觉没必要写,所以就先空着,过两天再补上吧。本人水平有限,有不足之处请指出,后续我会持续更新修改。

时间: 2024-10-20 01:28:01

PowerManagerService流程分析的相关文章

android4.4 PowerManagerService流程分析

这几日,闲来无事,想研究一下android Powermanager机制,之前也通过网络的论坛之类文章有了一定的了解,此一番本打算是重温旧梦,结果发现4.4的这一块代码较之之前的android低版本还是有较大变动的,于是,将系统休眠或唤醒的流程跟了一遍,现将自己的理解分析如下: 首先,我们来一个追本溯源,看看这个service是在哪里启动,如何起来的,我们知道系统的启动顺序是uboot->kernel->android,而kernel完成硬件设备的初始化以及系统资源的初始化,分配管理等工作后,

thttpd和cgilua安装与运行流程分析

安装 参考如下博文安装thttpd软件 http://blog.csdn.net/21aspnet/article/details/7045845 http://blog.csdn.net/dragoncheng/article/details/5614559 thttpd配置文件: [email protected]:/usr/local/bin# cat /usr/local/thttpd/conf/ etc/  logs/ man/  sbin/ www/  [email protecte

Linux系统启动流程分析与关机流程

Linux 系统启动流程分析 Linux系统的启动过程并不是大家想象中的那么复杂,其过程可以分为5个阶段: 内核的引导. 运行 init. 系统初始化. 建立终端. 用户登录系统. init程序的类型: SysV: init, CentOS 5之前, 配置文件: /etc/inittab. Upstart: init,CentOS 6, 配置文件: /etc/inittab, /etc/init/*.conf. Systemd: systemd, CentOS 7,配置文件: /usr/lib/

u-boot启动流程分析(2)_板级(board)部分

转自:http://www.wowotech.net/u-boot/boot_flow_2.html 目录: 1. 前言 2. Generic Board 3. _main 4. global data介绍以及背后的思考 5. 前置的板级初始化操作 6. u-boot的relocation 7. 后置的板级初始化操作 1. 前言 书接上文(u-boot启动流程分析(1)_平台相关部分),本文介绍u-boot启动流程中和具体版型(board)有关的部分,也即board_init_f/board_i

Cocos2d-x3.3RC0的Android编译Activity启动流程分析

本文将从引擎源代码Jni分析Cocos2d-x3.3RC0的Android Activity的启动流程,以下是具体分析. 1.引擎源代码Jni.部分Java层和C++层代码分析 watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveXV4aWt1b18x/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" > watermark/2/text/aHR0cDov

HBase1.0.0源码分析之请求处理流程分析以Put操作为例(二)

HBase1.0.0源码分析之请求处理流程分析以Put操作为例(二) 1.通过mutate(put)操作,将单个put操作添加到缓冲操作中,这些缓冲操作其实就是Put的父类的一个List的集合.如下: private List<Row> writeAsyncBuffer = new LinkedList<>(); writeAsyncBuffer.add(m); 当writeAsyncBuffer满了之后或者是人为的调用backgroundFlushCommits操作促使缓冲池中的

从注册流程 分析如何安全退出多个Activity 多种方式(附DEMO)

前言 由于一个同学问到我如何按照一个流程走好之后回到首页,我以前看到过4个解决方案,后来发现有做个记录和总结的必要,就写了这篇博文.(之前看小强也写过一篇,这里通过自身的分析完整的总结一下以下6种方案,并加上一个DEMO便于大家了解大体流程) 在android的用户交互中,按钮触发的意图(Intent)跳转会为你重新打开新的一个界面活动(Activity),对于之前的界面根据需求进行摧毁(Finish())或则保留. 如果一个交互流程中,是从A开始,按照A - B - C - D - A这样的顺

基于linux与busybox的reboot命令流程分析

http://www.xuebuyuan.com/736763.html 基于Linux与Busybox的Reboot命令流程分析 *************************************************************************************************************************** 作者:EasyWave                                                

[国嵌笔记][030][U-Boot工作流程分析]

uboot工作流程分析 程序入口 1.打开顶层目录的Makefile,找到目标smdk2440_config的命令中的第三项(smdk2440) 2.进入目录board/samsung/smdk2440/,找到u-boot.lds文件.uboot的链接都是由这个链接器脚本来控制的 3.打开u-boot.lds文件,找到.text(代码段)的第一个文件cup/s3c24xx/start.o,该文件就是uboot的入口代码.链接器脚本中的ENTRY用来表明整个程序的入口,那么标号_start就是整个