一. 前言
电源管理是AAOS上又一个比较特殊的部分. 由于车辆的使用场景的特殊性和复杂性, 同时需要和其他ECU(Electronic Control Unit)电子控制单元的配合, 都增加了车载系统电源管理的难度.
和手机不同, 手机可以频繁充电, 哪怕长时间不用,手机电量耗尽, 使用时再充上电就ok了, 不会有什么问题. 可是车机不同, 行驶过程中车机需要始终保持工作, 用户是不能随意重启车机的, 否则可能会影响驾驶安全; 而在停车熄火后,车机就要尽量降低其功耗, 否则如果将电瓶中电耗尽, 那可不是插上充电线这么简单了,需要车辆救援搭电才能启动.
但另一方面, 如果过分追求熄火后的能耗也会影响用户体验, 就会导致: 启动车机的时间过长, 会让用户每次上车都需要等待车机的启动. 同时,相关的法律规定要求车机的启动需要足够迅速,以支持倒车影像的功能.
以下列出一些具体的用户场景, 帮助读者更直观的了解车载系统电源管理可能遇到的情况:
1. 短时间的熄火停车, 如在加油站,下车买一些小的物品等.
2. 长达数周的熄火停车, 如在机场停车场内停放数周.
3. 长途驾驶始终不熄火, 如长途旅游.
4. 一天内多次启动熄火, 如周末的使用场景.
5. 停车状态下的车内娱乐场景
6. 对部分远程控车功能的支持.
二. 汽车电源管理服务
与其他的CarService中的服务不同, 除了提供了java类的接口CarPowerManager以外, CarPowerManagementService还有对应的C++类的接口, 类名同样也叫CarPowerManager. 这两个的源码位置分别位于:
packages/services/Car/car-lib/src/android/car/hardware/power/CarPowerManager.java
packages/services/Car/car-lib/native/CarPowerManager/CarPowerManager.cpp
增加 C++类的接口主要是为了向一些使用 C++编写的服务提供CarPowerManager相关的功能. 帮助其管理电源的状态. 在接口的定义和功能上面, 无论是java 还是 C++的 CarPowerManager都是一样的, 他们都对应于同一个CarPowerManagerService.
电源管理服务关系如下图:
三. CarPowerManager用法
本节介绍CarPowerManager相关的API的用法. CarPowerManager提供了电源状态变化通知, 调节电源状态的功能, 主要的方法和常量如下面的类图所示:
CarPowerManager主要提供了四个公开的方法.
1. setListener 和 setListenerWithCompletion方法用于监听电源状态的变化. 不同的地方是setListenerWithCompletion传递的CarPowerStateListenerWithCompletion接口的回调中包含
CompletableFuture<Void>对象, 用于通知CarPowerManagementService该注册监听的应用已经完成了相关流程的处理.
2. requestShutdownOnNextSuspend 和 scheduleNextWakeupTime 方法作用分别是请求在下次进入关机流程时关闭车机而非进入深度休眠 和 设置下次唤醒的间隔.
在CarPowerManager的CarPowerStateListener中定义了如下表中的几种不同的电源状态.
状态 | 含义 |
SHUTDOWN_CANCELLED | 取消关机 |
SHUTDOWN_ENTER | 关机 |
SUSPEND_ENTER | 深度睡眠 |
SUSPEND_EXIT | 退出睡眠 |
WAIT_FOR_VHAL | 等待Vehicle Hal启动 |
ON | 启动 |
SHUTDOWN_PREPARE | 进入关机准备 |
在此, 以注册CarPowerStateListenerWithCompletion为例, 看一下如何使用 CarPowerManager
CarPowerStateListenerWithCompletion的作用是监听电源状态的变化, 同时监听者可以通知自身任务的完成状态, 该方法并非任何应用都能使用.
3.1 首先需要在清单文件中声明权限:
<uses-permission android:name="android.car.permission.CAR_POWER"/>
该权限为系统级别的权限, 只有特权应用才能使用.
通过Car对象获取CarPowerManager实例
Car car = Car.createCar(this);
CarPowerManager carPowerManager = (CarPowerManager) car.getCarManager(Car.POWER_SERVICE);
实现CarPowerStateListenerWithCompletion接口,并注册监听器:
//注册监听器
CarPowerManager.CarPowerStateListenerWithCompletion mListener =
new CarPowerManager.CarPowerStateListenerWithCompletion() {
@Override
public void onStateChanged(int state, CompletableFuture<Void> completableFuture) {
if (state == CarPowerManager.CarPowerStateListener.SHUTDOWN_PREPARE) {
//车辆进入准备关机状态
doSomething();
//完成处理流程后通知CarPowerManagementService 该任务已经完成
//否则可能影响关机流程
if(completableFuture != null) {
completableFuture.complete(null);
}
}
return;
}
};
使用方法并不复杂, 需要额外注意以下几点:
1. 调用CarPowerStateListenerWithCompletion方法除了需要android.car.permission.CAR_POWER权限外, 还需要以System UID运行,否则会抛出异常, 因此一般情况下会使用CarPowerStateListener. CarPowerStateListener在使用和CarPowerStateListenerWithCompletion基本一致. 只是少了ComplettableFuture<Void>参数, 使用者仅可以收到状态通知的变化的通知, 而无法控制进入下一个状态的时机.
2. 同一个CarPowerManager只能同时注册一个CarPowerStateListenerWithCompletion 或 CarPowerStateListener
3. 注册监听可以获取ON SUSPEND_EXIT SHUTDOWN_CANCELLED等状态, 其中SHUTDOWN_PREPARE状态可能是最为常用的. 因为在进入休眠前应用往往希望保存某些状态
另一方面, ON状态会在系统冷启动或者睡眠重新唤醒的时候被触发. 在手机上 应用开发者习惯接收BOOT_COMPLETED广播获取系统的启动事件, 但这在AAOS上并不可靠, 如果车机只是睡眠唤醒且未发生用户切换, 那么BOOT_COMPLETED是不会被发送的, 这一点需要我们留意.
四. CarPowerManagementService处理流程
本节通过源码介绍CarPowerManagementService处理电源状态的变化的具体流程.
总体来说, 电源状态的变化由车辆主控单元由下往上推送至CarPowerManagementService
举例来说, 由于用户的熄火状态(具体的信号触发条件不同), 车辆的电源状态开始变化, 车辆主控单元将信号发送给车载娱乐系统(In-Vehicle Infotainment , IVI)单元 即 AAOS车载娱乐系统. 进而在由 VehicleHAL硬件抽象层上报给 CarPowerManagementService, 最后进入到Android系统的关机流程.
VehicleHAL接收到电源变化的信号后, 通过PowerHalService在分发给CarPowerManagementService. 电源事件在VehicleHAL定义了相关的属性ID, 通过属性ID进行分发.
PowerHalService 对象是在VehicleHAL(此处并非指车辆硬件抽象层, 而是CarService中的VehicleHal类)的构造函数中创建的. 最后再由CarPowerManagementService根据不同状态进行处理.并通知相关使用了CarPowerManager监听状态变化的应用.