当前位置: 首页 > article >正文

Android AutoMotive—CarPowerManagementService

1、电源状态概述

电源管理是Android AutoMotive OS中较手机Android系统差异化比较大的模块,这是因为车机面临的使用场景比手机更加复杂。既要考虑车辆短时间使用间隔的休眠,也要考虑长时间停放下的关机;休眠状态下可以快速响应唤醒,但是这种状态如果管理不好,又会存在持续耗电的情况,如果电瓶亏电,后果就很严重;同时我们还要考虑到车机系统的OTA升级,通常是在人离开车后,车辆空闲的状态去做的升级,称之为地库模式;还有哨兵模式,在车辆停放的时候摄像头会开启;以及远程控车,通过TBox唤醒车机系统,等等。
对于Android AutoMotive OS,电源状态的迁移如下:
在这里插入图片描述
(1) 车机系统处于STR(Suspend To RAM)深度睡眠状态,此时CUP已经掉电,但是RAM内存还保持着原有的数据;
(2) 用户操作车辆,唤醒车机系统,VHAL(Vehicle HAL,车辆硬件抽象层)开始启动车辆相关服务;
(3) 车机系统启动完成;
(4) 用户停止使用车辆,触发关机前的准备流程,等待上层APP做关机前的确认;
(5) 上层APP确认完毕可以关机,并通知到VHAL,等待VHAL关闭;
(6) VHAL关闭完成,AP掉电,车机再次进入STR休眠状态。

2、CarPowerManager

CarPowerManagementService运行在Carservice进程中,它对上层APP提供的客户端API是CarPowerManager,它主要提供了如下几个方法:

方法名注解
requestShutdownOnNextSuspend()请求在下次进入关机流程时直接关机,而非休眠挂起
scheduleNextWakeupTime(int seconds)设置下次唤醒的时间间隔
getPowerState()获取到电源状态
setListener(@NonNull @CallbackExecutor Executor executor, @NonNull CarPowerStateListener listener)设置电源变化监听
setListenerWithCompletion(@NonNull @CallbackExecutor Executor executor, @NonNull CarPowerStateListenerWithCompletion listener)设置电源变化监听,回调包含结果通知

CarPowerStateListenerWithCompletion监听器和CarPowerStateListener监听器不同的是,后者只有一个状态结果的通知;而前者的状态回调接口中,还包含了一个CompletableFuture对象,APP需要通过这个对象告诉CarPowerManagementService,APP层已经完成了关机前的动作,现在可以继续接下来的流程。
电源状态列表如下:

常量定义注解
STATE_SHUTDOWN_ENTER关机
STATE_WAIT_FOR_VHAL等待VHAL启动
STATE_ON开机
STATE_SHUTDOWN_PREPARE进入关机前的准备
STATE_SHUTDOWN_CANCELLED取消关机
STATE_SUSPEND_ENTER进入深度休眠,内存供电
STATE_HIBERNATION_ENTER更深度休眠,内存掉电
STATE_SUSPEND_EXIT退出休眠

需要注意的是,调用setListenerWithCompletion方法除了需要android.car.permission.CAR_POWER权限外,还需要以system UID的用户组运行。这是因为CarPowerStateListenerWithCompletion监听的回调方法,是可以阻塞关机流程的,这必定是要核心的系统级应用和服务才能有权使用。
在手机Android系统中,我们可能会监听BOOT_COMPLETED开机广播,去做程序数据的初始化,但是在AAOS中,如果车机只是休眠唤醒且没有用户切换的情况下,是没有开机广播的。所以除了开机广播外,我们更应该监听电源状态,STATE_ON、STATE_SHUTDOWN_PREPARE是最为常用的,AAOS中特有的地库模式,就是基于对STATE_SHUTDOWN_PREPARE的监听实现的。

3、CarPowerManagementService

CarPowerManagementService的处理流程如下:
在这里插入图片描述
VMCU是车辆微控制器,电源的状态上报就是从它发出来的,通过厂商定制的VHAL层到达CarPowermanagementService,接下来就会处理不同的状态,以SHUTDOWN_PREPARE流程为例,代码如下:

// packages/services/Car/service/src/com/android/car/power/CarPowerManagementService.java
private void doHandlePowerStateChange() {
	switch (newState.mState) {
			case CpmsState.SHUTDOWN_PREPARE:
            handleShutdownPrepare(newState, prevState);
     }
}

然后调用到doShutdownPrepare()方法,这里会去给各个APP注册的监听器发送状态改变的回调:

private void doShutdownPrepare() {
	sendPowerManagerEvent(CarPowerManager.STATE_SHUTDOWN_PREPARE, timeoutMs);
    mHal.sendShutdownPrepare();
    waitForShutdownPrepareListenersToComplete(timeoutMs, intervalMs);
}

最后会执行到waitForCompletionAsync 方法:

// Waits for listeners to complete.
    // If {@code intervalMs} is non-positive value, it is ignored and the method waits up to
    // {@code timeoutMs}.
    private void waitForCompletionAsync(Runnable taskAtCompletion, Runnable taskAtInterval,
            long timeoutMs, long intervalMs) {
            
        //这里使用信号量去进程间通信,获取远程APP prepare的状态。
		boolean isNotified = mListenerCompletionSem.tryAcquire(waitTimeMs, TimeUnit.MILLISECONDS); 
		
		//超过最大等待时间,则进入下一步流程
		if (isLastWait) {
                 Slogf.w(TAG, "Waiting for listener completion is timeout(%d)",waitTimeMs);
                 taskAtCompletion.run(); 
                  return;
         }
         
		//判断所有的监听等待对象是否已经完成准备,等待队列为空之后,也会进入下一步流程
		isComplete = mListenersWeAreWaitingFor.isEmpty(); 
		if (isComplete) {
                  Slogf.i(TAG, "All listeners completed");
                  taskAtCompletion.run();
                  mIsListenerWaitingCancelled.set(false);
                  return;
        }
}

所以CarPowermanagementService的执行逻辑总体概括,就是把状态信号回调给各个监听器,同时开启对各个监听器回执状态的检测。

4、Garage Mode 车库模式

车库模式是AAOS中特有的一种空闲模式,它的触发时机是在用户停止使用车辆之后,即收到SHUTDOWN_PREPARE状态信号。车库模式的作用,是利用这段空闲时间,做一些开机时候不能做的事情,最典型的就是系统升级。
Garage Mode对应的服务GarageModeService也是运行在Carservice进程里面,属于CarService的一部分,它内部有一个GarageModeController,会去注册监听CarPowerManagementService的状态:

// packages/services/Car/service/src/com/android/car/garagemode/GarageModeController.java
public class GarageModeController extends ICarPowerStateListener.Stub {
	mCarPowerService.registerInternalListener(GarageModeController.this);
	@Override
	public void onStateChanged(int state, long expirationTimeMs) {
		case CarPowerManager.STATE_SHUTDOWN_PREPARE:
                initiateGarageMode(
                        () -> mCarPowerService.completeHandlingPowerStateChange(state,
                                GarageModeController.this));
           break;
	}
}

调用registerInternalListener去注册,就会让CarPowerService去把这个监听器加入到上面提到的等待队列中去。
在收到STATE_SHUTDOWN_PREPARE状态后,就会开启车库模式。

// packages/services/Car/service/src/com/android/car/garagemode/GarageModeController.java
void enterGarageMode(Runnable completor) {
	broadcastSignalToJobScheduler(true);
startMonitoringThread();
}

这里最重要的就是做了两个事情:一是发送开启车库模式的广播,从方法名可以看到,在广播接收方会去执行JobScheduler任务,也就是OTA升级任务;二是开启对线程的观察,其实也就是观察JobSchedulerJobInfo任务队列是否已经全部执行结束。
跟随广播的发送,我们来到广播的接受方,代码位于frameworks/base/apex/jobscheduler/service/java/com/android/server/job/controllers/idle/CarIdlenessTracker.java
CarIdlenessTracker已经不在Carservice的一部分,属于AOSP的framework下,它是由IdleController创建。当设备运行在车载环境时,就会创建CarIdlenessTracker,而在手机上则会创建DeviceIdlenessTracker。这样,CarService就会和原有的Android JobScheduler机制完美结合了起来。
看CarIdlenessTracker:

// frameworks/base/apex/jobscheduler/service/java/com/android/server/job/controllers/idle/CarIdlenessTracker.java
public final class CarIdlenessTracker extends BroadcastReceiver implements IdlenessTracker {
	@Override
	public void onReceive(Context context, Intent intent) {
		if (action.equals(ACTION_GARAGE_MODE_ON)) {
            logIfDebug("GarageMode is on...");
            mGarageModeOn = true;
            updateIdlenessState();
        }
	}

	private void updateIdlenessState() {
        final boolean newState = (mForced || mGarageModeOn);
        mIdle = newState;
            mIdleListener.reportNewIdleState(mIdle);
        
	}

}

这里就会通知IdleController现在的处于空闲状态,可以去执行相关的JobInfo调度。


http://www.kler.cn/a/519380.html

相关文章:

  • 基于单片机的智能小区门禁系统设计(论文+源码)
  • FastExcel的使用
  • java后端之事务管理
  • Go中的三种锁
  • 数据结构:log-structed结构MemTableSSTable
  • 使用 Elasticsearch 导航检索增强生成图表
  • 使用shell脚本修改linux静态网络IP、网关和hosts文件
  • PSD是什么图像格式?如何把PSD转为JPG格式?
  • zookeeper的介绍和简单使用
  • Plesk 2个安全功能介绍
  • 2025年01月25日Github流行趋势
  • 基于物联网的风机故障检测装置的设计与实现
  • OpenHarmony 5.0.2 Release来了!
  • (Halcon)轮廓等分切割(项目分析)
  • 性能优化案例:通过合理设置spark.storage.memoryFraction参数的值来优化PySpark程序的性能
  • Flutter_学习记录_Tab的简单Demo~真的很简单
  • 【开源免费】基于SpringBoot+Vue.JS智慧图书管理系统(JAVA毕业设计)
  • 【DB】Oracle存储过程
  • doris:MySQL Load
  • 【2025年数学建模美赛E题】(农业生态系统)完整解析+模型代码+论文
  • Vue.js 路由懒加载
  • 【STM32项目实战系列】了解ST系列MCU外设:定时器TIM
  • HTML-新浪新闻-实现标题-排版
  • WPS计算机二级•幻灯片的页面布局
  • 【unity游戏开发之InputSystem——07】InputSystem+UGUI配合使用(基于unity6开发介绍)
  • 【问题解决】el-upload数据上传成功后不显示成功icon