跳转至

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 服务。

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);
    }
}

实现了 VehicleHalCallbackCarSystemService 接口,负责管理与车辆硬件抽象层(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() 初始化 HalServiceCarSystemService等。
    • 调用 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() 方法。

在后续的文章中,我们将逐步深入分析每个服务的启动过程。

评论