android休眠與喚醒驅(qū)動流程分析_第1頁
android休眠與喚醒驅(qū)動流程分析_第2頁
android休眠與喚醒驅(qū)動流程分析_第3頁
android休眠與喚醒驅(qū)動流程分析_第4頁
android休眠與喚醒驅(qū)動流程分析_第5頁
已閱讀5頁,還剩7頁未讀 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

1、android休眠與喚醒驅(qū)動流程分析標準linux休眠過程:powermanagementnotifiersareexecutedwithPM_SUSPEND_PREPAREtasksarefrozentargetsystemsleepstateisannouncedtotheplatform-handlingcodedevicesaresuspendedplatform-specificglobalsuspendpreparationmethodsareexecutednon-bootCPUsaretakenoff-lineinterruptsaredisabledontheremainin

2、g(main)CPUlatesuspendofdevicesiscarriedout(一般有一些BUSdriver的動作進行)?platform-specificglobalmethodsareinvokedtoputthesystemtosleep標準linux喚醒過程:themainCPUisswitchedtotheappropriatemode,ifnecessaryearlyresumeofdevicesiscarriedout(一般有一些BUSdriver的動作進行)?interruptsareenabledonthemainCPUnon-bootCPUsareenabledpla

3、tform-specificglobalresumepreparationmethodsareinvokeddevicesarewokenuptasksarethawedpowermanagementnotifiersareexecutedwithPM_POST_SUSPEND用戶可以通過sys文件系統(tǒng)控制系統(tǒng)進入休眠:查看系統(tǒng)支持的休眠方式:#cat/sys/power/state常見有standby(suspendtoRAM)、mem(suspendtoRAM)和disk(suspendtodisk),只是standby耗電更多,返回到正常工作狀態(tài)的時間更短。通過#echomem>/

4、sys/power/state讓系統(tǒng)進入休眠。Android休眠與喚醒android是在傳統(tǒng)的linux內(nèi)核電源管理設(shè)計的基礎(chǔ)上,結(jié)合手機設(shè)計的實際需求而進化出的一套電源管理系統(tǒng),其核心內(nèi)容有:wakelock、early_suspend與late_resume。wakelock在Android的電源管理系統(tǒng)中扮演一個核心的角色。wakelock是一種鎖的機制,只要有人拿著這個鎖,系統(tǒng)就無法進入休眠,可以被用戶態(tài)程序和內(nèi)核獲得。這個鎖可以是有超時的或者是沒有超時的,超時的鎖會在時間過去以后自動解鎖。如果沒有鎖了或者超時了,內(nèi)核就會啟動休眠的那套機制來進入休眠。當系統(tǒng)在啟動完畢后,會自己去加一把

5、名為“main'的鎖,而當系統(tǒng)有意愿去睡眠時則會先去釋放這把"main”鎖,在android中,在early_suspend的最后一步會去釋放“main”鎖(wake_unlock:main)。釋放完后則會去檢查是否還有其他存在的鎖,如果沒有則直接進入睡眠過程。它的缺點是,如果有某一應(yīng)用獲鎖而不釋放或者因一直在執(zhí)行某種操作而沒時間來釋放的話,則會導致系統(tǒng)一直進入不了睡眠狀態(tài),功耗過大。early_suspend:先與linux內(nèi)核的睡眠過程被調(diào)用。一般在手機系統(tǒng)的設(shè)計中對背光的操作等采用此類方法,因為背光需要的能耗過大。當然此操作與late_resume是配套使用的。一些在內(nèi)

6、核中要預先進行處理的事件可以先注冊上會首先調(diào)用這些注冊的函數(shù)。early_suspend函數(shù),當系統(tǒng)要進入睡眠之前本文中,linuxkernel版本為linux-2.6.29,android版本為android2.1與android休眠喚醒主要相關(guān)的文件主要有:linux_source/kernel/power/main.clinux_source/kernel/power/earlysuspend.clinux_source/kernel/power/wakelock.clinux_source/kernel/power/process.clinux_source/driver/base/p

7、ower/main.clinux_source/arch/xxx/mach-xxx/pm.c或linux_source/arch/xxx/plat-xxx/pm.cAndroid休眠過程如下:當用戶讀寫/sys/power/state時,linux_source/kernel/power/main.c中的state_store()函數(shù)會被調(diào)用。其中,android的early_suspend會執(zhí)行request_suspend_state(state);而標準的linux休眠貝U執(zhí)行error=enter_state(state);staticssize_tstate_store(struct

8、kobject*kobj,structkobj_attribute*attr,constchar*buf,size_tn)-#ifdefCONFIG_SUSPEND#ifdefCONFIG_EARLYSUSPENDsuspend_state_tstate=PM_SUSPEND_ON;#elsesuspend_state_tstate=PM_SUSPEND_STANDBY;#endifconstchar*const*s;#endifchar*p;intlen;interror=-EINVAL;p=memchr(buf,'n',n);len=p?p-buf:n;/*First,ch

9、eckifwearerequestedtohibernate*/if(len=4&&!strncmp(buf,"disk",len)error=hibernate();gotoExit;#ifdefCONFIG_SUSPENDfor(s=&pm_statesstate;state<PM_SUSPEND_MAX;s+,state+)if(*s&&len=strlen(*s)&&!strncmp(buf,*s,len)break;if(state<PM_SUSPEND_MAX&&*s)#ifde

10、fCONFIG_EARLYSUSPENDif(state=PM_SUSPEND_ON|valid_state(state)error=0;request_suspend_state(state);-#elseerror=enter_state(state);#endif在request_suspend_state(state函數(shù)中,會調(diào)用early_suspend_work的工作隊列,從而進入early_suspend()函數(shù)中。staticDECLARE_WORK(early_suspend_work,early_suspend);voidrequest_suspend_state(susp

11、end_state_tnew_state)-unsignedlongirqflags;intold_sleep;spin_lock_irqsave(&state_lock,irqflags);old_sleep"=state&SUSPEND_REQUESTED;if(debug_mask&DEBUG_USER_STATE)structtimespects;structrtc_timetm;getnstimeofday(&ts);rtc_time_to_tm(ts.tv_sec,&tm);pr_info("request_suspend

12、_state:%s(%d->%d)at%lld"-"(%d-%02=%02d%02d:%O2d:%O2d.%O9luUTC)n",new_state!=PM_SUSPEND_ON?"sleep":"wakeup",requested_suspend_state,new_state,ktime_to_ns(ktime_get(),tm.tm_year+1900,tm.tm_mon+1,tm.tm_mday,tm.tm_hour,tm.tm_min,tm.tm_sec,ts.tv_nsec);-if(!old_sleep&

13、amp;&new_state!=PM_SUSPEND_ON)state|=SUSPEND_REQUESTED;queue_work(suspend_work_queue,&early_suspend_work);elseif(old_sleep&&new_state=PM_SUSPEND_ON)state&=SUSPEND_REQUESTED;wakeock(&main_wakeock);queue_work(suspend_work_queue,&late_resume_work);-requested_suspend_state=ne

14、w_state;spin_unlock_irqrestore(&state_lock,irqflags);-在early_suspend()函數(shù)中,首先要判斷當前請求的狀態(tài)是否還是suspend,若不是,則直接退出了;若是,函數(shù)會調(diào)用已經(jīng)注冊的early_suspend的函數(shù)。然后同步文件系統(tǒng),最后釋放main_wake_lock。staticvoidearly_suspend(structwork_struct*work)-structearly_suspend*pos;unsignedlongirqflags;intabort=0;mutex_lock(&early_sus

15、pend_lock);spin_lock_irqsave(&state_lock,irqflags);if(state=SUSPEND_REQUESTED)state|=SUSPENDED;elseabort=1;spin_unlock_irqrestore(&state_lock,irqflags);if(abort)if(debug_mask&DEBUG_SUSPEND)pr_info("early_suspend:abort,state%dn",state);mutex_uniock(&early_suspend_lock);gotoa

16、bort;if(debug_mask&DEBUG_SUSPEND)pr_info("early_suspend:callhandlersn");list_for_each_entry(pos,&early_suspend_handlers,link)if(pos->suspend!=NULL)pos->suspend(pos);mutex_uniock(&early_suspend_lock);if(debug_mask&DEBUG_SUSPEND)pr_info("early_suspend:syncn”);sys_s

17、ync();abort:spin_lock_irqsave(&state_lock,irqflags);if(state=SUSPEND_rEqUESTED_AND_SUSPENDED)wake_unlock(&main_wake_lock);spin_unlock_irqrestore(&state_lock,irqflags);-在wake_unlock()中,刪除鏈表中wake_lock節(jié)點,判斷當前是否存在wake_lock,若wake_lock的數(shù)目為0,則調(diào)用工作隊列suspend_work,進入suspend狀態(tài)。staticDECLARE_WORK(su

18、spend_work,suspend);voidwake_unlock(structwake_lock*lock)-inttype;unsignedlongirqflags;spin_lock_irqsave(&list_lock,irqflags);type:lock->flags&wAkE_LOCK_TYPE_MASK;#ifdefCONFIG_WAKELOCK_STATwake_uniock_stat_locked(lock,0);#endifif(debug_mask&DEBUG_WAKE_LOCK)pr_info("wake_uniock:%s

19、n",lock->name);lock->flags&=(WAKE_LOCK_ACTIVE|WAKE_LOCK_AUTO_EXPIRE);list_del(&lock->link);list_add(&lock->link,&inactive_locks);if(type=WAKE_LOCK_SUSPEND)longhas_lock=has_wake_lock_locked(type);if(has_lock>0)if(debug_mask&DEBUG_EXPIRE)pr_info("wake_unioc

20、k:%s,startexpiretimer,""%ldn",lock->name,has_lock);mod_timer(&expire_timer,jiffies+has_lock);elseif(del_timer(&expire_timer)if(debug_mask&DEBUG_EXPIRE)pr_info("wake_uniock:%s,stopexpire""timern",lock->name);if(has_iock=0)queue_work(suspend_work_qu

21、eue,&suspend_work);-if(lock=&main_wakeock)if(debug_mask&DEBUG_SUSPEND)print_active_locks(WAKE_LOCK_SUSPEND);#ifdefCONFIG_WAKELOCK_STATupdate_sleep_wait_stats_locked(0);#endifspin_unlock_irqrestore(&list_lock,irqflags);-在suspend()函數(shù)中,先判斷當前是否有wake_lock,若有,則退出;然后同步文件系統(tǒng),最后調(diào)用pm_suspend()函

22、數(shù)。staticvoidsuspend(structwork_struct*work)-intret;intentry_event_num;if(has_wake_lock(WAKE_LOCK_SUSPEND)if(debug_mask&DEBUG_SUSPEND)pr_info("suspend:abortsuspendn”);return;entry_event_num=current_event_num;sys_sync();if(dbug_mask&DEBUG_SUSPEND)pr_info("suspend:entersuspendn”);ret=

23、pm_suspend(requested_suspend_state);if(debug_mask&DEBUG_EXIT_SUSPEND)structtimespects;structrtc_timetm;getnstimeofday(&ts);rtc_time_to_tm(ts.tv_sec,&tm);pr_info("suspend:exitsuspend,ret=%d"-"(%d-%02d-%02d%02d:%02d:%02d.%09luUTC)n",ret,tm.tm_year+1900,tm.tm_mon+1,tm.tm

24、_mday,tm.tm_hour,tm.tm_min,tm.tm_sec,ts.tv_nsec);-if(current_event_num=entry_event_num)if(debug_mask&DEBuG_SUSPEND)pr_info("suspend:pm_suspendreturnedwithnoevent'n”);wakeock_timeout(&unknown_wakeup,HZ/2);-在pm_suspend()函數(shù)中,enter_state()函數(shù)被調(diào)用,從而進入標準linux休眠過程。intpm_suspend(suspend_stat

25、e_tstate)-if(state>PM_SUSPEND_ON&&state<=PM_SUSPEND_MAX)returnenter_state(state);return-EINVAL;在enter_state()函數(shù)中,首先檢查一些狀態(tài)參數(shù),再同步文件系統(tǒng),然后調(diào)用suspend_prepare()來凍結(jié)進程,最后調(diào)用suspend_devices_and_enter()讓外設(shè)進入休眠。staticintenter_state(suspend_state_tstate)interror;if(!valid_state(state)return-ENODEV;i

26、f(!mutextrylock(&pmmutex)return-EBUSY;-printk(KERN_INFO"PM:Syncingfilesystems.");sys_sync();printk("done.n");pr_debug("PM:Preparingsystemfor%ssleepn",pm_statesstate);error=suspend_prepare();if(error)gotoUniock;if(suspend_test(TEST_FREEZER)gotoFinish;pr_debug("P

27、M:Entering%ssleepn",pm_statesstate);error=suspend_devices_and_enter(state);Finish:pr_debug("PM:Finishingwakeup.'n");suspend_finish();Unlock:mutex_uniock(&pm_mutex);returnerror;在suspend_prepare()函數(shù)中,先通過pm_prepare_console();給suspend分配一個虛擬終端來輸出信息,再廣播一個系統(tǒng)進入suspend的通報,關(guān)閉用戶態(tài)的helper進

28、程,然后調(diào)用suspend_freeze_processes(來凍結(jié)進程,最后會嘗試釋放一些內(nèi)存。staticintsuspend_prepare(void)-interror;unsignedintfree_pages;if(!suspend_ops|!suspend_ops->enter)return-EPERM;pm_prepare_console();error=pm_notifier_call_chain(PM_SUSPEND_PREPARE);if(error)gotoFinish;error=usermodehelper_disable();if(error)gotoFin

29、ish;if(suspend_freeze_processes()error=-EAGAIN;gotoThaw;free_pages=global_page_state(NR_FREE_PAGES);if(free_pages<FREE_PAGE_NUMBER)pr_debug("PM:freesomememory'n");shrink_all_memory(FREE_PAGE_NUMBER-free_pages);if(nr_free_pages()<FREE_PAGE_NUMBER)-error=-ENOMEM;printk(KERN_ERR&quo

30、t;PM:Noenoughmemory'n");-if(!error)return0;Thaw:suspend_thaw_processes();usermodehelper_enable();Finish:pm_notifier_call_chain(PM_POST_SUSPEND);pm_restore_console();returnerror;在suspend_freeze_processes(函數(shù)中調(diào)用了freeze_processes()函數(shù),而freeze_processes()函數(shù)中又調(diào)用了try_to_freeze_tasks()來完成凍結(jié)任務(wù)。在凍結(jié)過程中

31、,會判斷當前進程是否有wake_lock,若有,則凍結(jié)失敗,函數(shù)會放棄凍結(jié)。staticinttry_to_freeze_tasks(boolsig_only)""-structtask_struct*g,*p;unsignedlongend_time;unsignedinttodo;structtimevalstart,end;u64elapsed_csecs64;unsignedintelapsed_csecs;unsignedintwakeup=0;do_gettimeofday(&start);end_time=jiffies+TIMEOUT;dotodo=

32、0;readock(&tasklist_lock);do_each_thread(g,p)if(frozen(p)|!freezeable(p)continue;if(!freeze_task(p,sig_only)continue;/* Nowthatwe'vedoneset_freeze_flag,don't* perturbataskinTASK_STOPPEDorTASK_TRACED.* Itis"frozenenough".Ifthetaskdoeswake* up,itwillimmediatelycalltry_to_freeze.*

33、/if(!task_is_stopped_or_traced(p)&&!freezer_should_skip(p)todo+;while_each_thread(g,p);read_unlock(&tasklist_lock);yield();/*Yieldisokayhere*/if(todo&&has_wake_lock(WAKE_LOCK_SUSPEND)wakeup=1;break;if(time_after(jiffies,end_time)break;while(todo);do_gettimeofday(&end);elapsed

34、_csecs64=timeval_to_ns(&end)-timeval_to_ns(&start);do_div(elapsed_csecs64,NSEC_PER_SEC/100);elapsed_csecs=elapsed_csecs64;if(todo)/*Thisdoesnotunfreezeprocessesthatarealreadyfrozen* (wehaveslightlyuglycallingconventioninthatrespect,* andcallermustcallthaw_processes()ifsomethingfails),* butit

35、cleansupleftoverPF_FREEZErequests.*/-if(wakeup)printk("n");printk(KERN_ERR"Freezingof%sabortedn",sig_only?"userspace":"tasks");-elseprintk("n");printk(KERN_ERR"Freezingoftasksfailedafter%d.%02dseconds""(%dtasksrefusingtofreeze):n"

36、,elapsed_csecs/100,elapsed_csecs%100,todo);show_state();-readock(&tasklist_lock);do_each_thread(g,p)task_lock(p);if(freezing(p)&&!freezer_should_skip(p)printk(KERN_ERR"%sn",p->comm);cancel_freezing(p);task_uniock(p);while_each_thread(g,p);read_unlock(&tasklist_lock);else

37、printk("(elapsed%d.%02dseconds)",elapsed_csecs/100,elapsed_csecs%100);-returntodo?-EBUSY:0;到現(xiàn)在,所有的進程(也包括workqueue/kthread)都已經(jīng)停止了,內(nèi)核態(tài)進程有可能在停止的時候握有一些信號量,所以如果這時候在外設(shè)里面去解鎖這個信號量有可能會發(fā)生死鎖,所以在外設(shè)suspend()函數(shù)里面作lock/unlock鎖要非常小心,建議不要在外設(shè)的suspend()里面等待鎖。而且suspend的過程中,有一些log是無法輸出的,所以一旦出現(xiàn)問題,非常難調(diào)試。回到enter_

38、state()函數(shù)中,再凍結(jié)進程完成后,調(diào)用suspend_devices_and_enter()函數(shù)讓外設(shè)進入休眠。該函數(shù)中,首先休眠串口(之后不能再顯示log,解決方法為在kernel配置選項的cmdine中,添加”o_console_suspend"選項),再通過device_suspend()函數(shù)調(diào)用各驅(qū)動的suspend函數(shù)。當外設(shè)進入休眠后,suspend_ops->prepare()被調(diào)用,suspend_ops是板級的PM操作(本文中粉紅色的函數(shù),依賴于具體的平臺),以S3C6410為例,其注冊在linux_source/arch/arm/plat-s3c64x

39、x/pm.c中,只定義了suspend_ops->enter()函數(shù)。staticstructplatform_suspend_opss3c6410_pm_ops=.enter=s3c6410_pm_enter,.valid=suspend_valid_only_mem,;-接下來,多CPU中的非啟動CPU被關(guān)閉。intsuspend_devices_and_enter(suspend_state_tstate)-interror;if(!suspend_ops)return-ENOSYS;if(suspend_ops->begin)error=suspend_ops->be

40、gin(state);if(error)gotoClose;suspend_console();suspend_test_start();error=device_suspend(PMSG_SUSPEND);if(error)printk(KERN_ERR"PM:Somedevicesfailedtosuspendn");gotoRecover_platform;-suspend_test_finish("suspenddevices");if(suspend_test(TEST_DEVICES)gotoRecover_platform;if(suspe

41、nd_ops->prepare)error=suspend_ops->prepare();if(error)gotoResume_devices;-if(suspend_test(TEST_PLATFORM)gotoFinish;error=disable_nonboot_cpus();if(!error&&!suspend_test(TEST_CPUS)suspend_enter(state);enable_nonboot_cpus();Finish:if(suspend_ops->finish)suspend_ops->finish();Resume

42、_devices:suspend_test_start();device_resume(PMSG_RESUME);suspend_test_finish("resumedevices");resume_console();Close:if(suspend_ops->end)suspend_ops->end();returnerror;Recover_platform:if(suspend_ops->recover)suspend_ops->recover();gotoResume_devices;-接下來suspend_enter()被調(diào)用,該函數(shù)首

43、先關(guān)閉IRQ,然后調(diào)用device_power_down(),它會調(diào)用suspend_late()函數(shù),這個函數(shù)是系統(tǒng)真正進入休眠最后調(diào)用的函數(shù),通常會在這個函數(shù)中作最后的檢查,接下來休眠所有的系統(tǒng)設(shè)備和總線。最后調(diào)用suspend_pos->enter()來使CPU進入省電狀態(tài)。這時候,整個休眠過程完成,代碼的執(zhí)行也就停在這里了。staticintsuspend_enter(suspend_state_tstate)-interror=0;device_pm_lock();#ifdefcOnFG_CPU_FREQcpufreq_get_cpufreq_name(0);strcpy(go

44、vernor_name,cpufreq_governor_name);if(strnicmp(governor_name,userspace_governor,CPUFREQ_NAME_LEN)cpufreq_set_policy(0,"performanee");-#endif/*CONFIG_CPU_FREQ*/arch_suspend_disable_irqs();BUG_ON(!irqs_disabled();if(error=device_power_down(PMSG_SUSPEND)printk(KERN_ERR"PM:Somedevicesfail

45、edtopowerdownn");gotoDone;error=sysdev_suspend(PMSG_SUSPEND);if(!error)if(!suspend_test(TEST_CORE)error=suspend_ops->enter(state);sysdev_resume();-device_power_up(PMSG_RESUME);Done:arch_suspend_enable_irqs();#ifdefCONFIG_CPU_FREQif(strnicmp(governor_name,userspace_governor,CPUFREQ_NAME_LEN)c

46、pufreq_set_policy(0,governor_name);-#endif/*CONFIG_CPU_FREQ*/BUG_ON(irqs_disabled();device_pm_uniock();returnerror;在suspend_pos->enter()所對應(yīng)的函數(shù)中,代碼最終停止在pm_cpu_sleep();處。staticints3c6410_pm_enter(suspend_state_tstate)-s3c6410_pm_do_save(gpio_save,ARRAY_SIZE(gpio_save);s3c6410_pm_do_save(irq_save,AR

47、RAY_SIZE(irq_save);s3c6410_pm_do_save(core_save,ARRAY_SIZE(core_save);s3c6410_pm_do_save(sromc_save,ARRAY_SIZE(sromc_save);/*ClearWAKEUP_STATregisterfornextwakeup-jc.lee*/*Ifthisregisterdonotbecleared,Wakeupwillbefailed*/_raw_writel(_raw_readl(S3C_WAKEUP_STAT),S3C_WAKEUP_STAT);#ifdefCONFIG_MACH_SMDK

48、6410/*ALLsubblock"ON"beforeenterringsleepmode-EVT0bug*/_raw_writel(0xffffff00,S3C_NORMAL_CFG);/*Openallclockgatetoentersleepmode-EVT0bug*/_raw_writel(0xffffffff,S3C_HCLK_GATE);_raw_writel(0xffffffff,S3C_PCLK_GATE);_raw_writel(0xffffffff,S3C_SCLK_GATE);/*s3c6410_cpu_savewillalsoactasourretu

49、rnpointfromwhen* weresumeasitsavesitsownregisterstate,sousethereturn* codetodifferentiatereturnfromsaveandreturnfromsleep*/if(s3c6410_cpu_save(regs_save)=0)flush_cache_all();pm_cpu_sleep();-/*restorethecpustate*/cpu_init();_raw_writel(s3c_eint_mask_val,S3C_EINT_MASK);/*restorethesystemstate*/s3c6410_pm_do_restore_core(core_save,ARRAY_SIZE(core_save);s3c6410_pm_do_restore(sromc_save,ARRAY_SIZE(sromc_save);Android喚醒過程如下:如果在休眠中系統(tǒng)被中斷或者其他

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
  • 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論