Android休眠唤醒机制简介二 android 监听休眠唤醒
下面我将分别以两条路线(第一:获得wakelock唤醒锁。第二:系统进入睡眠。)来分别说明各自的流程,让读者对android睡眠唤醒机制有更深入的理解!
第一部分:获得wakelock唤醒锁
比如在应用程序中,当获得wakelock唤醒锁的时候,它首先是调用/android/frameworks/base/core/java/
android/os/PowerManager类中的public voidacquire()方法,而该方法通过android特有的通讯机制,会接着调用到PowerManagerService类中的publicvoid acquireWakeLock。
public void acquireWakeLock(int flags, IBinder lock, Stringtag, 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 voidacquireWakeLock方法又调用了acquireWakeLockLocked。
public void acquireWakeLockLocked(int flags, IBinder lock, intuid, int pid, String tag, WorkSourcews){ 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 thelock sources have changed, need to first release the // oldones. noteStopWakeLocked(wl, oldsource); } if (newlock || diffsource) { noteStartWakeLocked(wl, ws); }}
我们可以看到在acquireWakeLockLocked 方法调用Power类中的public static native voidacquireWakeLock(int lock, Stringid)方法。而该方法是调用android_os_Power.cpp中的static voidacquireWakeLock()函数。
static void acquireWakeLock(JNIEnv *env, jobject clazz, jintlock, jstring idObj)
{ if (idObj == NULL){ throw_NullPointerException(env, "id isnull"); 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) returng_error; int fd; if (lock ==PARTIAL_WAKE_LOCK) { fd = g_fds[ACQUIRE_PARTIAL_WAKE_LOCK]; } else { return EINVAL; } return write(fd, id,strlen(id));} 到现在为止,我们的代码流程已经走了一大半了,我们一开始介绍的android的上面几层Framework层、JNI层、HAL层都已经介绍了就剩下Kernel层了。下面就应该是和kernel层进行交互了。
但是在android/hardware/libhardware_legacy/power/power.c中的acquire_wake_lock()函数似乎没法和kernel层进行通信啊??不急要淡定!!在这个函数的最后不是还有一个返回语句return write(fd, id,strlen(id))嘛!!有人会说这句话看不出什么啊,我一开始用SourceInsight代码阅读器跟踪的时候也没有找到它的原型,那个叫急啊!!呵呵最后经过我的继续不断的努力查找(其实方法很简单,既然我从上往下的路断了,那我就换个方向,我最后又从下往上顺着代码走了一遍),终于被我发现了。
我们先看一下android/kernel/kernel/power/main.c中的一段代码,我将会做简单的分析,之后你就会明白刚才上面所产生的疑问了。
#ifdef CONFIG_USER_WAKELOCKpower_attr(wake_lock);power_attr(wake_unlock);#endif
static struct attribute * g[] = {&state_attr.attr,#ifdef CONFIG_PM_TRACE&pm_trace_attr.attr,#endif
#ifdef CONFIG_PM_SLEEP&pm_async_attr.attr,#ifdef CONFIG_PM_DEBUG&pm_test_attr.attr,#endif
#ifdef CONFIG_USER_WAKELOCK&wake_lock_attr.attr,&wake_unlock_attr.attr,#endif
#endifNULL,};
static struct attribute_groupattr_group = {.attrs = g,};
#ifdef CONFIG_PM_RUNTIMEstruct workqueue_struct *pm_wq;EXPORT_SYMBOL_GPL(pm_wq);
static int __init pm_start_workqueue(void){pm_wq = create_freezeable_workqueue("pm");return pm_wq ? 0 : -ENOMEM;}#elsestatic inline int pm_start_workqueue(void) { return 0; }#endifstatic int __init pm_init(void){int error = pm_start_workqueue();if (error)return error;power_kobj = kobject_create_and_add("power", NULL);if (!power_kobj)return -ENOMEM;return sysfs_create_group(power_kobj,&attr_group);}core_initcall(pm_init);
这段代码虽然简短,但看起来是不是还是比较费劲,没关系,我们倒过来看就比较清楚了。上面代码中的sysfs_create_group(power_kobj,&attr_group);的意思就是当我们在对sysfs/下相对的节点进行操作的时候会调用与attr_group里的相关函数,再往上面看其实就是指&wake_lock_attr.attr(对不同情况的操作会调用不同的attr_group,在第二条路的里面我们还会再次接触到这里)。power_attr(wake_lock)就是使具体的操作函数与其挂钩。我们现在来看一看这个挂钩过程是怎么实现的。
#define power_attr(_name) static struct kobj_attribute _name##_attr = {.attr = { .name = __stringify(_name),.mode = 0644, }, .show = _name##_show,.store = _name##_store,}
在该函数中##的作用通俗点讲就是“连接”的意思,比如power_attr(wake_lock), static structkobj_attribute wake_lock_attr = {.attr = { .name = __stringify(wake_lock),.mode = 0644, }, .show = wake_lock_show, .store = wake_lock_store, }
函数wake_lock_store和wake_lock_show就定义在android/kernel/kernel/power/userwakelock.c中。因此当我们对/sys/power/wake_lock进行操作的时候就会调用到userwakelock.c中定义的wake_lock_store()函数。 好了,我们该回到原来我们产生疑问的地方了,在power.c中我们将重新研究一下这这段代码,这时我们还得关注其中的另一个函数initialize_fds()。
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) returng_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 bethis: //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; }} 其实这个函数中最和新的步骤就是open_file_descriptors(NEW_PATHS) ;而const char * const NEW_PATHS[] = { "/sys/power/wake_lock", "/sys/power/wake_unlock", "/sys/power/state"}; 总之经过着一些列的步骤后,最终我们将在return write(fd, id,strlen(id));时调用android/kernel/kernel/power/userwakelock.c 中的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 %ldn", 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中的函数staticvoid wake_lock_internal()。
static void wake_lock_internal(struct wake_lock *lock, longtimeout, int has_timeout){int type;unsigned long irqflags;long expire_in;spin_lock_irqsave(&list_lock, irqflags);type = lock->flags &WAKE_LOCK_TYPE_MASK;BUG_ON(type >= WAKE_LOCK_TYPE_COUNT);BUG_ON(!(lock->flags &WAKE_LOCK_INITIALIZED));#ifdef CONFIG_WAKELOCK_STATif (type == WAKE_LOCK_SUSPEND&& wait_for_wakeup) {if (debug_mask & DEBUG_WAKEUP)pr_info("wakeup wake lock: %sn",lock->name);wait_for_wakeup = 0;lock->stat.wakeup_count++;}
if ((lock->flags &WAKE_LOCK_AUTO_EXPIRE) && (long)(lock->expires - jiffies) <= 0){wake_unlock_stat_locked(lock, 0);lock->stat.last_time = ktime_get();}#endifif (!(lock->flags &WAKE_LOCK_ACTIVE)) {lock->flags |= WAKE_LOCK_ACTIVE;#ifdef CONFIG_WAKELOCK_STATlock->stat.last_time = ktime_get();#endif}list_del(&lock->link);if (has_timeout) {if (debug_mask & DEBUG_WAKE_LOCK)pr_info("wake_lock: %s, type %d, timeout %ld.lun",lock->name, type, timeout / HZ,(timeout % HZ) * MSEC_PER_SEC / HZ);lock->expires = jiffies + timeout;lock->flags |= WAKE_LOCK_AUTO_EXPIRE;list_add_tail(&lock->link,&active_wake_locks[type]);} else {if (debug_mask & DEBUG_WAKE_LOCK)pr_info("wake_lock: %s, type %dn", lock->name,type);lock->expires = LONG_MAX;lock->flags &=~WAKE_LOCK_AUTO_EXPIRE;list_add(&lock->link,&active_wake_locks[type]);}if (type == WAKE_LOCK_SUSPEND) {current_event_num++;#ifdef CONFIG_WAKELOCK_STATif (lock == &main_wake_lock)update_sleep_wait_stats_locked(1);else if(!wake_lock_active(&main_wake_lock))update_sleep_wait_stats_locked(0);#endifif (has_timeout)expire_in = has_wake_lock_locked(type);elseexpire_in = -1;if (expire_in > 0) {if (debug_mask & DEBUG_EXPIRE)pr_info("wake_lock: %s, start expire timer, ""%ldn", lock->name, expire_in);mod_timer(&expire_timer, jiffies +expire_in);} else {if (del_timer(&expire_timer))if (debug_mask & DEBUG_EXPIRE)pr_info("wake_lock: %s, stop expire timern",lock->name);if (expire_in == 0)queue_work(suspend_work_queue,&suspend_work);}}spin_unlock_irqrestore(&list_lock,irqflags);}
到这里为止,我们走的第一条路就到目的地了,这个函数具体做了什么,在这里就不仔细分析了,大家可以自己再跟下或者上网查相关资料,理解这个函数不难。
第二部分:系统进入睡眠
有了上面第一部分的学习,再看第二部分的话,会容易很多。假如现在我们按了PAD上的power睡眠键,经过一些列的事件处理后,它会调用到PowerManager类中的
public void goToSleep(longtime) { 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, jbooleanon) { returnset_screen_state(on); }
函数中returnset_screen_state()的实现是android/hardware/libhardware_legacy/power/power.c set_screen_state(inton){ QEMU_FALLBACK(set_screen_state(on)); LOGI("***set_screen_state %d", on); initialize_fds(); //LOGI("go_to_sleepeventTime=%lld now=%lld g_error=%sn", eventTime, // systemTime(),strerror(g_error)); if (g_error) returng_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] =' '; len =write(g_fds[REQUEST_STATE], buf, len); if(len <0) { LOGE("Failed setting last user activity:g_error=%dn", g_error); } return 0;
看!!代码到这里是不是跟第一部分很相似?不错,如果接着往下分析的话,可以套用上面第一部分的分析思路,最终len =write(g_fds[REQUEST_STATE], buf,len);语句调用的是android//kernel/kernel/power/main.c中的set_screen_state();
当我们在sys/power/state(android/hardware/libhardware_legacy/power/power.c)进行读写操作的时候,(linux/kernel/power/main.c)中的state_store()函数会被调用,在该函数中会分成两个分支:
static ssize_t state_store(struct kobject *kobj, structkobj_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#endifExit: return error ? error : n;} Android特有的earlysuspend: request_suspend_state(state)Linux标准的suspend: enter_state(state)
注意:如果CONFIG_EARLYSUSPEND宏开的话,kernel会先走earlysuspend,反之则直接走suspend;从这里开始就要分两个分支了,如果支持earlysuspend的话就进入request_suspend_state(state)函数,如果不支持的话就进入标准Linux的enter_state(state)函数。、
这两个函数分别在两个文件中kernel/kernel/power/earlysuspend.c和suspend.c。现在再回过头来看的话,感觉整个android中睡眠唤醒机制还是很清晰的。这两个函数体里又做了什么,在这里就不再做具体分析,大家可以自己对照代码或者上网查资料,因为本文的主旨是带读者从最上层应用层一直到最底层kernel层,把整个android的睡眠唤醒机制给走通。
PowerManager.java goToSleep( )PowerManagerService.java goToSleep()PowerManagerService.java goToSleepWithReason()PowerManagerService.java setPowerState()PowerManagerService.java SetScreenStateLocked ()Power.java setScreenState()android_os_Power.cpp setScreenState()power.c set_screen_state( )main.c state_store( )
更多阅读
如何监听别人手机 怎么查手机是否被监听
如何监听别人手机——简介这个问题涉及到隐私侵犯,不好过多解释,在国内,个人行为很难,但有几点意见望采纳。如何监听别人手机——工具/原料手机如何监听别人手机——方法/步骤如何监听别人手机 1、温馨提示:这是属于非法手段,找专业人员
当代二王-王文学-王树民书法艺术简介 二王书法
转载 监听天碟 《值得珍藏的-精湛录音.专业监听天碟》 发烧天碟
原文地址:[监听天碟]《值得珍藏的-精湛录音.专业监听天碟》19CD/10.2GB/百度作者:jiangkuaihe[监听天碟]《值得珍藏的-精湛录音.专业监听天碟》19CD/10.2GB/百度[监听
中国已故电影演员生平简介 二 已故电影演员
【中国已故电影演员生平简介】 (二)【石挥】(1915—1957)中国电影、话剧演员、电影导演。1937年到上海后,先后参加了中国旅行剧团、上海剧艺社、上海职业剧团、苦干剧团、中国演剧社等演出团体,演出过《家》、《大雷雨》等十多部重要剧目
沅陵县二酉苗族乡简介 二酉苗族乡
沅陵县二酉苗族乡概览二酉苗族乡地处沅陵县西北部,跨酉水、酉溪两岸,东与明溪口镇相交,西与泸溪县接壤,南与沅陵镇毗邻,北与古丈县为界。 2005年10月,全乡部分行政村合并,由原来的47个行政村合并为现在的39个行政村,现全乡共辖39个行政村