赞
踩
之前博客说了CarPower的开机启动流程
这里分析一下,Android CarPower实现深度睡眠的流程。
首先,什么是深度睡眠(Deep Sleep)?
Android进入Deep Sleep后,关闭屏幕、关闭CPU的电源,保持RAM的电源(激活状态)。深度睡眠会进行Suspend-to-RAM挂起到内存(做车载的经常会听到的STR)。当然深度睡眠,还有一种方式是挂起到硬盘(Suspend-to-Disk),不过目前主要用的是STR。STR指的是深度睡眠时的状态,但STR不等于深度睡眠。
DeepSleep或STR,需要内核配合实现。通过这种技术,车载系统可以进入低能耗模式,同时又可以再用户需要时实现快速(非常快,因为从内存中恢复状态)的启动。
感觉这种方式,跟snapshot快启动有点类似。不过是两个概念上的事情了。
下面摘自Android官网对这种状态的介绍。
也称为“挂起到 RAM”(S2R 或 STR)。将 SoC 置于 S3 电源模式,CPU 断电而 RAM 仍通电。
VMCU 应将 SoC 置于“深度睡眠”状态,并断开应用处理器的电源。然后,AAOS 将进入“挂起到 RAM”状态,但不执行任何代码。
整套深度睡眠的实现,涉及的主要模块(这里指单Android系统。当前还有Qnx之类的hypervisor)
下面是摘自Android官网的深入睡眠流程描述;
只有 VMCU 可以启动深度睡眠。启动深度睡眠后,VMCU 会通过 VHAL 向 CPMS 发送通知。CPMS 通过使用由 CPM 提供的新状态 ID 调用 onStateChanged() 方法,将状态更改为“关闭准备”并向所有观察者(监控 CPMS 的应用和服务)广播此状态转换。
CPM 在应用/服务与 CPMS 之间进行协调。在 CPM 的 onStateChanged() 方法中,同步调用应用/服务的
onStateChanged() 方法。大多数应用和服务需要完成其准备后才能从该调用返回。特权服务可以在为
PRE_SHUTDOWN_PREPARE、SUSPEND_ENTER 和 POST_SUSPEND_ENTER
返回后,异步继续关闭准备。在此情况下,特权服务应在完成准备时对提供的 CompletablePowerStateChangeFuture
对象调用 complete()。请注意,SHUTDOWN_PREPARE 不允许异步准备。在向 VHAL 发送
DEEP_SLEEP_ENTRY 之前,CPMS 会定期向 VHAL 发送推迟关闭的请求。
当所有 CPM 对象完成关闭准备后,CPMS 会向 VHAL 发送 AP_POWER_STATE_REPORT,VHAL 随后通知
VMCU,告知它 AP 已准备好挂起。CPMS 还会调用其挂起方法以挂起内核。
下面的图,是Android官网对于深度睡眠的时序图。这里贴在这里。后面会根据源码,分析并画一个跟代码对应的时序图。
首先,VMCU请求挂起。Vehicle HAL (Hal层的nativeservice)发送“AP_POWER_STATE_REQ(SHUTDOWN_PREPARE)”, 这样CarService中的 VehicleHal(Client端 )就收到了这个通知。一路通知给CPMS进行状态处理。
public void onPropertyEvent(ArrayList<VehiclePropValue> propValues) {
// 省略
for (HalServiceBase s : mServicesToDispatch) {
// 通知给监听者
s.onHalEvents(s.getDispatchList());
s.getDispatchList().clear();
}
mServicesToDispatch.clear();
}
@Override public void onHalEvents(List<VehiclePropValue> values) { // 省略 dispatchEvents(values, listener); } private void dispatchEvents(List<VehiclePropValue> values, PowerEventListener listener) { for (VehiclePropValue v : values) { switch (v.prop) { case AP_POWER_STATE_REPORT: // Ignore this property event. It was generated inside of CarService. break; case AP_POWER_STATE_REQ: int state = v.value.int32Values.get(VehicleApPowerStateReqIndex.STATE); int param = v.value.int32Values.get(VehicleApPowerStateReqIndex.ADDITIONAL); Log.i(CarLog.TAG_POWER, "Received AP_POWER_STATE_REQ=" + powerStateReqName(state) + " param=" + param); // 通知状态给CPMS对象 // AP_POWER_STATE_REQ(SHUTDOWN_PREPARE, CAN_SLEEP) listener.onApPowerStateChange(new PowerState(state, param)); break; case DISPLAY_BRIGHTNESS: { // 省略 } break; } } }
@Override public void onApPowerStateChange(PowerState state) { synchronized (mLock) { mPendingPowerStates.addFirst(new CpmsState(state)); mLock.notify(); } mHandler.handlePowerStateChange(); } private void handlePowerStateChange() { Message msg = obtainMessage(MSG_POWER_STATE_CHANGE); sendMessage(msg); } @Override public void handleMessage(Message msg) { CarPowerManagementService service = mService.get(); if (service == null) { Slog.i(TAG, "handleMessage null service"); return; } switch (msg.what) { case MSG_POWER_STATE_CHANGE: // 开始处理 // service是doHandlePowerStateChange对象 service.doHandlePowerStateChange(); break; // 省略 } } private void doHandlePowerStateChange() { // 省略了 mCurrentState = state; switch (state.mState) { case CpmsState.WAIT_FOR_VHAL: handleWaitForVhal(state); break; case CpmsState.ON: handleOn(); break; case CpmsState.SHUTDOWN_PREPARE: // 处理SHUTDOWN_PREPARE handleShutdownPrepare(state); break; // 省略 default: // Illegal state // TODO: Throw exception? break; } }
CarPowerManagementService开始处理SHUTDOWN_PREPARE。主要是关闭VR交互、关闭屏幕。通知状态给CPMS的客户端,启动超时等待客户端处理完成(使用****CarPowerStateListenerWithCompletion的客户端)
private void handleShutdownPrepare(CpmsState newState) { setVoiceInteractionDisabled(true); mSystemInterface.setDisplayState(false); // Shutdown on finish if the system doesn't support deep sleep or doesn't allow it. // 通知状态给客户端 sendPowerManagerEvent(CarPowerStateListener.SHUTDOWN_PREPARE); mHal.sendShutdownPrepare(); doHandlePreprocessing(); } private void doHandlePreprocessing() { int intervalMs; int pollingCount; synchronized (mLock) { intervalMs = mShutdownPollingIntervalMs; pollingCount = (mShutdownPrepareTimeMs / mShutdownPollingIntervalMs) + 1; } if (Build.IS_USERDEBUG || Build.IS_ENG) { // 这里省略了,主要是可以通过属性,修改超时时间。 } Slog.i(TAG, "processing before shutdown expected for: " + mShutdownPrepareTimeMs + " ms, adding polling:" + pollingCount); // 启动超时任务,定期检查。那些使用 CarPowerStateListenerWithCompletion //(带有future,告知CPMS自己是否处理完了)的应用端是否处理完毕。 // 如果超时还没完成,强制走DeepSleep流程。 synchronized (mLock) { mProcessingStartTime = SystemClock.elapsedRealtime(); releaseTimerLocked(); mTimer = new Timer(); mTimerActive = true; mTimer.scheduleAtFixedRate( new ShutdownProcessingTimerTask(pollingCount), 0 /*delay*/, intervalMs); } if (mSwitchGuestUserBeforeSleep) { switchToNewGuestIfNecessary(); } } // 超时处理Task private class ShutdownProcessingTimerTask extends TimerTask { private final int mExpirationCount; private int mCurrentCount; private ShutdownProcessingTimerTask(int expirationCount) { mExpirationCount = expirationCount; mCurrentCount = 0; } @Override public void run() { synchronized (mLock) { if (!mTimerActive) { // Ignore timer expiration since we got cancelled return; } mCurrentCount++; if (mCurrentCount > mExpirationCount) { // 超时处理。给Vehicle HAL通知DEEP_SLEEP_ENTRY,告知可以开始进入深入睡眠状态。 PowerHandler handler; releaseTimerLocked(); handler = mHandler; handler.handleProcessingComplete(); } else { // 定期通过PowerServiceHAL向Vehicle HAL发送延时通知。 mHal.sendShutdownPostpone(SHUTDOWN_EXTEND_MAX_MS); } } } }
这里假设走正常的处理了,即所有客户端(CarPowerStateListenerWithCompletion)期限内完成了处理。那么CPMS,就会通过PowerserviceHAL告知 VehicleHAL “DEEP_SLEEP_ENTRY”状态。下面是CarPowerStateListenerWithCompletion的一个例子。
mCarPowerManager.setListenerWithCompletion(mCarPowerStateListener);
private final CarPowerStateListenerWithCompletion mCarPowerStateListener =
new CarPowerStateListenerWithCompletion() {
@Override
public void onStateChanged(int state, CompletableFuture<Void> future) {
if (state == CarPowerManager.CarPowerStateListener.SHUTDOWN_PREPARE) {
// 例子,应用端处理完成后,调用future.complete 告知CPMS处理完成
if (future != null) {
future.complete(null);
}
}
}
};
// future.complete 会触发CPMS这个函数。 @Override public void finished(ICarPowerStateListener listener) { ICarImpl.assertPermission(mContext, Car.PERMISSION_CAR_POWER); ICarImpl.assertCallingFromSystemProcessOrSelf(); finishedImpl(listener.asBinder()); } private void finishedImpl(IBinder binder) { boolean allAreComplete; synchronized (mLock) { mListenersWeAreWaitingFor.remove(binder); allAreComplete = mListenersWeAreWaitingFor.isEmpty(); } // 所有Listener处理完成了。 if (allAreComplete) { signalComplete(); } } private void signalComplete() { if (mCurrentState.mState == CpmsState.SHUTDOWN_PREPARE || mCurrentState.mState == CpmsState.SIMULATE_SLEEP) { PowerHandler powerHandler; // All apps are ready to shutdown/suspend. synchronized (mLock) { if (!mShutdownOnFinish) { if (mLastSleepEntryTime > mProcessingStartTime && mLastSleepEntryTime < SystemClock.elapsedRealtime()) { Slog.i(TAG, "signalComplete: Already slept!"); return; } } powerHandler = mHandler; } Slog.i(TAG, "Apps are finished, call handleProcessingComplete()"); powerHandler.handleProcessingComplete(); } } private void handleProcessingComplete() { removeMessages(MSG_PROCESSING_COMPLETE); Message msg = obtainMessage(MSG_PROCESSING_COMPLETE); sendMessage(msg); } @Override public void handleMessage(Message msg) { CarPowerManagementService service = mService.get(); if (service == null) { Slog.i(TAG, "handleMessage null service"); return; } switch (msg.what) { case MSG_POWER_STATE_CHANGE: service.doHandlePowerStateChange(); break; case MSG_DISPLAY_BRIGHTNESS_CHANGE: service.doHandleDisplayBrightnessChange(msg.arg1); break; case MSG_MAIN_DISPLAY_STATE_CHANGE: service.doHandleMainDisplayStateChange((Boolean) msg.obj); break; case MSG_PROCESSING_COMPLETE: // 走这里 service.doHandleProcessingComplete(); break; } } private void doHandleProcessingComplete() { int listenerState; synchronized (mLock) { releaseTimerLocked(); if (!mShutdownOnFinish && mLastSleepEntryTime > mProcessingStartTime) { // entered sleep after processing start. So this could be duplicate request. Slog.w(TAG, "Duplicate sleep entry request, ignore"); return; } // 可以设置关机,即不进入挂起。 // 默认状态,走SUSPEND_ENTER listenerState = mShutdownOnFinish ? CarPowerStateListener.SHUTDOWN_ENTER : CarPowerStateListener.SUSPEND_ENTER; } // 处理状态变化(这个函数是两参的,并且是private的) onApPowerStateChange(CpmsState.WAIT_FOR_FINISH, listenerState); } private void onApPowerStateChange(int apState, int carPowerStateListenerState) { CpmsState newState = new CpmsState(apState, carPowerStateListenerState); synchronized (mLock) { mPendingPowerStates.addFirst(newState); mLock.notify(); } // 用 handler线程处理。下面省略了中间流程,最终调用的是doHandlePowerStateChange mHandler.handlePowerStateChange(); } private void doHandlePowerStateChange() { mCurrentState = state; switch (state.mState) { // 省略 case CpmsState.WAIT_FOR_FINISH: // 走这里 handleWaitForFinish(state); break; // 省略 default: // Illegal state // TODO: Throw exception? break; } } private void handleWaitForFinish(CpmsState state) { // 通知给CPMS的监听者当前状态 sendPowerManagerEvent(state.mCarPowerStateListenerState); int wakeupSec; synchronized (mLock) { // If we're shutting down immediately, don't schedule // a wakeup time. // 可以设置,进入休眠状态后的唤醒时间(默认是不设置的),0表示一直Sleep(除非VMCU主动唤起) wakeupSec = mGarageModeShouldExitImmediately ? 0 : mNextWakeupSec; } switch (state.mCarPowerStateListenerState) { case CarPowerStateListener.SUSPEND_ENTER: // // 给Vehicle HAL发送状态 // 发送的是DEEP_SLEEP_ENTRY,告知可以进入休眠状态了。 mHal.sendSleepEntry(wakeupSec); break; case CarPowerStateListener.SHUTDOWN_ENTER: mHal.sendShutdownStart(wakeupSec); break; } }
到这里,就是告诉了VMCU,Android 挂起Ready了,也就是一切准备完成。然后MCU就会发送AP_POWER_STATE_REQ(FINISHED),告知Android侧调用Linux内核的实现,把自己挂起来(Supend)。消息通知流程,跟上面的onPropertyEvent一致,这部分下面就省略了。
private void doHandlePowerStateChange() { mCurrentState = state; switch (state.mState) { // 省略 case CpmsState.SUSPEND: // Received FINISH from VHAL // 走这里 handleFinish(); break; default: // Illegal state // TODO: Throw exception? break; } } private void handleFinish() { // 省略 // 关闭Voice setVoiceInteractionDisabled(true); // To make Kernel implementation simpler when going into sleep. disableWifi(); if (mustShutDown) { // shutdown HU mSystemInterface.shutdown(); } else { // 处理深入睡眠 doHandleDeepSleep(simulatedMode); } mShutdownOnNextSuspend = false; } private void doHandleDeepSleep(boolean simulatedMode) { // keep holding partial wakelock to prevent entering sleep before enterDeepSleep call // enterDeepSleep should force sleep entry even if wake lock is kept. mSystemInterface.switchToPartialWakeLock(); mHandler.cancelProcessingComplete(); synchronized (mLock) { mLastSleepEntryTime = SystemClock.elapsedRealtime(); } int nextListenerState; if (simulatedMode) { // 省略 } else { // 最终会调用Kernel接口,Supend To RAM(感兴趣的小伙伴可以顺着这个接口看下去。 // 挂成功的情况下面,下面的代码就不会走了(CPU都没电了)。 // 之后的代码,就是CPU上电后的恢复流程了。 // 可以看出恢复前,要刷新一下屏幕亮度。然后走WAIT_FOR_VHAL状态。 boolean sleepSucceeded = suspendWithRetries(); if (!sleepSucceeded) { // Suspend failed and we shut down instead. // We either won't get here at all or we will power off very soon. return; } // We suspended and have now resumed nextListenerState = CarPowerStateListener.SUSPEND_EXIT; } synchronized (mLock) { mIsResuming = true; // Any wakeup time from before is no longer valid. mNextWakeupSec = 0; } Slog.i(TAG, "Resuming after suspending"); mSystemInterface.refreshDisplayBrightness(); onApPowerStateChange(CpmsState.WAIT_FOR_VHAL, nextListenerState); }
综上是Android CarPower的深入睡眠睡眠主要流程,实际开发过程中。根据业务进行扩展,一般会添加一个跟CPMS平行,或者基于它的新的电源模块。下面是上面代码的时序图,供参考。
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。