Preliminary Research on Android O: Android Vehicle HAL

Keywords: Android Attribute less ascii

Android Automotive

Android Automotive is a new feature of Android Oreo. From AOSP's code, Android O already contains the whole framework from Application to Framework to HAL. In this chapter, we briefly go through the following Android Vehicle framework and focus on Vehicle HAL. The overall structure is roughly the following:

The above structure should be a more general framework in Android Oreo. From Application to Framework to HAL, compared with previous versions of Android, the former Framework either contacted a Daemon through a binder, the Daemon then loaded the relevant HAL, or the service of these frameworks loaded these HAL libraries directly through JNI. Now Android Oreo uses HIDL to communicate directly between Framework and HAL. Next, let's move Android from bottom to top. Give Vehicle a skeleton. First, we will analyze Vehicle HAL, through which we will review and practice the Android HIDL we have studied before.

Android Vehicle HAL

Type. Hal defines some data structures, IVehicle.hal defines the interface that calls from Framework to HAL, and IVehicleCallback.hal is the interface that HAL calls back to Framework. It still looks clear.  
And the IVehicle.hal interface is not very many.

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);
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88

And IVehicle.hal is even less:

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);
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44

Curious is that these interfaces can achieve these functions of Android locomotive? Let's take a look at it first and study it carefully afterwards.

Compilation of Android Vehicle HAL

According to our previous research, let's see how these Android Vehicle HAL s are compiled and what they are compiled into. First look at the header file generated by compiling the.hal file:

The CPP file generated by.hal file:

The. h file has been analyzed before, and the meaning of Bp/Bn/Bs has not been forgotten. I will not go into more details here, but the implementation of C++ Class file defined in the generated. h file is actually those in Vehicle All. cpp/Vehicle CallbackAll. cpp. These related implementations are written in these. CPP files.

These. cpp /. h files will eventually generate a library called android.hardware.automotive.vehicle@2.0.so. For details, please refer to hardware/interfaces/automotive/vehicle/2.0/Android.bp.

Also refer to hardware/interfaces/automotive/vehicle/2.0/default/Android.mk,
A static library named android.hardware.automotive.vehicle@2.0-default-impl-lib will be compiled in the hardware/interfaces/automotive/vehicle/2.0/default/impl/directory, while a static library named android.hardware.automotive.vehicle@2.0-manager-lib-shared will be compiled in the hardware/interfaces/automotive/vehicle/2.0/default/common/directory, both of which are static libraries. Link to the android.hardware.automotive.vehicle@2.0.so dynamic library generated above.

And eventually it will be compiled into an executable program:

include $(CLEAR_VARS)
LOCAL_MODULE := $(vhal_v2_0)-service
LOCAL_INIT_RC := $(vhal_v2_0)-service.rc
LOCAL_PROPRIETARY_MODULE := true
LOCAL_MODULE_RELATIVE_PATH := hw

LOCAL_SRC_FILES := \
    VehicleService.cpp

LOCAL_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 -Werror

include $(BUILD_EXECUTABLE)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

This executable will be started by the Init system at boot time and become a Daemon:
service vehicle-hal-2.0 /vendor/bin/hw/android.hardware.automotive.vehicle@2.0-service 
class hal 
user vehicle_network 
group system inet

Use of Android Vehicle HAL

After compiling everything, let's see how Vehicle HAL works.

1) Android Vehicle HAL Service end use:
Let's look at the hardware/interfaces/automotive/vehicle/2.0/default/VehicleService.cpp file:

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();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

To tell you the truth, I just saw this code, what a ghost is auto, what a ghost is std::make_unique, these years are all JAVA/Android, like these new C++ specifications, new things are emerging more and more, it is really a day without learning to lag behind.

Fortunately, this is also very simple. std::make_unique is equivalent to new first. auto means that the variable type is uncertain when declared, and the variable type is determined according to the actual situation when the variable is defined.

The most important of these two sentences are:

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

Let's look at the definition of Vehicle Hal Manager:

  class VehicleHalManager : public IVehicle 
  • 1
  • 2

The Vehicle HalManager class is derived from the IVehicle class, and IVehicle is compiled from the. hal file we introduced above.

Let's continue with the following sentence:

   service->registerAsService();
  • 1
  • 2

From the compiled. cpp file of. hal file, the directory of the generated cpp file is: out/soong/.intermediates/hardware/interfaces/automotive/vehicle/2.0/android.hardware.automotive.vehicle@2.0_genc+/gen/android/hardware/automotive/vehicle/2.0/Vehicle All.cpp

The concrete realization of this function is as follows:

::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();
    // Getting the default service manager is very similar to the Binder mechanism. If you have time, you can go deep into it.

    if (sm == nullptr) {
        return ::android::INVALID_OPERATION;
    }
    ::android::hardware::Return<bool> ret = sm->add(serviceName.c_str(), this);
    //Adding services to service manager is the same as Binder mechanism.

    return ret.isOk() && ret ? ::android::OK : ::android::UNKNOWN_ERROR;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

But the odd thing is that add in is the this pointer, that is, it should be an IVehicle object, that is, an object of Vehicle HalManager. Shouldn't it be the object of Bnxxxx??? I have a dull face here. This is the first one, and the second one is even more incredible.

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));
            });
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

Let's look at this code. First, attribute((constructor)) is also a mechanism of gcc, which basically means that the static_constructor function will be called before the main function is called.


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

This code means inserting a key/value in gBnConstructorMap, which is

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

What the hell is this??? The search should be a Raman expression, but the dot is void *iIntf, which is a parameter. How does this parameter pass in? I searched for half a day and couldn't find out how the parameters were passed in. But after looking at the definition of BnHwVehicle, it's clear that the IVehicle class is used.

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;
        }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

From the perspective of BnHwVehicle class, it really undertakes the work of HIDL Service. From BnHwVehicle, the IVehicle class will be called, and the IVehicle class will be inherited as the real implementation operation class. So far, we have not found a solution to this problem.

Here's a brief summary of the service side:
1) A new class will be derived from the Ixxxx class, which will be the real operation class.  
2) Call registerAsService from a derived class of Ixxxx class to register itself in hw service manager.  
3) At present, it seems that if a client makes a request, BnXXXXX will correspond, and BnXXXXX will call its own Ixxxx implementation function to complete an operation request.

1) Android Vehicle HAL Client uses:
This Client side exists in the Car Service of the Android Framework.
In the onCreate function:

"` 
@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();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

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

Get Vehicle HAL.

@Nullable
private 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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

After you theoretically get the IVehicle vehicle object, you should be able to make related calls to Vehicle HAL. Let's finish this part here.

Original address: http://blog.csdn.net/ljp1205/article/details/78080954

Posted by hellouthere on Tue, 01 Jan 2019 14:33:08 -0800