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一定需要注意下!


更多相关文章

  1. android调用系统通讯录,并返回联系人号码和称呼
  2. 做自己的Android ROM,屏蔽对framework中的系统APK的签名检查
  3. Android系统启动流程 -- android
  4. Android 通过Volley 模拟登录教务系统 出错,出错原因:系统正忙
  5. Android_照相机Camera_调用系统照…
  6. 尝试在安卓系统中获得USSD响应
  7. android手机联网时会有什么系统广播发出呢??
  8. [置顶] Android系统的样式style
  9. Android实现一键复制粘贴,兼容低版本系统(api 11以下)

随机推荐

  1. Android 单选队列 RadioGroup与RadioButt
  2. 48.Android(安卓)标签TextView的点击技巧
  3. Android界面开发
  4. Android Handler机制4之Looper与Handler
  5. android Toast大全(五种情形)建立属于你自
  6. android 应用移植到ophone 平台需注意
  7. 设置TextView文字居中
  8. Android 音视频汇总
  9. Android内嵌H5(1)
  10. Android学习笔记(2)---android字体风格设置