1. framework層
1.1 java層
休眠流程中上層有很多種,比如按power key進入休眠流程,還是就是settings下面的自動息屏流程。
1.1.1 power key休眠流程
當用戶按下power key的時候,PhoneWindowManager類下的interceptBeforeQueueing, 在handle special key流程中,會命中KeyEvent.KEYCODE_POWER.
其業務邏輯里面就會調用到inteceptPowerKeyDown和interceptPowerKeyUp, 而休眠流程的起始條件,滅屏流程就是從這個interceptPowerKeyUp開始的。之后會就interceptPowerKeyUp展開,
但我們先來看下從key event發出后,怎么走到interceptBeforeQueueing的,這里主要看下framework層的獲得key event事件后響應流程,至於key event事件怎么分發的和怎么獲得的 需要InuptDispatcher(inputFlinger)部分來分析,之后有時間再補充。
com_android_server_input_InputManagerService.cpp在收到InputDispatcher分發的出來PowerKey 事件之后,就會走到NativeInputManager::dispatchUnhandledKey方法,
這里方法里通過回調的機制回調到InputManagerService.java下面的native方法dispatchUnhandleKey,注意這個方法是回調方法。然后在調到InputManagerCallback下面的dispatchUnhandleKey,
然后再調到PhoneWindowManager下面的dispatchUnhandleKey方法, 然后調到interceptFallback方法,最終從這里面調到interceptBeforeQueueing這個方法。
(類似的,ARN機制里面關於framework的一部分流程也是通過InputManagerService實現的,從native類com_android_server_input_InputManagerService.cpp的notifyANR通過反射開始回調java的方法InputManagerService類下的notifyANR方法,當然通信機制還是Binder了)。
interceptPowerKeyUp流程展開,這里方法里會調用powerPress這個方法,源碼如下
1 private void interceptPowerKeyUp(KeyEvent event, boolean interactive, boolean canceled) { 2 ...
3 if (!handled) {
5 ...
6 // Figure out how to handle the key now that it has been released.
7 mPowerKeyPressCounter += 1; 8
9 final int maxCount = getMaxMultiPressPowerCount(); 10 final long eventTime = event.getDownTime(); 11 if (mPowerKeyPressCounter < maxCount) { 12 // This could be a multi-press. Wait a little bit longer to confirm. 13 // Continue holding the wake lock.
14 Message msg = mHandler.obtainMessage(MSG_POWER_DELAYED_PRESS, 15 interactive ? 1 : 0, mPowerKeyPressCounter, eventTime); 16 msg.setAsynchronous(true); 17 mHandler.sendMessageDelayed(msg, ViewConfiguration.getMultiPressTimeout()); 18 return; 19 } 20
21 // No other actions. Handle it immediately.
22 powerPress(eventTime, interactive, mPowerKeyPressCounter);/*這里開始滅屏流程*/ 23 } 24
25 // Done. Reset our state.
26 finishPowerKeyPress(); 27 }
powerPress主要實現的是根據power key按鍵次數來決定走什么流程,當按1次的時候走的是goToSleepFromPowerButton(), 其中SHORT_PRESS_POWER_GO_TO_SLEEP走doze流程,
SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP走的是直接sleep的流程,還有按power key喚醒到到home的流程也走這里。
1 private void powerPress(long eventTime, boolean interactive, int count) { 2 ... 3 4 if (count == 2) { 5 powerMultiPressAction(eventTime, interactive, mDoublePressOnPowerBehavior); 6 } else if (count == 3) { 7 powerMultiPressAction(eventTime, interactive, mTriplePressOnPowerBehavior); 8 } else if (interactive && !mBeganFromNonInteractive) { 9 switch (mShortPressOnPowerBehavior) { 10 case SHORT_PRESS_POWER_NOTHING: 11 break; 12 case SHORT_PRESS_POWER_GO_TO_SLEEP: 13 goToSleepFromPowerButton(eventTime, 0);//走DOZE流程 14 break; 15 case SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP: 16 goToSleepFromPowerButton(eventTime, PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE);//直接走sleep流程 17 break; 18 case SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP_AND_GO_HOME: 19 if (goToSleepFromPowerButton(eventTime, 20 PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE)) { 21 launchHomeFromHotKey(DEFAULT_DISPLAY); 22 } 23 break; 24 case SHORT_PRESS_POWER_GO_HOME: 25 shortPressPowerGoHome(); 26 break; 27 case SHORT_PRESS_POWER_CLOSE_IME_OR_GO_HOME: { 28 if (mDismissImeOnBackKeyPressed) { 29 if (mInputMethodManagerInternal == null) { 30 mInputMethodManagerInternal = 31 LocalServices.getService(InputMethodManagerInternal.class); 32 } 33 if (mInputMethodManagerInternal != null) { 34 mInputMethodManagerInternal.hideCurrentInputMethod(); 35 } 36 } else { 37 shortPressPowerGoHome(); 38 } 39 break; 40 } 41 } 42 } 43 }
接下來就通過2段代碼調了PMS的goToSleep方法
1 /** 2 * Sends the device to sleep as a result of a power button press. 3 * 4 * @return True if the was device was sent to sleep, false if sleep was suppressed. 5 */ 6 private boolean goToSleepFromPowerButton(long eventTime, int flags) { 7 // Before we actually go to sleep, we check the last wakeup reason. 8 // If the device very recently woke up from a gesture (like user lifting their device) 9 // then ignore the sleep instruction. This is because users have developed 10 // a tendency to hit the power button immediately when they pick up their device, and we 11 // don't want to put the device back to sleep in those cases. 12 final PowerManager.WakeData lastWakeUp = mPowerManagerInternal.getLastWakeup(); 13 if (lastWakeUp != null && lastWakeUp.wakeReason == PowerManager.WAKE_REASON_GESTURE) { 14 final int gestureDelayMillis = Settings.Global.getInt(mContext.getContentResolver(), 15 Settings.Global.POWER_BUTTON_SUPPRESSION_DELAY_AFTER_GESTURE_WAKE, 16 POWER_BUTTON_SUPPRESSION_DELAY_DEFAULT_MILLIS); 17 final long now = SystemClock.uptimeMillis(); 18 if (mPowerButtonSuppressionDelayMillis > 0 19 && (now < lastWakeUp.wakeTime + mPowerButtonSuppressionDelayMillis)) { 20 Slog.i(TAG, "Sleep from power button suppressed. Time since gesture: " 21 + (now - lastWakeUp.wakeTime) + "ms"); 22 return false; 23 } 24 } 25 26 goToSleep(eventTime, PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, flags); 27 return true; 28 }
private void goToSleep(long eventTime, int reason, int flags) {
mRequestedOrGoingToSleep = true;
mPowerManager.goToSleep(eventTime, reason, flags);
}
1 //PowerManager.java 2 public void goToSleep(long time, int reason, int flags) { 3 try { 4 mService.goToSleep(time, reason, flags); 5 } catch (RemoteException e) { 6 throw e.rethrowFromSystemServer(); 7 } 8 }
@Override // Binder call
public void goToSleep(long eventTime, int reason, int flags) {
if (eventTime > SystemClock.uptimeMillis()) {
throw new IllegalArgumentException("event time must not be in the future");
}
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.DEVICE_POWER, null);
final int uid = Binder.getCallingUid();
final long ident = Binder.clearCallingIdentity();
try {
goToSleepInternal(eventTime, reason, flags, uid);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
private void goToSleepInternal(long eventTime, int reason, int flags, int uid) {
synchronized (mLock) {
if (goToSleepNoUpdateLocked(eventTime, reason, flags, uid)) {
updatePowerStateLocked();
}
}
}
到此,可以看出PowerManager.java下的updatePowerStateLocked是一個統一的接口,也PMS的核心方法,也就是無論是按power key休眠還是自動息屏休眠,都會走到這里。
之后的流程本文后面統一分析,先看自動息屏流程。
1.1.2 自動息屏流程
為什么會自動息屏,簡單的理解就是用戶長時間內沒有跟設備進行交互,然后觸發了自動息屏流程。
自動休眠流程從PMS初始化開始就執行這個核心方法,這個方法又會去調updateUserActivitySummaryLocked,正是這個方法去計算用戶沒有響應的時間,當沒有相應的時間
達到用戶設置的息屏時間時,就設置mUserActivitySummary 為USER_ACTIVITY_SCREEN_DIM,再設置成USER_ACTIVITY_SCREEN_DREAM,最后設置成0。mUserActivitySummary為0時就會觸發updatePowerStateLocked里的休眠流程了,也就是updateSuspendBlockerLocked。
額外提一下,與power key 的上報事件流程類似, userAcivity也是類似從底層開始接受用戶跟設備的交互事件,這里直接從JAVA層開始講,PMS有這樣一個native方法userActivityFromNative。
1.1.3 updateSuspendBlockerLocked
1 /** 2 * Updates the suspend blocker that keeps the CPU alive. 3 * 4 * This function must have no other side-effects. 5 */ 6 private void updateSuspendBlockerLocked() {11 12 // Disable auto-suspend if needed. 13 // FIXME We should consider just leaving auto-suspend enabled forever since 14 // we already hold the necessary wakelocks. 15 if (!autoSuspend && mDecoupleHalAutoSuspendModeFromDisplayConfig) { 16 setHalAutoSuspendModeLocked(false); 17 } 18 19 // First acquire suspend blockers if needed. 20 if (needWakeLockSuspendBlocker && !mHoldingWakeLockSuspendBlocker) { 21 mWakeLockSuspendBlocker.acquire(); 22 mHoldingWakeLockSuspendBlocker = true; 23 } 24 if (needDisplaySuspendBlocker && !mHoldingDisplaySuspendBlocker) { 25 mDisplaySuspendBlocker.acquire(); 26 mHoldingDisplaySuspendBlocker = true; 27 } 28 29 // Inform the power HAL about interactive mode. 30 // Although we could set interactive strictly based on the wakefulness 31 // as reported by isInteractive(), it is actually more desirable to track 32 // the display policy state instead so that the interactive state observed 33 // by the HAL more accurately tracks transitions between AWAKE and DOZING. 34 // Refer to getDesiredScreenPolicyLocked() for details. 35 if (mDecoupleHalInteractiveModeFromDisplayConfig) { 36 // When becoming non-interactive, we want to defer sending this signal 37 // until the display is actually ready so that all transitions have 38 // completed. This is probably a good sign that things have gotten 39 // too tangled over here... 40 if (interactive || mDisplayReady) { 41 setHalInteractiveModeLocked(interactive); 42 } 43 } 44 45 // Then release suspend blockers if needed. 46 if (!needWakeLockSuspendBlocker && mHoldingWakeLockSuspendBlocker) { 47 mWakeLockSuspendBlocker.release(); 48 mHoldingWakeLockSuspendBlocker = false; 49 } 50 if (!needDisplaySuspendBlocker && mHoldingDisplaySuspendBlocker) { 51 mDisplaySuspendBlocker.release(); 52 mHoldingDisplaySuspendBlocker = false; 53 } 54 55 // Enable auto-suspend if needed. 56 if (autoSuspend && mDecoupleHalAutoSuspendModeFromDisplayConfig) { 57 setHalAutoSuspendModeLocked(true); 58 } 59 }
1 /** Wrapper for PowerManager.nativeSetAutoSuspend */ 2 public void nativeSetAutoSuspend(boolean enable) { 3 PowerManagerService.nativeSetAutoSuspend(enable); 4 }
setHalAutoSuspendModeLocked 最終調用到了native方法nativeSetAutoSuspend。
1.2 native層
從native層開始,不管是power key鍵還是自動息屏休眠流程,都走的是nativeSetAutoSuspend, 別誤以為autosuspend就是自動息屏休眠。autosuspend是android對linux源生suspend機制的補充。
從源碼里可以看到從java傳下來的enable參數是true的時候,它就去enblesuspend,如果是false,就去申請鎖。同時這個鎖會在enable為true的時候去釋放,所以不影響休眠流程。
1 static void nativeSetAutoSuspend(JNIEnv* /* env */, jclass /* clazz */, jboolean enable) { 2 if (enable) { 3 enableAutoSuspend(); 4 } 5 } else { 6 disableAutoSuspend(); 7 } 8 } 9 } 10 11 void enableAutoSuspend() { 12 static bool enabled = false; 13 if (!enabled) { 14 sp<ISuspendControlService> suspendControl = getSuspendControl(); 15 suspendControl->enableAutosuspend(&enabled); 16 } 17 18 { 19 std::lock_guard<std::mutex> lock(gSuspendMutex); 20 if (gSuspendBlocker) { 21 gSuspendBlocker->release(); 22 gSuspendBlocker.clear(); 23 } 24 } 25 } 26 27 void disableAutoSuspend() { 28 std::lock_guard<std::mutex> lock(gSuspendMutex); 29 if (!gSuspendBlocker) { 30 sp<ISystemSuspend> suspendHal = getSuspendHal(); 31 gSuspendBlocker = suspendHal->acquireWakeLock(WakeLockType::PARTIAL, 32 "PowerManager.SuspendLockout"); 33 } 34 }
接下來再來看源碼,這個suspendControl->enableAutosuspend(&enabled); 是調用哪里的方法
1 void SuspendControlService::setSuspendService(const wp<SystemSuspend>& suspend) { 2 mSuspend = suspend; 3 } 4 5 binder::Status SuspendControlService::enableAutosuspend(bool* _aidl_return) { 6 const auto suspendService = mSuspend.promote(); 7 return retOk(suspendService != nullptr && suspendService->enableAutosuspend(), _aidl_return); 8 }
bool SystemSuspend::enableAutosuspend() {
static bool initialized = false;
if (initialized) {
LOG(ERROR) << "Autosuspend already started.";
return false;
}
initAutosuspend();
initialized = true;
return true;
}
所以最終調到了SystemSuspend.cpp下的enableAutosuspend函數。
來詳細看下initAutosuspend方法
1 void SystemSuspend::initAutosuspend() { 2 std::thread autosuspendThread([this] { 3 while (true) { 4 std::this_thread::sleep_for(mSleepTime); 5 lseek(mWakeupCountFd, 0, SEEK_SET); 6 const string wakeupCount = readFd(mWakeupCountFd); 7 8 auto counterLock = std::unique_lock(mCounterLock); 9 mCounterCondVar.wait(counterLock, [this] { return mSuspendCounter == 0; }); 10 // The mutex is locked and *MUST* remain locked until we write to /sys/power/state. 11 // Otherwise, a WakeLock might be acquired after we check mSuspendCounter and before we 12 // write to /sys/power/state. 13 14 if (!WriteStringToFd(wakeupCount, mWakeupCountFd)) { 15 PLOG(VERBOSE) << "error writing from /sys/power/wakeup_count"; 16 continue; 17 } 18 bool success = WriteStringToFd(kSleepState, mStateFd); 19 counterLock.unlock(); 20 21 mControlService->notifyWakeup(success); 22 23 updateSleepTime(success); 24 } 25 }); 26 autosuspendThread.detach(); 27 LOG(INFO) << "automatic system suspend enabled"; 28 }
實際上就是去寫了2個節點文件,"/sys/power/wakeup_count", "/sys/power/state", 當echo "mem" > /sys/power/state 且 "/sys/power/wakeup_count" 等於0的時候,系統就會進入suspend。
所以android本身就做了一些wrap, 只要上層能夠實現上面這2個條件,系統就會進入suspend狀態。而這些wrap就是kernel層的休眠機制,第2章接着講。
在講kernel休眠機制之前,先來總結下native層的框架,native層也采用RPC通信機制,也用到aidl接口。
實際上,com_android_server_power_PowerManagerService這個是這個機制中的客戶端,而SuspendControlService是這個機制的服務端,他是對ISuspendControlService.aidl接口的具體實現。
這個服務端中又調用到了一個HAL的具體實現類SystemSuspend.cpp,它可以理解為是硬件的一個具體模塊類。大致調用關系圖如下
2. kernel層
2.1 kernel休眠機制簡介
Android在Linux內核原有的睡眠喚醒模塊上基礎上,主要增加了下面三個機制:
Wake _Lock 喚醒鎖機制;
Early _Suspend 預掛起機制;
Late _Resume 遲喚醒機制;
其基本原理如下:
當啟動一個應用程序的時候,它都可以申請一個wake_lock喚醒鎖,每當申請成功之后都會在內核中注冊一下(通知系統內核,現在已經有鎖被申請),當應用程序在某種情況下釋放wake_lock的時候,會注銷之前所申請的wake_lock。特別要注意的是:只要是系統中有一個wake_lock的時候,系統此時都不能進行睡眠。但此時各個模塊可以進行early_suspend。當系統中所有的wake_lock都被釋放之后,系統就會進入真正的kernel的睡眠狀態。在系統啟動的時候會創建一個主喚醒鎖main_wake_lock,該鎖是內核初始化並持有的一個WAKE_LOCK_SUSPEND屬性的非限時喚醒鎖。因此,系統正常工作時,將始終因為該鎖被內核持有而無法進入睡眠狀態。也就是說在不添加新鎖的情況下,只需將main_wake_lock 解鎖,系統即可進入睡眠狀態。
結構圖如下:
在標准Linux中,休眠主要分三個主要的步驟:(1)凍結用戶態進程和內核態任務;(2)調用注冊的設備的suspend的回調函數,其調用順序是按照驅動加載時的注冊順序。(3)休眠核心設備和使CPU進入休眠態凍結進程是內核把進程列表中所有的進程的狀態都設置為停止,並且保存下所有進程的上下文。這個動作在android中也是有的。
備注:在andoird 早些時間的之前這些寫節點操作是libsuspend庫中完成的,具體目錄如下:
system/core/libsuspend/autosuspend.c
system/core/libsuspend/autosuspend_wakeup_count.c
2.2 休眠流程分析
講流程之前,先將kernel節點文件的創建。
2.2.1 /sys/power/state的創建
節點文件的創建在kernel/kernel/power/main.c中實現,
1)sys/power/state節點生成
1 #define power_attr(_name) \ 2 static struct kobj_attribute _name##_attr = { \ 3 .attr = { \ 4 .name = __stringify(_name), \ 5 .mode = 0644, \ 6 }, \ 7 .show = _name##_show, \ 8 .store = _name##_store, \ 9 } 10 11 power_attr(state); 12 13 static struct attribute * g[] = { 14 &state_attr.attr, 15 NULL, 16 }; 17 18 static struct attribute_group attr_group = { 19 .attrs = g, 20 }; 21 static int __init pm_init(void) 22 { 23 power_kobj = kobject_create_and_add("power", NULL); 24 if (!power_kobj) 25 return -ENOMEM; 26 error = sysfs_create_group(power_kobj, &attr_group); 27 28 } 29 30 core_initcall(pm_init);
2.2.2 /sys/power/wakeup_count的讀寫
這部分內容是用來記錄和讀取wakeup_count的次數,也在kernel/kernel/power/main.c中實現,后續詳細補充。
2.2.3 kernel流程
在framework層已經執行到寫"/sys/power/state"這個動作,那就會觸發kernel里面的邏輯,也就是節點文件store邏輯。
1 static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,const char *buf, size_t n) 2 { 3 state = decode_state(buf, n);//將"mem"轉換成對應的數字 4 error = pm_suspend(state);//這里才是真正開啟kernel的休眠流程 5 }
1 int pm_suspend(suspend_state_t state) 2 { 3 pm_suspend_marker("entry"); 4 error = enter_state(state); 5 pm_suspend_marker("exit"); 6 } 7 8 static void pm_suspend_marker(char *annotation) 9 { 10 struct timespec ts; 11 struct rtc_time tm; 12 13 getnstimeofday(&ts); 14 rtc_time_to_tm(ts.tv_sec, &tm); 15 pr_info("PM: suspend %s %d-%02d-%02d %02d:%02d:%02d.%09lu UTC\n", 16 annotation, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, 17 tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec); 18 } 19 20 static int enter_state(suspend_state_t state) 21 { 22 printk(KERN_INFO "PM: Syncing filesystems ... "); 23 sys_sync(); 24 printk("done.\n"); 25 26 pr_debug("PM: Preparing system for %s sleep\n", pm_states[state]); 27 error = suspend_prepare(state); 28 29 pr_debug("PM: Entering %s sleep\n", pm_states[state]); 30 pm_restrict_gfp_mask(); 31 error = suspend_devices_and_enter(state); 32 pm_restore_gfp_mask(); 33 34 Finish: 35 pr_debug("PM: Finishing wakeup.\n"); 36 suspend_finish(); 37 }
//在suspend_prepare的時候去 凍結cpu的中的任務
static int suspend_prepare(suspend_state_t state) { if (need_suspend_ops(state) && (!suspend_ops || !suspend_ops->enter)) //kernel/drivers/cpuidle/lpm-levels.c suspend_set_ops(&lpm_suspend_ops); return -EPERM; error = pm_notifier_call_chain(PM_SUSPEND_PREPARE); error = suspend_freeze_processes(); pm_notifier_call_chain(PM_POST_SUSPEND); return error; } static inline int suspend_freeze_processes(void) { error = freeze_processes(); error = freeze_kernel_threads(); }
//然后去suspend一些外設,最后走suspend_enter流程。
int suspend_devices_and_enter(suspend_state_t state) { int error; bool wakeup = false; if (need_suspend_ops(state) && !suspend_ops) return -ENOSYS; if (need_suspend_ops(state) && suspend_ops->begin) { error = suspend_ops->begin(state);//lpm相關的 if (error) goto Close; } suspend_console(); error = dpm_suspend_start(PMSG_SUSPEND);//dpm相關的 if (error) { printk(KERN_ERR "PM: Some devices failed to suspend\n"); goto Recover_platform; } suspend_test_finish("suspend devices"); if (suspend_test(TEST_DEVICES)) goto Recover_platform; do { error = suspend_enter(state, &wakeup); //正常休眠會停在該函數,如果喚醒了,則走下面的流程 } while (!error && !wakeup && need_suspend_ops(state) && suspend_ops->suspend_again && suspend_ops->suspend_again()); Resume_devices: dpm_resume_end(PMSG_RESUME);//dpm相關的 resume_console(); Close: if (need_suspend_ops(state) && suspend_ops->end) suspend_ops->end();//lpm相關的 return error; Recover_platform: if (need_suspend_ops(state) && suspend_ops->recover) suspend_ops->recover();//lpm相關的 goto Resume_devices; }
1 static int suspend_enter(suspend_state_t state, bool *wakeup) 2 { 3 error = dpm_suspend_end(PMSG_SUSPEND);//dpm相關的 4 error = disable_nonboot_cpus(); 5 arch_suspend_disable_irqs(); 6 error = syscore_suspend(); 7 if (!error) { 8 *wakeup = pm_wakeup_pending(); 9 if (!(suspend_test(TEST_CORE) || *wakeup)) { 10 error = suspend_ops->enter(state);//停在這.......... 11 events_check_enabled = false; 12 } 13 syscore_resume(); 14 } 15 arch_suspend_enable_irqs(); 16 Enable_cpus: 17 enable_nonboot_cpus(); 18 19 Platform_wake: 20 if (need_suspend_ops(state) && suspend_ops->wake) 21 suspend_ops->wake();//lpm相關的 22 23 dpm_resume_start(PMSG_RESUME);//dpm相關的 24 25 Platform_finish: 26 if (need_suspend_ops(state) && suspend_ops->finish) 27 suspend_ops->finish(); //lpm相關的 28 29 return error; 30 31 }
//這2個函數都會走到dpm里面的一些電源管理函數的邏輯和drive的里面的lpm相關的邏輯,
1 int dpm_suspend_start(pm_message_t state) 2 { 3 dpm_prepare(state); //prepare dpm_list 4 dpm_suspend(state); //suspend dpm_prepared_list 5 } 6 7 int dpm_suspend_end(pm_message_t state) 8 { 9 dpm_suspend_late(state); //suspend_late dpm_suspended_list 10 dpm_suspend_noirq(state); //suspend_noirq dpm_late_early_list 11 } 12 13 void dpm_resume_start(pm_message_t state) 14 { 15 dpm_resume_noirq(state); //resume_noirq 16 dpm_resume_early(state); //resume_early 17 } 18 19 void dpm_resume_end(pm_message_t state) 20 { 21 dpm_resume(state); //resume 22 dpm_complete(state);//complete 23 }
1 struct dev_pm_ops { 2 int (*prepare)(struct device *dev); 3 void (*complete)(struct device *dev); 4 int (*suspend)(struct device *dev); 5 int (*resume)(struct device *dev); 6 int (*freeze)(struct device *dev); 7 int (*thaw)(struct device *dev); 8 int (*poweroff)(struct device *dev); 9 int (*restore)(struct device *dev); 10 int (*suspend_late)(struct device *dev); 11 int (*resume_early)(struct device *dev); 12 int (*freeze_late)(struct device *dev); 13 int (*thaw_early)(struct device *dev); 14 int (*poweroff_late)(struct device *dev); 15 int (*restore_early)(struct device *dev); 16 int (*suspend_noirq)(struct device *dev); 17 int (*resume_noirq)(struct device *dev); 18 int (*freeze_noirq)(struct device *dev); 19 int (*thaw_noirq)(struct device *dev); 20 int (*poweroff_noirq)(struct device *dev); 21 int (*restore_noirq)(struct device *dev); 22 int (*runtime_suspend)(struct device *dev); 23 int (*runtime_resume)(struct device *dev); 24 int (*runtime_idle)(struct device *dev); 25 26 };
1 如 2 3 static const struct dev_pm_ops goodix_ts_dev_pm_ops = { 4 .suspend = goodix_ts_suspend, 5 .resume = goodix_ts_resume, 6 };
類dpm函數的作用是按順序執行相關的電源函數.
休眠prepare--->suspend--->suspend_late--->suspend_noirq
喚醒resume_noirq--->resume_early--->resume--->complete
//而且讓cpu休眠的流程在cpuidle的驅動中實現,也就是lpm, kernel/drivers/cpuidle/lpm-levels.c。
1 static int lpm_probe(struct platform_device *pdev) 2 { 3 suspend_set_ops(&lpm_suspend_ops); 4 } 5 6 static const struct platform_suspend_ops lpm_suspend_ops = { 7 .enter = lpm_suspend_enter, 8 .valid = suspend_valid_only_mem, 9 .prepare_late = lpm_suspend_prepare, 10 .wake = lpm_suspend_wake, 11 };
kernel/kernel/power/suspend.c
1 void suspend_set_ops(const struct platform_suspend_ops *ops) 2 { 3 suspend_ops = ops; 4 }