Android CarProperty

一、CarProperty介绍

在Android Automotive OS (AAOS)中,绝大部分与车辆硬件功能相关联的属性,如空调, 车舱功能, 车辆传感器等都是通过CarProperty来读取或者设置的,其中CarPropertyService作为CarService的子服务,负责调用HAL层(VehicleHAL)实现具体功能,而CarPropertyManager作为客户端接口由各个APP调用,如下为CarPropertyManager的Block图:

二、CarProperty相关类

CarProperty相关

CarPropertyManager

CarPropertyManager是Android Automotive OS中提供的一个与车载属性相关的管理类。它提供了访问和监控车辆属性的接口,可以获取车辆的各种信息,例如车速、引擎转速。同时也可以通过CarPropertyManager来控制车辆相关属性,例如打开空调,关闭车窗等。

CarPropertyManager代码位于:

packages/services/Car/car-lib/src/android/car/hardware/property/CarPropertyManager.java

CarPropertyManager的定义:

public class CarPropertyManager implements CarManagerBase {}

CarPropertyValue

CarPropertyValue是CarProperty的数据类,包括PropertyId、AreaId、Status、Timestamp、Value,通过CarPropertyManager.getProperty可以获取到CarPropertyValue。

CarPropertyValue代码位于:

packages/Car/car-lib/src/android/car/hardware/CarPropertyValue.java

CarPropertyValue的定义:

public final class CarPropertyValue<T> implements Parcelable {}

CarPropertyConfig

CarPropertyConfig表示有关汽车属性的配置信息,例如汽车区域的数据类型和最小/最大范围(如果适用)。也是实际开发中非常常用的类。

CarPropertyConfig代码位于:

packages/Car/car-lib/src/android/car/hardware/CarPropertyConfig.java

CarPropertyConfig的定义:

public final class CarPropertyConfig<T> implements Parcelable {}

CarPropertyService

CarPropertyService是CarPropertyManager的服务端,负责具体CarProperty相关设定和获取。

CarPropertyService代码位于:

packages/services/Car/service/src/com/android/car/CarPropertyService.java

CarPropertyService的定义:

public class CarPropertyService extends ICarProperty.Stub implements CarServiceBase, PropertyHalService.PropertyHalListener {}

PropertyHalService

PropertyHalService用于管理车辆属性的硬件抽象层服务。它充当了车辆属性与底层硬件之间的接口,通过HAL进行交互,实现对车辆属性的读取和控制。

PropertyHalService代码位于:

packages/services/Car/service/src/com/android/car/hal/PropertyHalService.java

PropertyHalService的定义:

public class PropertyHalService extends HalServiceBase {}

三、CarPropertyManager API

CarPropertyManager API如下:

  • CarPropertyValue<E> getProperty(@NonNull Class<E> clazz, int propId, int areaId):获取Property

  • CarPropertyValue<E> getProperty(int propId, int areaId) :获取Property

  • void setProperty(@NonNull Class<E> clazz, int propId, int areaId, @NonNull E val) :设置Property

  • boolean registerCallback(@NonNull CarPropertyEventCallback callback, int propertyId, @FloatRange(from = 0.0, to = 100.0) float rate):注册Property变化Callback

  • void unregisterCallback(@NonNull CarPropertyEventCallback callback) :解除注册Property变化Callback

  • List<CarPropertyConfig> getPropertyList() :获取CarPropertyConfig列表

  • List<CarPropertyConfig> getPropertyList(@NonNull ArraySet<Integer> propertyIds) :获取CarPropertyConfig列表

  • CarPropertyConfig<?> getCarPropertyConfig(int propId) :获取CarPropertyConfig

  • int getAreaId(int propId, int area) :获取AreaID

  • String getReadPermission(int propId) :获取读权限

  • String getWritePermission(int propId) :获取写权限

  • boolean isPropertyAvailable(int propId, int area) :判断Property是否可用

  • boolean getBooleanProperty(int prop, int area) :获取Boolean类型的Property

  • float getFloatProperty(int prop, int area) :获取Float类型的Property

  • int getIntProperty(int prop, int area) :获取Int类型的Property

  • int[] getIntArrayProperty(int prop, int area) :获取IntArray类型的Property

  • void setBooleanProperty(int prop, int areaId, boolean val) :设置Boolean类型的Property

  • void setFloatProperty(int prop, int areaId, float val) :设置Float类型的Property

  • void setIntProperty(int prop, int areaId, int val) :设置Int类型的Property

四、CarProperty流程分析

1、setProperty流程

下面我们分析setProperty流程,首先是CarPropertyManager :

//packages/services/Car/car-lib/src/android/car/hardware/property/CarPropertyManager.java
public class CarPropertyManager extends CarManagerBase {
    public <E> void setProperty(@NonNull Class<E> clazz, int propId, int areaId, @NonNull E val) {
        if (DBG) {
            Log.d(TAG, "setProperty, propId: 0x" + toHexString(propId)
                    + ", areaId: 0x" + toHexString(areaId) + ", class: " + clazz + ", val: " + val);
        }
        checkSupportedProperty(propId);
        try {
            if (mCarPropertyEventToService == null) {
                mCarPropertyEventToService = new CarPropertyEventListenerToService(this);
            }
            mService.setProperty(new CarPropertyValue<>(propId, areaId, val), 
                    mCarPropertyEventToService); //调用CarPropertyService的setProperty
        } catch (RemoteException e) {
            handleRemoteExceptionFromCarService(e);
        } catch (ServiceSpecificException e) {
            if (mAppTargetSdk < Build.VERSION_CODES.R) {
                if (e.errorCode == VehicleHalStatusCode.STATUS_TRY_AGAIN) {
                    throw new RuntimeException(String.format("Failed to set property: 0x%x, "
                            + "areaId: 0x%x", propId, areaId));
                } else {
                    throw new IllegalStateException(String.format("Failed to set property: 0x%x, "
                            + "areaId: 0x%x", propId, areaId));
                }
            }
            handleCarServiceSpecificException(e, propId, areaId, null);
        }
    }
}

在CarPropertyManager的setProperty调用CarPropertyService的setProperty:

//packages/services/Car/service/src/com/android/car/CarPropertyService.java
private final PropertyHalService mHal;
public class CarPropertyService extends ICarProperty.Stub
        implements CarServiceBase, PropertyHalService.PropertyHalListener {
    @Override
    public void setProperty(CarPropertyValue prop, ICarPropertyEventListener listener)
            throws IllegalArgumentException, ServiceSpecificException {
        int propId = prop.getPropertyId();
        checkPropertyAccessibility(propId);
        // need an extra permission for writing display units properties.
        if (mHal.isDisplayUnitsProperty(propId)) {
            CarServiceUtils.assertPermission(mContext, Car.PERMISSION_VENDOR_EXTENSION);
        }
        mHal.setProperty(prop); //调用PropertyHalService的setProperty
        IBinder listenerBinder = listener.asBinder();
        synchronized (mLock) {
            Client client = mClientMap.get(listenerBinder);
            if (client == null) {
                client = new Client(listener);
            }
            if (client.isDead()) {
                Slogf.w(TAG, "the ICarPropertyEventListener is already dead");
                return;
            }
            updateSetOperationRecorderLocked(propId, prop.getAreaId(), client);
        }
    }
}

在CarPropertyService的setProperty调用PropertyHalService的setProperty:

//packages/services/Car/service/src/com/android/car/hal/PropertyHalService.java
private final VehicleHal mVehicleHal;
public class PropertyHalService extends HalServiceBase {
    public void setProperty(CarPropertyValue prop)
            throws IllegalArgumentException, ServiceSpecificException {
        int halPropId = managerToHalPropId(prop.getPropertyId());
        if (!isPropertySupportedInVehicle(halPropId)) {
            throw new IllegalArgumentException("Invalid property Id : 0x"
                    + toHexString(prop.getPropertyId()));
        }
        HalPropConfig propConfig;
        synchronized (mLock) {
            propConfig = mHalPropIdToPropConfig.get(halPropId);
        }
        HalPropValue halPropValue = mPropValueBuilder.build(prop, halPropId, propConfig);
        // CarPropertyManager catches and rethrows exception, no need to handle here.
        mVehicleHal.set(halPropValue); //调用VehicleHal的set
    }
}

在PropertyHalService的setProperty调用VehicleHal的set方法:

//packages/services/Car/service/src/com/android/car/hal/VehicleHal.java
public class VehicleHal implements HalClientCallback {
    private volatile HalClient mHalClient;
    public void set(HalPropValue propValue)
            throws IllegalArgumentException, ServiceSpecificException {
        mHalClient.setValue(propValue); //调用HalClient的setValue方法
    }
}

在VehicleHal的set方法中调用HalClient的setValue方法:

//packages/services/Car/service/src/com/android/car/hal/HalClient.java
final class HalClient {
    private final VehicleStub mVehicle;
    public void setValue(HalPropValue propValue)
            throws IllegalArgumentException, ServiceSpecificException {
        ObjectWrapper<String> errorMsgWrapper = new ObjectWrapper<>();
        errorMsgWrapper.object = new String();


        int status = invokeRetriable(() -> {
            try {
                mVehicle.set(propValue); //调用VehicleStub的set方法
                errorMsgWrapper.object = new String();
                return StatusCode.OK;
            } catch (RemoteException e) {
                errorMsgWrapper.object = e.toString();
                return StatusCode.TRY_AGAIN;
            } catch (ServiceSpecificException e) {
                errorMsgWrapper.object = e.toString();
                return e.errorCode;
            }
        }, mWaitCapMs, mSleepMs);


        String errorMsg = errorMsgWrapper.object;


        if (StatusCode.INVALID_ARG == status) {
            throw new IllegalArgumentException(getValueErrorMessage("set", propValue, errorMsg));
        }


        if (StatusCode.OK != status) {
            throw new ServiceSpecificException(
                    status, getValueErrorMessage("set", propValue, errorMsg));
        }
    }
}

在HalClient的setValue方法中调用VehicleStub的set方法,而VehicleStub是一个抽象类,其实现子类为AidlVehicleStub :

//packages/services/Car/service/src/com/android/car/AidlVehicleStub.java
final class AidlVehicleStub extends VehicleStub {
    private final IVehicle mAidlVehicle;
    public void set(HalPropValue propValue) throws RemoteException, ServiceSpecificException {
        SetValueRequest request = new SetValueRequest();
        long requestId = mRequestId.getAndIncrement();


        AndroidFuture<SetValueResult> resultFuture = new AndroidFuture();
        synchronized (mLock) {
            mPendingSetValueRequests.put(requestId, resultFuture);
        }


        request.requestId = requestId;
        request.value = (VehiclePropValue) propValue.toVehiclePropValue();
        SetValueRequests requests = new SetValueRequests();
        requests.payloads = new SetValueRequest[]{request};
        requests = (SetValueRequests) LargeParcelable.toLargeParcelable(requests, () -> {
            SetValueRequests newRequests = new SetValueRequests();
            newRequests.payloads = new SetValueRequest[0];
            return newRequests;
        });


        mAidlVehicle.setValues(mGetSetValuesCallback, requests);


        AndroidAsyncFuture<SetValueResult> asyncResultFuture = new AndroidAsyncFuture(resultFuture);
        try {
            SetValueResult result = asyncResultFuture.get(mTimeoutMs, TimeUnit.MILLISECONDS);
            if (result.status != StatusCode.OK) {
                throw new ServiceSpecificException(
                        result.status, "failed to set value: " + request.value);
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt(); // Restore the interrupted status
            throw new ServiceSpecificException(StatusCode.INTERNAL_ERROR,
                    "thread interrupted, possibly exiting the thread");
        } catch (ExecutionException e) {
            throw new ServiceSpecificException(StatusCode.INTERNAL_ERROR,
                    "failed to resolve SetValue future, error: " + e);
        } catch (TimeoutException e) {
            synchronized (mLock) {
                mPendingSetValueRequests.remove(requestId);
            }
            throw new ServiceSpecificException(StatusCode.INTERNAL_ERROR,
                    "set value request timeout for property: " + request.value);
        }
    }
}

在AidlVehicleStub的set方法中调用了IVehicle 的setValues方法,IVehicle为AIDL接口,由DefaultVehicleHal进行处理。

2、VHAL向CarProperty发送PropertyEvent流程

在Vehicle章节,我们分析了Vehicle事件分发流程,在VehicleHal的onPropertyEvent中调用调用各个HalService的onHalEvents,如PowerHalService、PropertyHalService,之后由不同HalService继续对PropertyEvent进行处理。

我们继续分析PropertyHalService的onHalEvents:

//packages/services/Car/service/src/com/android/car/hal/PropertyHalService.java
public class PropertyHalService extends HalServiceBase {
    public void onHalEvents(List<HalPropValue> values) {
        PropertyHalListener listener;
        synchronized (mLock) {
            listener = mListener;
        }
        if (listener != null) {
            for (HalPropValue v : values) {
                if (v == null) {
                    continue;
                }
                int propId = v.getPropId();
                if (!isPropertySupportedInVehicle(propId)) {
                    Slogf.w(TAG, "Property is not supported: 0x" + toHexString(propId));
                    continue;
                }
                // Check payload if it is a userdebug build.
                if (BuildHelper.isDebuggableBuild() && !mPropIds.checkPayload(v)) {
                    Slogf.w(TAG, "Drop event for property: " + v + " because it is failed "
                            + "in payload checking.");
                    continue;
                }
                int mgrPropId = halToManagerPropId(propId);
                HalPropConfig propConfig;
                synchronized (mLock) {
                    propConfig = mHalPropIdToPropConfig.get(propId);
                }
                CarPropertyValue<?> propVal = v.toCarPropertyValue(mgrPropId, propConfig); //HalPropValue转换为CarPropertyValue
                CarPropertyEvent event = new CarPropertyEvent( 
                        CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE, propVal); //创建CarPropertyEvent对象,Event为PROPERTY_EVENT_PROPERTY_CHANGE,参数为CarPropertyValue值
                mEventsToDispatch.add(event); //将CarPropertyEvent对象
            }
            listener.onPropertyChange(mEventsToDispatch); //调用PropertyHalListener的onPropertyChange方法
            mEventsToDispatch.clear();
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值