该系列文章总纲链接:专题分纲目录 Android Framework 电源子系统


本章关键点总结 & 说明:

本章节主要关注➕ 以上思维导图即可。该章节 主要是 对 PMS 启动的分析,从systemServer启动 到 构造器、systemReady、、接口userActicity、接口gotoSleep的 一个简要的整体分析。

1 PowerManagerService启动

PowerManagerService负责Andorid系统中电源管理方面的工作。作为系统核心服务之一,PowerManagerService与其他服务及HAL层等都有交互关系,同时 因为很多服务都会涉及它,因此启动会比较早一些,在SystemServer的startBootstrapServices中就启动了,代码如下:

 private void startBootstrapServices() {//...anager 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);//...}

因此 整个分析就基于此,接下来看PowerManagerService的构造器,代码实现如下:

public PowerManagerService(Context context) {super(context);mContext = context;//创建处理消息的线程和Handler对象mHandlerThread = new ServiceThread(TAG,Process.THREAD_PRIORITY_DISPLAY, false /*allowIo*/);mHandlerThread.start();mHandler = new PowerManagerHandler(mHandlerThread.getLooper());synchronized (mLock) {//创建对象mWakeLockSuspendBlocker和mDisplaySuspendBlockermWakeLockSuspendBlocker = createSuspendBlockerLocked("PowerManagerService.WakeLocks");mDisplaySuspendBlocker = createSuspendBlockerLocked("PowerManagerService.Display");mDisplaySuspendBlocker.acquire();mHoldingDisplaySuspendBlocker = true;mHalAutoSuspendModeEnabled = false;mHalInteractiveModeEnabled = true;//注意:这里共有4种状态//    WAKEFULNESS_AWAKE 正常运行状态//    WAKEFULNESS_DREAMING 正在播放屏保状态//    WAKEFULNESS_DOZING 处于doze状态,此时只有“低耗电”的屏保可以运行,其他进程均被挂起//    WAKEFULNESS_ASLEEP 休眠状态,只能被wakeup唤醒mWakefulness = WAKEFULNESS_AWAKE;//设置PowerManagerService的状态nativeInit();//进入PMS的native层调用nativeSetAutoSuspend(false);nativeSetInteractive(true);}
}

@1 createSuspendBlockerLocked分析

这里创建对象mWakeLockSuspendBlocker和mDisplaySuspendBlocker的createSuspendBlockerLocked方法实现如下:

private SuspendBlocker createSuspendBlockerLocked(String name) {SuspendBlocker suspendBlocker = new SuspendBlockerImpl(name);mSuspendBlockers.add(suspendBlocker);return suspendBlocker;
}

这里创建了SuspendBlockerImpl类型的对象,接下来主要是SuspendBlockerImpl的acquire方法和release方法的实现,核心代码实现如下:

@Override
public void acquire() {synchronized (this) {mReferenceCount += 1;if (mReferenceCount == 1) {nativeAcquireSuspendBlocker(mName);}}
}@Override
public void release() {synchronized (this) {mReferenceCount -= 1;if (mReferenceCount == 0) {nativeReleaseSuspendBlocker(mName);} else if (mReferenceCount < 0) {mReferenceCount = 0;}}
}

这里两个关键方法nativeAcquireSuspendBlocker和 nativeReleaseSuspendBlocker在native层的实现,代码如下:

static void nativeAcquireSuspendBlocker(JNIEnv *env, jclass clazz, jstring nameStr) {ScopedUtfChars name(env, nameStr);acquire_wake_lock(PARTIAL_WAKE_LOCK, name.c_str());
}static void nativeReleaseSuspendBlocker(JNIEnv *env, jclass clazz, jstring nameStr) {ScopedUtfChars name(env, nameStr);release_wake_lock(name.c_str());
}

继续分析acquire_wake_lock 和 release_wake_lock的实现,代码如下:

int acquire_wake_lock(int lock, const char* id)
{initialize_fds();if (g_error) return g_error;int fd;if (lock == PARTIAL_WAKE_LOCK) {fd = g_fds[ACQUIRE_PARTIAL_WAKE_LOCK];}else {return EINVAL;}return write(fd, id, strlen(id));
}int release_wake_lock(const char* id)
{initialize_fds();if (g_error) return g_error;ssize_t len = write(g_fds[RELEASE_WAKE_LOCK], id, strlen(id));return len >= 0;
}

这里实际上是通过向驱动中写入数据来实现功能的,所写的数据就是创建变量时传递的PowerManagerService.WakeLocks和PowerManagerService.Display,同时 文件句柄的创建是通过方法initialize_fds来实现的,代码如下:

const char * const OLD_PATHS[] = {"/sys/android_power/acquire_partial_wake_lock","/sys/android_power/release_wake_lock",
};const char * const NEW_PATHS[] = {"/sys/power/wake_lock","/sys/power/wake_unlock",
};
//...
static inline void initialize_fds(void)
{//pthread_once(&g_initialized, open_file_descriptors);if (g_initialized == 0) {//文件操作open 相关if(open_file_descriptors(NEW_PATHS) < 0)open_file_descriptors(OLD_PATHS);g_initialized = 1;}
}

说明:

Android防止系统休眠的方式是通过向设备节点"/sys/power/wake_lock"写入数据

  1. 如果写的是PowerManagerService.WakeLocks,系统将不能休眠,但屏幕会关闭
  2. 如果写的是PowerManagerService.Display,系统将不能休眠,同时屏幕也不会关闭

如果系统要恢复休眠,则向"/sys/power/wake_unlock"写入同样的字符串就可以了。

@2 nativeInit分析

native层的代码实现如下:

static void nativeInit(JNIEnv* env, jobject obj) {gPowerManagerServiceObj = env->NewGlobalRef(obj);status_t err = hw_get_module(POWER_HARDWARE_MODULE_ID,(hw_module_t const**)&gPowerModule);if (!err) {gPowerModule->init(gPowerModule);}//...
}

这里主要是装载Power模块,然后执行它的init方法。

2 PowerManagerService的systemReady方法

同时在startOtherServices中执行 最后的systemReady方法,代码如下:

 private void startOtherServices() {final Context context = mSystemContext;//...try {// TODO: use boot phasemPowerManagerService.systemReady(mActivityManagerService.getAppOpsService());} catch (Throwable e) {reportWtf("making Power Manager Service ready", e);}//...}

继续看systemReady的代码实现,如下:

public void systemReady(IAppOpsService appOps) {synchronized (mLock) {mSystemReady = true;mAppOps = appOps;//获得DreamManager的引用mDreamManager = getLocalService(DreamManagerInternal.class);//获得DisplayManager的引用mDisplayManagerInternal = getLocalService(DisplayManagerInternal.class);mPolicy = getLocalService(WindowManagerPolicy.class);//获得BatteryManager的引用mBatteryManagerInternal = getLocalService(BatteryManagerInternal.class);//获取最大、最小、默认的屏幕亮度值PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);mScreenBrightnessSettingMinimum = pm.getMinimumScreenBrightnessSetting();mScreenBrightnessSettingMaximum = pm.getMaximumScreenBrightnessSetting();mScreenBrightnessSettingDefault = pm.getDefaultScreenBrightnessSetting();//获取sensorManager引用,用于和SensorService(native服务,管理 传感器设备)交互SensorManager sensorManager = new SystemSensorManager(mContext, mHandler.getLooper());//获取BatteryStatsService引用mBatteryStats = BatteryStatsService.getService();//创建Notifier,广播和Power相关的变化,屏幕的打开和关闭mNotifier = new Notifier(Looper.getMainLooper(), mContext, mBatteryStats,mAppOps, createSuspendBlockerLocked("PowerManagerService.Broadcasts"),mPolicy);//获取 检测无线充电的对象mWirelessChargerDetector = new WirelessChargerDetector(sensorManager,createSuspendBlockerLocked("PowerManagerService.WirelessChargerDetector"),mHandler);//监听系统设置变化的对象mSettingsObserver = new SettingsObserver(mHandler);//获取LightsService的引用mLightsManager = getLocalService(LightsManager.class);mAttentionLight = mLightsManager.getLight(LightsManager.LIGHT_ID_ATTENTION);//初始化显示模块电源管理模块mDisplayManagerInternal.initPowerManagement(mDisplayPowerCallbacks, mHandler, sensorManager);// Register for broadcasts from other components of the system.//监听其他广播的intent,很多都和电源管理有关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);//Dock插拔事件通知mContext.registerReceiver(new DockReceiver(), filter, null, mHandler);//监听系统设置Setting的变化final ContentResolver resolver = mContext.getContentResolver();resolver.registerContentObserver(Settings.Secure.getUriFor(Settings.Secure.SCREENSAVER_ENABLED),false, mSettingsObserver, UserHandle.USER_ALL);//监听更多setting的变化...resolver.registerContentObserver(Settings.Global.getUriFor(Settings.Global.THEATER_MODE_ON),false, mSettingsObserver, UserHandle.USER_ALL);readConfigurationLocked();updateSettingsLocked();mDirty |= DIRTY_BATTERY_STATE;updatePowerStateLocked();}
}

3 接口userActivity分析

PowerManager(简称PM)是PowerManagerService(后简称PMS)的代理类,这里接口userActivity用于用户进程向PMS报告用户影响系统休眠的活动,比如:用户点击屏幕时,系统会调用该方法userActivity告诉PMS用户点击的时间,这样PMS将更新内部保存的时间值,从而推迟系统休眠的时间,userActivity实现如下:

@Override // Binder call
public void userActivity(long eventTime, int event, int flags) {final long now = SystemClock.uptimeMillis();//权限检测 & 异常处理final int uid = Binder.getCallingUid();final long ident = Binder.clearCallingIdentity();try {userActivityInternal(eventTime, event, flags, uid);} finally {Binder.restoreCallingIdentity(ident);}
}

继续分析userActivityInternal,内部实现如下:

private void userActivityInternal(long eventTime, int event, int flags, int uid) {synchronized (mLock) {if (userActivityNoUpdateLocked(eventTime, event, flags, uid)) {updatePowerStateLocked();}}
}

这里关键两行代码:userActivityNoUpdateLocked的判定和执行updatePowerStateLocked,其中userActivityNoUpdateLocked只是将参数保存在内部变量中,并不采取任何操作,代码实现如下:

private boolean userActivityNoUpdateLocked(long eventTime, int event, int flags, int uid) {//...try {if (eventTime > mLastInteractivePowerHintTime) {powerHintInternal(POWER_HINT_INTERACTION, 0);mLastInteractivePowerHintTime = eventTime;}mNotifier.onUserActivity(event, uid);//发出通知if (mWakefulness == WAKEFULNESS_ASLEEP|| mWakefulness == WAKEFULNESS_DOZING|| (flags & PowerManager.USER_ACTIVITY_FLAG_INDIRECT) != 0) {return false;//如果系统处于休眠或doze模式,返回}/*关键变量mLastUserActivityTimeNoChangeLightsmLastUserActivityTimemDirty将会作为是否执行睡眠/唤醒操作的依据*/if ((flags & PowerManager.USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS) != 0) {if (eventTime > mLastUserActivityTimeNoChangeLights&& eventTime > mLastUserActivityTime) {//记录userActivity方法的时间mLastUserActivityTimeNoChangeLights = eventTime;mDirty |= DIRTY_USER_ACTIVITY;return true;}} else {if (eventTime > mLastUserActivityTime) {//记录userActivity方法的时间mLastUserActivityTime = eventTime;//记录用户的操作类型mDirty |= DIRTY_USER_ACTIVITY;return true;}}} //...return false;
}

接下来 调用 updatePowerStateLocked开始更新 休眠 or 唤醒状态我们会在下一节中专门分析该方法此处先略过。

4 接口gotoSleep分析

gotoSleep接口是用来强制系统进入休眠模式。当系统一段时间无操作时,将调用gotoSleep接口来进入该模式,PMS的接口gotoSleep实现如下:

@Override // Binder call
public void goToSleep(long eventTime, int reason, int flags) {//...final int uid = Binder.getCallingUid();final long ident = Binder.clearCallingIdentity();try {goToSleepInternal(eventTime, reason, flags, uid);} finally {Binder.restoreCallingIdentity(ident);}
}

这里主要调用了方法goToSleepInternal,代码实现如下:

private void goToSleepInternal(long eventTime, int reason, int flags, int uid) {synchronized (mLock) {if (goToSleepNoUpdateLocked(eventTime, reason, flags, uid)) {updatePowerStateLocked();}}
}

继续分析关键方法goToSleepNoUpdateLocked的实现,代码如下:

// This method is called goToSleep for historical reasons but we actually start
// dozing before really going to sleep.
@SuppressWarnings("deprecation")
private boolean goToSleepNoUpdateLocked(long eventTime, int reason, int flags, int uid) {if (eventTime < mLastWakeTime|| mWakefulness == WAKEFULNESS_ASLEEP|| mWakefulness == WAKEFULNESS_DOZING|| !mBootCompleted || !mSystemReady) {return false;}Trace.traceBegin(Trace.TRACE_TAG_POWER, "goToSleep");try {//打印日志...//更新成员变量 值mLastSleepTime = eventTime;mSandmanSummoned = true;setWakefulnessLocked(WAKEFULNESS_DOZING, reason);// Report the number of wake locks that will be cleared by going to sleep.int numWakeLocksCleared = 0;final int numWakeLocks = mWakeLocks.size();for (int i = 0; i < numWakeLocks; i++) {final WakeLock wakeLock = mWakeLocks.get(i);switch (wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK) {case PowerManager.FULL_WAKE_LOCK:case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:case PowerManager.SCREEN_DIM_WAKE_LOCK:numWakeLocksCleared += 1;break;}}//打印EventLog 日志EventLog.writeEvent(EventLogTags.POWER_SLEEP_REQUESTED, numWakeLocksCleared);// Skip dozing if requested.if ((flags & PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE) != 0) {reallyGoToSleepNoUpdateLocked(eventTime, uid);}} finally {Trace.traceEnd(Trace.TRACE_TAG_POWER);}return true;
}

这里执行了setWakefulnessLocked,代码如下:

private void setWakefulnessLocked(int wakefulness, int reason) {if (mWakefulness != wakefulness) {finishWakefulnessChangeLocked();mWakefulness = wakefulness;mWakefulnessChanging = true;mDirty |= DIRTY_WAKEFULNESS;mNotifier.onWakefulnessChangeStarted(wakefulness, reason);}
}

这里的核心操作是修改了成员变量的值,在这之后发送了休眠的通知。接下来 调用 updatePowerStateLocked开始更新 休眠 or 唤醒状态我们会在 本模块 第3 4 5 节中专门分析该方法,因此 此处先略过。

Android Framework 电源子系统(01)PowerManagerService启动分析相关推荐

  1. Android Framework 电源子系统(05)核心方法updatePowerStateLocked分析-3 更新屏保  发送通知  更新wakelock

    该系列文章总纲链接:专题分纲目录 Android Framework 电源子系统 本章关键点总结 & 说明: 本章节主要关注➕ updatePowerStateLocked 方法中 更新屏保 ...

  2. Android Framework 电源子系统(04)核心方法updatePowerStateLocked分析-2 循环处理  更新显示设备状态

    该系列文章总纲链接:专题分纲目录 Android Framework 电源子系统 本章关键点总结 & 说明: 本章节主要关注➕ updatePowerStateLocked 方法中 循环处理 ...

  3. Android Framework 窗口子系统 (08)窗口动画之动画系统框架

    该系列文章总纲链接:专题分纲目录 Android Framework 窗口子系统 本章关键点总结 & 说明: 导图是不断迭代的,这里主要关注➕ 左上角 Android 窗口动画系统部分(因为导 ...

  4. Android性能优化之App应用启动分析与优化

    前言: 昨晚新版本终于发布了,但是还是记得有测试反馈app启动好长时间也没进入app主页,所以今天准备加个班总结一下App启动那些事! app的启动方式: 1.)冷启动      当启动应用时,后台没 ...

  5. 专题总纲目录 Android Framework 总纲

    专题总纲说明: 本系列文章虽说是 Android 的知识体系专题,同时也是学习Android Framework 系统的一个思路,尤其是当我们对Android 框架层 一点都不了解的时候,但前提是要有 ...

  6. Android系统源码分析/多媒体框架/音频子系统/常用结构体分析-audio.h

    audio_stream_type_t 定义音频流类型,主要是手机系统各类典型的音频流做出属性上的区分,举个例子:电话和媒体2种类型的音频不管从输出的设备(耳机.功放.还是蓝牙)都是存在明显的不同.把 ...

  7. Android PowerManagerService简单分析

    PowerManagerService是负责管理.协调设备电源管理的系统服务之一,它在Framework层建立起一个策略控制方案,向下决策HAL层以及kernel层来控制设备待机状态,控制显示屏,背光 ...

  8. Android系统电池管理(PowerManagerService)框架分析及其在实体设备和虚拟设备上的差异(一)

    0 前言 移动设备的电池一直是影响移动设备用户体验的关键问题之一,电池容量.充电速度.以及系统待机时长都在用户考虑范围内. 在众多嵌入式设备系统中,Android系统的设计的主要目的就是为了通过触摸屏 ...

  9. 图解Android - Zygote, System Server 启动分析

    Init 是所有Linux程序的起点,而Zygote于Android,正如它的英文意思,是所有java程序的'孵化池'(玩过星际虫族的兄弟都晓得的).用ps 输出可以看到 >adb shell ...

最新文章

  1. 视觉人工智能市场格局初成型,国内企业占半壁江山
  2. 《2021年全球创新指数报告》发布!
  3. Nginx(四)------nginx 负载均衡
  4. 【转】HashTable 和 HashMap的区别
  5. python 使用小知识总结(持续更新ing)
  6. C/C++:Windows获取电脑机器指纹
  7. Optional类的使用
  8. amazeui学习笔记--css(基本样式2)--基础设置Base
  9. 实战 | Python批量提取Win10锁屏壁纸
  10. Swift - 高级运算符介绍
  11. 统计信号处理基础 习题解答3-9
  12. 使用开票组件快速开具清单发票
  13. rhino插件-创建犀牛软件皮肤-rhino皮肤-界面开发-犀牛插件
  14. 有关十二个“一”的文艺创作-拓展版
  15. 如何成为一个游戏制作人——第5.5章一个小游戏的框架
  16. 异常(Exceptation)
  17. Echarts基础圆环图
  18. (3)无人车线控底盘开发
  19. 重磅!中期科技ZONTREE智慧公厕整体解决方案
  20. MTK平台TP驱动框架解析

热门文章

  1. C++实现Socket编程
  2. Android 闪屏启动页全面屏适配
  3. 根据字符类型和密码长度随机生成密码
  4. Android 过渡动画(Transition)
  5. 调查电视节目受欢迎程度
  6. java冒泡排序获取最大值_Java干货分享:冒泡排序
  7. 解决Linux下终端无法输入的假死现象
  8. WebDAV之葫芦儿·派盘+恒星播放器
  9. linux传输文件命令scp乱码,CP,SCP 命令(包括windows与linux用xshell互传)
  10. linux centos网卡配置,Linux之Centos配置网卡信息