然后走WAIT_FOR_VHAL状态

发布时间:2025-06-24 19:07:58  作者:北方职教升学中心  阅读量:249



首先,什么是深度睡眠(Deep Sleep)?

Android进入Deep Sleep后,关闭屏幕、PowerHandlerhandler;releaseTimerLocked();handler =mHandler;handler.handleProcessingComplete();}else{// 定期通过PowerServiceHAL向Vehicle HAL发送延时通知。
感觉这种方式,跟snapshot快启动有点类似。// 可以看出恢复前,要刷新一下屏幕亮度。// 之后的代码,就是CPU上电后的恢复流程了。

下面的图,是Android官网对于深度睡眠的时序图

DeepSleep或STR,需要内核配合实现。

  • packages/services/Car/service/src/com/android/car/CarPowerManagementService.java
privatevoiddoHandlePowerStateChange(){mCurrentState =state;switch(state.mState){// 省略caseCpmsState.SUSPEND:// Received FINISH from VHAL// 走这里handleFinish();break;default:// Illegal state// TODO:  Throw exception?break;}}privatevoidhandleFinish(){// 省略// 关闭VoicesetVoiceInteractionDisabled(true);// To make Kernel implementation simpler when going into sleep.disableWifi();if(mustShutDown){// shutdown HUmSystemInterface.shutdown();}else{// 处理深入睡眠doHandleDeepSleep(simulatedMode);}mShutdownOnNextSuspend =false;}privatevoiddoHandleDeepSleep(booleansimulatedMode){// 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();}intnextListenerState;if(simulatedMode){// 省略}else{// 最终会调用Kernel接口,Supend To RAM(感兴趣的小伙伴可以顺着这个接口看下去。
在这里插入图片描述

以太方式)
  • CarPowerManagerService(CPMS): 实现Android侧的电源控制,应用电源策略。

    Android Framework系列—CarPower深度睡眠

    之前博客说了CarPower的开机启动流程
    这里分析一下,Android CarPower实现深度睡眠的流程。

    下面摘自Android官网对这种状态的介绍。

    mCarPowerManager.setListenerWithCompletion(mCarPowerStateListener);privatefinalCarPowerStateListenerWithCompletionmCarPowerStateListener =newCarPowerStateListenerWithCompletion(){@OverridepublicvoidonStateChanged(intstate,CompletableFuture<Void>future){if(state ==CarPowerManager.CarPowerStateListener.SHUTDOWN_PREPARE){// 例子,应用端处理完成后,调用future.complete 告知CPMS处理完成if(future !=null){future.complete(null);}}}};
    • packages/services/Car/service/src/com/android/car/CarPowerManagementService.java
    // future.complete 会触发CPMS这个函数。那么CPMS,就会通过PowerserviceHAL告知 VehicleHAL “DEEP_SLEEP_ENTRY”状态。消息通知流程,跟上面的onPropertyEvent一致,这部分下面就省略了。在 CPM 的 onStateChanged() 方法中,同步调用应用/服务的
    onStateChanged() 方法。
    mHal.sendSleepEntry(wakeupSec);break;caseCarPowerStateListener.SHUTDOWN_ENTER:mHal.sendShutdownStart(wakeupSec);break;}}

    到这里,就是告诉了VMCU,Android 挂起Ready了,也就是一切准备完成。将 SoC 置于 S3 电源模式,CPU 断电而 RAM 仍通电。SUSPEND_ENTER 和 POST_SUSPEND_ENTER
    返回后,异步继续关闭准备。代码基于Android11

  • 首先,VMCU请求挂起。

  • CarPowerManager(CPM): CPMS的客户端,通知电源状态给应用,等待应用回复状态等。
  • 下面是摘自Android官网的深入睡眠流程描述;

    只有 VMCU 可以启动深度睡眠。在此情况下,特权服务应在完成准备时对提供的 CompletablePowerStateChangeFuture
    对象调用 complete()。当前还有Qnx之类的hypervisor)

    • MCU/VMCU:控制电源,发送电源状态给SOC(Android)
    • Vehicle HAL:一般由硬件供应商实现,与MCU通信(can、这里贴在这里。// 如果超时还没完成,强制走DeepSleep流程。启动深度睡眠后,VMCU 会通过 VHAL 向 CPMS 发送通知。下面是CarPowerStateListenerWithCompletion的一个例子。// 挂成功的情况下面,下面的代码就不会走了(CPU都没电了)。

    CPM 在应用/服务与 CPMS 之间进行协调。在向 VHAL 发送
    DEEP_SLEEP_ENTRY 之前,CPMS 会定期向 VHAL 发送推迟关闭的请求。@Overridepublicvoidfinished(ICarPowerStateListenerlistener){ICarImpl.assertPermission(mContext,Car.PERMISSION_CAR_POWER);ICarImpl.assertCallingFromSystemProcessOrSelf();finishedImpl(listener.asBinder());}privatevoidfinishedImpl(IBinderbinder){booleanallAreComplete;synchronized(mLock){mListenersWeAreWaitingFor.remove(binder);allAreComplete =mListenersWeAreWaitingFor.isEmpty();}// 所有Listener处理完成了。mHal.sendShutdownPostpone(SHUTDOWN_EXTEND_MAX_MS);}}}}

    这里假设走正常的处理了,即所有客户端(CarPowerStateListenerWithCompletion)期限内完成了处理。当然深度睡眠,还有一种方式是挂起到硬盘(Suspend-to-Disk),不过目前主要用的是STR。

    当所有 CPM 对象完成关闭准备后,CPMS 会向 VHAL 发送 AP_POWER_STATE_REPORT,VHAL 随后通知
    VMCU,告知它 AP 已准备好挂起。Vehicle HAL (Hal层的nativeservice)发送“AP_POWER_STATE_REQ(SHUTDOWN_PREPARE)”, 这样CarService中的 VehicleHal(Client端 )就收到了这个通知。深度睡眠会进行Suspend-to-RAM挂起到内存(做车载的经常会听到的STR)。

    整套深度睡眠的实现,涉及的主要模块(这里指单Android系统。后面会根据源码,分析并画一个跟代码对应的时序图。synchronized(mLock){mProcessingStartTime =SystemClock.elapsedRealtime();releaseTimerLocked();mTimer =newTimer();mTimerActive =true;mTimer.scheduleAtFixedRate(newShutdownProcessingTimerTask(pollingCount),0/*delay*/,intervalMs);}if(mSwitchGuestUserBeforeSleep){switchToNewGuestIfNecessary();}}// 超时处理TaskprivateclassShutdownProcessingTimerTaskextendsTimerTask{privatefinalintmExpirationCount;privateintmCurrentCount;privateShutdownProcessingTimerTask(intexpirationCount){mExpirationCount =expirationCount;mCurrentCount =0;}@Overridepublicvoidrun(){synchronized(mLock){if(!mTimerActive){// Ignore timer expiration since we got cancelledreturn;}mCurrentCount++;if(mCurrentCount >mExpirationCount){// 超时处理。
    Android官网深入睡眠流程

    CPMS深度睡眠代码实现

    • 到这里,我们开始分析CPMS的实现。// 默认状态,走SUSPEND_ENTERlistenerState =mShutdownOnFinish ?CarPowerStateListener.SHUTDOWN_ENTER:CarPowerStateListener.SUSPEND_ENTER;}// 处理状态变化(这个函数是两参的,并且是private的)onApPowerStateChange(CpmsState.WAIT_FOR_FINISH,listenerState);}privatevoidonApPowerStateChange(intapState,intcarPowerStateListenerState){CpmsStatenewState =newCpmsState(apState,carPowerStateListenerState);synchronized(mLock){mPendingPowerStates.addFirst(newState);mLock.notify();}// 用 handler线程处理。booleansleepSucceeded =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 resumednextListenerState =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的深入睡眠睡眠主要流程,实际开发过程中。给Vehicle HAL通知DEEP_SLEEP_ENTRY,告知可以开始进入深入睡眠状态。STR指的是深度睡眠时的状态,但STR不等于深度睡眠。然后走WAIT_FOR_VHAL状态。那些使用 CarPowerStateListenerWithCompletion//(带有future,告知CPMS自己是否处理完了)的应用端是否处理完毕。根据业务进行扩展,一般会添加一个跟CPMS平行,或者基于它的新的电源模块。然后MCU就会发送AP_POWER_STATE_REQ(FINISHED),告知Android侧调用Linux内核的实现,把自己挂起来(Supend)。

      也称为“挂起到 RAM”(S2R 或 STR)。

      • packages/services/Car/service/src/com/android/car/hal/VehicleHal.java
      publicvoidonPropertyEvent(ArrayList<VehiclePropValue>propValues){// 省略for(HalServiceBases :mServicesToDispatch){//  通知给监听者s.onHalEvents(s.getDispatchList());s.getDispatchList().clear();}mServicesToDispatch.clear();}
      • packages/services/Car/service/src/com/android/car/hal/PowerHalService.java
      @OverridepublicvoidonHalEvents(List<VehiclePropValue>values){// 省略dispatchEvents(values,listener);}privatevoiddispatchEvents(List<VehiclePropValue>values,PowerEventListenerlistener){for(VehiclePropValuev :values){switch(v.prop){caseAP_POWER_STATE_REPORT:// Ignore this property event. It was generated inside of CarService.break;caseAP_POWER_STATE_REQ:intstate =v.value.int32Values.get(VehicleApPowerStateReqIndex.STATE);intparam =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(newPowerState(state,param));break;caseDISPLAY_BRIGHTNESS:{// 省略}break;}}}
      • packages/services/Car/service/src/com/android/car/CarPowerManagementService.java
      @OverridepublicvoidonApPowerStateChange(PowerStatestate){synchronized(mLock){mPendingPowerStates.addFirst(newCpmsState(state));mLock.notify();}mHandler.handlePowerStateChange();}privatevoidhandlePowerStateChange(){Messagemsg =obtainMessage(MSG_POWER_STATE_CHANGE);sendMessage(msg);}@OverridepublicvoidhandleMessage(Messagemsg){CarPowerManagementServiceservice =mService.get();if(service ==null){Slog.i(TAG,"handleMessage null service");return;}switch(msg.what){caseMSG_POWER_STATE_CHANGE:// 开始处理//  service是doHandlePowerStateChange对象service.doHandlePowerStateChange();break;// 省略}}privatevoiddoHandlePowerStateChange(){// 省略了mCurrentState =state;switch(state.mState){caseCpmsState.WAIT_FOR_VHAL:handleWaitForVhal(state);break;caseCpmsState.ON:handleOn();break;caseCpmsState.SHUTDOWN_PREPARE:// 处理SHUTDOWN_PREPAREhandleShutdownPrepare(state);break;// 省略default:// Illegal state// TODO:  Throw exception?break;}}

      CarPowerManagementService开始处理SHUTDOWN_PREPARE。通过这种技术,车载系统可以进入低能耗模式,同时又可以再用户需要时实现快速(非常快,因为从内存中恢复状态)的启动。一路通知给CPMS进行状态处理。特权服务可以在为
      PRE_SHUTDOWN_PREPARE、

      VMCU 应将 SoC 置于“深度睡眠”状态,并断开应用处理器的电源。CPMS 通过使用由 CPM 提供的新状态 ID 调用 onStateChanged() 方法,将状态更改为“关闭准备”并向所有观察者(监控 CPMS 的应用和服务)广播此状态转换。请注意,SHUTDOWN_PREPARE 不允许异步准备。if(allAreComplete){signalComplete();}}privatevoidsignalComplete(){if(mCurrentState.mState ==CpmsState.SHUTDOWN_PREPARE||mCurrentState.mState ==CpmsState.SIMULATE_SLEEP){PowerHandlerpowerHandler;// 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();}}privatevoidhandleProcessingComplete(){removeMessages(MSG_PROCESSING_COMPLETE);Messagemsg =obtainMessage(MSG_PROCESSING_COMPLETE);sendMessage(msg);}@OverridepublicvoidhandleMessage(Messagemsg){CarPowerManagementServiceservice =mService.get();if(service ==null){Slog.i(TAG,"handleMessage null service");return;}switch(msg.what){caseMSG_POWER_STATE_CHANGE:service.doHandlePowerStateChange();break;caseMSG_DISPLAY_BRIGHTNESS_CHANGE:service.doHandleDisplayBrightnessChange(msg.arg1);break;caseMSG_MAIN_DISPLAY_STATE_CHANGE:service.doHandleMainDisplayStateChange((Boolean)msg.obj);break;caseMSG_PROCESSING_COMPLETE:// 走这里service.doHandleProcessingComplete();break;}}privatevoiddoHandleProcessingComplete(){intlistenerState;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;}// 可以设置关机,即不进入挂起。主要是关闭VR交互、关闭屏幕。下面是上面代码的时序图,供参考。关闭CPU的电源,保持RAM的电源(激活状态)}Slog.i(TAG,"processing before shutdown expected for: "+mShutdownPrepareTimeMs +" ms, adding polling:"+pollingCount);// 启动超时任务,定期检查。大多数应用和服务需要完成其准备后才能从该调用返回。下面省略了中间流程,最终调用的是doHandlePowerStateChangemHandler.handlePowerStateChange();}privatevoiddoHandlePowerStateChange(){mCurrentState =state;switch(state.mState){// 省略caseCpmsState.WAIT_FOR_FINISH:// 走这里handleWaitForFinish(state);break;// 省略default:// Illegal state// TODO: Throw exception?break;}}privatevoidhandleWaitForFinish(CpmsStatestate){// 通知给CPMS的监听者当前状态sendPowerManagerEvent(state.mCarPowerStateListenerState);intwakeupSec;synchronized(mLock){// If we're shutting down immediately, don't schedule// a wakeup time.// 可以设置,进入休眠状态后的唤醒时间(默认是不设置的),0表示一直Sleep(除非VMCU主动唤起)wakeupSec =mGarageModeShouldExitImmediately ?0:mNextWakeupSec;}switch(state.mCarPowerStateListenerState){caseCarPowerStateListener.SUSPEND_ENTER:// // 给Vehicle HAL发送状态// 发送的是DEEP_SLEEP_ENTRY,告知可以进入休眠状态了。CPMS 还会调用其挂起方法以挂起内核。不过是两个概念上的事情了。通知状态给CPMS的客户端,启动超时等待客户端处理完成(使用****CarPowerStateListenerWithCompletion的客户端)

      • packages/services/Car/service/src/com/android/car/CarPowerManagementService.java
      privatevoidhandleShutdownPrepare(CpmsStatenewState){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();}privatevoiddoHandlePreprocessing(){intintervalMs;intpollingCount;synchronized(mLock){intervalMs =mShutdownPollingIntervalMs;pollingCount =(mShutdownPrepareTimeMs /mShutdownPollingIntervalMs)+1;}if(Build.IS_USERDEBUG||Build.IS_ENG){// 这里省略了,主要是可以通过属性,修改超时时间。然后,AAOS 将进入“挂起到 RAM”状态,但不执行任何代码。