Android Automotive (ten) add a vehicle attribute

Android Automotive (ten) add a vehicle attribute

I introduced a lot of technologies in the Android Automotive framework, and finally shared some of my own use methods.

Add a vehicle attribute

hardware abstraction layer


Modify types.hal

First define the new vehicle property in types.hal

code path:hardware\interfaces\automotive\vehicle\2.0\type.hal

/**
  * NEW_VENDOR_PROPERTY
  *
  * @change_mode VehiclePropertyChangeMode:ONCHANGE
  * @access VehiclePropertyAccess:READ_WRITE
  */
NEW_VENDOR_PROPERTY = (
    0xAAAA
    | VehiclePropertyGroup:VENDOR
    | VehiclePropertyType:INT32
    | VehicleArea:SEAT),

Add data structure in types.hal

enum NewVendorPropertyMenu : int32_t {
    
    
    ENUM_1 = 0x1,
    ENUM_2 = 0x2
}

Modify DefaultConfig.h

code path:hardware\interfaces\automotive\vehicle\2.0\default\impl\vhal_v2_0\DefaultConfig.h

Add scope configuration.

constexpr int NEW_VENDOR_PROPERTY_AREA_1 = (int)VehicleAreaSeat::ROW_1_LEFT;
constexpr int NEW_VENDOR_PROPERTY_AREA_2 = (int)VehicleAreaSeat::ROW_1_RIGHT;

Add vehicle attribute configuration

{.config = 
    {
        .prop = toInt(VehicleProperty::NEW_VENDOR_PROPERTY),
        .access = VehiclePropertyAccess::READ_WRITE,
        .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
        .areaConfigs = {
            VehicleAreaConfig{.areaId = (int)(VehicleAreaSeat::ROW_1_LEFT), .minInt32Value = 0, .maxInt32Value = 5},
            VehicleAreaConfig{.areaId = (int)(VehicleAreaSeat::ROW_1_RIGHT), .minInt32Value = 0, .maxInt32Value = 5}
        },
    },
    .initialAreaValues = {
        {(int)(VehicleAreaSeat::ROW_1_LEFT), {.int32Values = {toInt(NewVendorPropertyMenu::ENUM_1)} } },
        {(int)(VehicleAreaSeat::ROW_1_RIGHT), {.int32Values = {toInt(NewVendorPropertyMenu::ENUM_2)} } },
    }
},

Add vehicle attribute initial value

.initialAreaValues = {
    {(int)(VehicleAreaSeat::ROW_1_LEFT), {.int32Values = {toInt(NewVendorPropertyMenu::ENUM_1)} } },
    {(int)(VehicleAreaSeat::ROW_1_RIGHT), {.int32Values = {toInt(NewVendorPropertyMenu::ENUM_2)} } },
}

Test and add a fake callback in EmulatedVehicleHal.cpp

pathhardware\interfaces\automotive\vehicle\2.0\default\impl\vhal_v2_0\EmulatedVehicleHal.cpp

StatusCode EmulatedVehicleHal::set(const VehiclePropValue& propValue) {
     
     
    ······
//mock hal callback event
    ALOGI("%s propId: 0x%x, areaId: 0x%x", __func__, propValue.prop, propValue.areaId);
    doHalEvent(getValuePool()->obtain(propValue));
//mock hal callback event
    ······
    getEmulatorOrDie()->doSetValueFromClient(propValue);

    return StatusCode::OK;
}

Modify Android.bp

Add a custom type

code path:hardware\interfaces\automotive\vehicle\2.0\Android.bp

types: [
	"NewVendorPropertyMenu", 
]

No longer used after Android P version


System framework layer Car-lib


Modify VehiclePropertyIds.java

code path:packages\services\Car\car-lib\src\android\car\VehiclePropertyIds.java

public static final int NEW_VENDOR_PROPERTY = 624994986;/* (0xAAAA | VehiclePropertyGroup:VENDOR | VehiclePropertyType:INT32 | VehicleArea:SEAT) */
public static  String toString(int o) {
    
    
    if (o == NEW_VENDOR_PROPERTY) {
    
    
        return "NEW_VENDOR_PROPERTY";
    }
}

Modify system-current.txt

Add the modification of carlib here

code path:packages\services\Car\car-lib\api\system-current.txt

field public static final int NEW_VENDOR_PROPERTY = 624994986; // 0x2540AAAA

System framework layer CarService


Modify PropertyHalServiceIds.java

Code path: packages\services\Car\service\src\com\android\car\hal\PropertyHalServiceIds.java
Put permissions and propertycorrespondences mapin

mProps.put(VehicleProperty.NEW_VENDOR_PROPERTY, new Pair<>(
                Car.PERMISSION_NEW_VENDOR_PROPERTY,
                Car.PERMISSION_NEW_VENDOR_PROPERTY));

Modify AndroidManifest.xml

Add permission in AndroidManifest.

code path:packages\services\Car\service\AndroidManifest.xml

<permission               
    android:name="android.car.permission.NEW_VENDOR_PROPERTY"
    android:protectionLevel="system|signature"
    android:label="@string/car_permission_vendor_property"
    android:description="@string/car_permission_desc_vendor_property"
/>

call system interface

The system framework layer calls car-lib

private CarPropertyManager mCarPropertyManager;
private CarPropertyManager.CarPropertyEventCallback mCallback = new CarPropertyManager.CarPropertyEventCallback() {
    
    
    @Override
    public void onChangeEvent(CarPropertyValue carPropertyValue) {
    
    
        //数据发生变化
        switch (carPropertyValue.getPropertyId()) {
    
    
            case VehiclePropertyIds.PERF_VEHICLE_SPEED:
                //数据发生变化
                float value = (float) carPropertyValue.getValue();
                break;
            default:

        }
    }

    @Override
    public void onErrorEvent(int i, int i1) {
    
    
        //发生错误
    }
};

private void init() {
    
    
    //创建Car实例
    car = Car.createCar(mContext, new ServiceConnection() {
    
    
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
    
    
            //和服务绑定成功
            //获取CarPropertyManager实例
            mCarPropertyManager = (CarPropertyManager) car.getCarManager(Car.PROPERTY_SERVICE);
            //订阅一个属性,变化时获取通知
            mCarPropertyManager.registerCallback(mCallback, VehiclePropertyIds.PERF_VEHICLE_SPEED, CarPropertyManager.SENSOR_RATE_NORMAL);
            //获取一个属性值
            mCarPropertyManager.getIntProperty(VehiclePropertyIds.PERF_VEHICLE_SPEED, 0);
            //设置一个属性值
            mCarPropertyManager.setIntProperty(VehiclePropertyIds.HVAC_FAN_SPEED, VehicleAreaSeat.SEAT_ROW_1_LEFT, 0);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
    
    
            //和服务断开连接
        }
    });
    //请求和服务绑定
    car.connect();
}

The system framework layer calls HIDL

import android.hardware.automotive.vehicle.V2_0.IVehicle;
import android.hardware.automotive.vehicle.V2_0.IVehicleCallback;
import android.hardware.automotive.vehicle.V2_0.SubscribeOptions;

private IVehicle mVehicle;
private final VehicleDeathRecipient mVehicleDeathRecipient = new VehicleDeathRecipient();
rivate static class VehicleCallback extends IVehicleCallback.Stub {
    
    
    private Handler mHandler;

    VehicleCallback(Handler handler) {
    
    
        mHandler = handler;
    }

    @Override
    public void onPropertyEvent(ArrayList<VehiclePropValue> propValues) {
    
    
        mHandler.sendMessage(Message.obtain(
            mHandler, CallbackHandler.MSG_ON_PROPERTY_EVENT, propValues));
    }

    @Override
    public void onPropertySet(VehiclePropValue propValue) {
    
    
        mHandler.sendMessage(Message.obtain(
            mHandler, CallbackHandler.MSG_ON_PROPERTY_SET, propValue));
    }

    @Override
    public void onPropertySetError(int errorCode, int propId, int areaId) {
    
    
        mHandler.sendMessage(Message.obtain(
            mHandler, CallbackHandler.MSG_ON_SET_ERROR,
            new PropertySetError(errorCode, propId, areaId)));
    }
}
private final IVehicleCallback mInternalCallback;

private void init(){
    
    
    try {
    
    
        mVehicle =  android.hardware.automotive.vehicle.V2_0.IVehicle.getService();
    } 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");
    }

    try {
    
    
        mVehicle.linkToDeath(mVehicleDeathRecipient, 0);
    } catch (RemoteException e) {
    
    
        throw new IllegalStateException("Failed to linkToDeath Vehicle HAL");
    }

    mInternalCallback = new VehicleCallback(handler);
    //SubscribeOptions opts = new SubscribeOptions();
    SubscribeOptions opts = new SubscribeOptions();
    opts.propId = property;
    opts.sampleRate = samplingRateHz;
    opts.flags = flags;

    subscribe(opts)}

public void subscribe(SubscribeOptions... options) throws RemoteException {
    
    
    mVehicle.subscribe(mInternalCallback, new ArrayList<>(Arrays.asList(options)));
}

The hardware abstraction layer calls HIDL

head File

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <vector>
#include <binder/IBinder.h>
#include <utils/String8.h>

#include <android/hardware/automotive/vehicle/2.0/IVehicle.h>
#include <android/hardware/automotive/vehicle/2.0/IVehicleCallback.h>
using ::android::hardware::Return;
using ::android::hardware::Void;
using ::android::hardware::hidl_vec;
using ::android::hardware::hidl_handle;
using ::android::hardware::hidl_death_recipient;
using ::android::sp;
using namespace ::android::hardware::automotive::vehicle::V2_0;

namespace com{
namespace vhal{
namespace helper {

class VhalHelper : public IVehicleCallback
{
    /*Overrides*/
    Return<void> onPropertyEvent(const hidl_vec<VehiclePropValue>& propValues) override;
    Return<void> onPropertySet(const VehiclePropValue& propValue) override;
    Return<void> onPropertySetError(StatusCode errorCode, int32_t propId, int32_t areaId) override;

    void handleVehicleHalDeath();

    class VehicleHalDeathRecipient : public hidl_death_recipient
    {
        public:
            VehicleHalDeathRecipient(const sp<FaceIdVhalHelper> faceIdVhalHelper) :
                    mFaceIdVhalHelper(faceIdVhalHelper) {}
            virtual void serviceDied(uint64_t cookie,
                    const android::wp<android::hidl::base::V1_0::IBase>& who);
        private:
            sp<FaceIdVhalHelper> mFaceIdVhalHelper;
    };
public:
    VhalHelper();
    virtual ~VhalHelper();
    android::status_t initVehicle();
private:
    sp<IVehicle> mVehicle;
    sp<VehicleHalDeathRecipient> mVehicleHalDeathRecipient;
};

cpp file

#define LOG_TAG "VhalHelper"
#define LOG_NDEBUG 0
#define LOG_NDDEBUG 0

#include <VhalHelper.h>
#include <log/log.h>
#include <vhal_v2_0/VehicleUtils.h>
#include "android-base/macros.h"

#define VEHICLE_SPEED                   (toInt(VehicleProperty::VEHICLE_SPEED))
#define MAX_RETRY_TIME                  100
#define VEHICLE_INIT_SLEEP_WAIT         100 /* 100 ms */
static SubscribeOptions reqVehicleProperties[] = {
    {
       .propId = VEHICLE_SPEED,
        .flags = SubscribeFlags::EVENTS_FROM_CAR
    },
};

namespace com{
namespace vhal{
namespace helper {

    VhalHelper::VhalHelper() {
    }

    VhalHelper::~VhalHelper() {
    }

    android::status_t VhalHelper::initVehicle()
    {     ALOGE("VhalHelper initVehicle");
          StatusCode status;
          hidl_vec<SubscribeOptions> options;

          if (mVehicle == 0) {
              mVehicle = IVehicle::getService();
              if (mVehicle != 0) {
                  mVehicle->linkToDeath(mVehicleHalDeathRecipient, 0 /*cookie*/);
              } else {
                  return android::FAILED_TRANSACTION;
              }
              options.setToExternal(reqVehicleProperties, arraysize(reqVehicleProperties));
              status = mVehicle->subscribe(new FaceIdVhalHelper(), options);
              if (status != StatusCode::OK) {
                  return android::FAILED_TRANSACTION;
              }
          }
          return android::OK;
    }

    Return<void> VhalHelper::onPropertyEvent(const hidl_vec <VehiclePropValue> & propValues) {
		int32_t rxProprtyCount = propValues.size();
        for(int i = 0; i < rxProprtyCount; i++) {
            ALOGD("VhalHelper. Val:%f , Time:%u ",  propValues[i].value.floatValues[0], (unsigned int)(propValues[i].timestamp/1000000));
        }
        return Return<void>();
    }

    Return<void> VhalHelper::onPropertySet(const VehiclePropValue & propValue) {
        return Return<void>();
    }

    Return<void> VhalHelper::onPropertySetError(StatusCode errorCode,
                                    int32_t    propId,
                                    int32_t    areaId) { 
        return Return<void>();
    }

    void VhalHelper::handleVehicleHalDeath()
    {
        mVehicle->unlinkToDeath(mVehicleHalDeathRecipient);
        mVehicle = NULL;
        int retryCount = 0;
        do {
            if (initVehicle() == android::OK) {
                break;
            } else {
                if (++retryCount <= MAX_RETRY_TIME) {
                    usleep(VEHICLE_INIT_SLEEP_WAIT*1000);
                } else {
                    break;
                }
            }
        } while (1);
    }

    void FaceIdVhalHelper::VehicleHalDeathRecipient::serviceDied(uint64_t cookie __unused,
            const android::wp<android::hidl::base::V1_0::IBase>& who __unused) {
        mFaceIdVhalHelper->handleVehicleHalDeath();
    }
}
}
}

Modify the bp file

cc_library_shared {
    
    
    name: "libvhalplugin",
    owner: "ts",
    srcs: [
        "VhalHelper.cpp", 
    ],
    // add cflags.
    cflags: [
        "-Wall",
        "-Wextra",
        "-Werror",
    ],
    clang_cflags: ["-Wno-error=unused-lambda-capture"],

    shared_libs: [
        "liblog",
        "libutils",
        "libbinder",
        "libhwbinder",
        "libhidlbase",
        "libhidltransport",
        "[email protected]",
        "[email protected]",
    ],
    vendor: true,
}

おすすめ

転載: blog.csdn.net/Jun_P/article/details/127116749