Android 待机功能流程分析
Android智能手机或机顶盒子为了进入省电模式、所以就需要有待机功能。
PowerManager.java 类提供了如下的电源管理功能:
public void goToSleep(long time) 强迫设备进入睡眠状态
public void reboot(String reason) 重启设备
提供了内部类: public final class WakeLock
public void acquire(long timeout) 申请待机锁
public void release(int flags) 释放待机锁
我这里讲的主要是:
利用Linux内核原有的睡眠唤醒模块上基础上,在Android系统上主要增加了下面三个机制:
• Wake Lock 唤醒锁机制;
• Early Suspend 预挂起机制;
• Late Resume 迟唤醒机制;
基本原理:
当启动一个应用程序的时候,它可以申请一个wake_lock唤醒锁,每当申请成功之后都会在内核中注册一下(通知系统内核,现在已经有锁被申请,系统内核的wake_lock_store把它加入红黑树中),当应用程序在某种情况下释放wake_lock的时候,会注销之前所申请的wake_lock。特别要注意的是:只要是系统中有一个wake_lock的时候,系统此时都不能进行睡眠。但此时各个模块可以进行early_suspend。当系统中所有的wake_lock都被释放之后,系统就会进入真正的kernel的睡眠状态。在系统启动的时候会创建一个主唤醒锁main_wake_lock,该锁是内核初始化并持有的一个WAKE_LOCK_SUSPEND属性的非限时唤醒锁。因此,系统正常工作时,将始终因为该锁被内核持有而无法进入睡眠状态。也就是说在不添加新锁的情况下,只需将main_wake_lock 解锁,系统即可进入睡眠状态。
先看一下整体流程层次结构图:
下面按照层次结构从java层分析:
frameworks/base/core/java/android/os/PowerManager.java
@public final class WakeLock 内部类
获取待机锁:
public void acquire() {synchronized (mToken) {acquireLocked();}}private void acquireLocked() {if (!mRefCounted || mCount++ == 0) {// Do this even if the wake lock is already thought to be held (mHeld == true)// because non-reference counted wake locks are not always properly released.// For example, the keyguard's wake lock might be forcibly released by the// power manager without the keyguard knowing. A subsequent call to acquire// should immediately acquire the wake lock once again despite never having// been explicitly released by the keyguard.mHandler.removeCallbacks(mReleaser);try {mService.acquireWakeLock(mToken, mFlags, mTag, mWorkSource);} catch (RemoteException e) {}mHeld = true;}}
以上代码很清楚,判定标志mRefCounted 为false 或mCount 值为0即可进入获取待机锁、并将mCount加1
此时调用 mService.acquireWakeLock(mToken, mFlags, mTag, mWorkSource);
mService 就是 PowerManagerService 类
frameworks/base/services/java/com/android/server/PowerManagerService.java
@acquireWakeLock -> acquireWakeLockInternal ->updatePowerStateLocked
重要的操作都在这里做的,五个步骤
private void updatePowerStateLocked() {if (!mSystemReady || mDirty == 0) {return;}// Phase 0: Basic state updates.updateIsPoweredLocked(mDirty);updateStayOnLocked(mDirty);// Phase 1: Update wakefulness.// Loop because the wake lock and user activity computations are influenced// by changes in wakefulness.final long now = SystemClock.uptimeMillis();int dirtyPhase2 = 0;for (;;) {int dirtyPhase1 = mDirty;dirtyPhase2 |= dirtyPhase1;mDirty = 0;updateWakeLockSummaryLocked(dirtyPhase1);updateUserActivitySummaryLocked(now, dirtyPhase1);if (!updateWakefulnessLocked(dirtyPhase1)) {break;}}// Phase 2: Update dreams and display power state.updateDreamLocked(dirtyPhase2);updateDisplayPowerStateLocked(dirtyPhase2);// Phase 3: Send notifications, if needed.if (mDisplayReady) {sendPendingNotificationsLocked();}// Phase 4: Update suspend blocker.// Because we might release the last suspend blocker here, we need to make sure// we finished everything else first!updateSuspendBlockerLocked();}
最后一个方法 updateSuspendBlockerLocked() 将会调用native方法
@mWakeLockSuspendBlocker.acquire(); -> nativeAcquireSuspendBlocker
private static native void nativeAcquireSuspendBlocker(String name);
此时将进入jni 层:
com_android_server_power_PowerManagerService.cpp
static void nativeAcquireSuspendBlocker(JNIEnv *env, jclass clazz, jstring nameStr) {ScopedUtfChars name(env, nameStr);acquire_wake_lock(PARTIAL_WAKE_LOCK, name.c_str());}
实现相当简单、不解释了。
hardware/libhardware_legacy/power/power.c
int acquire_wake_lock(int lock, const char* id){initialize_fds(); // 打开句柄 open("/sys/power/wake_lock")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)); // 写入命令
}
此时将进入内核代码分析是如何做的。
kernel/power/main.c - PM subsystem core functionality.
static ssize_t wake_lock_store(struct kobject *kobj,struct kobj_attribute *attr,const char *buf, size_t n)
{int error = pm_wake_lock(buf);return error ? error : n;
}
kernel/power/wakelock.c
int pm_wake_lock(const char *buf)
{const char *str = buf;struct wakelock *wl;u64 timeout_ns = 0;size_t len;int ret = 0;while (*str && !isspace(*str))str++;len = str - buf;if (!len)return -EINVAL;if (*str && *str != '\n') {/* Find out if there's a valid timeout string appended. */ret = kstrtou64(skip_spaces(str), 10, &timeout_ns);if (ret)return -EINVAL;}mutex_lock(&wakelocks_lock);wl = wakelock_lookup_add(buf, len, true);if (IS_ERR(wl)) {ret = PTR_ERR(wl);goto out;}if (timeout_ns) {u64 timeout_ms = timeout_ns + NSEC_PER_MSEC - 1;do_div(timeout_ms, NSEC_PER_MSEC);__pm_wakeup_event(&wl->ws, timeout_ms);} else {__pm_stay_awake(&wl->ws);}wakelocks_lru_most_recent(wl);out:mutex_unlock(&wakelocks_lock);return ret;
}
这块没有细看、有兴趣的朋友可以看看。本质就是利用红黑树查看锁的情况,最后该函数首先sync文件系统,然后调用pm_suspend(request_suspend_state),接下来pm_suspend()就会调用 enter_state()来进入 linux的suspend流程。
机顶盒的资源也可以实现待机函数、这样子即可快速进入待机模式。
释放待机锁的流程与获取待机锁差不多就不多说了。
最后说明一下:
WakeLock 类型以及说明:
PARTIAL_WAKE_LOCK:保持CPU 运转,屏幕和键盘灯有可能是关闭的。
SCREEN_DIM_WAKE_LOCK:保持CPU 运转,允许保持屏幕显示但有可能是灰的,允许关闭键盘灯
SCREEN_BRIGHT_WAKE_LOCK:保持CPU 运转,允许保持屏幕高亮显示,允许关闭键盘灯
FULL_WAKE_LOCK:保持CPU 运转,保持屏幕高亮显示,键盘灯也保持亮度
ACQUIRE_CAUSES_WAKEUP:强制使屏幕亮起,这种锁主要针对一些必须通知用户的操作.
ON_AFTER_RELEASE:当锁被释放时,保持屏幕亮起一段时间
最后 AndroidManifest.xml 声明权限:
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.DEVICE_POWER"/>
应用程序中如果要在待机前保存数据状态的话,要保证此过程中不会进入待机。可以在 onResume() 或者 onStart() 中申请 wakelock 锁,即调用acquireWakeLock()方法。
在 onPause() 或者 onDistroy() 中处理应用待机后再释放掉 wakelock 锁,此时调用releaseWakeLock()方法
最后一点需要注意下:
另外WakeLock的设置是 Activiy 级别的,不是针对整个Application应用的。所以application下有多个activity一定需要注意下!
Android 待机功能流程分析相关推荐
- Android SDCard UnMounted 流程分析(三)
前篇地址 Android SDCard UnMounted 流程分析(一) Android SDCard UnMounted 流程分析(二) 前一篇讲到SDCard unmout onEvent 发送 ...
- android camera2 API流程分析
Android camera2 API流程分析 Android5.0之后,新推出来了一个类,android.hardware.camera2,与原来的camera的类实现照相和拍视频的流程有所不同,原 ...
- Android UI绘制流程分析(三)measure
源码版本Android 6.0 请参阅:http://androidxref.com/6.0.1_r10 本文目的是分析从Activity启动到走完绘制流程并显示在界面上的过程,在源码展示阶段为了使跟 ...
- Android -- Wifi启动流程分析
Android -- Wifi启动流程分析 Android网络各个模式中,Wifi应该是目前最常用的一种网络方式了:下面就简单介绍下Android中Wifi的启动流程. 当我在Setting菜单里点击 ...
- 【SemiDrive源码分析】【X9芯片启动流程】27 - AP1 Android Preloader启动流程分析(加载atf、tos、bootloader镜像后进入BL31环境)
[SemiDrive源码分析][X9芯片启动流程]27 - AP1 Android Preloader启动流程分析(加载atf.tos.bootloader镜像后进入BL31环境) 一.Android ...
- android volume挂载流程,Android SDCard UnMounted 流程分析(一)
Android SDCard框架 Android SDCard框架,我们修改一般涉及到四大模块 Linux Kernel 用于检测热拔插,作为框架开发者来说,这者不用涉及 Vold 作为Kernel ...
- Android流媒体处理流程分析
文章目录 1. WiFiDisplay简介 2.RTSP协议流程分析 3. 流媒体协议简介 4. RTP.RTCP协议简介 4.1 RTP协议 4.1 RTP载荷H264码流 4.2 RTP载荷PS码 ...
- android app启动流程分析,Android应用开发之Android 7.0 Launcher3的启动和加载流程分析...
本文将带你了解Android应用开发Android 7.0 Launcher3的启动和加载流程分析,希望本文对大家学Android有所帮助. Android 7.0 Launcher3的启动和加载流程 ...
- Android SDCard Mount 流程分析(一)
点击打开链接 前段时间对Android 的SDCard unmount 流程进行了几篇简短的分析,由于当时只是纸上谈兵,没有实际上的跟进,可能会有一些误导人或者小错误.今天重新梳理了头绪,针对moun ...
最新文章
- Fork and Join: Java Can Excel at Painless Parallel Programming Too!---转
- Google 出品的 Java 编码规范,权威又科学,强烈推荐
- mysql中find_in_set()函数的使用
- Spring之AOP由浅入深
- js 实现“倒计时” 以及 N秒后跳转页面
- 最全面实用的MySql操作大全。
- 邓侃:深度强化学习“深”在哪里?
- windowskb2685811补丁_KB898461补丁
- Python使用技巧
- Python TypeError: object() takes no parameters
- cefsharp异步抓取html5,winform插件cefsharp65最新版完美demo,完美flash、html5、和调用摄像头支持,部署就能用...
- spark学习-70-源代码:Endpoint模型介绍(2)-启动流程
- Linux内核深入理解定时器和时间管理(4):定时器 timer
- 搜索引擎中用到的一些拆词方式解析
- 系统动力学仿真软件Vensim下载
- 《码出高效:Java开发手册》百度网盘下载
- kiv8测量方法_measure_测量 | measure_Scikit image_参考手册_非常教程
- Rust 限流算法crate调研
- 《OKR:源于英特尔和谷歌的目标管理利器》读书笔记
- CSU 1726-你经历过绝望吗?两次!(BFS+剪枝)
热门文章
- 打印日期(华中科技大学考研机试)
- 微信企业号信息接收服务器,微信企业号拟部署HTTPS协议,移步到微:早已升级...
- 诱骗芯片HUSB238A:USB PD3.1 EPR助力24V直流电机驱动
- Failed to execute goal org.codehaus.mojo:exec-maven-plugin:1.6.0
- JavaEye被封杀,求真想
- 【广州市青年科技工作者协会主办 | 青年论坛 | 往届均已见刊检索 | 稳定EI 】
- Escaping closure captures non-escaping parameter 'xx'
- Matlab灰度图像反转,对数变换,幂次变换
- [原创]大部调整的IT遐想
- 我从研究院转型为头部互联网分析师