Android 待机功能流程分析
来源:互联网 发布:python random.choice 编辑:程序博客网 时间:2024/04/30 11:08
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待机流程分析
- Android待机流程分析
- Android待机流程分析
- Android待机流程分析
- Android待机流程分析
- android待机流程分析
- android 真待机流程分析
- Android待机流程分析---锁屏、解锁模块
- Android待机锁屏流程分析
- Android待机流程分析---锁屏、解锁模块
- Android待机流程分析---锁屏、解锁模块
- Android待机锁屏流程分析
- Android待机流程分析---锁屏、解锁模块 .
- android 待机流程
- Android待机流程解析
- Android 待机流程解析
- Android待机流程解析
- iOS导航栏 如果只想改变单一自控制导航栏按钮 标题颜色 请进
- 基于ZooKeeper的Dubbo注册中心
- 如何使用javadoc
- App installation failed A valid provisioning profile for this executable was not found.
- C++的数组和指针
- Android 待机功能流程分析
- iOS上传错误 ERROR ITMS-90049 立即解决方法
- Fragment的构造函数
- UIView —— 所有控件的载体
- Boot strap 垂直居中
- 房屋中介信息管理平台
- Linux memcached安装
- const T、const T*、T *const、const T&和const T*&的区别
- SelectionSort -- 选择排序(C++)