Android 15 CarService源码02-服务初始化¶
背景¶
在上一篇文章 Android 15 CarService源码01-服务启动 中,我们详细分析了CarService进程的启动流程。本篇文章将重点聚焦于CarService服务的初始化过程。
CarServiceImpl.onCreate()¶
// packages/services/Car/service/src/com/android/car/CarServiceImpl.java
@Override
public void onCreate() {
// 创建一个用于跟踪初始化时间的日志对象,CAR_SERVICE_INIT_TIMING_TAG是日志标签,
// TraceHelper.TRACE_TAG_CAR_SERVICE是跟踪标记,CAR_SERVICE_INIT_TIMING_MIN_DURATION_MS是最小持续时间。
TimingsTraceLog initTiming = new TimingsTraceLog(CAR_SERVICE_INIT_TIMING_TAG,
TraceHelper.TRACE_TAG_CAR_SERVICE, CAR_SERVICE_INIT_TIMING_MIN_DURATION_MS);
// 开始跟踪CarService.onCreate方法的执行时间。
initTiming.traceBegin("CarService.onCreate");
// 开始跟踪获取车辆对象的时间。
initTiming.traceBegin("getVehicle");
// 创建一个新的VehicleStub对象并赋值给mVehicle。
mVehicle = VehicleStub.newVehicleStub();
// 结束跟踪获取车辆对象的时间。
initTiming.traceEnd(); // "getVehicle"
// 记录一个事件日志,标记CarService的创建,并指明是否有有效的车辆硬件抽象层(VHAL)。
EventLogHelper.writeCarServiceCreate(/* hasVhal= */ mVehicle.isValid());
// 获取车辆接口的描述符名称。
mVehicleInterfaceName = mVehicle.getInterfaceDescriptor();
// 打印一个信息日志,标记已经连接到车辆接口。
Slogf.i(CarLog.TAG_SERVICE, "Connected to " + mVehicleInterfaceName);
// 记录一个事件日志,标记CarService已经连接到车辆接口。
EventLogHelper.writeCarServiceConnected(mVehicleInterfaceName);
// 构建一个ICarImpl对象,设置服务上下文、内置包上下文、车辆对象、系统接口和车辆接口名称。
mICarImpl = new ICarImpl.Builder()
.setServiceContext(this)
.setBuiltInContext(getBuiltinPackageContext())
.setVehicle(mVehicle)
.setSystemInterface(
SystemInterface.Builder.defaultSystemInterface(this).build())
.setVehicleInterfaceName(mVehicleInterfaceName)
.build();
// 初始化ICarImpl对象。
mICarImpl.init();
// 为车辆对象注册死亡通知接收器。
mVehicle.linkToDeath(mVehicleDeathRecipient);
// 将ICarImpl对象添加为系统服务,服务名称为"car_service"。
ServiceManagerHelper.addService("car_service", mICarImpl);
// 设置系统属性,标记CarService已经创建。
SystemPropertiesHelper.set("boot.car_service_created", "1");
// 调用父类的onCreate方法。
super.onCreate();
// 结束跟踪CarService.onCreate方法的执行时间。
initTiming.traceEnd(); // "CarService.onCreate"
}
这个函数很简单,主要是完成了如下功能:
- 通过
VehicleStub.newVehicleStub()
创建一个车辆接口的对象(mVehicle
),用于与车辆硬件抽象层(VHAL)进行交互 - 使用
ICarImpl.Builder
构建一个ICarImpl
对象,设置必要的上下文、车辆对象、系统接口等,并调用init()
方法进行初始化。 - 将
ICarImpl
对象添加为系统服务,服务名称为"car_service"
,使其可以被系统中的其他组件访问。
VehicleStub¶
// packages/services/Car/service/src/com/android/car/VehicleStub.java
/**
* VehicleStub 表示一个 IVehicle 服务接口,可以是 AIDL 或遗留的 HIDL 版本。
* 它提供了一个通用接口,使客户端不需要关心底层 IVehicle 服务是哪种版本。
*/
public abstract class VehicleStub {
/**
* 创建一个新的 VehicleStub 以连接到车辆硬件抽象层(Vehicle HAL)。
*
* 根据可用的后端(AIDL 或 HIDL)创建一个新的 VehicleStub 以连接到车辆 HAL。
* 如果没有可用的车辆 HAL,此函数将抛出 {@link IllegalStateException}。
*
* @return 一个连接到车辆 HAL 的 vehicle stub。
* @throws IllegalStateException 如果没有可用的车辆 HAL 服务。
*/
public static VehicleStub newVehicleStub() throws IllegalStateException {
// 尝试创建一个 AIDL 版本的 VehicleStub。
VehicleStub stub = new AidlVehicleStub();
// 检查 AIDL 版本的 VehicleStub 是否有效。
if (stub.isValid()) {
// 如果是用户调试版本或工程版本,并且启用了 FakeVehicleStub,则尝试创建 FakeVehicleStub。
if ((BuildHelper.isUserDebugBuild() || BuildHelper.isEngBuild())
&& FakeVehicleStub.doesEnableFileExist()) {
try {
// 返回一个 FakeVehicleStub 实例。
return new FakeVehicleStub(stub);
} catch (Exception e) {
// 如果创建 FakeVehicleStub 失败,记录错误日志并回退到使用真实的 VehicleStub。
Slogf.e(CarLog.TAG_SERVICE, e, "Failed to create FakeVehicleStub. "
+ "Fallback to using real VehicleStub.");
}
}
// 返回有效的 AIDL 版本的 VehicleStub。
return stub;
}
// 如果没有找到 AIDL 版本的车辆 HAL,记录信息日志并尝试使用 HIDL 版本。
Slogf.i(CarLog.TAG_SERVICE, "No AIDL vehicle HAL found, fall back to HIDL version");
// 尝试创建一个 HIDL 版本的 VehicleStub。
stub = new HidlVehicleStub();
// 如果 HIDL 版本的 VehicleStub 也无效,则抛出异常。
if (!stub.isValid()) {
throw new IllegalStateException("Vehicle HAL service is not available.");
}
// 返回有效的 HIDL 版本的 VehicleStub。
return stub;
}
}
创建并返回一个 VehicleStub
实例,该实例用于连接到车辆硬件抽象层(Vehicle HAL)。函数根据当前系统中可用的后端(AIDL 或 HIDL)来决定使用哪种版本的 VehicleStub
。
- 尝试使用 Stable AIDL 版本
- 首先,函数尝试创建一个
AidlVehicleStub
实例。 - 检查该实例是否有效(
isValid()
方法)。 - 如果有效,并且在用户调试版本或工程版本中启用了
FakeVehicleStub
,则尝试创建并返回一个FakeVehicleStub
。 - 如果创建
FakeVehicleStub
失败,则记录错误日志并回退到使用真实的AidlVehicleStub
。
- 首先,函数尝试创建一个
- 回退到 HIDL 版本
- 如果 AIDL 版本不可用,函数记录信息日志并尝试创建一个
HidlVehicleStub
实例。 - 检查该实例是否有效。
- 如果 HIDL 版本也不可用,则抛出
IllegalStateException
异常,表示没有可用的车辆 HAL 服务。
- 如果 AIDL 版本不可用,函数记录信息日志并尝试创建一个
Android 从 Android 12 开始,将 HIDL(HAL Interface Definition Language)逐步替换为 Stable AIDL(Android Interface Definition Language)。这一切换的目标是简化接口定义,并提供更高的稳定性和向后兼容性。
Vehicle HAL 是在 Android 13 中实现了从 HIDL 到 Stable AIDL 的迁移。
在分析 Android 15 时,我们专注于使用 Stable AIDL 接口,而不再考虑 HIDL 版本。VehicleStub
是一个抽象类,其具体实现用于通过 IPC 与车辆硬件抽象层(Vehicle HAL)进行交互。在深入分析之前,我们需要先了解 Vehicle HAL 提供的主要 IPC 接口,以便更好地理解其功能和交互方式。
IVehicle.aidl¶
// hardware/interfaces/automotive/vehicle/aidl/android/hardware/automotive/vehicle/IVehicle.aidl
// Vehicle HAL 接口,定义了与车辆硬件抽象层(Vehicle HAL)进行通信的接口。
@VintfStability
interface IVehicle {
/* 一个无效的内存 ID,用于标识无效的共享内存。 */ const long INVALID_MEMORY_ID = 0;
/* 每个订阅客户端的最大共享内存文件数,限制了每个客户端可以使用的共享内存文件数量。 */ const int MAX_SHARED_MEMORY_FILES_PER_CLIENT = 3;
/**
* 返回车辆 HAL 支持的所有属性配置的列表。
*
* @return 一个可打包的对象,可能包含配置列表或一个共享内存文件(如果配置列表超出了 binder 内存限制)。
* 必须使用 {@code android-automotive-large-parcelable} 库来解析返回的对象。
*/
VehiclePropConfigs getAllPropConfigs();
/**
* 返回指定属性的配置列表。
*
* 如果请求的属性中有未找到的,必须返回 {@link StatusCode#INVALID_ARG},
* 否则返回包含 {@link StatusCode#OK} 的车辆属性配置列表。
*
* @param props 要获取配置的属性 ID 列表。
* @return 一个可打包的对象,可能包含配置列表或一个共享内存文件(如果配置列表超出了 binder 内存限制)。
* 必须使用 {@code android-automotive-large-parcelable} 库来解析返回的对象。
*/
VehiclePropConfigs getPropConfigs(in int[] props);
/**
* 异步获取车辆属性值。
*
* 当值被获取时,将调用 {@link IVehicleCallback#onGetValues} 方法。
* 该方法可能会被多次调用,每次调用时传递已获取的属性的子集。
* 例如,如果请求属性 [A, B, C],回调可能会被调用两次,分别传递 [A, C] 和 [B]。
* 调用者不应期望 {@link IVehicleCallback#onGetValues} 的调用顺序。
*
* 如果此方法返回错误,则表示我们无法获取所有属性。
* 如果此方法返回 OK,仍然有可能无法获取某些属性,这些属性的状态由 {@link GetValueResult#status} 指示。
*
* 对于 {@link VehiclePropertyChangeMode#STATIC} 属性,此方法必须始终返回相同的值。
* 对于 {@link VehiclePropertyChangeMode#ON_CHANGE} 属性,必须返回最新可用的值。
* 对于可缓存的属性,将返回缓存中的值,而无需与实际的车辆总线通信。
*
* 某些属性(如 {@code RADIO_PRESET})需要在 {@link VehiclePropValue} 对象中传递附加数据。
*
* 如果尚无可用数据(这可能发生在初始阶段),{@link GetValueResult#status} 包含 {@link StatusCode#TRY_AGAIN}。
*
* 调用者必须为每个请求传递一个唯一的 RequestID,如果任何给定的请求 ID 与挂起的请求 ID 重复,
* 此函数必须返回 {@link StatusCode#INVALID_ARG}。
*
* 为防止混淆,单个调用中不允许重复属性(相同的属性 ID 和相同的区域 ID)。
* 此函数必须为重复属性返回 {@link StatusCode#INVALID_ARG}。
*
* 请求中的 {@link VehiclePropValue#timestamp} 字段将被忽略。
* {@link GetValueResult} 中的 {@link VehiclePropValue#timestamp} 字段必须是自启动以来的系统运行时间,
* 当值发生变化时适用于 ON_CHANGE 属性,或根据轮询率检查值时适用于 CONTINUOUS 属性。
* 请注意,对于 CONTINUOUS 属性,VHAL 客户端在轮询间隔内多次读取属性将获得相同的时间戳。
*
* @param callback 一个回调接口,在值被获取后调用其 'onGetValues'。
* 调用者应使用 {@code android-automotive-large-parcelable} 库来解析返回的 {@link GetValueResult} 对象。
* @param requests 一个对象,包含请求的属性列表或包含属性的共享内存文件。
* 该对象必须使用发送方和接收方的辅助库进行解析。
*/
void getValues(IVehicleCallback callback, in GetValueRequests requests);
/**
* 设置车辆属性值。
*
* 在值设置请求通过车辆总线发送或设置失败后,将调用 {@link IVehicleCallback#onSetValues} 函数。
* 如果总线协议支持确认,则在收到确认后调用回调。
*
* 对于某些不支持确认的车辆总线(如 CAN 总线),OnSetValues 不一定意味着值的变化会立即反映在 {@link #getValues} 中。
*
* 如果输出状态包含错误,则表示我们无法设置所有属性。
* 如果我们无法设置某些值,它们将反映为非 OK 的 {@link SetValueResult#status}。
*
* 请求中每个属性的设置顺序不保证。如果调用者需要确保设置值的顺序,调用者应设置一个值,等待其回调,然后设置另一个值。
*
* 数据的时间戳在设置操作中必须被忽略。
*
* 设置某些属性需要有可用的初始状态。如果初始数据尚不可用,{@link SetValueResult#status} 必须是 {@link StatusCode#TRY_AGAIN}。
* 对于具有独立电源控制的属性,如果属性未通电,{@link SetValueResult#status} 必须是 {@link StatusCode#NOT_AVAILABLE}。
*
* 调用者必须为每个请求传递一个唯一的 RequestID,如果任何给定的请求 ID 与挂起的请求 ID 重复,
* 此函数必须返回 {@link StatusCode#INVALID_ARG}。
*
* 为防止混淆,单个调用中不允许重复属性(相同的属性 ID 和相同的区域 ID)。
* 此函数必须为重复属性返回 {@link StatusCode#INVALID_ARG}。
*
* @param callback 回调,在设置值请求发送到总线后调用其 'onSetValues'。
* @param requests 一个对象,包含 {@link SetValueRequest} 列表或存储请求列表的共享内存文件(如果它们超过 binder 内存限制),
* 必须使用发送方和接收方的辅助库进行解析。
*/
void setValues(IVehicleCallback callback, in SetValueRequests requests);
/**
* 订阅属性事件。
*
* 客户端必须能够根据 options 参数中提供的数据一次订阅多个属性。
*
* 对于一个回调,一个属性只有一个订阅。具有不同采样率的新订阅将覆盖旧订阅。
* 一个属性可以为不同的回调多次订阅。
*
* 如果返回错误,则表示某些属性订阅失败。
* 调用者可以安全地重试,因为订阅已订阅的属性是可以的。
*
* 指定的采样率只是一个指导。根据轮询刷新率,无法保证采样率是可实现的。
* 实际的属性事件率可能高于或低于指定的 sampleRate。
* 例如,如果轮询率可以是每秒 5 次或 10 次,订阅 7 的采样率可能会使用每秒 5 次的轮询率,从而生成每秒 5 次事件。
* 我们只要求平均而言,{@code minSampleRate} 和 {@code maxSampleRate} 可以实现,
* 所有在最小和最大之间的 sampleRate 平均而言生成事件的速率 >= {@code minSampleRate} 且 <= {@code maxSampleRate}。
*
* 每个属性事件的 {@link VehiclePropValue#timestamp} 字段必须是自启动以来的系统运行时间,
* 当值发生变化时适用于 ON_CHANGE 属性,或根据轮询率检查值时适用于 CONTINUOUS 属性。
* 请注意,对于 CONTINUOUS 属性,VHAL 客户端在轮询间隔内多次读取属性将获得相同的时间戳。
* 例如,如果属性的轮询率是每秒 10 次,无论 {@code options} 中指定的 sampleRate 是什么,时间戳每秒更新 10 次。
*
* 如果由于某些电源状态关闭而无法读取属性,则在属性可用之前可能不会生成属性更改事件。
* 对于 ON_CHANGE 属性,如果属性从 NOT_AVAILABLE 更改为 OKAY 以读取某些或所有区域,
* 对于每个可供读取的区域,必须生成一个属性更改事件。事件必须包含该区域的当前值并具有 {@code AVAILABLE} 状态。
*
* @param callback 订阅回调。
* 当新属性事件到达时,将调用 {@link IVehicleCallback#onPropertyEvent}。
* 当属性设置请求异步失败时,将调用 {@link IVehicleCallback#onPropertySetError}。
* 这通常是由车辆总线发送的属性设置失败消息引起的。
* @param options 订阅选项列表。SubscribeOption 包含属性 ID、区域 ID、采样率等信息。
* 对于连续属性,必须提供采样率。如果采样率小于 {@link VehiclePropConfig#minSampleRate},
* 则采样率将为 minSampleRate。如果采样率大于 {@link VehiclePropValue#maxSampleRate},
* 则采样率将为 maxSampleRate。
* @param maxSharedMemoryFileCount 为此订阅在 VHAL 中分配的最大共享内存文件数。
* 当内存文件返回给客户端时,在调用 returnSharedMemory 将缓冲区返回给 VHAL 之前,
* VHAL 不能使用该内存文件来传递另一个事件。较大的 maxSharedMemoryFileCount 意味着在处理大量数据时性能更好,
* 但也意味着更大的内存占用。如果不期望事件非常频繁地到达,建议值为 2。值为 0 表示对于每个新属性,
* 将创建一个新的共享内存文件,并且不会重用任何共享内存文件。这仅应为不频繁的事件或内存有限的设备配置。
* 此值必须 >=0 且 < {@link MAX_SHARED_MEMORY_FILES_PER_CLIENT}。
*/
void subscribe(in IVehicleCallback callback, in SubscribeOptions[] options,
int maxSharedMemoryFileCount);
/**
* 取消订阅属性事件。
*
* 如果 'callback' 无效,此方法必须返回 {@link StatusCode#INVALID_ARG}。
* 如果指定的 propId 之前未订阅,此方法必须忽略该 propId。
*
* 如果返回错误,则表示某些属性取消订阅失败。
* 调用者可以安全地重试,因为取消订阅已取消订阅的属性是可以的。
*
* @param callback 在先前订阅中使用的回调。
* @param propIds 要取消订阅的属性的 ID。
*/
void unsubscribe(in IVehicleCallback callback, in int[] propIds);
/**
* 将共享内存文件返回给 VHAL 以供回收。
*
* 在客户端不再使用由 {@link IVehicleCallback#onPropertyEvent} 返回的共享内存文件后,必须调用此方法。
* 通常在 'onPropertyEvent' 结束时调用此方法。
*
* 如果 'callback' 无效或 'sharedMemoryId' 与传递给 {@link IVehicleCallback#onPropertyEvent} 的
* 'VehiclePropValues' 中的任何 SharedMemoryId 不匹配,此方法必须返回 {@link StatusCode#INVALID_ARG}。
*
* @param callback 在订阅中使用的回调。
* @param sharedMemoryId 由 'onPropertyEvent' 返回的 ID,表示要返回的已使用共享内存文件。
*/
void returnSharedMemory(in IVehicleCallback callback, long sharedMemoryId);
}
以上是 IVehicle.aidl 代码,从其接口可以看出,其主要是与车辆 HAL 交互的核心接口,支持获取和设置车辆属性,处理异步操作和资源管理。
-
getAllPropConfigs() 返回车辆 HAL 支持的所有属性配置的列表。
-
getPropConfigs(): 返回指定属性的配置列表。
-
getValues(): 异步获取车辆属性值。通过回调函数返回结果,可能多次调用以返回属性的子集。支持不同的属性变化模式(静态、变化、连续),并处理缓存和时间戳。
-
setValues(): 设置车辆属性值。通过回调函数通知设置结果。处理设置顺序、确认机制、初始状态需求和重复请求 ID 等问题。
-
subscribe(): 订阅属性事件。
-
unsubscribe 方法: 取消订阅指定属性的事件。
IVehicleCallback.aidl¶
// hardware/interfaces/automotive/vehicle/aidl/android/hardware/automotive/vehicle/IVehicleCallback.aidl
// IVehicleCallback 接口,定义了与车辆硬件抽象层(Vehicle HAL)进行通信时的回调接口。
@VintfStability
interface IVehicleCallback {
/**
* {@link IVehicle#getValues} 函数的回调。
*
* 当一些要获取的值准备好时调用。对于一个 'getValues' 请求,这个方法可能被调用一次或多次。
* 每个回调包含部分请求的值。保证所有请求的值都会在某个回调中返回,但每个值准备好的顺序不保证。
*
* @param responses 一个对象,包含 {@link GetValueResult} 的列表(如果它们符合 binder 内存限制)或包含响应的共享内存文件。
* 每个 {@link GetValueResult} 要么包含属性值,要么包含获取值时发生的错误。
*
* {@link GetValueResult} 还包含一个 requestId,指示该响应是针对哪个请求的。
* 响应对象应由 {@code android-automotive-large-parcelable} 库解析。
*/
oneway void onGetValues(in GetValueResults responses);
/**
* {@link IVehicle#setValues} 函数的回调。
*
* 当 VHAL 完成处理一些属性设置请求时调用。对于一个 'setValues' 请求,这个方法可能被调用一次或多次。
* 每个回调包含部分请求的值。保证所有设置的值状态都会在某个回调中返回,但每个值设置的顺序不保证。
*
* @param responses {@link SetValueResult} 的列表。每个 SetValueResult 包含一个状态,指示设置特定属性的状态。
* requestId 指示该响应是针对哪个请求的。
*/
oneway void onSetValues(in SetValueResults responses);
/**
* 当 API 用户订阅的一个或多个变量需要报告时发生的事件回调。
* 这可能纯粹基于阈值和频率(常规订阅,参见 subscribe 调用的参数)或当调用 {@link IVehicle#setValues} 方法并需要报告实际更改时。
*
* @param propValues 包含更新的属性值的对象。
* 如果属性在 binder 限制内,它们将位于 {@code propValues.payloads} 中,否则,它们将位于共享内存文件 {@code propValues.sharedMemoryFd} 中。
* 共享内存文件由 VHAL 创建,使用后必须使用 {@link IVehicle#returnSharedMemory} 返回给 VHAL。
* 为每个订阅创建的内存文件数量有限,如果客户端不返回共享内存,客户端可能无法在未来获得事件。
* @param sharedMemoryFileCount 为此订阅分配的共享内存文件数量。
* 该值可用于调整 {@link IVehicle#subscribe} 中的 {@code maxSharedMemoryFileCount}。
* 例如,如果您通常看到 sharedMemoryFileCount 是您设置的 maxSharedMemoryFileCount,这意味着您可能需要增加 maxSharedMemoryFileCount。
*/
oneway void onPropertyEvent(in VehiclePropValues propValues, int sharedMemoryFileCount);
/**
* 设置属性值通常是异步操作。因此,即使客户端从 {@link IVehicle#setValues} 收到 {@link StatusCode#OK},
* 或在 {@link #onSetValues} 中收到 {@link StatusCode#OK},这并不保证值已成功传播到车辆网络。
* 如果发生这种罕见事件,则必须调用此方法。
*
* @param errors 属性设置错误的列表。如果 VHAL 实现不批量处理错误,这可能只包含一个错误。
*/
oneway void onPropertySetError(in VehiclePropErrors errors);
}
-
onGetValues(): 用于处理
IVehicle#getValues
请求的回调。当请求的属性值准备好时调用,可能会多次调用以返回部分结果。 -
onSetValues(): 用于处理
IVehicle#setValues
请求的回调。当请求的属性设置完成时调用,可能会多次调用以返回部分结果。 -
onPropertyEvent(): 当订阅的属性事件发生时调用。可能基于订阅的阈值和频率或属性设置的变化。
-
onPropertySetError(): 当属性设置过程中发生错误时调用。即使之前的操作返回成功状态,也可能出现错误。
现在我们知道了跟 Vehicle HAL 交互的主要接口了,我们返回到VehicleStub.newVehicleStub()中,其获取 Stable AIDL 版本就是创建一个AidlVehicleStub实例。
AidlVehicleStub构造函数¶
// packages/services/Car/service/src/com/android/car/AidlVehicleStub.java
// AidlVehicleStub 类是 VehicleStub 的具体实现,用于通过 AIDL 接口与车辆硬件抽象层(Vehicle HAL)进行通信。
final class AidlVehicleStub extends VehicleStub {
// IVehicle 接口的实例,用于与车辆 HAL 进行通信。
private final IVehicle mAidlVehicle;
// 用于构建 HAL 属性值的构建器,指定为 AIDL 版本。
private final HalPropValueBuilder mPropValueBuilder;
// 用于处理异步操作的 HandlerThread。
private final HandlerThread mHandlerThread;
// 用于处理消息和异步任务的 Handler。
private final Handler mHandler;
// 用于处理获取和设置值回调的内部类实例。
private final GetSetValuesCallback mGetSetValuesCallback;
// 用于管理挂起的异步请求的池。
private final PendingAsyncRequestPool mPendingAsyncRequestPool;
// 默认构造函数,使用静态方法 getAidlVehicle() 获取 IVehicle 实例。
AidlVehicleStub() {
this(getAidlVehicle());
}
// 测试可见的构造函数,允许传入自定义的 IVehicle 实例。
@VisibleForTesting
AidlVehicleStub(IVehicle aidlVehicle) {
// 使用默认的 HandlerThread 实例化 AidlVehicleStub。
this(aidlVehicle,
CarServiceUtils.getHandlerThread(AidlVehicleStub.class.getSimpleName()));
}
// 测试可见的构造函数,允许传入自定义的 IVehicle 实例和 HandlerThread。
@VisibleForTesting
AidlVehicleStub(IVehicle aidlVehicle, HandlerThread handlerThread) {
// 初始化成员变量。
mAidlVehicle = aidlVehicle; // 赋值 IVehicle 实例。
mPropValueBuilder = new HalPropValueBuilder(/*isAidl=*/true); // 初始化属性值构建器。
mHandlerThread = handlerThread; // 赋值 HandlerThread 实例。
mHandler = new Handler(mHandlerThread.getLooper()); // 创建 Handler 实例。
mGetSetValuesCallback = new GetSetValuesCallback(); // 初始化回调实例。
mPendingAsyncRequestPool = new PendingAsyncRequestPool(mHandler.getLooper()); // 初始化异步请求池。
}
}
- 调用
getAidlVehicle()
方法获取IVehicle
实例。 - 初始化回调实例 mGetSetValuesCallback。
getAidlVehicle()¶
// packages/services/Car/service/src/com/android/car/AidlVehicleStub.java
// AidlVehicleStub 类是 VehicleStub 的具体实现,用于通过 AIDL 接口与车辆硬件抽象层(Vehicle HAL)进行通信。
final class AidlVehicleStub extends VehicleStub {
// 定义 AIDL VHAL 服务的名称,用于从服务管理器中获取服务实例。
private static final String AIDL_VHAL_SERVICE =
"android.hardware.automotive.vehicle.IVehicle/default";
/**
* 获取 AIDL 车辆服务的实例。
*
* 尝试从服务管理器中获取名为 AIDL_VHAL_SERVICE 的车辆服务。
* 如果获取成功,则返回 IVehicle 接口的实例。
* 如果获取失败,则记录警告日志并返回 null。
*
* @return IVehicle 接口的实例,如果获取失败则返回 null。
*/
@Nullable
private static IVehicle getAidlVehicle() {
try {
// 从服务管理器中等待并获取声明的服务,然后将其转换为 IVehicle 接口。
return IVehicle.Stub.asInterface(
ServiceManagerHelper.waitForDeclaredService(AIDL_VHAL_SERVICE));
} catch (RuntimeException e) {
// 如果在获取服务时发生运行时异常,记录警告日志。
Slogf.w(TAG, "Failed to get \"" + AIDL_VHAL_SERVICE + "\" service", e);
}
// 如果获取服务失败,返回 null。
return null;
}
}
通过获取服务并将其转换为 IVehicle
接口实例,我们就能够调用之前分析的 IVehicle.aidl
中定义的接口。这一过程使得 CarService 能够与车辆硬件抽象层(Vehicle HAL)进行交互,执行如获取和设置车辆属性、订阅属性事件等操作。
GetSetValuesCallback¶
// packages/services/Car/service/src/com/android/car/AidlVehicleStub.java
// GetSetValuesCallback 是一个私有的内部类,用于处理车辆属性的获取和设置操作的回调。
// 它继承自 IVehicleCallback.Stub,这是一个 AIDL 生成的抽象类,用于处理异步通信。
private final class GetSetValuesCallback extends IVehicleCallback.Stub {
/**
* 当车辆属性值获取操作完成时调用。
*
* @param responses 包含获取操作结果的对象。
* @throws RemoteException 如果远程调用失败。
*/
@Override
public void onGetValues(GetValueResults responses) throws RemoteException {
// 调用外部类 AidlVehicleStub 的 onGetValues 方法,将获取的结果传递给它进行处理。
AidlVehicleStub.this.onGetValues(responses);
}
/**
* 当车辆属性值设置操作完成时调用。
*
* @param responses 包含设置操作结果的对象。
* @throws RemoteException 如果远程调用失败。
*/
@Override
public void onSetValues(SetValueResults responses) throws RemoteException {
// 调用外部类 AidlVehicleStub 的 onSetValues 方法,将设置的结果传递给它进行处理。
AidlVehicleStub.this.onSetValues(responses);
}
/**
* 当订阅的属性事件发生时调用。
*
* @param propValues 包含更新的属性值的对象。
* @param sharedMemoryFileCount 共享内存文件的数量。
* @throws RemoteException 如果远程调用失败。
*/
@Override
public void onPropertyEvent(VehiclePropValues propValues, int sharedMemoryFileCount)
throws RemoteException {
// 该方法在 GetSetValuesCallback 中不支持,抛出异常。
throw new UnsupportedOperationException(
"GetSetValuesCallback only support onGetValues or onSetValues");
}
/**
* 当属性设置过程中发生错误时调用。
*
* @param errors 包含属性设置错误的对象。
* @throws RemoteException 如果远程调用失败。
*/
@Override
public void onPropertySetError(VehiclePropErrors errors) throws RemoteException {
// 该方法在 GetSetValuesCallback 中不支持,抛出异常。
throw new UnsupportedOperationException(
"GetSetValuesCallback only support onGetValues or onSetValues");
}
}
GetSetValuesCallback 继承自 IVehicleCallback.Stub,用于处理异步通信。
VehicleStub.newVehicleStub()
方法用于创建车辆接口对象 mVehicle
,我们到此为止已经对其进行了详细分析。接下来,我们将会有专门的文章深入探讨 AidlVehicleStub
类中设置属性和监听属性的具体过程。目前,我们仅对其初始化过程进行了简单分析。
ICarImpl创建¶
回到 CarServiceImpl.onCreate() 中,创建完 VehicleStub 之后就开始 ICarImpl 对象。
// packages/services/Car/service/src/com/android/car/CarServiceImpl.java
@Override
public void onCreate() {
// 构建一个ICarImpl对象,设置服务上下文、内置包上下文、车辆对象、系统接口和车辆接口名称。
mICarImpl = new ICarImpl.Builder()
.setServiceContext(this)
.setBuiltInContext(getBuiltinPackageContext())
.setVehicle(mVehicle)
.setSystemInterface(
SystemInterface.Builder.defaultSystemInterface(this).build())
.setVehicleInterfaceName(mVehicleInterfaceName)
.build();
// 初始化ICarImpl对象。
mICarImpl.init();
}
ICarImpl.Builder()¶
// packages/services/Car/service/src/com/android/car/ICarImpl.java
// ICarImpl 类继承自 ICar.Stub,用于实现汽车服务的具体功能。
public class ICarImpl extends ICar.Stub {
// Builder 是 ICarImpl 的静态内部类,用于构建 ICarImpl 对象。
public static final class Builder {
// 服务上下文,用于获取应用程序的全局信息。
Context mContext;
// 汽车服务内置包的上下文。
Context mCarServiceBuiltinPackageContext;
// VehicleStub 对象,用于与车辆硬件抽象层(VHAL)进行通信。
VehicleStub mVehicle;
// 系统接口对象,用于与系统服务交互。
SystemInterface mSystemInterface;
// 车辆接口名称,用于标识车辆接口。
String mVehicleInterfaceName;
/**
* 构建由此构建器对象表示的 ICarImpl 对象。
*
* @return ICarImpl 对象
*/
public ICarImpl build() {
return new ICarImpl(this);
}
/**
* 设置 ICarImpl 构建器的服务上下文。
*
* @param serviceContext 服务上下文
* @return 当前构建器对象
*/
public Builder setServiceContext(Context serviceContext) {
mContext = serviceContext;
return this;
}
/**
* 设置 ICarImpl 构建器的内置上下文。
*
* @param builtInContext 汽车服务内置包的上下文
* @return 当前构建器对象
*/
public Builder setBuiltInContext(Context builtInContext) {
mCarServiceBuiltinPackageContext = builtInContext;
return this;
}
/**
* 设置 ICarImpl 构建器的车辆对象。
*
* @param vehicle 要使用的 VehicleStub 对象
* @return 当前构建器对象
*/
public Builder setVehicle(VehicleStub vehicle) {
mVehicle = vehicle;
return this;
}
/**
* 设置 ICarImpl 构建器的系统接口。
*
* @param systemInterface 系统接口对象
* @return 当前构建器对象
*/
public Builder setSystemInterface(SystemInterface systemInterface) {
mSystemInterface = systemInterface;
return this;
}
/**
* 设置 ICarImpl 构建器的车辆接口名称。
*
* @param vehicleInterfaceName 车辆接口名称
* @return 当前构建器对象
*/
public Builder setVehicleInterfaceName(String vehicleInterfaceName) {
mVehicleInterfaceName = vehicleInterfaceName;
return this;
}
}
}
在上一篇文章 Android 15 CarService源码01-服务启动 中,有一个细节我们当时没有深入探讨。在 ServiceProxy.init()
方法中调用 mRealService.setBuiltinPackageContext(this)
,实际上是将 builtin app 的上下文传递给了可更新应用中的 CarServiceImpl
。因此,setBuiltInContext
方法用于设置 builtin app
的上下文,而 setServiceContext
方法则用于设置 updatable app
自身的上下文。
个人感觉 SystemInterface 暂时不重要,先不分析。
ICarImpl构造函数¶
// packages/services/Car/service/src/com/android/car/ICarImpl.java
// ICarImpl 类继承自 ICar.Stub,用于实现汽车服务的具体功能。
public class ICarImpl extends ICar.Stub {
// ICarImpl 的私有构造函数,通过 Builder 对象进行初始化。
private ICarImpl(Builder builder) {
// 当前大约有 36 个服务,因此使用 40 作为初始容量来创建服务列表。
List<CarSystemService> allServices = new ArrayList<>(40);
// 构建 VehicleHal 实例,并将其添加到服务列表中。
mHal = constructWithTrace(t, VehicleHal.class,
() -> new VehicleHal(mContext, builder.mVehicle), allServices);
// 构建 CarPropertyService 实例,并将其添加到服务列表中。
mCarPropertyService = constructWithTrace(
t, CarPropertyService.class,
() -> new CarPropertyService.Builder()
.setContext(mContext)
.setPropertyHalService(mHal.getPropertyHal())
.build(), allServices);
// 从构建器获取或构建 CarUserService 实例,并将其添加到服务列表中。
mCarUserService = getFromBuilderOrConstruct(t, CarUserService.class,
builder.mCarUserService,
() -> {
int maxRunningUsers = UserManagerHelper.getMaxRunningUsers(mContext);
return new CarUserService(mContext, mHal.getUserHal(), userManager,
maxRunningUsers, mCarUXRestrictionsService, mCarPackageManagerService,
mCarOccupantZoneService);
},
allServices);
// 如果在构造时启用了优先初始化,则进行优先初始化。
if (mDoPriorityInitInConstruction) {
Slogf.i(TAG, "VHAL Priority Init Enabled");
Slogf.i(TAG, "Car User Service Priority Init Enabled");
priorityInit();
}
// 构建 CarInputService 实例,并将其添加到服务列表中。
mCarInputService = constructWithTrace(t, CarInputService.class,
() -> new CarInputService(mContext, mHal.getInputHal(), mCarUserService,
mCarOccupantZoneService, mCarBluetoothService, mCarPowerManagementService,
mSystemInterface), allServices);
// 将所有服务按初始化顺序存储在数组中。
mAllServicesInInitOrder = allServices.toArray(new CarSystemService[allServices.size()]);
}
}
创建一个初始容量为 40 的服务列表 allServices
,然后通过 constructWithTrace
方法构建各种服务实例,并将这些实例添加到服务列表中。最后,将所有服务按初始化顺序存储在 mAllServicesInInitOrder
数组中。
在调用 ICarImpl.Builder() 没有设置 setDoPriorityInitInConstruction,所以在 ICarImpl构造函数不会初始化 priority
ICarImpl.constructWithTrace()¶
// packages/services/Car/service/src/com/android/car/ICarImpl.java
// ICarImpl 类继承自 ICar.Stub,用于实现汽车服务的具体功能。
public class ICarImpl extends ICar.Stub {
// ICarImpl 的私有构造函数,通过 Builder 对象进行初始化。
private ICarImpl(Builder builder) {
// 构建 VehicleHal 实例,并将其添加到服务列表中。
// 使用 constructWithTrace 方法来创建 VehicleHal 实例。
mHal = constructWithTrace(t, VehicleHal.class,
() -> new VehicleHal(mContext, builder.mVehicle), allServices);
}
/**
* 使用构建跟踪来构建服务实例。
*
* @param t 用于跟踪构建过程的 TimingsTraceLog 对象。
* @param cls 要构建的服务类的 Class 对象。
* @param callable 一个 Callable 对象,用于实际创建服务实例。
* @param allServices 服务列表,用于存储所有构建的服务实例。
* @param <T> CarSystemService 的子类。
* @return 构建的服务实例。
*/
private static <T extends CarSystemService> T constructWithTrace(TimingsTraceLog t,
Class<T> cls, Callable<T> callable, List<CarSystemService> allServices) {
// 开始跟踪服务构建过程。
t.traceBegin(cls.getSimpleName());
T constructed;
try {
// 使用 callable.call() 方法实际创建服务实例。
constructed = callable.call();
// 将构建的服务实例添加到 CarLocalServices 中,以便其他组件可以访问。
CarLocalServices.addService(cls, constructed);
} catch (Exception e) {
// 如果在构建过程中发生异常,抛出运行时异常并记录错误信息。
throw new RuntimeException("Crash while constructing:" + cls.getSimpleName(), e);
} finally {
// 结束跟踪服务构建过程。
t.traceEnd();
}
// 将构建的服务实例添加到服务列表中。
allServices.add(constructed);
return constructed;
}
}
在这个例子中,我们以 VehicleHal
为例。constructWithTrace()
是一个泛型方法,用于构建 CarSystemService
的实例。Callable
是一个函数式接口,与 Runnable
类似,但它能够返回结果或抛出异常。callable.call()
方法执行 Callable
的逻辑并返回结果,在这里用于实际创建服务实例。通过使用 Callable
,我们可以将服务实例的创建逻辑封装在一个可调用对象中,并在需要时执行。这种设计提供了灵活性,允许在不同的上下文中复用相同的创建逻辑。
VehicleHal¶
我们来看下 VehicleHal 的创建过程。
// packages/services/Car/service/src/com/android/car/hal/VehicleHal.java
// VehicleHal 类实现了 VehicleHalCallback 和 CarSystemService 接口,负责管理车辆硬件抽象层(VHAL)的服务。
public class VehicleHal implements VehicleHalCallback, CarSystemService {
// 存储所有 HAL 服务的列表。
private final List<CarSystemService> mAllServices;
// 车辆存根对象,用于与 VHAL 进行通信。
private final VehicleStub mVehicleStub;
// 订阅客户端,用于处理属性事件的订阅。
private final SubscriptionClient mSubscriptionClient;
/**
* 构造一个新的 VehicleHal 对象,使用传入的 Context 和 VehicleStub。
*
* @param context 应用程序上下文。
* @param vehicle 车辆存根对象。
*/
public VehicleHal(Context context, VehicleStub vehicle) {
// 调用另一个构造函数,传入默认的 HAL 服务和处理线程。
this(context, /* powerHal= */ null, /* propertyHal= */ null,
/* inputHal= */ null, /* vmsHal= */ null, /* userHal= */ null,
/* diagnosticHal= */ null, /* clusterHalService= */ null,
/* timeHalService= */ null,
CarServiceUtils.getHandlerThread(VehicleHal.class.getSimpleName()), vehicle);
}
/**
* 构造一个新的 VehicleHal 对象,使用传入的服务和处理线程。
* 该方法仅供测试使用。
*
* @param context 应用程序上下文。
* @param powerHal 电源 HAL 服务。
* @param propertyHal 属性 HAL 服务。
* @param inputHal 输入 HAL 服务。
* @param vmsHal VMS HAL 服务。
* @param userHal 用户 HAL 服务。
* @param diagnosticHal 诊断 HAL 服务。
* @param clusterHalService 集群 HAL 服务。
* @param timeHalService 时间 HAL 服务。
* @param handlerThread 处理线程。
* @param vehicle 车辆存根对象。
*/
@VisibleForTesting
VehicleHal(Context context,
PowerHalService powerHal,
PropertyHalService propertyHal,
InputHalService inputHal,
VmsHalService vmsHal,
UserHalService userHal,
DiagnosticHalService diagnosticHal,
ClusterHalService clusterHalService,
TimeHalService timeHalService,
HandlerThread handlerThread,
VehicleStub vehicle) {
// 必须在 HalService 之前初始化,以便 HalService 可以使用它。
mPropValueBuilder = vehicle.getHalPropValueBuilder();
mHandlerThread = handlerThread;
mHandler = new Handler(mHandlerThread.getLooper());
// 初始化各个 HAL 服务,如果传入的服务为 null,则创建默认实例。
mPowerHal = powerHal != null ? powerHal : new PowerHalService(context, mFeatureFlags, this);
mPropertyHal = propertyHal != null ? propertyHal : new PropertyHalService(this);
mInputHal = inputHal != null ? inputHal : new InputHalService(this);
mVmsHal = vmsHal != null ? vmsHal : new VmsHalService(context, this);
mUserHal = userHal != null ? userHal : new UserHalService(this);
mDiagnosticHal = diagnosticHal != null ? diagnosticHal : new DiagnosticHalService(this);
mClusterHalService = clusterHalService != null
? clusterHalService : new ClusterHalService(context, this);
mEvsHal = new EvsHalService(this);
mTimeHalService = timeHalService != null
? timeHalService : new TimeHalService(context, this);
// 将所有 HAL 服务存储在列表中。
mAllServices = List.of(
mPowerHal,
mInputHal,
mDiagnosticHal,
mVmsHal,
mUserHal,
mClusterHalService,
mEvsHal,
mTimeHalService,
// mPropertyHal 必须是最后一个,以便在初始化/释放时可以用于所有其他 HAL 服务属性。
mPropertyHal);
// 初始化车辆存根和订阅客户端。
mVehicleStub = vehicle;
mSubscriptionClient = vehicle.newSubscriptionClient(this);
}
}
实现了 VehicleHalCallback
和 CarSystemService
接口,负责管理与车辆硬件抽象层(VHAL)的交互。
初始化各种 HAL 服务,并存储所有 HAL 服务到 mAllServices 中。
最后调用vehicle.newSubscriptionClient(this)订阅事件回调。
AidlVehicleStub.AidlSubscriptionClient¶
// packages/services/Car/service/src/com/android/car/AidlVehicleStub.java
final class AidlVehicleStub extends VehicleStub {
// AidlSubscriptionClient 是一个私有内部类,继承自 IVehicleCallback.Stub,并实现了 SubscriptionClient 接口。
// 它用于处理车辆属性的订阅和事件回调。
private class AidlSubscriptionClient extends IVehicleCallback.Stub
implements SubscriptionClient {
// 用于处理车辆 HAL 回调的接口。
private final VehicleHalCallback mCallback;
// 用于构建 HAL 属性值的构建器。
private final HalPropValueBuilder mBuilder;
// 构造函数,初始化回调和构建器。
AidlSubscriptionClient(VehicleHalCallback callback, HalPropValueBuilder builder) {
mCallback = callback;
mBuilder = builder;
}
/**
* 当获取属性值的操作完成时调用。
* 由于 AidlSubscriptionClient 不处理 getValues 操作,因此抛出异常。
*
* @param responses 包含获取操作结果的对象。
* @throws RemoteException 如果远程调用失败。
*/
@Override
public void onGetValues(GetValueResults responses) throws RemoteException {
// AidlSubscriptionClient 不支持 getValues 操作。
throw new UnsupportedOperationException(
"onGetValues should never be called on AidlSubscriptionClient");
}
/**
* 当设置属性值的操作完成时调用。
* 由于 AidlSubscriptionClient 不处理 setValues 操作,因此抛出异常。
*
* @param responses 包含设置操作结果的对象。
* @throws RemoteException 如果远程调用失败。
*/
@Override
public void onSetValues(SetValueResults responses) throws RemoteException {
// AidlSubscriptionClient 不支持 setValues 操作。
throw new UnsupportedOperationException(
"onSetValues should never be called on AidlSubscriptionClient");
}
/**
* 当订阅的属性事件发生时调用。
*
* @param propValues 包含更新的属性值的对象。
* @param sharedMemoryFileCount 共享内存文件的数量。
* @throws RemoteException 如果远程调用失败。
*/
@Override
public void onPropertyEvent(VehiclePropValues propValues, int sharedMemoryFileCount)
throws RemoteException {
// 重新构建稳定的 AIDL 可打包对象,不保留共享内存。
VehiclePropValues origPropValues = (VehiclePropValues)
LargeParcelable.reconstructStableAIDLParcelable(propValues,
/* keepSharedMemory= */ false);
// 创建一个列表,用于存储 HAL 属性值。
ArrayList<HalPropValue> values = new ArrayList<>(origPropValues.payloads.length);
// 遍历原始属性值,并使用构建器构建 HAL 属性值。
for (VehiclePropValue value : origPropValues.payloads) {
values.add(mBuilder.build(value));
}
// 调用回调接口,传递属性事件。
mCallback.onPropertyEvent(values);
}
/**
* 当属性设置过程中发生错误时调用。
*
* @param errors 包含属性设置错误的对象。
* @throws RemoteException 如果远程调用失败。
*/
@Override
public void onPropertySetError(VehiclePropErrors errors) throws RemoteException {
// 重新构建稳定的 AIDL 可打包对象,不保留共享内存。
VehiclePropErrors origErrors = (VehiclePropErrors)
LargeParcelable.reconstructStableAIDLParcelable(errors,
/* keepSharedMemory= */ false);
// 创建一个列表,用于存储属性错误。
ArrayList<VehiclePropError> errorList = new ArrayList<>(origErrors.payloads.length);
// 遍历原始错误,并添加到错误列表中。
for (VehiclePropError error : origErrors.payloads) {
errorList.add(error);
}
// 调用回调接口,传递属性设置错误。
mCallback.onPropertySetError(errorList);
}
/**
* 订阅属性事件。
*
* @param options 订阅选项数组。
* @throws RemoteException 如果远程调用失败。
* @throws ServiceSpecificException 如果服务特定错误发生。
*/
@Override
public void subscribe(SubscribeOptions[] options)
throws RemoteException, ServiceSpecificException {
// 调用 AIDL 车辆接口的 subscribe 方法进行订阅。
mAidlVehicle.subscribe(this, options, /* maxSharedMemoryFileCount= */ 2);
}
/**
* 取消订阅属性事件。
*
* @param prop 要取消订阅的属性 ID。
* @throws RemoteException 如果远程调用失败。
* @throws ServiceSpecificException 如果服务特定错误发生。
*/
@Override
public void unsubscribe(int prop) throws RemoteException, ServiceSpecificException {
// 调用 AIDL 车辆接口的 unsubscribe 方法进行取消订阅。
mAidlVehicle.unsubscribe(this, new int[]{prop});
}
/**
* 获取接口的哈希值。
*
* @return 接口的哈希值。
*/
@Override
public String getInterfaceHash() {
return IVehicleCallback.HASH;
}
/**
* 获取接口的版本。
*
* @return 接口的版本。
*/
@Override
public int getInterfaceVersion() {
return IVehicleCallback.VERSION;
}
}
}
AidlSubscriptionClient 继承自 IVehicleCallback.Stub
,实现了 SubscriptionClient
接口。用于处理车辆属性的订阅和事件回调。
在此,我们不再深入分析订阅和事件回调的细节,也不详细探讨 HAL 服务的初始化过程。在后续分析 Java 服务时,我们将顺便探讨与其关联的 HAL 服务。
ICarImpl.init()¶
在 CarServiceImpl.onCreate()
方法中,构造 ICarImpl
实例后,接下来调用其 init()
函数。
// packages/services/Car/service/src/com/android/car/ICarImpl.java
// ICarImpl 类继承自 ICar.Stub,用于实现汽车服务的具体功能。
public class ICarImpl extends ICar.Stub {
/**
* 初始化 ICarImpl 实例。
* 该方法在主线程上运行,负责初始化所有汽车系统服务。
*/
@MainThread
void init() {
// 创建一个用于跟踪初始化时间的日志对象。
TimingsTraceLog t = new TimingsTraceLog(CAR_SERVICE_INIT_TIMING_TAG,
TraceHelper.TRACE_TAG_CAR_SERVICE, CAR_SERVICE_INIT_TIMING_MIN_DURATION_MS);
// 开始跟踪 ICarImpl 初始化过程。
t.traceBegin("ICarImpl.init");
// 如果在构造时没有进行优先初始化,则在此进行。
if (!mDoPriorityInitInConstruction) {
priorityInit();
}
// 开始跟踪所有服务的初始化过程。
t.traceBegin("CarService.initAllServices");
for (CarSystemService service : mAllServicesInInitOrder) {
// 跟踪每个服务的初始化。
t.traceBegin(service.getClass().getSimpleName());
service.init(); // 调用服务的初始化方法。
t.traceEnd();
}
t.traceEnd(); // 结束跟踪 "CarService.initAllServices"
// 开始跟踪所有服务的初始化完成过程。
t.traceBegin("CarService.onInitComplete");
for (CarSystemService service : mAllServicesInInitOrder) {
// 确保 mCarPowerManagementService 的 onInitComplete 方法在最后运行,因为它可能会关闭设备。
if (service == mCarPowerManagementService) {
continue;
}
// 跟踪每个服务的初始化完成。
t.traceBegin("onInitComplete:" + service.getClass().getSimpleName());
service.onInitComplete(); // 调用服务的初始化完成方法。
t.traceEnd();
}
// 确保电源管理服务的初始化完成在最后执行。
mCarPowerManagementService.onInitComplete();
t.traceEnd(); // 结束跟踪 "CarService.onInitComplete"
t.traceEnd(); // 结束跟踪 "ICarImpl.init"
}
}
初始化的整过流程如下:
- 调用
priorityInit()
进行初始化。 - 遍历
mAllServicesInInitOrder
数组,依次调用每个服务的init()
方法进行初始化。 - 再次遍历
mAllServicesInInitOrder
数组,调用每个服务的onInitComplete()
方法,标记初始化完成。 - 特别处理
mCarPowerManagementService
,确保其onInitComplete()
方法在最后执行,以避免设备在初始化过程中被意外关闭。
ICarImpl.priorityInit()¶
// packages/services/Car/service/src/com/android/car/ICarImpl.java
/* package */ void priorityInit() {
mHal.priorityInit();
mCarUserService.priorityInit();
}
从前面 ICarImpl构造函数 的分析可知,这里的 mHal 就是 VehicleHal。
VehicleHal.priorityInit()¶
// packages/services/Car/service/src/com/android/car/hal/VehicleHal.java
/**
* VehicleHal 类是车辆硬件抽象层(HAL)的抽象。该类处理与本地 HAL 的接口,并对接收到的数据进行基本解析(类型检查)。
* 然后,每个事件被发送到相应的 {@link HalServiceBase} 实现。
* {@link HalServiceBase} 的责任是将数据转换为对应的 Car*Service,以便通过 Car*Manager API 使用。
*/
public class VehicleHal implements VehicleHalCallback, CarSystemService {
/**
* 为 VHAL 配置进行优先初始化。
*/
public void priorityInit() {
// 获取所有属性配置。
fetchAllPropConfigs();
// PropertyHalService 将处理大多数属性,因此需要足够大。
ArrayMap<HalServiceBase, ArrayList<HalPropConfig>> configsForAllServices;
synchronized (mLock) {
// 初始化存储每个服务的属性配置的映射。
configsForAllServices = new ArrayMap<>(mAllServices.size());
for (int i = 0; i < mAllServices.size(); i++) {
// 为每个服务创建一个属性配置列表。
ArrayList<HalPropConfig> configsForService = new ArrayList<>();
HalServiceBase service = mAllServices.get(i);
// 将服务和其属性配置列表添加到映射中。
configsForAllServices.put(service, configsForService);
// 获取服务支持的所有属性。
int[] supportedProps = service.getAllSupportedProperties();
if (supportedProps.length == 0) {
// 如果服务没有明确支持的属性,检查所有属性。
for (int j = 0; j < mAllProperties.size(); j++) {
Integer propId = mAllProperties.keyAt(j);
if (service.isSupportedProperty(propId)) {
HalPropConfig config = mAllProperties.get(propId);
// 将属性处理程序与服务关联。
mPropertyHandlers.append(propId, service);
// 将属性配置添加到服务的配置列表中。
configsForService.add(config);
}
}
} else {
// 如果服务有明确支持的属性,只处理这些属性。
for (int prop : supportedProps) {
HalPropConfig config = mAllProperties.get(prop);
if (config == null) {
continue;
}
// 将属性处理程序与服务关联。
mPropertyHandlers.append(prop, service);
// 将属性配置添加到服务的配置列表中。
configsForService.add(config);
}
}
}
}
// 初始化每个服务并传递其属性配置。
for (Map.Entry<HalServiceBase, ArrayList<HalPropConfig>> entry
: configsForAllServices.entrySet()) {
HalServiceBase service = entry.getKey();
ArrayList<HalPropConfig> configsForService = entry.getValue();
// 让服务接管其属性配置。
service.takeProperties(configsForService);
// 初始化服务。
service.init();
}
}
}
主要实现了:
- 调用
fetchAllPropConfigs()
方法获取所有属性配置。 - 使用同步块确保线程安全,初始化一个映射,用于存储每个服务的属性配置。
- 遍历所有 HAL 服务,检查每个服务支持的属性,并将属性配置与服务关联。
- 最后,遍历映射,初始化每个服务并传递其属性配置。
VehicleHal.fetchAllPropConfigs()¶
// packages/services/Car/service/src/com/android/car/hal/VehicleHal.java
public class VehicleHal implements VehicleHalCallback, CarSystemService {
/**
* 获取所有属性配置。
* 该方法用于从 VHAL 获取所有属性配置,并将其存储在 mAllProperties 中。
* 如果属性配置已经获取,则不再重复获取。
*/
@VisibleForTesting
void fetchAllPropConfigs() {
synchronized (mLock) {
// 如果属性配置已经存在,记录日志并返回。
if (mAllProperties.size() != 0) { // 已经设置
Slogf.i(CarLog.TAG_HAL, "fetchAllPropConfigs already fetched");
return;
}
}
HalPropConfig[] configs;
try {
// 从 VHAL 获取所有属性配置。
configs = getAllPropConfigs();
// 如果获取的配置为空,记录错误日志并返回。
if (configs == null || configs.length == 0) {
Slogf.e(CarLog.TAG_HAL, "getAllPropConfigs returned empty configs");
return;
}
} catch (RemoteException | ServiceSpecificException e) {
// 如果获取配置时发生异常,抛出运行时异常。
throw new RuntimeException("Unable to retrieve vehicle property configuration", e);
}
synchronized (mLock) {
// 创建所有属性的映射。
for (HalPropConfig p : configs) {
if (DBG) {
// 如果启用调试,记录属性配置的详细信息。
Slogf.d(CarLog.TAG_HAL, "Add config for prop: 0x%x config: %s", p.getPropId(),
p.toString());
}
// 将属性配置添加到 mAllProperties 中。
mAllProperties.put(p.getPropId(), p);
// 如果属性没有区域配置,使用默认区域 ID 0。
if (p.getAreaConfigs().length == 0) {
mAccessByPropIdAreaId.put(p.getPropId(), /* areaId */ 0, p.getAccess());
} else {
// 否则,为每个区域配置添加访问权限。
for (HalAreaConfig areaConfig : p.getAreaConfigs()) {
mAccessByPropIdAreaId.put(p.getPropId(), areaConfig.getAreaId(),
areaConfig.getAccess());
}
}
}
}
}
/**
* 从 VHAL 获取所有属性配置。
*
* @return 包含所有属性配置的数组。
* @throws RemoteException 如果远程调用失败。
* @throws ServiceSpecificException 如果发生服务特定错误。
*/
public HalPropConfig[] getAllPropConfigs() throws RemoteException, ServiceSpecificException {
// 调用 VehicleStub 的 getAllPropConfigs 方法获取配置。
return mVehicleStub.getAllPropConfigs();
}
}
从车辆硬件抽象层(VHAL)获取所有属性配置,并将其存储在 mAllProperties
中。
- 首先检查
mAllProperties
是否已经包含配置,如果是,则记录日志并返回。 - 调用
getAllPropConfigs()
方法从 VHAL 获取属性配置。 - 遍历获取的配置,将每个属性配置添加到
mAllProperties
中。 - 如果属性没有区域配置,使用默认区域 ID 0,并将访问权限存储在
mAccessByPropIdAreaId
中。 - 否则,为每个区域配置添加访问权限。
AidlVehicleStub.getAllPropConfigs()¶
// packages/services/Car/service/src/com/android/car/AidlVehicleStub.java
// AidlVehicleStub 类是 VehicleStub 的具体实现,用于通过 AIDL 接口与车辆硬件抽象层(VHAL)进行通信。
final class AidlVehicleStub extends VehicleStub {
/**
* 获取所有属性配置。
*
* @return 包含所有属性配置的数组。
* @throws RemoteException 如果远程操作失败。
* @throws ServiceSpecificException 如果 VHAL 返回服务特定错误。
*/
@Override
public HalPropConfig[] getAllPropConfigs()
throws RemoteException, ServiceSpecificException {
// 从 AIDL 接口获取所有属性配置,并重构为稳定的 AIDL 可打包对象。
VehiclePropConfigs propConfigs = (VehiclePropConfigs)
LargeParcelable.reconstructStableAIDLParcelable(
mAidlVehicle.getAllPropConfigs(), /* keepSharedMemory= */ false);
// 获取属性配置的有效负载。
VehiclePropConfig[] payloads = propConfigs.payloads;
int size = payloads.length;
// 创建一个 HalPropConfig 数组,用于存储转换后的配置。
HalPropConfig[] configs = new HalPropConfig[size];
// 遍历有效负载,将每个 VehiclePropConfig 转换为 AidlHalPropConfig。
for (int i = 0; i < size; i++) {
configs[i] = new AidlHalPropConfig(payloads[i]);
}
// 返回转换后的配置数组。
return configs;
}
}
过 AIDL 接口调用 mAidlVehicle.getAllPropConfigs()
获取属性配置。
- 创建一个
HalPropConfig
数组,用于存储转换后的配置。 - 遍历
payloads
数组,将每个VehiclePropConfig
转换为AidlHalPropConfig
,并存储在configs
数组中。 - 返回
configs
数组,包含所有转换后的属性配置。
这里我们暂时不深入探讨 VehiclePropConfig
的数据结构,后续将在 Vehicle HAL 系列中进行详细分析。
InputHalService.takeProperties()¶
// packages/services/Car/service/src/com/android/car/hal/InputHalService.java
/**
* 将 HAL (Hardware Abstraction Layer) 输入事件翻译为更高级别的语义信息。
* 该类继承自 HalServiceBase,并负责处理与输入事件相关的属性。
*/
public class InputHalService extends HalServiceBase {
// 支持的输入属性数组,表示该服务可以处理的 HAL 输入类型。
// 每个类型都对应一个硬件输入事件。
private static final int[] SUPPORTED_PROPERTIES = new int[]{
HW_KEY_INPUT, // 硬件按键输入
HW_KEY_INPUT_V2, // 硬件按键输入(版本2)
HW_MOTION_INPUT, // 硬件运动输入
HW_ROTARY_INPUT, // 硬件旋钮输入
HW_CUSTOM_INPUT // 自定义硬件输入
};
// 定义类的成员变量,用于标记不同类型的输入是否受支持。
private boolean mKeyInputSupported = false; // 是否支持按键输入
private boolean mKeyInputV2Supported = false; // 是否支持按键输入(版本2)
private boolean mMotionInputSupported = false; // 是否支持运动输入
private boolean mRotaryInputSupported = false; // 是否支持旋钮输入
private boolean mCustomInputSupported = false; // 是否支持自定义输入
/**
* 接收 HAL 属性配置的集合,并根据配置启用对应的输入支持。
*
* @param properties HAL 层传入的属性集合,每个属性包含配置信息。
*/
@Override
public void takeProperties(Collection<HalPropConfig> properties) {
synchronized (mLock) { // 确保多线程访问时的同步性。
for (HalPropConfig property : properties) {
// 根据属性 ID 判断支持的输入类型,并设置对应的标志位。
switch (property.getPropId()) {
case HW_KEY_INPUT:
mKeyInputSupported = true; // 启用按键输入支持
break;
case HW_KEY_INPUT_V2:
mKeyInputV2Supported = true; // 启用按键输入(版本2)支持
break;
case HW_MOTION_INPUT:
mMotionInputSupported = true; // 启用运动输入支持
break;
case HW_ROTARY_INPUT:
mRotaryInputSupported = true; // 启用旋钮输入支持
break;
case HW_CUSTOM_INPUT:
mCustomInputSupported = true; // 启用自定义输入支持
break;
default:
break; // 忽略未识别的属性 ID
}
}
}
}
}
SUPPORTED_PROPERTIES数组声明了服务支持的所有输入属性类型,每个属性类型都对应一个硬件输入事件的分类。
-
HW_KEY_INPUT 硬件按键输入
-
HW_KEY_INPUT_V2 硬件按键输入(版本2)
-
HW_MOTION_INPUT 硬件运动输入
-
HW_ROTARY_INPUT 硬件旋钮输入
-
HW_CUSTOM_INPUT 自定义硬件输入
InputHalService.init()¶
// packages/services/Car/service/src/com/android/car/hal/InputHalService.java
/**
* 将 HAL (Hardware Abstraction Layer) 输入事件翻译为更高级别的语义信息。
* 该类继承自 HalServiceBase,并负责处理与输入事件相关的属性。
*/
public class InputHalService extends HalServiceBase {
/**
* 初始化函数,当前未实现具体功能。
* 通常在 HAL 服务启动时调用,执行服务的初始化逻辑。
*/
@Override
public void init() {
// 当前未实现具体的初始化逻辑
}
}
init()
方法在当前示例中没有实现具体逻辑,但在其他服务中,通常会包含具体的实现。例如,可能用于初始化数据结构、注册监听器或设置与 HAL 层的通信等逻辑。
CarUserService.priorityInit()¶
// packages/services/Car/service/src/com/android/car/user/CarUserService.java
/**
* 用户服务(User Service)用于管理汽车用户的相关操作。
* 该服务继承了ICarUserService.Stub接口,并实现了CarServiceBase接口。
*/
public final class CarUserService extends ICarUserService.Stub implements CarServiceBase {
/**
* 优先初始化方法,用于设置启动用户(Boot User)。
* 该方法在HAL(硬件抽象层)已就绪但其他组件尚未初始化时调用。
*/
public void priorityInit() {
// 使用Handler将初始化用户的操作投递到消息队列,异步执行。
mHandler.post(() -> initBootUser(getInitialUserInfoRequestType()));
}
/**
* 初始化启动用户。
*
* @param requestType 请求类型,表示用户初始化的方式(如恢复用户、切换用户等)。
*/
private void initBootUser(int requestType) {
// 开启异步跟踪,用于性能分析,标识初始化启动用户的流程开始。
Trace.asyncTraceBegin(TraceHelper.TRACE_TAG_CAR_SERVICE, "initBootUser", requestType);
// 如果是恢复用户并且不需要在休眠前切换访客用户,则替换访客用户。
boolean replaceGuest = requestType == InitialUserInfoRequestType.RESUME && !mSwitchGuestUserBeforeSleep;
// 检查是否具有管理用户的权限,如果没有权限则抛出异常。
checkManageUsersPermission("startInitialUser");
// 检查用户HAL是否支持,若不支持或需要特殊处理,则使用默认行为。
if (!isUserHalSupported() || mIsVisibleBackgroundUsersOnDefaultDisplaySupported) {
// 回退到默认的启动用户行为。
fallbackToDefaultInitialUserBehavior(/* userLocales= */ null, replaceGuest,
/* supportsOverrideUserIdProperty= */ true, requestType);
// 写入事件日志,标记初始化完成。
EventLogHelper.writeCarUserServiceInitialUserInfoReqComplete(requestType);
// 结束跟踪。
Trace.asyncTraceEnd(TraceHelper.TRACE_TAG_CAR_SERVICE, "initBootUser", requestType);
return;
}
// 创建当前用户信息对象,获取用户管理器相关信息。
UsersInfo usersInfo = UserHalHelper.newUsersInfo(mUserManager, mUserHandleHelper);
// 记录事件日志,标记发起的用户信息请求。
EventLogHelper.writeCarUserServiceInitialUserInfoReq(requestType, mHalTimeoutMs,
usersInfo.currentUser.userId, usersInfo.currentUser.flags, usersInfo.numberUsers);
// 向HAL发起请求以获取初始用户信息,并注册回调处理响应。
mHal.getInitialUserInfo(requestType, mHalTimeoutMs, usersInfo, (status, resp) -> {
if (resp != null) {
// 记录响应日志,包含响应的动作和用户信息。
EventLogHelper.writeCarUserServiceInitialUserInfoResp(status, resp.action,
resp.userToSwitchOrCreate.userId, resp.userToSwitchOrCreate.flags,
resp.userNameToCreate, resp.userLocales);
String userLocales = resp.userLocales; // 用户的区域设置信息。
InitialUserInfo info;
// 根据响应动作(如切换用户、创建用户或默认)处理初始化逻辑。
switch (resp.action) {
case InitialUserInfoResponseAction.SWITCH:
int userId = resp.userToSwitchOrCreate.userId;
if (userId <= 0) {
// 若用户ID无效,则回退到默认行为。
Slogf.w(TAG, "invalid (or missing) user id sent by HAL: %d", userId);
fallbackToDefaultInitialUserBehavior(userLocales, replaceGuest,
/* supportsOverrideUserIdProperty= */ false, requestType);
break;
}
// 构建切换用户的初始化信息并设置。
info = new InitialUserSetter.Builder(InitialUserSetter.TYPE_SWITCH)
.setRequestType(requestType)
.setUserLocales(userLocales)
.setSwitchUserId(userId)
.setReplaceGuest(replaceGuest)
.build();
mInitialUserSetter.set(info);
break;
case InitialUserInfoResponseAction.CREATE:
int halFlags = resp.userToSwitchOrCreate.flags; // 用户标志信息。
String userName = resp.userNameToCreate; // 用户名。
// 构建创建用户的初始化信息并设置。
info = new InitialUserSetter.Builder(InitialUserSetter.TYPE_CREATE)
.setRequestType(requestType)
.setUserLocales(userLocales)
.setNewUserName(userName)
.setNewUserFlags(halFlags)
.build();
mInitialUserSetter.set(info);
break;
case InitialUserInfoResponseAction.DEFAULT:
// 默认响应动作,回退到默认行为。
fallbackToDefaultInitialUserBehavior(userLocales, replaceGuest,
/* supportsOverrideUserIdProperty= */ false, requestType);
break;
default:
// 无效响应动作时,记录日志并回退到默认行为。
Slogf.w(TAG, "invalid response action on %s", resp);
fallbackToDefaultInitialUserBehavior(/* userLocales= */ null, replaceGuest,
/* supportsOverrideUserIdProperty= */ false, requestType);
break;
}
} else {
// 若响应为空,记录日志并回退到默认行为。
EventLogHelper.writeCarUserServiceInitialUserInfoResp(status, /* action= */ 0,
/* userId= */ 0, /* flags= */ 0, /* safeName= */ "", /* userLocales= */ "");
fallbackToDefaultInitialUserBehavior(/* user locale */ null, replaceGuest,
/* supportsOverrideUserIdProperty= */ false, requestType);
}
// 标记请求完成并结束跟踪。
EventLogHelper.writeCarUserServiceInitialUserInfoReqComplete(requestType);
Trace.asyncTraceEnd(TraceHelper.TRACE_TAG_CAR_SERVICE, "initBootUser", requestType);
});
}
}
priorityInit()
方法通过异步消息机制,将初始化启动用户的任务提交到 Handler
,以确保不会阻塞当前线程。
initBootUser()
- 通过
requestType
参数决定如何初始化启动用户。 - 检查是否支持 User HAL 和其他特性,如果不支持,则回退到默认的行为。
调用 HAL 获取用户信息
- 使用
UserHalHelper
获取当前用户的信息,并调用 HAL 接口获取初始用户信息。 - 根据 HAL 返回的响应 (
resp
),决定是切换用户 (SWITCH
)、创建用户 (CREATE
),还是使用默认行为 (DEFAULT
)。
至此,priorityInit()
流程分析完,我们回到 ICarImpl.init() 继续分析调用每个服务的 init()
方法进行初始化。
这次我们换一个服务来分析吧。
CarInputService.init()¶
// packages/services/Car/service/src/com/android/car/CarInputService.java
/**
* CarInputService 监控和处理通过 Vehicle HAL 接收的输入事件。
* 该服务继承了 ICarInput.Stub 接口,并实现了 CarServiceBase 和 InputHalService.InputListener 接口。
*/
public class CarInputService extends ICarInput.Stub
implements CarServiceBase, InputHalService.InputListener {
/**
* 初始化 CarInputService。
* 如果 HAL(硬件抽象层)不支持按键输入,则直接返回。
* 如果支持按键输入,则完成输入监听器的设置以及用户生命周期和座位相关的初始化。
*/
@Override
public void init() {
// 检查 Vehicle HAL 是否支持按键输入功能。
if (!mInputHalService.isKeyInputSupported()) {
// 如果不支持,记录警告日志并直接返回。
Slogf.w(TAG, "Hal does not support key input.");
return;
}
// 如果支持按键输入,记录支持信息。
Slogf.d(TAG, "Hal supports key input.");
// 设置输入监听器,CarInputService 将会监听输入事件。
mInputHalService.setInputListener(this);
// 创建用户生命周期事件过滤器,只监听 "用户切换" 类型的事件。
UserLifecycleEventFilter userSwitchingEventFilter = new UserLifecycleEventFilter.Builder()
.addEventType(USER_LIFECYCLE_EVENT_TYPE_SWITCHING) // 添加事件类型:用户切换
.build();
// 注册用户生命周期监听器,当用户切换事件发生时,触发相应逻辑。
mUserService.addUserLifecycleListener(userSwitchingEventFilter, mUserLifecycleListener);
// 获取驾驶员座位的区域信息。
mDriverSeat = mCarOccupantZoneService.getDriverSeat();
// 检查是否存在驾驶员座位(即驾驶员座位是否为有效值)。
mHasDriver = (mDriverSeat != VehicleAreaSeat.SEAT_UNKNOWN);
}
}
CarInputService
是 Android 汽车系统中的一个服务,用于处理来自 Vehicle HAL
的输入事件,例如按键输入或其他硬件输入。它还监听用户生命周期事件(如用户切换)并管理驾驶员座位的相关信息。
这个 init()
方法我们暂不深入分析,后续我们会针对每一个服务进行深入分析。
CarPowerManagementService.onInitComplete()¶
分析完服务的 init() 方法初始化之后,继续分析服务的 onInitComplete()
方法。到这里我才发现其实就只有两个服务重写了 onInitComplete()
方法。
CarPowerManagementService 和 CarOemProxyService 。
// packages/services/Car/service/src/com/android/car/power/CarPowerManagementService.java
/**
* CarPowerManagementService 是一个专用于汽车的电源管理服务类。
* 它负责控制汽车的电源状态,并与系统的其他部分交互以确保电源状态的正常运作。
*
* 功能:
* - 监控和管理车辆的电源状态。
* - 支持车库模式(Garage Mode),在满足特定条件时启动或跳过该模式。
* - 与电源相关的 HAL(Hardware Abstraction Layer)服务进行通信,获取车辆的电源状态信息。
*/
public class CarPowerManagementService extends ICarPower.Stub implements
CarServiceBase, PowerHalService.PowerEventListener {
/**
* 服务初始化完成时的回调方法。
*
* 如果系统支持无服务器远程访问功能(Serverless Remote Access),
* 则在系统初始化完成后会检查是否需要进入车库模式。
*/
@Override
public void onInitComplete() {
// 检查是否启用了无服务器远程访问功能
if (mFeatureFlags.serverlessRemoteAccess()) {
// 如果启用,则尝试在启动时进入车库模式
maybeEnterGarageModeOnBoot();
}
}
/**
* 如果引导原因是 "进入车库模式",则进入车库模式。
*
* 车库模式是一种特殊的电源状态,车辆进入该模式后,可以完成一些后台任务(如维护、更新等),
* 然后在任务完成后关闭系统。
*/
private void maybeEnterGarageModeOnBoot() {
// 从 HAL 获取当前车辆的引导原因
@BootupReason int bootupReason = mHal.getVehicleApBootupReason();
// 打印当前车辆电源引导原因以供调试
Slogf.i(TAG, "Vehicle AP power bootup reason: " + bootupReason);
// 如果引导原因不是 "进入车库模式",直接退出
if (bootupReason != BOOTUP_REASON_SYSTEM_ENTER_GARAGE_MODE) {
return;
}
// 检查车辆是否正在使用中
if (mHal.isVehicleInUse()) {
Slogf.i(TAG, "Bootup reason is ENTER_GARAGE_MODE but vehicle is currently in use"
+ ", skip entering garage mode");
return;
}
// 如果引导原因符合并且车辆未被使用,尝试关闭设备并运行车库模式
try {
// 调用关闭设备的方法,并传入最后一次关机状态
requestShutdownAp(getLastShutdownState(), /* runGarageMode= */ true);
} catch (Exception e) {
// 如果调用 requestShutdownAp 方法时出现异常,记录错误日志
Slogf.wtf(TAG, "Failed to call requestShutdownAp", e);
}
}
}
onInitComplete()
方法在所有服务初始化完成后自动调用。检查系统是否启用了 "无服务器远程访问" 功能,如果启用,则会进一步调用 maybeEnterGarageModeOnBoot()
方法,检查是否需要在启动时进入车库模式。
maybeEnterGarageModeOnBoot() 调用 mHal.getVehicleApBootupReason()
方法从 HAL 获取车辆当前的引导原因。能的引导原因包括:正常启动、进入车库模式等。
- 如果引导原因不是
BOOTUP_REASON_SYSTEM_ENTER_GARAGE_MODE
,直接退出方法。 - 如果车辆正在被使用(如正在驾驶中),也跳过车库模式。
- 如果满足条件,则调用
requestShutdownAp()
方法关闭设备并进入车库模式。 - 传入
getLastShutdownState()
获取最后一次关机状态,同时设置runGarageMode
参数为true
。
总结¶
CarService 服务初始化从 CarServiceImpl.onCreate()
开始:
- 调用
VehicleStub.newVehicleStub()
创建VehicleStub
的实例,具体实现为AidlVehicleStub
的实例。 - 调用
new ICarImpl.Builder().build()
创建ICarImpl
的实例。 - 调用
ICarImpl.init()
初始化HalService
、CarSystemService
等。- 调用
ICarImpl.priorityInit()
。- 调用
VehicleHal.priorityInit()
。- 调用
VehicleHal.fetchAllPropConfigs()
。- 调用
AidlVehicleStub.getAllPropConfigs()
获取所有车辆属性配置。
- 调用
- 调用
HalServiceBase.takeProperties()
。 - 调用
HalServiceBase.init()
。
- 调用
- 调用
CarUserService.priorityInit()
。
- 调用
- 调用
CarSystemService.init()
。 - 调用
CarSystemService.onInitComplete()
。
- 调用
其代码精简如下:
public class CarServiceImpl extends ProxiedService {
private ICarImpl mICarImpl;
private VehicleStub mVehicle;
public void onCreate() {
mVehicle = VehicleStub.newVehicleStub();
mICarImpl = new ICarImpl.Builder()
.build();
mICarImpl.init();
}
}
public abstract class VehicleStub {
public static VehicleStub newVehicleStub() throws IllegalStateException {
VehicleStub stub = new AidlVehicleStub();
return stub;
}
}
final class AidlVehicleStub extends VehicleStub {
AidlVehicleStub() {
}
@Override
public HalPropConfig[] getAllPropConfigs()
}
}
public class ICarImpl extends ICar.Stub {
private final VehicleHal mHal;
private final CarUserService mCarUserService;
private final CarSystemService service;
private ICarImpl(Builder builder) {
}
void init() {
priorityInit();
service.init();
service.onInitComplete();
}
void priorityInit() {
mHal.priorityInit();
mCarUserService.priorityInit();
}
public static final class Builder {
public ICarImpl build() {
return new ICarImpl(this);
}
}
}
public class VehicleHal implements VehicleHalCallback, CarSystemService {
HalServiceBase service;
AidlVehicleStub mVehicleStub;
public void priorityInit() {
fetchAllPropConfigs();
service.takeProperties(configsForService);
service.init();
}
void fetchAllPropConfigs() {
configs = getAllPropConfigs();
}
public HalPropConfig[] getAllPropConfigs() throws RemoteException, ServiceSpecificException {
return mVehicleStub.getAllPropConfigs();
}
}
public abstract class HalServiceBase {
public void takeProperties(@NonNull Collection<HalPropConfig> properties) {
}
public abstract void init();
}
public interface CarSystemService {
void init();
default void onInitComplete() {}
}
时序图如下:
sequenceDiagram
participant CarServiceImpl
participant VehicleStub
participant AidlVehicleStub
participant ICarImpl
participant VehicleHal
participant HalServiceBase
participant CarSystemService
%% CarServiceImpl.onCreate()
rect rgb(191, 223, 255)
note over CarServiceImpl: CarServiceImpl.onCreate()
CarServiceImpl->>VehicleStub: newVehicleStub()
VehicleStub->>AidlVehicleStub: new AidlVehicleStub()
VehicleStub-->>CarServiceImpl: return AidlVehicleStub
CarServiceImpl->>ICarImpl: new ICarImpl.Builder().build()
ICarImpl->>ICarImpl: init()
end
%% ICarImpl.init() - priorityInit
rect rgb(255, 223, 191)
note over ICarImpl: ICarImpl.init() - priorityInit
ICarImpl->>ICarImpl: priorityInit()
end
%% VehicleHal.priorityInit()
rect rgb(223, 191, 255)
note over VehicleHal: VehicleHal.priorityInit()
ICarImpl->>VehicleHal: mHal.priorityInit()
VehicleHal->>VehicleHal: fetchAllPropConfigs()
VehicleHal->>AidlVehicleStub: getAllPropConfigs()
AidlVehicleStub-->>VehicleHal: return HalPropConfig[]
VehicleHal->>HalServiceBase: service.takeProperties(configsForService)
HalServiceBase->>HalServiceBase: init()
end
%% CarSystemService.init()
rect rgb(191, 255, 223)
note over CarSystemService: CarSystemService.init()
ICarImpl->>CarSystemService: service.init()
end
%% CarSystemService.onInitComplete()
rect rgb(255, 191, 223)
note over CarSystemService: CarSystemService.onInitComplete()
ICarImpl->>CarSystemService: service.onInitComplete()
end
在分析 CarService 服务初始化过程中,我们主要关注了 CarService 进程启动后的初始化步骤,而没有深入探讨每个具体服务的初始化细节。服务的初始化过程实际上包括以下几个步骤:
- Native服务的初始化
- 首先,构造每一个
HalService
实例。 - 然后,调用
HalService
的takeProperties()
方法。 - 接着,调用
HalService
的init()
方法。
- 首先,构造每一个
- Java服务的初始化
- 构造每一个
CarSystemService
实例。 - 调用
CarSystemService
的init()
方法。 - 最后,调用
CarSystemService
的onInitComplete()
方法。
- 构造每一个
在后续的文章中,我们将逐步深入分析每个服务的启动过程。