一、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();
}
}
}