分享

Android睡眠唤醒机制

 joy_chen 2014-07-12

在标准Linux中,休眠主要分三个主要的步骤:(1)冻结用户态进程和内核态任务;(2)调用注册的设备的suspend的回调函数,其调用顺序是按照驱动加载时的注册顺序。(3)休眠核心设备和使CPU进入休眠态冻结进程是内核把进程列表中所有的进程的状态都设置为停止,并且保存下所有进程的上下文。 当这些进程被解冻的时候,它们是不知道自己被冻结过的,只是简单的继续执行。

在标准的linux中,休眠主要分为三个步骤: 1.冻结用户进程和内核态进程。2.调用注册设备的suspend回调函数,调用顺序是按照驱动加载的注册顺序。3.休眠核心设备和CPU进入休眠态冻结进程是把进程列表中的所有进程都设置为停止,并保存所有进程的上下文。

 

Android除了在linux内核原有的休眠唤醒机制的基础上,又增加了三种机制“

Wake_lock : 唤醒锁机制

Early_suspend : 预暂停机制

Late_resume : 迟唤醒机制

 

* struct early_suspend {

#ifdef CONFIG_HAS_EARLYSUSPEND

         struct list_head link;     //suspend_work_queue链表

         int level;                               //suspend等级

         void (*suspend)(struct early_suspend *h);    //进入休眠

         void (*resume)(struct early_suspend *h);     //退出休眠

#endif

};

 

基本原理:

当启动一个应用程序时,都可以申请一个wake_lock唤醒锁,每当申请成功后都会向内核注册一下(为了通知系统内核有锁被申请)。当应用程序释放wake_lock的时候,就会注销掉原来申请的wake_lock。只要有一个wake_lock没被注销,系统都不会睡下去,但是系统的各个模块可以进入early_suspend。只有当所有的wake_lock注销掉,内核才能真正的进入kernel睡眠。

其实在系统启动时会创建一个主唤醒锁main_wake_lock该锁是内核初始化并持有的一个WAKE_LOCK_SUSPEND属性的非限时唤醒锁。因此,系统正常工作时,将始终因为该锁被内核持有而无法进入睡眠状态。也就是说在不添加新锁的情况下,只需将main_wake_lock 解锁,系统即可进入睡眠状态。

 

static int __init wakelocks_init(void)

{

         int ret;

         int i;

 

         for (i = 0; i < ARRAY_SIZE(active_wake_locks); i++)

                   INIT_LIST_HEAD(&active_wake_locks[i]);

 

#ifdef CONFIG_WAKELOCK_STAT

         wake_lock_init(&deleted_wake_locks, WAKE_LOCK_SUSPEND,

                            "deleted_wake_locks");

#endif

         wake_lock_init(&main_wake_lock, WAKE_LOCK_SUSPEND, "main");

         wake_lock(&main_wake_lock);

         wake_lock_init(&unknown_wakeup, WAKE_LOCK_SUSPEND, "unknown_wakeups");

         wake_lock_init(&suspend_backoff_lock, WAKE_LOCK_SUSPEND,

                          "suspend_backoff");

 

 

睡眠唤醒机制的基本框架

Android/linux(earlysuspend、lateresume)睡眠唤醒机制简介

(转载)

 

 

 

PowerManager类(PowerManager.java)是向上层应用程序提供的接口类,提供了wake_lock机制(睡眠唤醒子系统)的接口(获取唤醒锁合释放)。上层应用通过这个接口,对系统电源状态的监控。

public final class WakeLock {

        private final int mFlags;

        private final String mTag;

        private final String mPackageName;

        private final IBinder mToken;

        private int mCount;

        private boolean mRefCounted = true;

        private boolean mHeld;

        private WorkSource mWorkSource;

 

        private final Runnable mReleaser = new Runnable() {

            public void run() {

                release();

            }

        };;

PowerManager类通过IBinder这种Android中特有的通信模式,与PowerManagerService 类进行通信。PowerManagerService PowerManager 类中定义的接口的具体实现,并进一步调用Power 类来与下一层进行通信。PowerManagerService 类是WakeLock 机制在应用程序框架层的核心,他们对应用程调用PowerManager类接口时所传递的参数进行初步的分析和对应的设置,并管理一个唤醒锁队列,然后配合其他模块(例如WatchDogBatteryServiceShutdownThread 等)的状态信息,做出决策,调用Power类的对应接口,最终通过JNI 接口,调用到硬件抽象层中的函数,对sysfs 的用户接口进行操作<>

 

具体用到的文件

PowerManager.java                     提供上层应用程序的接口;

PowerManagerService.java         具体实现PowerManager类中的接口;

Power.java                                        PowerManagerService类调用;

android_os_Power.cpp                 实现Power类中的JNI接口;

power.c                                           进行sysfs用户接口的操作。

 

这里可以分两路走

一、wake_lock唤醒锁。

二、系统进入睡眠。

 

 

Wake_lock唤醒锁:

获得wakelock唤醒锁

比如在应用程序中,当获得wakelock唤醒锁的时候,它首先是调用/android/frameworks/base/core/java/

android/os/PowerManager类中的public void acquire()方法,而该方法通过android特有的通讯机制,会接着调用到PowerManagerService类中的public void acquireWakeLock

public void acquireWakeLock(int flags, IBinder lock, String tag, WorkSource ws) {

int uid = Binder.getCallingUid();

int pid = Binder.getCallingPid();

if (uid != Process.myUid()) {

mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);

}

if (ws != null) {

enforceWakeSourcePermission(uid, pid);

}

long ident = Binder.clearCallingIdentity();

try {

synchronized (mLocks) {

acquireWakeLockLocked(flags, lock, uid, pid, tag, ws);

}

} finally {

Binder.restoreCallingIdentity(ident);

}

}

 

 

public void acquireWakeLock方法又调用了acquireWakeLockLocked

public void acquireWakeLockLocked(int flags, IBinder lock, int uid, int pid, String tag,

WorkSource ws)

{

if (mSpew) {

Slog.d(TAG, "acquireWakeLock flags=0x" + Integer.toHexString(flags) + " tag=" + tag); }

if (ws != null && ws.size() == 0) {ws = null;}

int index = mLocks.getIndex(lock);

WakeLock wl;

boolean newlock;

boolean diffsource;

WorkSource oldsource;

………………

………………

Power.acquireWakeLock(Power.PARTIAL_WAKE_LOCK,PARTIAL_NAME);

}

if (diffsource) {

// If the lock sources have changed, need to first release the

// old ones.

noteStopWakeLocked(wl, oldsource);

}

if (newlock || diffsource) {

noteStartWakeLocked(wl, ws);

}

}

acquireWakeLockLocked 方法调用Power类中的public static native void acquireWakeLock(int lock, String id)方法。而该方法是调用android_os_Power.cpp中的static void acquireWakeLock()函数。

static void acquireWakeLock(JNIEnv *env, jobject clazz, jint lock, jstring idObj)

{

if (idObj == NULL) {

throw_NullPointerException(env, "id is null");

return ;

}

const char *id = env->GetStringUTFChars(idObj, NULL);

acquire_wake_lock(lock, id);

env->ReleaseStringUTFChars(idObj, id);

}

函数 acquire_wake_lock()的实现在 power.c中,其定义如下:

int acquire_wake_lock(int lock, const char* id)

{

initialize_fds();

// LOGI("acquire_wake_lock lock=%d id='%s'\n", lock, id);

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));

}

 

注意这个函数: write(fd, id, strlen(id));

android/kernel/kernel/power/main.c

static struct attribute * g[] = {

。。。。。。。。

#ifdef CONFIG_USER_WAKELOCK

         &wake_lock_attr.attr,

         &wake_unlock_attr.attr,

#endif

。。。。。。。。

}

--------------à     #ifdef CONFIG_USER_WAKELOCK

power_attr(wake_lock);

power_attr(wake_unlock);

#endif

 

static struct attribute_group attr_group = {

                                              .attrs = g,

};

 

static int __init pm_init(void)

{

         int error = pm_start_workqueue();

         if (error)

                   return error;

         hibernate_image_size_init();

         hibernate_reserved_size_init();

         power_kobj = kobject_create_and_add("power", NULL);

         if (!power_kobj)

                   return -ENOMEM;

         error = sysfs_create_group(power_kobj, &attr_group);

         if (error)

                   return error;

         pm_print_times_init();

         return pm_autosleep_init();

}

 

core_initcall(pm_init);

 

sysfs_create_group(power_kobj, &attr_group);的意思就是当我们在对sysfs/下相对的节点进行操作的时候会调用与attr_group里的相关函数,再往上看其实就是指&wake_lock_attr.attr(对不同情况的操作会调用不同的attr_group)。power_attr(wake_lock)就是使具体的操作函数与其挂钩。

 

(kernel/kernel/power/power.h)

#define power_attr(_name) \

static struct kobj_attribute _name##_attr = { \

.attr = { \

.name = __stringify(_name), \

.mode = 0644, \

}, \

.show = _name##_show, \

.store = _name##_store, \

}

 

##  符号类似于 “连接”所以

         -------------à static struct kobj_attribute wake_lock_attr = { \

.attr = { \

.name = __stringify(wake_lock), \

.mode = 0644, \

}, \

.show = wake_lock_show, \

.store = wake_lock_store, \

}

wake_lock_storewake_lock_show就定义在android/kernel/kernel/power/userwakelock.c

中。因此当我们对/sys/power/wake_lock进行操作的时候就会调用到userwakelock.c中定义的wake_lock_store()函数。

 

android/hardware/libhardware_legacy/power/power.c

int acquire_wake_lock(int lock, const char* id)

{

initialize_fds();

// LOGI("acquire_wake_lock lock=%d id='%s'\n", lock, id);

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));

}

initialize_fds(void)

{

// XXX: should be this:

//pthread_once(&g_initialized, open_file_descriptors);

// XXX: not this:

if (g_initialized == 0) {

if(open_file_descriptors(NEW_PATHS) < 0) {

open_file_descriptors(OLD_PATHS);

on_state = "wake";

off_state = "standby";

}

g_initialized = 1;

}

}

总之,在return write(fd, id, strlen(id));时会调用wake_lock_store()函数。

 

ssize_t wake_lock_store(

struct kobject *kobj, struct kobj_attribute *attr,

const char *buf, size_t n)

{

long timeout;

struct user_wake_lock *l;

mutex_lock(&tree_lock);

l = lookup_wake_lock_name(buf, 1, &timeout);

if (IS_ERR(l)) {

n = PTR_ERR(l);

goto bad_name;

}

if (debug_mask & DEBUG_ACCESS)

pr_info("wake_lock_store: %s, timeout %ld\n", l->name, timeout);

if (timeout)

wake_lock_timeout(&l->wake_lock, timeout);

else

wake_lock(&l->wake_lock);

bad_name:

mutex_unlock(&tree_lock);

return n;

}

该函数执行的基本流程为:首先调用lookup_wake_lock_name()来获得指定的唤醒锁,若延迟参数timeout为零的话,就调用 wake_lock()否则就调用wake_lock_timeout(),但不管调用哪个最后都会调用到android/kernel/kernel/power/wakelock.c中的函数static void wake_lock_internal()。

 

 

 

二、系统进入睡眠

 

假如现在我们按了手机上的power睡眠键,经过一些列的事件处理后,它会调用到PowerManager类中的

public void goToSleep(long time)

{

try {

mService.goToSleep(time);

} catch (RemoteException e) {

}

}

而该函数会调用到PowerManagerService类中的public void goToSleep()方法;

public void goToSleep(long time)

{

goToSleepWithReason(time, WindowManagerPolicy.OFF_BECAUSE_OF_USER);

}

goToSleepWithReason()会调用goToSleepLocked()方法,接着会调用setPowerState();setPowerState()方法里会调用setScreenStateLocked(),setScreenStateLocked()又会调用到Power类中的JNI接口setScreenState(),其具体实现是在android_os_Power.cpp文件中;

static int setScreenState(JNIEnv *env, jobject clazz, jboolean on)

{

return set_screen_state(on);

}

 

-------------------à             android/hardware/libhardware_legacy/power/power.c

set_screen_state(int on)

{

QEMU_FALLBACK(set_screen_state(on));

LOGI("*** set_screen_state %d", on);

initialize_fds();

//LOGI("go_to_sleep eventTime=%lld now=%lld g_error=%s\n", eventTime,

// systemTime(), strerror(g_error));

if (g_error) return g_error;

char buf[32];

int len;

if(on)

len = snprintf(buf, sizeof(buf), "%s", on_state);

else

len = snprintf(buf, sizeof(buf), "%s", off_state);

buf[sizeof(buf) - 1] = '\0';

len = write(g_fds[REQUEST_STATE], buf, len);

if(len < 0) {

LOGE("Failed setting last user activity: g_error=%d\n", g_error);

}

return 0;

 

len = write(g_fds[REQUEST_STATE], buf, len);语句调用的是android//kernel/kernel/power/main.c中的set_screen_state( )

 

wake_lock部分一样,这里也分两个分支。

static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t n)

{

#ifdef CONFIG_SUSPEND

#ifdef CONFIG_EARLYSUSPEND

suspend_state_t state = PM_SUSPEND_ON;

#else

suspend_state_t state = PM_SUSPEND_STANDBY;

#endif

const char * const *s;

#endif

char *p;

int len;

int error = -EINVAL;

p = memchr(buf, '\n', n);

len = p ? p - buf : n;

if (len == 4 && !strncmp(buf, "disk", len)) {

error = hibernate();

goto Exit;

}

#ifdef CONFIG_SUSPEND

for (s = &pm_states[state]; state < PM_SUSPEND_MAX; s++, state++) {

if (*s && len == strlen(*s) && !strncmp(buf, *s, len))

break;

}

if (state < PM_SUSPEND_MAX && *s)

#ifdef CONFIG_EARLYSUSPEND

if (state == PM_SUSPEND_ON || valid_state(state)) {

error = 0;

request_suspend_state(state);

}

#else

error = enter_state(state);

#endif

#endif

Exit:

return error ? error : n;

}

 

如果定义CONFIG_EARLYSUSPEND宏的话,kernel会先走request_suspend_state()。反之直接走标准Linuxenter_state()函数。

 

request_suspend_state()   kernel/kernel/power/earlysuspend.c

enter_state()                         kernel/kernel/power/suspend.c

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多