Android O 前期预研之三:Android Vehicle HAL

来源:互联网 发布:ubuntu安装ssh服务 编辑:程序博客网 时间:2024/05/17 22:09


本文章转载自:http://blog.csdn.net/ljp1205/article/details/78080954, 已获得作者授权

作者:影子LEON

Android Automotive

Android Automotive 是Android Oreo中的一个新的特色功能,从AOSP的代码上来看,Android O中已经包含有了从Application到Framework 到HAL的整体框架,这一章节,我们简单的过以下Android Vehicle 的框架,以及重点看下 Vehicle HAL的东西。总体结构大约是以下这个样子:
这里写图片描述

上图的结构应该是Android Oreo当中比较通用的框架结构了,从Application 到Framework到HAL,跟之前的Android版本相比,之前Framework要不通过binder联系上一个Daemon,这个Daemon再去load 相关的HAL,要不就是这些Framework的service直接通过JNI去load 这些个HAL 库。而现在的Android Oreo则是Framework 与HAL之间直接采用HIDL来做联络沟通了。接下来我们从下往上的来把Android Vehicle的框架捋一下吧。首先来分析下Vehicle HAL,通过这个来复习并且实践下之前研究学习过的Android HIDL.

Android Vehicle HAL

这里写图片描述

types.hal 定义的是一些数据结构,IVehicle.hal定义的是从Framework往HAL调用的接口,而IVehicleCallback.hal则是HAL往Framework 上报回调的接口。看起来还是挺清晰的吧。
而IVehicle.hal的接口也不是很多,

package android.hardware.automotive.vehicle@2.0;import IVehicleCallback;interface IVehicle {  /**   * Returns a list of all property configurations supported by this vehicle   * HAL.   */  getAllPropConfigs() generates (vec<VehiclePropConfig> propConfigs);  /**   * Returns a list of property configurations for given properties.   *   * If requested VehicleProperty wasn't found it must return   * StatusCode::INVALID_ARG, otherwise a list of vehicle property   * configurations with StatusCode::OK   */  getPropConfigs(vec<int32_t> props)          generates (StatusCode status, vec<VehiclePropConfig> propConfigs);  /**   * Get a vehicle property value.   *   * For VehiclePropertyChangeMode::STATIC properties, this method must always   * return the same value always.   * For VehiclePropertyChangeMode::ON_CHANGE properties, it must return the   * latest available value.   *   * Some properties like AUDIO_VOLUME requires to pass additional data in   * GET request in VehiclePropValue object.   *   * If there is no data available yet, which can happen during initial stage,   * this call must return immediately with an error code of   * StatusCode::TRY_AGAIN.   */  get(VehiclePropValue requestedPropValue)          generates (StatusCode status, VehiclePropValue propValue);  /**   * Set a vehicle property value.   *   * Timestamp of data must be ignored for set operation.   *   * Setting some properties require having initial state available. If initial   * data is not available yet this call must return StatusCode::TRY_AGAIN.   * For a property with separate power control this call must return   * StatusCode::NOT_AVAILABLE error if property is not powered on.   */  set(VehiclePropValue propValue) generates (StatusCode status);  /**   * Subscribes to property events.   *   * Clients must be able to subscribe to multiple properties at a time   * depending on data provided in options argument.   *   * @param listener This client must be called on appropriate event.   * @param options List of options to subscribe. SubscribeOption contains   *                information such as property Id, area Id, sample rate, etc.   */  subscribe(IVehicleCallback callback, vec<SubscribeOptions> options)          generates (StatusCode status);  /**   * Unsubscribes from property events.   *   * If this client wasn't subscribed to the given property, this method   * must return StatusCode::INVALID_ARG.   */  unsubscribe(IVehicleCallback callback, int32_t propId)          generates (StatusCode status);  /**   * Print out debugging state for the vehicle hal.   *   * The text must be in ASCII encoding only.   *   * Performance requirements:   *   * The HAL must return from this call in less than 10ms. This call must avoid   * deadlocks, as it may be called at any point of operation. Any synchronization   * primitives used (such as mutex locks or semaphores) must be acquired   * with a timeout.   *   */  debugDump() generates (string s);};

而IVehicle.hal则就更少了:

package android.hardware.automotive.vehicle@2.0;interface IVehicleCallback {    /**     * Event callback happens whenever a variable that the API user has     * subscribed to needs to be reported. This may be based purely on     * threshold and frequency (a regular subscription, see subscribe call's     * arguments) or when the IVehicle#set method was called and the actual     * change needs to be reported.     *     * These callbacks are chunked.     *     * @param values that has been updated.     */    oneway onPropertyEvent(vec<VehiclePropValue> propValues);    /**     * This method gets called if the client was subscribed to a property using     * SubscribeFlags::SET_CALL flag and IVehicle#set(...) method was called.     *     * These events must be delivered to subscriber immediately without any     * batching.     *     * @param value Value that was set by a client.     */    oneway onPropertySet(VehiclePropValue propValue);    /**     * Set property value is usually asynchronous operation. Thus even if     * client received StatusCode::OK from the IVehicle::set(...) this     * doesn't guarantee that the value was successfully propagated to the     * vehicle network. If such rare event occurs this method must be called.     *     * @param errorCode - any value from StatusCode enum.     * @param property - a property where error has happened.     * @param areaId - bitmask that specifies in which areas the problem has     *                 occurred, must be 0 for global properties     */    oneway onPropertySetError(StatusCode errorCode,                              int32_t propId,                              int32_t areaId);};

比较好奇的是这么些接口就能实现Android 车机的这么些功能?先还是这么看看吧,后续仔细研究研究。

Android Vehicle HAL 的编译

按照我们之前的研究来看看这么些Android Vehicle HAL被怎么编译,编译成什么东西。先看.hal文件编译生成的头文件:
这里写图片描述

.hal 文件生成的CPP文件:
这里写图片描述

.h 文件我们之前也都做过分析,Bp/Bn/Bs 代表啥意思相信都没忘记吧,在这里就不多赘述了,而VehicleAll.cpp/VehicleCallbackAll.cpp 里其实就是那些生成的.h文件中所定义的C++ Class 文件的实现,这些相关实现都是写在这些.cpp文件当中。

这些.cpp文件/.h文件最终会生成一个名叫android.hardware.automotive.vehicle@2.0.so的库,详情请参考hardware/interfaces/automotive/vehicle/2.0/Android.bp。

另外参考hardware/interfaces/automotive/vehicle/2.0/default/Android.mk,
hardware/interfaces/automotive/vehicle/2.0/default/impl/目录下会被编译出名叫android.hardware.automotive.vehicle@2.0-default-impl-lib的静态库,而hardware/interfaces/automotive/vehicle/2.0/default/common/目录会被编译出一个名叫android.hardware.automotive.vehicle@2.0-manager-lib-shared的静态库,而这两个静态库都会去链接上面生成的android.hardware.automotive.vehicle@2.0.so动态库。

而最终会被编译成一个可执行程序:

include $(CLEAR_VARS)LOCAL_MODULE := $(vhal_v2_0)-serviceLOCAL_INIT_RC := $(vhal_v2_0)-service.rcLOCAL_PROPRIETARY_MODULE := trueLOCAL_MODULE_RELATIVE_PATH := hwLOCAL_SRC_FILES := \    VehicleService.cppLOCAL_SHARED_LIBRARIES := \    libbase \    libhidlbase \    libhidltransport \    liblog \    libprotobuf-cpp-lite \    libutils \    $(vhal_v2_0) \LOCAL_STATIC_LIBRARIES := \    $(vhal_v2_0)-manager-lib \    $(vhal_v2_0)-default-impl-lib \    $(vhal_v2_0)-libproto-native \LOCAL_CFLAGS += -Wall -Wextra -Werrorinclude $(BUILD_EXECUTABLE)

而这个可执行程序会被Init 系统在开机的时候启动,成为一个Daemon:
service vehicle-hal-2.0 /vendor/bin/hw/android.hardware.automotive.vehicle@2.0-service
class hal
user vehicle_network
group system inet

Android Vehicle HAL 的使用

东西都编译出来后,我们看看Vehicle HAL怎么来使用。

1) Android Vehicle HAL Service 端使用:
我们来看下hardware/interfaces/automotive/vehicle/2.0/default/VehicleService.cpp文件:

int main(int /* argc */, char* /* argv */ []) {    auto store = std::make_unique<VehiclePropertyStore>();    auto hal = std::make_unique<impl::EmulatedVehicleHal>(store.get());    auto emulator = std::make_unique<impl::VehicleEmulator>(hal.get());    auto service = std::make_unique<VehicleHalManager>(hal.get());    configureRpcThreadpool(4, true /* callerWillJoin */);    ALOGI("Registering as service...");    service->registerAsService();    ALOGI("Ready");    joinRpcThreadpool();}

说实话,刚看到这段代码的我是一脸懵逼的,auto是个什么鬼, std::make_unique是个什么鬼,这几年弄的都是JAVA/Android,像这些C++的新规范,新东西越来越层出不穷了,真的是一天不学习就得落伍了哈。

幸亏这个也很简单, std::make_unique就先等同与new吧,auto的意思就是变量类型在声明的时候先不确定,等变量被定义的时候根据实际情况来确定变量类型。

其中最关键的是这两句:

auto service = std::make_unique<VehicleHalManager>(hal.get());ALOGI("Registering as service...");service->registerAsService();

我们看下 VehicleHalManager的定义:

  class VehicleHalManager : public IVehicle 

VehicleHalManager类是由 IVehicle类派生出来,而IVehicle则是从我们上面介绍的.hal文件里编译出来的。

我们继续来看下下面这句:

   service->registerAsService();

我们从.hal文件编译出来的.cpp文件来看下,这个中间生成的cpp文件所在目录为:out/soong/.intermediates/hardware/interfaces/automotive/vehicle/2.0/android.hardware.automotive.vehicle@2.0_genc++/gen/android/hardware/automotive/vehicle/2.0/VehicleAll.cpp

该函数的具体实现为:

::android::status_t IVehicle::registerAsService(const std::string &serviceName) {    ::android::hardware::details::onRegistration("android.hardware.automotive.vehicle@2.0", "IVehicle", serviceName);    const ::android::sp<::android::hidl::manager::V1_0::IServiceManager> sm            = ::android::hardware::defaultServiceManager();    // 获取到默认的service manager,非常类似于 Binder机制中。有时间的话可以深入研究下。    if (sm == nullptr) {        return ::android::INVALID_OPERATION;    }    ::android::hardware::Return<bool> ret = sm->add(serviceName.c_str(), this);    //往service manager 中添加service, 跟Binder机制也是一样一样的。    return ret.isOk() && ret ? ::android::OK : ::android::UNKNOWN_ERROR;}

但是比较奇怪的是add 进去是this 指针,也就是应该是 IVehicle对象,也就是VehicleHalManager的对象。不应该是Bnxxxx的对象么????我这里有一脸懵逼。这是第一个懵点,第二个懵点则来的更加不可思议:

const char* IVehicle::descriptor("android.hardware.automotive.vehicle@2.0::IVehicle");__attribute__((constructor))static void static_constructor() {    ::android::hardware::details::gBnConstructorMap.set(IVehicle::descriptor,            [](void *iIntf) -> ::android::sp<::android::hardware::IBinder> {                return new BnHwVehicle(static_cast<IVehicle *>(iIntf));            });    ::android::hardware::details::gBsConstructorMap.set(IVehicle::descriptor,            [](void *iIntf) -> ::android::sp<::android::hidl::base::V1_0::IBase> {                return new BsVehicle(static_cast<IVehicle *>(iIntf));            });};

我们来看看这段代码,首先attribute((constructor))也是gcc 的一个机制,大致意思是在main函数被调用之前 static_constructor函数会被调用。


::android::hardware::details::gBnConstructorMap.set(IVehicle::descriptor,
[](void *iIntf) -> ::android::sp<::android::hardware::IBinder> {
return new BnHwVehicle(static_cast<IVehicle *>(iIntf));
});

这段代码意思是指在 gBnConstructorMap中插入一个key/value,这个value 值是

[](void *iIntf) -> ::android::sp<::android::hardware::IBinder> {                return new BnHwVehicle(static_cast<IVehicle *>(iIntf));  }

这又是什么鬼啊???搜了下应该是拉曼达表达式,但是懵点是 void *iIntf 这个是参数,这个参数是怎么传递进来的?我都搜了半天都没找到参数怎么传递进来的。但是看了下BnHwVehicle这个类的定义,明显是使用了 IVehicle类。

BnHwVehicle::BnHwVehicle(const ::android::sp<IVehicle> &_hidl_impl)        : ::android::hidl::base::V1_0::BnHwBase(_hidl_impl, "android.hardware.automotive.vehicle@2.0", "IVehicle") {             _hidl_mImpl = _hidl_impl;            auto prio = ::android::hardware::details::gServicePrioMap.get(_hidl_impl, {SCHED_NORMAL, 0});            mSchedPolicy = prio.sched_policy;            mSchedPriority = prio.prio;}::android::status_t BnHwVehicle::onTransact(        uint32_t _hidl_code,        const ::android::hardware::Parcel &_hidl_data,        ::android::hardware::Parcel *_hidl_reply,        uint32_t _hidl_flags,        TransactCallback _hidl_cb) {    ::android::status_t _hidl_err = ::android::OK;    switch (_hidl_code) {        case 1 /* getAllPropConfigs */:        {            if (!_hidl_data.enforceInterface(IVehicle::descriptor)) {                _hidl_err = ::android::BAD_TYPE;                break;            }           …………………           ………………...            bool _hidl_callbackCalled = false;            _hidl_mImpl->getAllPropConfigs([&](const auto &_hidl_out_propConfigs) {            …………………….            …………………...            break;        }

从BnHwVehicle这个类来看,它确实承担的是HIDL Service的工作,从BnHwVehicle里会来调用IVehicle类,IVehicle类会被继承成为真正的实现操作类。这个懵点2,到目前还没有找到怎么解决点。

到这里,我们来简单总结service端:
1) 从Ixxxx类中会派生出新的类,这个类会作为真正的操作类。
2) 从Ixxxx类的派生类中调用 registerAsService 去把自己注册进hw service manager中。
3) 目前看起来,如果有client 发出请求的话,BnXXXXX会相应,BnXXXXX会调用自己的Ixxxx的实现函数来完成某一个操作请求。

1) Android Vehicle HAL Client 端使用:
这个Client端存在Android Framework的Car Service当中
在onCreate 函数当中:

“`
@Override
public void onCreate() {
Log.i(CarLog.TAG_SERVICE, “Service onCreate”);
mCanBusErrorNotifier = new CanBusErrorNotifier(this /* context */);
mVehicle = getVehicle(null /* Any Vehicle HAL interface name */);

    if (mVehicle == null) {        throw new IllegalStateException("Vehicle HAL service is not available.");    }    try {        mVehicleInterfaceName = mVehicle.interfaceDescriptor();    } catch (RemoteException e) {        throw new IllegalStateException("Unable to get Vehicle HAL interface descriptor", e);    }    Log.i(CarLog.TAG_SERVICE, "Connected to " + mVehicleInterfaceName);    mICarImpl = new ICarImpl(this, mVehicle, SystemInterface.getDefault(this),            mCanBusErrorNotifier);    mICarImpl.init();    SystemProperties.set("boot.car_service_created", "1");    linkToDeath(mVehicle, mVehicleDeathRecipient);    super.onCreate();}

mVehicle = getVehicle(null /* Any Vehicle HAL interface name */);

获取到Vehicle HAL.

@Nullableprivate static IVehicle getVehicle(@Nullable String interfaceName) {    try {        boolean anyVersion = interfaceName == null || interfaceName.isEmpty();        IVehicle vehicle = null;        if (ENABLE_VEHICLE_HAL_V2_1 && (anyVersion || IVHAL_21.equals(interfaceName))) {            vehicle = android.hardware.automotive.vehicle.V2_1.IVehicle                    .getService();        }        if (vehicle == null && (anyVersion || IVHAL_20.equals(interfaceName))) {            vehicle = android.hardware.automotive.vehicle.V2_0.IVehicle                    .getService();        }        return vehicle;    } catch (RemoteException e) {        Log.e(CarLog.TAG_SERVICE, "Failed to get IVehicle service", e);    } catch (NoSuchElementException e) {        Log.e(CarLog.TAG_SERVICE, "IVehicle service not registered yet");    }    return null;}

理论上拿到IVehicle vehicle 对象后,就应该能够来做对Vehicle HAL做相关调用了。这一部分就先到这里完结吧。