Android4.4电源管理——电源锁
//创建电源锁
[cpp] view plain copyPowerManagerService.java
mWakeLockSuspendBlocker = createSuspendBlockerLocked("PowerManagerService.WakeLocks");
mDisplaySuspendBlocker = createSuspendBlockerLocked("PowerManagerService.Display");
private SuspendBlocker createSuspendBlockerLocked(String name) {
SuspendBlocker suspendBlocker = new SuspendBlockerImpl(name);
mSuspendBlockers.add(suspendBlocker);
return suspendBlocker;
}
//电源锁操作类的实现
[cpp] view plain copyprivate 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) {
if (DEBUG_SPEW) {
Slog.d(TAG, "Acquiring suspend blocker \"" + mName + "\".");
}
nativeAcquireSuspendBlocker(mName);
}
}
}
@Override
public void release() {
synchronized (this) {
mReferenceCount -= 1;
if (mReferenceCount == 0) {
if (DEBUG_SPEW) {
Slog.d(TAG, "Releasing suspend blocker \"" + mName + "\".");
}
nativeReleaseSuspendBlocker(mName);
} else if (mReferenceCount < 0) {
Log.wtf(TAG, "Suspend blocker \"" + mName
+ "\" was released without being acquired!", new Throwable());
mReferenceCount = 0;
}
}
}
}
//JNI层函数实现电源锁的获取
[cpp] view plain copycom_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());
}
//将电源锁写入到相应的文件中,相当于获得了电源锁
power.c
[cpp] view plain copyint 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));
}
//打开记录电源锁的文件
[cpp] view plain copystatic inline void
initialize_fds(void)
{
if (g_initialized == 0) {
if(open_file_descriptors(NEW_PATHS) < 0)
open_file_descriptors(OLD_PATHS);
g_initialized = 1;
}
}
//记录电源锁的文件路径
[cpp] view plain copyconst char * const OLD_PATHS[] = {
"/sys/android_power/acquire_partial_wake_lock",
"/sys/android_power/release_wake_lock",
};
const char * const NEW_PATHS[] = {
"/sys/power/wake_lock",
"/sys/power/wake_unlock",
};
到现在为止,我们的代码流程已经走了一大半了,我们一开始介绍的android的上面几层Framework层、JNI层、HAL层都已经介绍了。下面就应该是和kernel层进行交互了。
但是在android/hardware/libhardware_legacy/power/power.c中的acquire_wake_lock()函数似乎没法和kernel层进行通信啊?最后的返回语句return write(fd, id, strlen(id))是一个系统调用,这里就实现了与kernel的交互。
kernel/power/main.c中的power_attr宏很多地方用到:
- #definepower_attr(_name)\
- staticstructkobj_attribute_name##_attr={\
- .attr={\
- .name=__stringify(_name),\
- .mode=0644,\
- },\
- .show=_name##_show,\
- .store=_name##_store,\
- }
- #ifdefCONFIG_USER_WAKELOCK
- power_attr(wake_lock);
- power_attr(wake_unlock);
- #endif
User-space wake lock api. Write "lockname" or "lockname timeout"
to /sys/power/wake_lock lock and if needed create a wake lock.
Write "lockname" to /sys/power/wake_unlock to unlock a user wake
lock.
[cpp] view plain copy
- #ifdefCONFIG_PM_WAKELOCKS
- power_attr(wake_lock);
- power_attr(wake_unlock);
- #endif
Allow user space to create, activate and deactivate wakeup source
objects with the help of a sysfs-based interface.
宏展开,等价于:
[cpp] view plain copy
- staticstructkobj_attributewake_lock_attr={
- .attr={
- .name=“wake_lock”,
- .mode=0644,
- },
- .show=wake_lock_show,
- .store=wake_lock_store,
- }
- staticstructkobj_attributewake_unlock_attr={
- .attr={
- .name=“wake_unlock”,
- .mode=0644,
- },
- .show=wake_unlock_show,
- .store=wake_unlock_store,
- }
[cpp] view plain copy
- staticstructattribute*g[]={
- &state_attr.attr,
- #ifdefCONFIG_PM_TRACE
- &pm_trace_attr.attr,
- &pm_trace_dev_match_attr.attr,
- #endif
- #ifdefCONFIG_PM_SLEEP
- &pm_async_attr.attr,
- &wakeup_count_attr.attr,
- #ifdefCONFIG_USER_WAKELOCK
- &wake_lock_attr.attr,
- &wake_unlock_attr.attr,
- #endif
- #ifdefCONFIG_PM_AUTOSLEEP
- &autosleep_attr.attr,
- #endif
- #ifdefCONFIG_PM_WAKELOCKS
- &wake_lock_attr.attr,
- &wake_unlock_attr.attr,
- #endif
- #ifdefCONFIG_PM_DEBUG
- &pm_test_attr.attr,
- #endif
- #ifdefCONFIG_PM_SLEEP_DEBUG
- &pm_print_times_attr.attr,
- #endif
- #endif
- #ifdefCONFIG_FREEZER
- &pm_freeze_timeout_attr.attr,
- #endif
- NULL,
- };
- staticstructattribute_groupattr_group={
- .attrs=g,
- };
error = sysfs_create_group(power_kobj, &attr_group);
好了,我们该回到原来我们产生疑问的地方了这时我们还得关注其中的另一个函数acquire_wake_lock()->initialize_fds()。 [cpp] view plain copy
- initialize_fds(void)
- {
- //XXX:shouldbethis:
- //pthread_once(&g_initialized,open_file_descriptors);
- //XXX:notthis:
- if(g_initialized==0){
- if(open_file_descriptors(NEW_PATHS)<0)
- open_file_descriptors(OLD_PATHS);
- g_initialized=1;
- }
- }
其实这个函数中最核心的步骤就是open_file_descriptors(NEW_PATHS),顺序打开NEW_PATHS[ ]中的文件:
[cpp] view plain copy- staticint
- open_file_descriptors(constchar*constpaths[])
- {
- inti;
- for(i=0;i<OUR_FD_COUNT;i++){
- intfd=open(paths[i],O_RDWR);
- if(fd<0){
- fprintf(stderr,"fatalerroropening\"%s\"\n",paths[i]);
- g_error=errno;
- return-1;
- }
- g_fds[i]=fd;
- }
- g_error=0;
- return0;
- }
- constchar*constNEW_PATHS[]={
- "/sys/power/wake_lock",
- "/sys/power/wake_unlock",
- };
总之经过着一系列的步骤后,最终我们将在 return write(fd, id, strlen(id));时调用android/kernel/kernel/power/userwakelock.c 中的 wake_lock_store()函数。
- ssize_twake_lock_store(
- structkobject*kobj,structkobj_attribute*attr,
- constchar*buf,size_tn)
- {
- longtimeout;
- structuser_wake_lock*l;
- mutex_lock(&tree_lock);
- l=lookup_wake_lock_name(buf,1,&timeout);
- if(IS_ERR(l)){
- n=PTR_ERR(l);
- gotobad_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);
- returnn;
- }
- structrb_rootuser_wake_locks;
- staticstructuser_wake_lock*lookup_wake_lock_name(
- constchar*buf,intallocate,long*timeoutptr)
- {
- structrb_node**p=&user_wake_locks.rb_node;
- structrb_node*parent=NULL;
- structuser_wake_lock*l;
- intdiff;
- u64timeout;
- intname_len;
- constchar*arg;
- /*Findlengthoflocknameandstartofoptionaltimeoutstring*/
- arg=buf;
- while(*arg&&!isspace(*arg))
- arg++;
- //lockname的长度
- name_len=arg-buf;
- if(!name_len)
- gotobad_arg;
- while(isspace(*arg))
- arg++;
- /*Processtimeoutstring*/
- if(timeoutptr&&*arg){
- //(char**)&arg存储的是解析string的结束字符
- timeout=simple_strtoull(arg,(char**)&arg,0);
- while(isspace(*arg))
- arg++;
- //如果解析string的结束字符不是’\0’
- if(*arg)
- gotobad_arg;
- /*converttimeoutfromnanosecondstojiffies>0*/
- timeout+=(NSEC_PER_SEC/HZ)-1;
- //do_div(a,b)的返回值是余数,商保存到a中
- do_div(timeout,(NSEC_PER_SEC/HZ));
- if(timeout<=0)
- timeout=1;
- *timeoutptr=timeout;
- }elseif(*arg)
- //timeoutptr为NULL
- gotobad_arg;
- elseif(timeoutptr)
- //*arg为0,没有timeout
- *timeoutptr=0;
- /*Lookupwakelockinrbtree*/
- //对于一颗空的红黑树,略过while。wakelock按照name从小到大的顺序存储到user_wake_locks红黑树中
- while(*p){
- parent=*p;
- l=rb_entry(parent,structuser_wake_lock,node);
- diff=strncmp(buf,l->name,name_len);
- //如果buf是l->name的子串,那么l->name[name_len]就不会为0,但是buf[name_len]会为0
- if(!diff&&l->name[name_len])
- diff=-1;
- if(debug_mask&DEBUG_ERROR)
- pr_info("lookup_wake_lock_name:compare%.*s%s%d\n",
- name_len,buf,l->name,diff);
- if(diff<0)
- p=&(*p)->rb_left;
- elseif(diff>0)
- p=&(*p)->rb_right;
- else
- returnl;
- }
- /*Allocateandaddnewwakelocktorbtree*/
- //allocate为0,表示不需要分配新的wakelock,只在rbtree上查找,找不到就出错了
- if(!allocate){
- if(debug_mask&DEBUG_ERROR)
- pr_info("lookup_wake_lock_name:%.*snotfound\n",
- name_len,buf);
- returnERR_PTR(-EINVAL);
- }
- l=kzalloc(sizeof(*l)+name_len+1,GFP_KERNEL);
- if(l==NULL){
- if(debug_mask&DEBUG_FAILURE)
- pr_err("lookup_wake_lock_name:failedtoallocate"
- "memoryfor%.*s\n",name_len,buf);
- returnERR_PTR(-ENOMEM);
- }
- memcpy(l->name,buf,name_len);
- if(debug_mask&DEBUG_NEW)
- pr_info("lookup_wake_lock_name:newwakelock%s\n",l->name);
- wake_lock_init(&l->wake_lock,WAKE_LOCK_SUSPEND,l->name);
- //插入结点,并染成红色
- rb_link_node(&l->node,parent,p);
- rb_insert_color(&l->node,&user_wake_locks);
- returnl;
- bad_arg:
- if(debug_mask&DEBUG_ERROR)
- pr_info("lookup_wake_lock_name:wakelock,%.*s,badarg,%s\n",
- name_len,buf,arg);
- returnERR_PTR(-EINVAL);
- }
wake_lock_store()执行的基本流程为:首先调用lookup_wake_lock_name()来获得指定的唤醒锁,若延迟参数timeout为零的话,就调用 wake_lock()否则就调用wake_lock_timeout(),但不管调用哪个最后都会调用到android/kernel/kernel/power/wakelock.c中的函数static void wake_lock_internal()。
[cpp] view plain copy- staticvoidwake_lock_internal(
- structwake_lock*lock,longtimeout,inthas_timeout)
- {
- inttype;
- unsignedlongirqflags;
- longexpire_in;
- spin_lock_irqsave(&list_lock,irqflags);
- type=lock->flags&WAKE_LOCK_TYPE_MASK;
- //检查type是否合法
- BUG_ON(type>=WAKE_LOCK_TYPE_COUNT);
- //检查是否初始化过
- BUG_ON(!(lock->flags&WAKE_LOCK_INITIALIZED));
- #ifdefCONFIG_WAKELOCK_STAT
- if(type==WAKE_LOCK_SUSPEND&&wait_for_wakeup){
- if(debug_mask&DEBUG_WAKEUP)
- pr_info("wakeupwakelock:%s\n",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();
- }
- #endif
- if(!(lock->flags&WAKE_LOCK_ACTIVE)){
- lock->flags|=WAKE_LOCK_ACTIVE;
- #ifdefCONFIG_WAKELOCK_STAT
- lock->stat.last_time=ktime_get();
- #endif
- }
- //从inactive_locks上删除
- list_del(&lock->link);
- if(has_timeout){
- if(debug_mask&DEBUG_WAKE_LOCK)
- pr_info("wake_lock:%s,type%d,timeout%ld.%03lu\n",
- 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%d\n",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++;
- #ifdefCONFIG_WAKELOCK_STAT
- if(lock==&main_wake_lock)
- update_sleep_wait_stats_locked(1);
- elseif(!wake_lock_active(&main_wake_lock))
- update_sleep_wait_stats_locked(0);
- #endif
- if(has_timeout)
- expire_in=has_wake_lock_locked(type);
- else
- expire_in=-1;
- if(expire_in>0){
- if(debug_mask&DEBUG_EXPIRE)
- pr_info("wake_lock:%s,startexpiretimer,"
- "%ld\n",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,stopexpiretimer\n",
- lock->name);
- if(expire_in==0)
- queue_work(suspend_work_queue,&suspend_work);
- }
- }
- spin_unlock_irqrestore(&list_lock,irqflags);
- }
//电源锁的使用
[cpp] view plain copy /**
* Updates the suspend blocker that keeps the CPU alive.
*
* This function must have no other side-effects.
*/
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;
}
}
//判断是否处于亮屏或者正在变化阶段
[cpp] view plain copy private boolean needDisplaySuspendBlocker() { //正处于变化阶段
if (!mDisplayReady) {
return true;
}
if (mDisplayPowerRequest.screenState != DisplayPowerRequest.SCREEN_STATE_OFF) {
//有疑问?
// If we asked for the screen to be on but it is off due to the proximity
// sensor then we may suspend but only if the configuration allows it.
// On some hardware it may not be safe to suspend because the proximity
// sensor may not be correctly configured as a wake-up source.
if (!mDisplayPowerRequest.useProximitySensor || !mProximityPositive
|| !mSuspendWhenScreenOffDueToProximityConfig) {
return true;
}
}
return false;
}
更多相关文章
- JAVA按钮显示用户名+密码
- 五分钟学会之AsyncTask
- Android组播域名服务
- Service详解一
- 地图测试
- Android通过广播接收者调用服务内方法
- Android(安卓)开发游戏中的SurfaceView,Callback,SurfaceHolder
- setonClickListener()的解释
- handler机制(二)源码分析