http://blog.csdn.net/myarrow/article/details/8137952

一、简介

Android在Linux内核原有的睡眠唤醒模块上基础上,主要增加了下面三个机制:

• 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 解锁,系统即可进入睡眠状态。

从Android最上层(Java的应用程序),经过Java、C++和C语言写的Framework层、JNI层、HAL层最后到达android的最底层(Kernel层)。

下图是Android睡眠唤醒模块框架:

二、相关代码

• Frameworks

//供给上层应用程序调用的接口
frameworks/base/core/java/android/os/PowerManager.java

//具体实现PowerManager类中的接口
frameworks/base/services/java/com/android/server/PowerManagerService.java

// 被PowerManagerService类调用

frameworks/base/core/java/android/os/ Power.java

• JNI

// 实现Power类中的JNI接口
frameworks/base/core/jni/android_os_Power.cpp

• HAL

// 进行sysfs用户接口的操作
hardware/libhardware_legacy/power/power.c

• Kernel

kernel/kernel/power/main.c
kernel/kernel/power/earlysuspend.c
kernel/kernel/power/suspend.c
kernel/kernel/power/wakelock.c
kernel/kernel/power/userwakelock.c

在应用程序框架层中,PowerManager类是面向上层应用程序的接口类,提供了Wake Lock机制(同时也是睡眠唤醒子系统)的基本接口(唤醒锁的获取和释放)。上层应用程序通过调用这些接口,实现对系统电源状态的监控。

• PowerManager类通过IBinder这种Android中特有的通信模式,与PowerManagerService 类进行通信。

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

三、获得wakelock唤醒锁
比如在应用程序中,当获得wakelock唤醒锁的时候,它首先调用/android/frameworks/base/core/java/android/os/PowerManager类中的public void acquire()办法,而此方法通过Binder将调用PowerManagerService类中的public void acquireWakeLock。

在用户态的调用流程如下:

[cpp] view plain copy
  1. PowerManager.acquire()->
  2. PowerManager.acquireLocked()->
  3. PowerManagerService.acquireWakeLock(intflags,IBinderlock,Stringtag,WorkSourcews)->
  4. PowerManagerService.acquireWakeLockLocked(intflags,IBinderlock,intuid,intpid,
  5. Stringtag,WorkSourcews)->
  6. Power.acquireWakeLock(Power.PARTIAL_WAKE_LOCK,PARTIAL_NAME)->
  7. android_os_Power.cpp::acquireWakeLock(JNIEnv*env,jobjectclazz,jintlock,jstringidObj)->
  8. power.c::acquire_wake_lock(intlock,constchar*id)->
  9. write(fd,id,strlen(id))

上述write实质上是文件sysfs: /sys/power/wake_lock,当write时,它将调用userwakelock.c::wake_lock_store()函数,其实现如下:

[cpp] view plain copy
  1. ssize_twake_lock_store(
  2. structkobject*kobj,structkobj_attribute*attr,
  3. constchar*buf,size_tn)
  4. {
  5. longtimeout;
  6. structuser_wake_lock*l;
  7. mutex_lock(&tree_lock);
  8. l=lookup_wake_lock_name(buf,1,&timeout);
  9. if(IS_ERR(l)){
  10. n=PTR_ERR(l);
  11. gotobad_name;
  12. }
  13. if(debug_mask&DEBUG_ACCESS)
  14. pr_info("wake_lock_store:%s,timeout%ld\n",l->name,timeout);
  15. if(timeout)
  16. wake_lock_timeout(&l->wake_lock,timeout);
  17. else
  18. wake_lock(&l->wake_lock);
  19. bad_name:
  20. mutex_unlock(&tree_lock);
  21. returnn;
  22. }


1. 根据name在红黑树中查找user_wake_lock,若找到则直接返回;否则为它分配内存、调用wake_lock_init初始化、然后增加到红黑树中。

2. 调用wake_lock或wake_lock_timeout,它将调用wake_lock_internal

[cpp] view plain copy
  1. staticvoidwake_lock_internal(
  2. structwake_lock*lock,longtimeout,inthas_timeout)
  3. {
  4. inttype;
  5. unsignedlongirqflags;
  6. longexpire_in;
  7. spin_lock_irqsave(&list_lock,irqflags);
  8. type=lock->flags&WAKE_LOCK_TYPE_MASK;
  9. BUG_ON(type>=WAKE_LOCK_TYPE_COUNT);
  10. BUG_ON(!(lock->flags&WAKE_LOCK_INITIALIZED));
  11. #ifdefCONFIG_WAKELOCK_STAT
  12. if(type==WAKE_LOCK_SUSPEND&&wait_for_wakeup){
  13. if(debug_mask&DEBUG_WAKEUP)
  14. pr_info("wakeupwakelock:%s\n",lock->name);
  15. wait_for_wakeup=0;
  16. lock->stat.wakeup_count++;
  17. }
  18. if((lock->flags&WAKE_LOCK_AUTO_EXPIRE)&&
  19. (long)(lock->expires-jiffies)<=0){
  20. wake_unlock_stat_locked(lock,0);
  21. lock->stat.last_time=ktime_get();
  22. }
  23. #endif
  24. if(!(lock->flags&WAKE_LOCK_ACTIVE)){
  25. lock->flags|=WAKE_LOCK_ACTIVE;
  26. #ifdefCONFIG_WAKELOCK_STAT
  27. lock->stat.last_time=ktime_get();
  28. #endif
  29. }
  30. list_del(&lock->link);
  31. if(has_timeout){
  32. if(debug_mask&DEBUG_WAKE_LOCK)
  33. pr_info("wake_lock:%s,type%d,timeout%ld.%03lu\n",
  34. lock->name,type,timeout/HZ,
  35. (timeout%HZ)*MSEC_PER_SEC/HZ);
  36. lock->expires=jiffies+timeout;
  37. lock->flags|=WAKE_LOCK_AUTO_EXPIRE;
  38. list_add_tail(&lock->link,&active_wake_locks[type]);
  39. }else{
  40. if(debug_mask&DEBUG_WAKE_LOCK)
  41. pr_info("wake_lock:%s,type%d\n",lock->name,type);
  42. lock->expires=LONG_MAX;
  43. lock->flags&=~WAKE_LOCK_AUTO_EXPIRE;
  44. list_add(&lock->link,&active_wake_locks[type]);
  45. }
  46. if(type==WAKE_LOCK_SUSPEND){
  47. current_event_num++;
  48. #ifdefCONFIG_WAKELOCK_STAT
  49. if(lock==&main_wake_lock)
  50. update_sleep_wait_stats_locked(1);
  51. elseif(!wake_lock_active(&main_wake_lock))
  52. update_sleep_wait_stats_locked(0);
  53. #endif
  54. if(has_timeout)
  55. expire_in=has_wake_lock_locked(type);
  56. else
  57. expire_in=-1;
  58. if(expire_in>0){
  59. if(debug_mask&DEBUG_EXPIRE)
  60. pr_info("wake_lock:%s,startexpiretimer,"
  61. "%ld\n",lock->name,expire_in);
  62. mod_timer(&expire_timer,jiffies+expire_in);
  63. }else{
  64. if(del_timer(&expire_timer))
  65. if(debug_mask&DEBUG_EXPIRE)
  66. pr_info("wake_lock:%s,stopexpiretimer\n",
  67. lock->name);
  68. if(expire_in==0)
  69. queue_work(suspend_work_queue,&suspend_work);
  70. }
  71. }
  72. spin_unlock_irqrestore(&list_lock,irqflags);
  73. }

wake_lock_internal()函数流程: 
1) 判断锁的类型是否有效,即是否为WAKE_LOCK_SUSPEND或WAKE_LOCK_IDLE某一种 
2) 如果定义了CONFIG_WAKELOCK_STAT, 则更新struct wake_lock里面的用于统计锁信息的成员变量 
3) 将锁从inactive_locks链表上取下,加到active_wake_locks链表上。如果是超期锁则设置锁的flag|=WAKE_LOCK_AUTO_EXPIRE,否则取消WAKE_LOCK_AUTO_EXPIRE标志。如果锁是WAKE_LOCK_SUSPEND型的,则继续下面的步骤。 
4) 对于WAKE_LOCK_SUSPEND型的锁如果它是超期锁,则调用has_wake_lock_locked函数检查所有处于活动状态的WAKE_LOCK_SUSPEND锁(即在active_wake_locks链表上的WAKE_LOCK_SUSPEND锁,或者说当前被加锁了的WAKE_LOCK_SUSPEND锁),是否有超期锁已经过期,如果有则把过期超期锁从active_wake_locks上删除,挂到inactive_locks上。同时它还检查链表上有没有非超期锁,如果有则直接返回-1,否则它最终返回的是所有超期锁过期时间的最大值 
5) 如果has_wake_lock_locked函数返回的是-1(表示当前活动锁有非超时锁)或者0(表示所有活动锁都是超时锁,且全已经超时),则删除expire_timer,并排队一个suspend工作到suspend_work_queue工作队列,最终系统会suspend。suspend函数完成suspend系统的任务,它是suspend_work这个工作的处理函数,suspend_workk排队到suspend_work_queue工作队列中,最终系统会处理这个work,调用其handler即suspend函数。该函数首先sync文件系统,然后调用pm_suspend(request_suspend_state),接下来pm_suspend()就会调用 enter_state()来进入 linux的suspend流程。
四、系统进入睡眠(suspend)
当按了MID上的power键,经过一系统列的事务处理后,它会调用到PowerManager类中的goToSleep。在用户态的调用流程如下所示:

[cpp] view plain copy
  1. PowerManager.goToSleep(longtime)->
  2. PowerManagerService.goToSleep(longtime)->
  3. PowerManagerService.goToSleepWithReason(time,WindowManagerPolicy.OFF_BECAUSE_OF_USER)->
  4. PowerManagerService.goToSleepLocked(longtime,intreason)->
  5. PowerManagerService.setPowerState(SCREEN_OFF,false,reason)->
  6. PowerManagerService.sendNotificationLocked(false,WindowManagerPolicy.OFF_BECAUSE_OF_USER)
  7. PowerManagerService.setScreenStateLocked(true)->
  8. Power.setScreenState->
  9. android_os_Power.cpp::setScreenState->
  10. Power.c::set_screen_state(inton)->
  11. write(g_fds[REQUEST_STATE],buf,len)

上面的write将把"mem"写入/sys/power/state中。接下来,在kernel态,state_store函数将被调用。

•Android特有的earlysuspend: request_suspend_state(state)
•Linux标准的suspend: enter_state(state)

在state_store中,若定义了CONFIG_EARLYSUSPEND,则执行request_suspend_state(state)以先进入earlysuspend,然后根据wake_lock的状态决定是否进入suspend;否则直接执行enter_state(state)以进入suspend状态。


更多相关文章

  1. Android(安卓)persistent属性研究
  2. phonegap+jquerymobile开发android的心得(2)
  3. Android学习笔记(十七)——使用意图调用内置应用程序
  4. (ios实战)实现类似于android 的toast控件
  5. [置顶] Android(安卓)WebView 踩过的坑
  6. Android(安卓)性能优化 二 TraceView工具的使用
  7. android 10.0 以上隐藏方法无法调用 #Accessing hidden method
  8. Android(安卓)AsyncTask 浅析(源代码取自 API level 23)
  9. android常用的API接口调用

随机推荐

  1. android游戏开发须知!
  2. android strings.xml转义字符, 注意细节
  3. Android(安卓)杂七杂八记录
  4. 网络图片浏览器
  5. Android(安卓)事件分发机制详解
  6. Android百度地图开发(二):显示地图界面
  7. Android中级篇之用JAVA代码执行shell命令
  8. Android目录结构--drawable和drawable-v2
  9. Android(安卓)Menu 主菜单是使用
  10. Google Gson 加入到Android中, 打包编译