【Android休眠】之休眠鎖的獲取和釋放
阿新 • • 發佈:2019-02-15
Linux 3.10
Android 4.4
http://blog.csdn.net/u013686019/article/details/53691895
一、PowerManagerService
引起休眠動作(進入休眠前執行一些必要的操作)的事件有兩個:
- PowerKey事件,通過JNI呼叫PowerManagerService中的goToSleepFromNative()方法
- Timeout,指【設定->顯示->休眠】中設定的Timeout數值
Android休眠在PowerManagerService中的流程如下圖:
圖示:最終都會呼叫到updatePowerStateLocked()方法,在更新一些標誌的狀態、傳送休眠通知後,呼叫updateSuspendBlockerLocked()執行休眠鎖的釋放動作 。
二、PowerManagerService中Timeout處理流程
/** * PowerManagerService設定了很多的標誌位,用來標識某個事件的狀態是否發生改變,比如: * DIRTY_SETTINGS,一旦系統設定發生變化,DIRTY_SETTINGS位就會被設定, * 處理函式檢測到DIRTY_SETTINGS被置位,就進行相應的動作 * dirty:包含了所有發生變化的標誌 */ private void updateUserActivitySummaryLocked(long now, int dirty) { // Update the status of the user activity timeout timer. if ((dirty & (DIRTY_USER_ACTIVITY | DIRTY_WAKEFULNESS | DIRTY_SETTINGS)) != 0) { // 1、訊息佇列中含有尚未處理的MSG_USER_ACTIVITY_TIMEOUT,就移除,避免重複進入休眠操作 mHandler.removeMessages(MSG_USER_ACTIVITY_TIMEOUT); long nextTimeout = 0; // 2、mWakefulness != WAKEFULNESS_ASLEEP:當前醒著 if (mWakefulness != WAKEFULNESS_ASLEEP) { // 3、獲取Timeout的值,比如30s final int screenOffTimeout = getScreenOffTimeoutLocked(); // 螢幕在熄滅前,會先變暗一段時間,這段時間叫DimDuration,計算方式: // SCREEN_DIM_DURATION = 7s,MAXIMUM_SCREEN_DIM_RATIO = 0.2 // Math.min(SCREEN_DIM_DURATION, (int)(screenOffTimeout * MAXIMUM_SCREEN_DIM_RATIO)) // 4、獲取DimDuration的值,30s x 0.2 = 6s final int screenDimDuration = getScreenDimDurationLocked(screenOffTimeout); mUserActivitySummary = 0; // 5、mLastUserActivityTime >= mLastWakeTime: 使用者最後使用機器的時間在上次喚醒時間之後 if (mLastUserActivityTime >= mLastWakeTime) { // nextTimeout:此處指到螢幕Dim的時間間隔 // 6、nextTimeout的時間:BASE + 30 - 6 = BASE + 24 nextTimeout = mLastUserActivityTime + screenOffTimeout - screenDimDuration; if (now < nextTimeout) { // now在螢幕Dim之前,說明螢幕亮著,設定flag mUserActivitySummary |= USER_ACTIVITY_SCREEN_BRIGHT; } else { // extTimeout:此處指到螢幕熄滅的時間間隔 //7、nextTimeout的時間:BASE + 30 = BASE + 30 nextTimeout = mLastUserActivityTime + screenOffTimeout; // 8、now處於螢幕Dim之後、螢幕熄滅之前設定DIM flag if (now < nextTimeout) { mUserActivitySummary |= USER_ACTIVITY_SCREEN_DIM; } } } if (mUserActivitySummary == 0 && mLastUserActivityTimeNoChangeLights >= mLastWakeTime) { nextTimeout = mLastUserActivityTimeNoChangeLights + screenOffTimeout; if (now < nextTimeout && mDisplayPowerRequest.screenState != DisplayPowerRequest.SCREEN_STATE_OFF) { mUserActivitySummary = mDisplayPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_BRIGHT ? USER_ACTIVITY_SCREEN_BRIGHT : USER_ACTIVITY_SCREEN_DIM; } } // mUserActivitySummary發生了改變 if (mUserActivitySummary != 0) { Message msg = mHandler.obtainMessage(MSG_USER_ACTIVITY_TIMEOUT); Slog.i(TAG, "updateUserActivitySummaryLocked, send MSG_USER_ACTIVITY_TIMEOUT"); msg.setAsynchronous(true); mHandler.sendMessageAtTime(msg, nextTimeout); } } else { mUserActivitySummary = 0; } } }
MSG_USER_ACTIVITY_TIMEOUT事件處理:
private final class PowerManagerHandler extends Handler { @Override public void handleMessage(Message msg) { switch (msg.what) { case MSG_USER_ACTIVITY_TIMEOUT: handleUserActivityTimeout(); break; } } /** * Called when a user activity timeout has occurred. * Simply indicates that something about user activity has changed so that the new * state can be recomputed when the power state is updated. */ private void handleUserActivityTimeout() { // runs on handler thread mDirty |= DIRTY_USER_ACTIVITY; updatePowerStateLocked(); }
三、PowerManagerService中休眠鎖的獲取/釋放
這部分程式碼清晰,直接看下:
private void updatePowerStateLocked() {
if (!mSystemReady || mDirty == 0) {
return;
}
// Phase 0: Basic state updates.
// Phase 1: Update wakefulness.
// Phase 2: Update dreams and display power state.
// Phase 3: Send notifications, if needed.
// 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();
}
/**
* Updates the suspend blocker that keeps the CPU alive.
*/
private void updateSuspendBlockerLocked() {
final boolean needWakeLockSuspendBlocker = ((mWakeLockSummary & WAKE_LOCK_CPU) != 0);
final boolean needDisplaySuspendBlocker = needDisplaySuspendBlocker();
// First acquire suspend blockers if needed.
if (needWakeLockSuspendBlocker && !mHoldingWakeLockSuspendBlocker) {
mWakeLockSuspendBlocker.acquire();
mHoldingWakeLockSuspendBlocker = true;
}
if (needDisplaySuspendBlocker && !mHoldingDisplaySuspendBlocker) {
mDisplaySuspendBlocker.acquire();
mHoldingDisplaySuspendBlocker = true;
}
// Then release suspend blockers if needed.
if (!needWakeLockSuspendBlocker && mHoldingWakeLockSuspendBlocker) {
mWakeLockSuspendBlocker.release();
mHoldingWakeLockSuspendBlocker = false;
}
if (!needDisplaySuspendBlocker && mHoldingDisplaySuspendBlocker) {
mDisplaySuspendBlocker.release();
mHoldingDisplaySuspendBlocker = false;
}
}
private final class SuspendBlockerImpl implements SuspendBlocker {
private final String mName;
private int mReferenceCount;
public SuspendBlockerImpl(String name) {
mName = name;
}
@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);
}
}
}
}
休眠鎖的獲取和釋放,最終通過JNI方式讀寫/sys/power/wake_lock、/sys/power/wake_unlock:
// 1、JNI介面
com_android_server_power_PowerManagerService.cpp (frameworks\base\services\jni)
static void nativeAcquireSuspendBlocker(JNIEnv *env, jclass clazz, jstring nameStr) {
ScopedUtfChars name(env, nameStr);
acquire_wake_lock(PARTIAL_WAKE_LOCK, name.c_str());
}
// 2、定義要操作的檔案
power.c (hardware\libhardware_legacy\power)
const char * const NEW_PATHS[] = {
"/sys/power/wake_lock",
"/sys/power/wake_unlock",
};
// 3、初始化裝置節點
static inline void initialize_fds(void)
{
if (g_initialized == 0) {
if(open_file_descriptors(NEW_PATHS) < 0)
open_file_descriptors(OLD_PATHS);
g_initialized = 1;
}
}
static int open_file_descriptors(const char * const paths[])
{
int i;
for (i=0; i<OUR_FD_COUNT; i++) {
int fd = open(paths[i], O_RDWR);
if (fd < 0) {
fprintf(stderr, "fatal error opening \"%s\"\n", paths[i]);
g_error = errno;
return -1;
}
g_fds[i] = fd;
}
g_error = 0;
return 0;
}
// 4、id即為鎖的名字,之後就是讀寫裝置
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));
}