Android Automotive(五) CarService
CarService は、システム フレームワーク レイヤーの Android Automotive のコア サービスです。これは SystemServer に似ており、サービス内の数十のサブサービスを管理します。
開始プロセス
CarService は SystemServer によって起動され、起動プロセスは次のようになります。
- SystemServer 启动CarServiceHelperService
- CarServiceHelperService は CarService をバインドします
- CarService は ICarImpl のインスタンスを作成し、init メソッドを呼び出します
- ICarImpl は他のサービスを開始します
SystemServer
コード:frameworks/base/services/java/com/android/server/SystemServer.java
private static final String CAR_SERVICE_HELPER_SERVICE_CLASS =
"com.android.internal.car.CarServiceHelperService";
private void startOtherServices() {
mActivityManagerService.systemReady(() -> {
if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
traceBeginAndSlog("StartCarServiceHelperService");
mSystemServiceManager.startService(CAR_SERVICE_HELPER_SERVICE_CLASS);
traceEnd();
}
});
}
CarServiceHelperService
コード:frameworks/opt/car/services/src/com/android/internal/car/CarServiceHelperService.java
private static final String CAR_SERVICE_INTERFACE = "android.car.ICar";
public class CarServiceHelperService extends SystemService {
@Override
public void onStart() {
Intent intent = new Intent();
intent.setPackage("com.android.car");
intent.setAction(CAR_SERVICE_INTERFACE);
if (!getContext().bindServiceAsUser(intent, mCarServiceConnection, Context.BIND_AUTO_CREATE, UserHandle.SYSTEM)) {
Slog.wtf(TAG, "cannot start car service");
}
System.loadLibrary("car-framework-service-jni");
}
}
SystemServer
真ん中が活性化されActivityManagerService.systemReady
た後SystemServiceManager
CarServiceHelperService
CarServiceHelperService
バインディングCarService
CarService
マニフェスト ファイル:packages/services/Car/service/AndroidManifest.xml
<service android:name=".CarService"
android:singleUser="true">
<intent-filter>
<action android:name="android.car.ICar" />
</intent-filter>
</service>
- の設定により、パッケージ名と の名前で実装およびバインドでき
CarService
ます。AndroidManifest
CarServiceHelperService
action
CarService
CarService
コード:packages/services/Car/service/src/com/android/car/CarService.java
private ICarImpl mICarImpl;
private IVehicle mVehicle;
@Override
public void onCreate() {
Log.i(CarLog.TAG_SERVICE, "Service onCreate");
mCanBusErrorNotifier = new CanBusErrorNotifier(this /* context */);
mVehicle = getVehicle();
EventLog.writeEvent(EventLogTags.CAR_SERVICE_CREATE, mVehicle == null ? 0 : 1);
Log.i(CarLog.TAG_SERVICE, "Connected to " + mVehicleInterfaceName);
EventLog.writeEvent(EventLogTags.CAR_SERVICE_CONNECTED, mVehicleInterfaceName);
mICarImpl = new ICarImpl(this,
mVehicle,
SystemInterface.Builder.defaultSystemInterface(this).build(),
mCanBusErrorNotifier,
mVehicleInterfaceName);
mICarImpl.init();
linkToDeath(mVehicle, mVehicleDeathRecipient);
ServiceManager.addService("car_service", mICarImpl);
SystemProperties.set("boot.car_service_created", "1");
super.onCreate();
}
@Override
public IBinder onBind(Intent intent) {
return mICarImpl;
}
- CarService には、mICarImpl と mVehicle という 2 つの重要な変数があります。
- mICarImpl は、ICar インターフェイスを実装し、アプリケーション層との通信に使用される AIDL サーバーです。
- mVehicle は、hal レイヤーとの通信用に HIDL を実装する VehicleHal サービス インターフェースです。
ICarImpl
コード:packages/services/Car/service/src/com/android/car/ICarImpl.java
private final VehicleHal mHal;
@VisibleForTesting
ICarImpl(Context serviceContext, IVehicle vehicle, SystemInterface systemInterface,
CanBusErrorNotifier errorNotifier, String vehicleInterfaceName,
@Nullable CarUserService carUserService,
@Nullable CarWatchdogService carWatchdogService) {
mContext = serviceContext;
mSystemInterface = systemInterface;
mHal = new VehicleHal(serviceContext, vehicle);
allServices.add(mCarWatchdogService);
// Always put mCarExperimentalFeatureServiceController in last.
addServiceIfNonNull(allServices, mCarExperimentalFeatureServiceController);
mAllServices = allServices.toArray(new CarServiceBase[allServices.size()]);
}
@MainThread
void init() {
mBootTiming = new TimingsTraceLog(VHAL_TIMING_TAG, Trace.TRACE_TAG_HAL);
traceBegin("VehicleHal.init");
mHal.init();
traceEnd();
traceBegin("CarService.initAllServices");
for (CarServiceBase service : mAllServices) {
service.init();
}
traceEnd();
}
ICarImpl
最初にVehicleHal
オブジェクトを作成します。VehicleHal
クラスはオブジェクトのCarService
カプセル化であり、オブジェクトとのすべての相互作用はここで処理されます。また、他のサービスもここで初期化されます。好き:Vehicle Service
VehicleHal
hal
PowerHalService
ICarImpl
すべてのサービスが作成され、mAllServices に追加されCarLocalServices
、变量中,
mAllServices は後で使用されますinit
。init
メソッド呼び出しVehicleHal
のinit
メソッド初期化mHal.init()
init
メソッドはmAllServices
サービスをトラバースし、init
各サービスのメソッドを呼び出して初期化します。
建築
カーサービス
コード パス:packages/services/Car/service/src/com/android/car/CarService.java
サービスのストレージとして、CarService は実際には多くのことを行いませんが、主に次のようになります。
-
サービスプロセスを作成する
これは Android アーキテクチャの機能で、CarService は Service を継承し、システムのバックグラウンドでサービスとして実行できます。 -
CrashTracker を作成し
、Vehicle hal が 10 分以内に 10 回クラッシュすると、CarService で例外がスローされます。private final CrashTracker mVhalCrashTracker = new CrashTracker( 10, // Max crash count. 10 * 60 * 1000, // 10 minutes - sliding time window. () -> { if (IS_USER_BUILD) { Log.e(CarLog.TAG_SERVICE, "Vehicle HAL keeps crashing, notifying user..."); mCanBusErrorNotifier.reportFailure(CarService.this); } else { throw new RuntimeException( "Vehicle HAL crashed too many times in a given time frame"); } } )
-
IVehicle インスタンスを取得する
IVehicle は HIDL のインターフェイスであり、HAL レイヤーとの通信がこれを介して完了します -
サブサービスの作成を完了し、サブサービスを初期化します。
public void onCreate() {
Log.i(CarLog.TAG_SERVICE, "Service onCreate");
mCanBusErrorNotifier = new CanBusErrorNotifier(this /* context */);
mVehicle = getVehicle();
EventLog.writeEvent(EventLogTags.CAR_SERVICE_CREATE, mVehicle == null ? 0 : 1);
Log.i(CarLog.TAG_SERVICE, "Connected to " + mVehicleInterfaceName);
EventLog.writeEvent(EventLogTags.CAR_SERVICE_CONNECTED, mVehicleInterfaceName);
mICarImpl = new ICarImpl(this,
mVehicle,
SystemInterface.Builder.defaultSystemInterface(this).build(),
mCanBusErrorNotifier,
mVehicleInterfaceName);
mICarImpl.init();
linkToDeath(mVehicle, mVehicleDeathRecipient);
ServiceManager.addService("car_service", mICarImpl);
SystemProperties.set("boot.car_service_created", "1");
super.onCreate();
}
-
mVehicle = getVehicle();
VehicleService
ハードウェア抽象化レイヤーのインスタンスを取得getService
旧バージョンに比べ、String
パラメータが追加されています。private static IVehicle getVehicle() { final String instanceName = SystemProperties.get("ro.vehicle.hal", "default"); try { return android.hardware.automotive.vehicle.V2_0.IVehicle.getService(instanceName); } catch (RemoteException e) { Log.e(CarLog.TAG_SERVICE, "Failed to get IVehicle/" + instanceName + " service", e); } catch (NoSuchElementException e) { Log.e(CarLog.TAG_SERVICE, "IVehicle/" + instanceName + " service not registered yet"); } return null; }
-
mICarImpl = new ICarImpl(this
ICarImpl
オブジェクトの作成はCarService
プロキシと同等であり、すべてのサービスの読み込みと管理はプロキシによって行われます。 -
mICarImpl.init()
サブサービスの初期化を完了する -
linkToDeath(mVehicle, mVehicleDeathRecipient);
監視対象VehicleService
プロセスのステータス。 -
ServiceManager.addService("car_service", mICarImpl);
自分自身を追加して、ServiceManager
他のモジュールが取得できるようにします
ICarImpl
コード パス:
packages/services/Car/service/src/com/android/car/ICarImpl.java
ICarImpl は、アプリケーション層 AIDL と通信するサーバーである ICar.Stub を実装します。CarService のすべてのサービスの読み込みと初期化は、内部で完了します。アプリケーション層は実際には、このクラスを通じて関連サービスを取得する AIDL エージェントです。
関連するサービス オブジェクトを作成する
ICarImpl(Context serviceContext, IVehicle vehicle, SystemInterface systemInterface,
CanBusErrorNotifier errorNotifier, String vehicleInterfaceName,
@Nullable CarUserService carUserService,
@Nullable CarWatchdogService carWatchdogService) {
mContext = serviceContext;
mSystemInterface = systemInterface;
mHal = new VehicleHal(serviceContext, vehicle);
......
mCarPropertyService = new CarPropertyService(serviceContext, mHal.getPropertyHal());
......
List<CarServiceBase> allServices = new ArrayList<>();
allServices.add(mCarPropertyService);
mAllServices = allServices.toArray(new CarServiceBase[allServices.size()]);
}
初期化
@MainThread
void init() {
mBootTiming = new TimingsTraceLog(VHAL_TIMING_TAG, Trace.TRACE_TAG_HAL);
traceBegin("VehicleHal.init");
mHal.init();//初始化VehicleHal
traceEnd();
traceBegin("CarService.initAllServices");
for (CarServiceBase service : mAllServices) {
service.init();//各个子service调用init
}
traceEnd();
}
Initialize を実行しVehicleHal
、各サブサービスがinit
メソッドを呼び出せるようにします
サブサービスを取得する
getCarService
サービス プロキシのインターフェイスを取得する
public static final String CABIN_SERVICE = "cabin";
public static final String HVAC_SERVICE = "hvac";
public static final String INFO_SERVICE = "info";
public static final String PROPERTY_SERVICE = "property";
public static final String SENSOR_SERVICE = "sensor";
public static final String VENDOR_EXTENSION_SERVICE = "vendor_extension";
@Override
public IBinder getCarService(String serviceName) {
switch (serviceName) {
case Car.CABIN_SERVICE:
case Car.HVAC_SERVICE:
case Car.INFO_SERVICE:
case Car.PROPERTY_SERVICE:
case Car.SENSOR_SERVICE:
case Car.VENDOR_EXTENSION_SERVICE:
return mCarPropertyService;
}
}
上記のすべてのフィールドのインターフェースが返されますCarPropertyService
が、ここを除きPROPERTY_SERVICE
、他のフィールドの使用は推奨されません ( @deprecated
)。
車プロパティ サービス
システムアプリケーション層とハードウェア抽象化層との間のデータ通信を車両属性で完結させる、車両属性管理サービス。PropertyHalService
インターフェイス呼び出しによって特定の機能を実現する重要なメンバー変数がありますPropertyHalService
。CarPropertyService
その機能は、主にクライアントによって登録されたリスナーを維持することです。CarPropertyService は車両プロパティの管理を担当し、上位層のアプリケーションが車両プロパティを処理しやすくします。
CarProperty
ICarProperty.Stub
システムアプリケーションと通信するサーバーとして継承
public class CarPropertyService extends ICarProperty.Stub
ICarProperty
コード:packages/services/Car/car-lib/src/android/car/hardware/property/ICarProperty.aidl
package android.car.hardware.property;
import android.car.hardware.CarPropertyConfig;
import android.car.hardware.CarPropertyValue;
import android.car.hardware.property.ICarPropertyEventListener;
/**
* @hide
*/
interface ICarProperty {
void registerListener(int propId, float rate, in ICarPropertyEventListener callback) = 0;
void unregisterListener(int propId, in ICarPropertyEventListener callback) = 1;
List<CarPropertyConfig> getPropertyList() = 2;
CarPropertyValue getProperty(int prop, int zone) = 3;
void setProperty(in CarPropertyValue prop, in ICarPropertyEventListener callback) = 4;
String getReadPermission(int propId) = 5;
String getWritePermission(int propId) = 6;
}
重要な属性の説明
private final Map<IBinder, Client> mClientMap = new ConcurrentHashMap<>();
private final Map<Integer, CarPropertyConfig<?>> mConfigs = new HashMap<>();
private final PropertyHalService mHal;
private boolean mListenerIsSet = false;
private final Map<Integer, List<Client>> mPropIdClientMap = new ConcurrentHashMap<>();
private final SparseArray<SparseArray<Client>> mSetOperationClientMap = new SparseArray<>();
private final HandlerThread mHandlerThread =
CarServiceUtils.getHandlerThread(getClass().getSimpleName());
private final Handler mHandler = new Handler(mHandlerThread.getLooper());
-
mCientMap
listener
オブジェクトを格納するMap オブジェクトClient
。Client
コールバック インターフェイスの補助クラスが維持されService
、新しい登録ごとにcallback
Client オブジェクトが作成されますprivate class Client implements IBinder.DeathRecipient { private final ICarPropertyEventListener mListener; private final IBinder mListenerBinder; private final SparseArray<Float> mRateMap = new SparseArray<Float>(); }
-
mConfigs
システムがサポートするすべての車両属性を保存 -
mHal
PropertyHalService
インスタンス、hal と対話する処理ロジック -
mPropIdClientMap
登録された車両属性の保存に使用Client
-
mSetOperationClientMap
set
運用のための車両属性レコードの保存
CarPropertyService::registerListener
車両プロパティのリスナーを登録します。登録中に権限が検出されICarImpl.assertPermission(mContext, mHal.getReadPermission(propId));
、登録が成功するとすぐにコールバックが行われますmHandler.post(() -> getAndDispatchPropertyInitValue(propertyConfig, finalClient));
client.getListener().onEvent(events);
@Override
public void registerListener(int propId, float rate, ICarPropertyEventListener listener) {
if (DBG) {
Log.d(TAG, "registerListener: propId=0x" + toHexString(propId) + " rate=" + rate);
}
if (listener == null) {
Log.e(TAG, "registerListener: Listener is null.");
throw new IllegalArgumentException("listener cannot be null.");
}
IBinder listenerBinder = listener.asBinder();
CarPropertyConfig propertyConfig;
Client finalClient;
synchronized (mLock) {
propertyConfig = mConfigs.get(propId);
if (propertyConfig == null) {
// Do not attempt to register an invalid propId
Log.e(TAG, "registerListener: propId is not in config list: 0x" + toHexString(
propId));
return;
}
ICarImpl.assertPermission(mContext, mHal.getReadPermission(propId));
// Get or create the client for this listener
Client client = mClientMap.get(listenerBinder);
if (client == null) {
client = new Client(listener);
}
client.addProperty(propId, rate);
// Insert the client into the propId --> clients map
List<Client> clients = mPropIdClientMap.get(propId);
if (clients == null) {
clients = new CopyOnWriteArrayList<Client>();
mPropIdClientMap.put(propId, clients);
}
if (!clients.contains(client)) {
clients.add(client);
}
// Set the HAL listener if necessary
if (!mListenerIsSet) {
mHal.setListener(this);
}
// Set the new rate
if (rate > mHal.getSampleRate(propId)) {
mHal.subscribeProperty(propId, rate);
}
finalClient = client;
}
// propertyConfig and client are NonNull.
mHandler.post(() ->
getAndDispatchPropertyInitValue(propertyConfig, finalClient));
}
private void getAndDispatchPropertyInitValue(CarPropertyConfig config, Client client) {
List<CarPropertyEvent> events = new LinkedList<>();
int propId = config.getPropertyId();
if (config.isGlobalProperty()) {
CarPropertyValue value = mHal.getProperty(propId, 0);
if (value != null) {
CarPropertyEvent event = new CarPropertyEvent(
CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE, value);
events.add(event);
}
} else {
for (int areaId : config.getAreaIds()) {
CarPropertyValue value = mHal.getProperty(propId, areaId);
if (value != null) {
CarPropertyEvent event = new CarPropertyEvent(
CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE, value);
events.add(event);
}
}
}
try {
client.getListener().onEvent(events);
} catch (RemoteException ex) {
// If we cannot send a record, its likely the connection snapped. Let the binder
// death handle the situation.
Log.e(TAG, "onEvent calling failed: " + ex);
}
}
CarPropertyService::unregisterListener
車両プロパティ リスナーの登録解除
@Override
public void unregisterListener(int propId, ICarPropertyEventListener listener) {
if (DBG) {
Log.d(TAG, "unregisterListener propId=0x" + toHexString(propId));
}
ICarImpl.assertPermission(mContext, mHal.getReadPermission(propId));
if (listener == null) {
Log.e(TAG, "unregisterListener: Listener is null.");
throw new IllegalArgumentException("Listener is null");
}
IBinder listenerBinder = listener.asBinder();
synchronized (mLock) {
unregisterListenerBinderLocked(propId, listenerBinder);
}
}
CarPropertyService::getPropertyList
車両属性のリストを取得する
@Override
public List<CarPropertyConfig> getPropertyList() {
List<CarPropertyConfig> returnList = new ArrayList<CarPropertyConfig>();
Set<CarPropertyConfig> allConfigs;
synchronized (mLock) {
allConfigs = new HashSet<>(mConfigs.values());
}
for (CarPropertyConfig c : allConfigs) {
if (ICarImpl.hasPermission(mContext, mHal.getReadPermission(c.getPropertyId()))) {
// Only add properties the list if the process has permissions to read it
returnList.add(c);
}
}
if (DBG) {
Log.d(TAG, "getPropertyList returns " + returnList.size() + " configs");
}
return returnList;
}
CarPropertyService::getProperty
車両のプロパティを取得する
@Override
public CarPropertyValue getProperty(int prop, int zone) {
synchronized (mLock) {
if (mConfigs.get(prop) == null) {
// Do not attempt to register an invalid propId
Log.e(TAG, "getProperty: propId is not in config list:0x" + toHexString(prop));
return null;
}
}
ICarImpl.assertPermission(mContext, mHal.getReadPermission(prop));
return mHal.getProperty(prop, zone);
}
CarPropertyService::setProperty
車両のプロパティを設定する
@Override
public void setProperty(CarPropertyValue prop, ICarPropertyEventListener listener) {
int propId = prop.getPropertyId();
checkPropertyAccessibility(propId);
// need an extra permission for writing display units properties.
if (mHal.isDisplayUnitsProperty(propId)) {
ICarImpl.assertPermission(mContext, Car.PERMISSION_VENDOR_EXTENSION);
}
mHal.setProperty(prop);
IBinder listenerBinder = listener.asBinder();
synchronized (mLock) {
Client client = mClientMap.get(listenerBinder);
if (client == null) {
client = new Client(listener);
}
updateSetOperationRecorder(propId, prop.getAreaId(), client);
}
}
CarPropertyService::onPropertyChange
車両属性のコールバックを処理し、ハードウェア抽象化レイヤーで車両属性の変更をシステム アプリケーション レイヤーに通知します。
@Override
public void onPropertyChange(List<CarPropertyEvent> events) {
Map<IBinder, Pair<ICarPropertyEventListener, List<CarPropertyEvent>>> eventsToDispatch =
new HashMap<>();
for (CarPropertyEvent event : events) {
int propId = event.getCarPropertyValue().getPropertyId();
List<Client> clients = mPropIdClientMap.get(propId);
if (clients == null) {
Log.e(TAG, "onPropertyChange: no listener registered for propId=0x"
+ toHexString(propId));
continue;
}
for (Client c : clients) {
IBinder listenerBinder = c.getListenerBinder();
Pair<ICarPropertyEventListener, List<CarPropertyEvent>> p =
eventsToDispatch.get(listenerBinder);
if (p == null) {
// Initialize the linked list for the listener
p = new Pair<>(c.getListener(), new LinkedList<CarPropertyEvent>());
eventsToDispatch.put(listenerBinder, p);
}
p.second.add(event);
}
}
// Parse the dispatch list to send events
for (Pair<ICarPropertyEventListener, List<CarPropertyEvent>> p: eventsToDispatch.values()) {
try {
p.first.onEvent(p.second);
} catch (RemoteException ex) {
// If we cannot send a record, its likely the connection snapped. Let binder
// death handle the situation.
Log.e(TAG, "onEvent calling failed: " + ex);
}
}
}
プロパティハルサービス
CarPropertyService
ハードウェア抽象化層との通信を扱うクラスは、主にこのツールクラスを利用してシステムフレームワーク層とハードウェア抽象化層のデータ構造を変換しますCarPropertyUtils
。
重要な属性の説明
private final LinkedList<CarPropertyEvent> mEventsToDispatch = new LinkedList<>();
@GuardedBy("mLock")
private final Map<Integer, CarPropertyConfig<?>> mMgrPropIdToCarPropConfig = new HashMap<>();
@GuardedBy("mLock")
private final SparseArray<VehiclePropConfig> mHalPropIdToVehiclePropConfig =
new SparseArray<>();
// Only contains propId if the property Id is different in HAL and manager
private static final Map<Integer, Integer> PROPERTY_ID_HAL_TO_MANAGER = Map.of(
VehicleProperty.VEHICLE_SPEED_DISPLAY_UNITS,
VehiclePropertyIds.VEHICLE_SPEED_DISPLAY_UNITS);
// Only contains propId if the property Id is different in HAL and manager
private static final Map<Integer, Integer> PROPERTY_ID_MANAGER_TO_HAL = Map.of(
VehiclePropertyIds.VEHICLE_SPEED_DISPLAY_UNITS,
VehicleProperty.VEHICLE_SPEED_DISPLAY_UNITS);
private static final String TAG = "PropertyHalService";
private final VehicleHal mVehicleHal;
private final PropertyHalServiceIds mPropIds;
@GuardedBy("mLock")
private PropertyHalListener mListener;
@GuardedBy("mLock")
private Set<Integer> mSubscribedHalPropIds;
-
mEventsToDispatch
レポートされるデータのリスト。このデータはCarPropertyService
レポートに直接送信されます。このデザインは素晴らしいです。受信したデータはリストに保存され、データの損失を防ぎます。リスト全体が処理のために上位層に送信され、PropertyHalService
データのブロッキングが回避されます。 -
mProps
車両属性の設定、takeSupportedProperties
属性の追加はメソッドで行います。 -
mVehicleHal
VehicleHal
のインスタンス -
mPropIds
PropertyHalServiceIds
システムの車両属性の権限を保持するデータ クラスのインスタンスprivate final PropertyHalServiceIds mPropIds; public PropertyHalService(VehicleHal vehicleHal) { mPropIds = new PropertyHalServiceIds(); } public String getReadPermission(int propId) { return mPropIds.getReadPermission(propId); } @Nullable public String getWritePermission(int propId) { return mPropIds.getWritePermission(propId); }
-
mSubscribedPropIds
車両属性のコレクションを監視します。コレクションを使用すると、繰り返し登録の監視を効果的にブロックできます
PropertyHalService::getProperty
車両属性を取得し、ハードウェア抽象化レイヤーのデータ構造をシステム フレームワーク レイヤーのデータ構造に変換します。
public CarPropertyValue getProperty(int mgrPropId, int areaId) {
int halPropId = managerToHalPropId(mgrPropId);
if (!isPropertySupportedInVehicle(halPropId)) {
throw new IllegalArgumentException("Invalid property Id : 0x" + toHexString(mgrPropId));
}
// CarPropertyManager catches and rethrows exception, no need to handle here.
VehiclePropValue value = mVehicleHal.get(halPropId, areaId);
if (isMixedTypeProperty(halPropId)) {
VehiclePropConfig propConfig;
synchronized (mLock) {
propConfig = mHalPropIdToVehiclePropConfig.get(halPropId);
}
boolean containBooleanType = propConfig.configArray.get(1) == 1;
return value == null ? null : toMixedCarPropertyValue(value,
mgrPropId, containBooleanType);
}
return value == null ? null : toCarPropertyValue(value, mgrPropId);
}
isPropertySupportedInVehicle(halPropId)
この車両属性がサポートしているかどうかを判断するVehiclePropValue value = mVehicleHal.get(halPropId, areaId)
VehicleHal
車両属性を取得するtoCarPropertyValue(value, mgrPropId)
ハードウェア抽象化レイヤーのデータ構造をシステム フレームワーク レイヤーのデータ構造に変換します。
PropertyHalService::setProperty
車両属性を設定して、システム フレームワーク レイヤーのデータ構造をハードウェア抽象化レイヤーのデータ構造に変換します。
public void setProperty(CarPropertyValue prop) {
int halPropId = managerToHalPropId(prop.getPropertyId());
if (!isPropertySupportedInVehicle(halPropId)) {
throw new IllegalArgumentException("Invalid property Id : 0x"
+ toHexString(prop.getPropertyId()));
}
VehiclePropValue halProp;
if (isMixedTypeProperty(halPropId)) {
// parse mixed type property value.
VehiclePropConfig propConfig;
synchronized (mLock) {
propConfig = mHalPropIdToVehiclePropConfig.get(prop.getPropertyId());
}
int[] configArray = propConfig.configArray.stream().mapToInt(i->i).toArray();
halProp = toMixedVehiclePropValue(prop, halPropId, configArray);
} else {
halProp = toVehiclePropValue(prop, halPropId);
}
// CarPropertyManager catches and rethrows exception, no need to handle here.
mVehicleHal.set(halProp);
}
int halPropId = managerToHalPropId(prop.getPropertyId())
ハードウェア抽象化レイヤーで使用される車両属性 ID に変換されますtoVehiclePropValue(prop, halPropId)
システム フレーム レイヤーのデータ構造は、ハードウェア抽象化レイヤーのデータ構造に変換されます。mVehicleHal.set(halProp)
VehicleHal
車両のプロパティを設定する
PropertyHalService::onHalEvents
VehiclePropValue
(ハードウェア抽象化層のデータ構造) から (システムフレームワーク層のデータ構造) への変換を完了しCarPropertyValue
、CarPropertyEvent
データにカプセル化して上位層に通知します。
@Override
public void onHalEvents(List<VehiclePropValue> values) {
PropertyHalListener listener;
synchronized (mLock) {
listener = mListener;
}
if (listener != null) {
for (VehiclePropValue v : values) {
if (v == null) {
continue;
}
if (!isPropertySupportedInVehicle(v.prop)) {
Log.e(TAG, "Property is not supported: 0x" + toHexString(v.prop));
continue;
}
// Check payload if it is a userdebug build.
if (Build.IS_DEBUGGABLE && !mPropIds.checkPayload(v)) {
Log.e(TAG, "Drop event for property: " + v + " because it is failed "
+ "in payload checking.");
continue;
}
int mgrPropId = halToManagerPropId(v.prop);
CarPropertyValue<?> propVal;
if (isMixedTypeProperty(v.prop)) {
// parse mixed type property value.
VehiclePropConfig propConfig;
synchronized (mLock) {
propConfig = mHalPropIdToVehiclePropConfig.get(v.prop);
}
boolean containBooleanType = propConfig.configArray.get(1) == 1;
propVal = toMixedCarPropertyValue(v, mgrPropId, containBooleanType);
} else {
propVal = toCarPropertyValue(v, mgrPropId);
}
CarPropertyEvent event = new CarPropertyEvent(
CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE, propVal);
mEventsToDispatch.add(event);
}
listener.onPropertyChange(mEventsToDispatch);
mEventsToDispatch.clear();
}
}
PropertyHalService::getPropertyList
getPropertyList
ビークル プロパティのリストを返します。これは、実際にはmProps
それ自体が保持するオブジェクトです。CarPropertyService でも維持されますmConfigs
public Map<Integer, CarPropertyConfig<?>> getPropertyList() {
if (mDbg) {
Log.d(TAG, "getPropertyList");
}
return mProps;
}
ビークルハル
それらをすべて管理するために*halservice
、これらのサービスは車両属性によるデータ通信を実現していますが、サポートされている車両属性は比較的独立しており、互いに影響を与えることはありません。現在含まれているサービスは次のとおりです。
PowerHalService
PropertyHalService
InputHalService
VmsHalService
DiagnosticHalService
VehicleHal
継承されIVehicleCallback.Stub
、ハードウェア抽象化レイヤーの HIDL コールバックを受け取ることができます。
VehicleHal::init
初期化してmAllProperties
、HAL レイヤーから車両属性構成を取得し、マップに追加します。すべてのサブサービスを初期化します。
public void init() {
fetchAllPropConfigs();//遍历所有属性,从hal层获取将属性加到mAllProperties对象中
// PropertyHalService will take most properties, so make it big enough.
ArrayList<VehiclePropConfig> configsForService = new ArrayList<>(mAllServices.size());
for (int i = 0; i < mAllServices.size(); i++) {
HalServiceBase service = mAllServices.get(i);
int[] supportedProps = service.getAllSupportedProperties();//获取子服务支持的车辆属性
configsForService.clear();
synchronized (mLock) {
if (supportedProps.length == 0) {
//这里是PropertyHalService
for (Integer propId : mAllProperties.keySet()) {
if (service.isSupportedProperty(propId)) {
VehiclePropConfig config = mAllProperties.get(propId);
mPropertyHandlers.append(propId, service);
configsForService.add(config);
}
}
} else {
//这里是其他
for (int prop : supportedProps) {
VehiclePropConfig config = mAllProperties.get(prop);
if (config == null) {
continue;
}
mPropertyHandlers.append(prop, service);
configsForService.add(config);
}
}
}
service.takeProperties(configsForService);
service.init();
}
}
-
fetchAllPropConfigs
すべてのアトリビュートをトラバースし、ハードウェア レイヤから取得して、アトリビュートをmAllProperties
オブジェクトに追加します -
getAllSupportedProperties
サブサービスでサポートされている車両属性を取得する -
PropertyHalService
上記の判断を下しますpublic int[] getAllSupportedProperties() { return CarServiceUtils.EMPTY_INT_ARRAY; } private static final int[] EMPTY_INT_ARRAY = new int[0];
-
mPropertyHandlers
属性がサポートされていると判断した後、とに属性を設定しconfigsForService
、mPropertyHandlers
処理対象の車両属性とサブサービスを記録し、configsForService
車両属性を記録します。VehiclePropConfig
-
takeProperties
fw の構成がそれをサポートしているかどうかを確認するサブサービスを呼び出す方法、および構成は で定義されておりPropertyHalServiceIds.java
、車両のプロパティで必要なシステム権限を定義します。
VehicleHal::get
get
メソッドは車両属性を取得するために使用され、実際のエグゼキュータはHalClient
public VehiclePropValue get(int propertyId, int areaId) {
if (DBG) {
Log.i(CarLog.TAG_HAL, "get, property: 0x" + toHexString(propertyId)
+ ", areaId: 0x" + toHexString(areaId));
}
VehiclePropValue propValue = new VehiclePropValue();
propValue.prop = propertyId;
propValue.areaId = areaId;
return mHalClient.getValue(propValue);
}
VehicleHal::セット
set
メソッドは車両のプロパティを設定するために使用され、実際のエグゼキュータはHalClient
protected void set(VehiclePropValue propValue) {
mHalClient.setValue(propValue);
}
VehicleHal::getAllPropConfigs
getAllPropConfigs
このメソッドは、ハードウェア抽象化レイヤーからすべての車両属性構成を取得するために使用されます
public Collection<VehiclePropConfig> getAllPropConfigs() {
return mAllProperties.values();
}
VehicleHal::onPropertyEvent
onPropertyEvent
このメソッドは、ハードウェア抽象化レイヤーから車両属性の変更を監視するために使用されます。
@Override
public void onPropertyEvent(ArrayList<VehiclePropValue> propValues) {
synchronized (mLock) {
for (VehiclePropValue v : propValues) {
HalServiceBase service = mPropertyHandlers.get(v.prop);
if(service == null) {
Log.e(CarLog.TAG_HAL, "HalService not found for prop: 0x"
+ toHexString(v.prop));
continue;
}
service.getDispatchList().add(v);
mServicesToDispatch.add(service);
VehiclePropertyEventInfo info = mEventLog.get(v.prop);
if (info == null) {
info = new VehiclePropertyEventInfo(v);
mEventLog.put(v.prop, info);
} else {
info.addNewEvent(v);
}
}
}
for (HalServiceBase s : mServicesToDispatch) {
s.onHalEvents(s.getDispatchList());
s.getDispatchList().clear();
}
mServicesToDispatch.clear();
}
-
onPropertyEvent
書き直された HIDL インターフェースIVehicleCallback
コード パス:automotive\vehicle\2.0\IVehicleCallback.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::EVENTS_FROM_ANDROID 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 つはハードウェア抽象化レイヤーから取得され
ArrayList
、リスト内の各車両属性がここでループされます。 -
HalServiceBase service = mPropertyHandlers.get(v.prop);
これは、通知が必要な現在の車両属性を取得するため子HalService
、または車両属性を管理するサービスを取得するためです。 -
service.getDispatchList().add(v)
この車両属性を、このサービスを管理するディスパッチ リストに追加します。 -
mServicesToDispatch.add(service);
このサブサービスをサービス配布リストに追加します。 -
s.onHalEvents(s.getDispatchList());
事前に特定された車両属性を使用して、対応するサービスに配信操作を実行させることです。一般的なビークル プロパティのエグゼキュータは ですPropertyHalService
。
HalClient
同等のVehicleHal
プロキシ クラスは、VehicleHal
ハードウェア アブストラクション レイヤーとやり取りするインターフェイスを定義しますが、実際の実装は実際には を介して呼び出されますHalClient
。ハードウェア抽象化レイヤーへのハンドルをHalClient
保持します。VehicleService
HalClient::getAllPropConfigs
すべての車両属性構成を取得する
ArrayList<VehiclePropConfig> getAllPropConfigs() throws RemoteException {
return mVehicle.getAllPropConfigs();
}
HalClient::サブスクライブ
車両プロパティの変更を購読する
public void subscribe(SubscribeOptions... options) throws RemoteException {
mVehicle.subscribe(mInternalCallback, new ArrayList<>(Arrays.asList(options)));
}
HalClient::登録解除
車両プロパティのサブスクリプションをキャンセルする
public void unsubscribe(int prop) throws RemoteException {
mVehicle.unsubscribe(mInternalCallback, prop);
}
HalClient::setValue
車両プロパティを設定する
public void setValue(VehiclePropValue propValue) {
int status = invokeRetriable(() -> {
try {
return mVehicle.set(propValue);
} catch (RemoteException e) {
Log.e(TAG, getValueErrorMessage("set", propValue), e);
return StatusCode.TRY_AGAIN;
}
}, mWaitCapMs, mSleepMs);
if (StatusCode.INVALID_ARG == status) {
throw new IllegalArgumentException(getValueErrorMessage("set", propValue));
}
if (StatusCode.OK != status) {
Log.e(TAG, getPropertyErrorMessage("set", propValue, status));
throw new ServiceSpecificException(status,
"Failed to set property: 0x" + Integer.toHexString(propValue.prop)
+ " in areaId: 0x" + Integer.toHexString(propValue.areaId));
}
}
HalClient::getValue
車両プロパティを取得する
VehiclePropValue getValue(VehiclePropValue requestedPropValue) {
final ObjectWrapper<VehiclePropValue> valueWrapper = new ObjectWrapper<>();
int status = invokeRetriable(() -> {
ValueResult res = internalGet(requestedPropValue);
valueWrapper.object = res.propValue;
return res.status;
}, mWaitCapMs, mSleepMs);
if (StatusCode.INVALID_ARG == status) {
throw new IllegalArgumentException(getValueErrorMessage("get", requestedPropValue));
}
if (StatusCode.OK != status || valueWrapper.object == null) {
// If valueWrapper.object is null and status is StatusCode.Ok, change the status to be
// NOT_AVAILABLE.
if (StatusCode.OK == status) {
status = StatusCode.NOT_AVAILABLE;
}
Log.e(TAG, getPropertyErrorMessage("get", requestedPropValue, status));
throw new ServiceSpecificException(status,
"Failed to get property: 0x" + Integer.toHexString(requestedPropValue.prop)
+ " in areaId: 0x" + Integer.toHexString(requestedPropValue.areaId));
}
return valueWrapper.object;
}
private ValueResult internalGet(VehiclePropValue requestedPropValue) {
final ValueResult result = new ValueResult();
try {
mVehicle.get(requestedPropValue,
(status, propValue) -> {
result.status = status;
result.propValue = propValue;
});
} catch (RemoteException e) {
Log.e(TAG, getValueErrorMessage("get", requestedPropValue), e);
result.status = StatusCode.TRY_AGAIN;
}
return result;
}
車のプロパティ構成
車両属性の属性構成は FW 層で使用され、VehiclePropConfig
ハードウェア抽象化層から変換されます。車両属性の基本情報を定義します。読み取りと書き込みの性質、タイプ、変更モードなどを含みます。
private final int mAccess;
private final int mAreaType;
private final int mChangeMode;
private final ArrayList<Integer> mConfigArray;
private final String mConfigString;
private final float mMaxSampleRate;
private final float mMinSampleRate;
private final int mPropertyId;
private final SparseArray<AreaConfig<T>> mSupportedAreas;
private final Class<T> mType;
車のプロパティユーティリティ
ハードウェア抽象化レイヤーのデータ構造とシステム フレームワーク レイヤーのデータ構造を相互に変換するツール クラス。
-
toCarPropertyValue
換算VehiclePropValue
となりますCarPropertyValue
。(HAL→FW)static CarPropertyValue<?> toCarPropertyValue( VehiclePropValue halValue, int propertyId)
-
toVehiclePropValue
換算CarPropertyValue
となりますVehiclePropValue
。(HW->HAL)static VehiclePropValue toVehiclePropValue(CarPropertyValue carProp, int halPropId)
-
toCarPropertyConfig
換算VehiclePropConfig
となりますCarPropertyConfig
。(HAL→FW)static CarPropertyConfig<?> toCarPropertyConfig(VehiclePropConfig p, int propertyId)
換算関係
方法 | 換算関係 |
---|---|
toCarPropertyValue | VehiclePropValue ->CarPropertyValue(fw) |
toVehiclePropValue | CarPropertyValue ->VehiclePropValue(hal) |
toCarPropertyConfig | VehiclePropConfig ->CarPropertyConfig(fw) |
CarPropertyConfig は、特定の車両プロパティの情報です。Map の KEY に相当します。
CarPropertyValue は、車のプロパティによって返される値です。マップの値に相当します。
VehiclePropConfig と VehiclePropValue の定義は、実際には types.hal にあります。
CarPropertyValue 変数の対応
車のプロパティ値 | VehiclePropValue |
---|---|
mPropertyIdint |
小道具int32_t |
mAreaIdint |
エリアIDint32_t |
ステータスint |
スターテスint32_t |
mTimestamplong |
タイムスタンプint64_t |
m値T |
価値RawValue |
システム フレームワーク レイヤーの戻り値CarPropertyValue
はジェネリック型であり、対応する型は属性の実際の定義に従って決定できます。RawValue
ハードウェア抽象化レイヤーの定義は、従来型の配列と文字列を定義するデータ構造です。
struct RawValue {
vec<int32_t> int32Values;
vec<float> floatValues;
vec<int64_t> int64Values;
vec<uint8_t> bytes;
string stringValue;
};
データ型が配列でない場合は、配列の 0 番目の位置を占めて戻り、ブール型はint32Values.get(0) == 1
CarPropertyConfig 変数の対応
車のプロパティ構成 | VehiclePropConfig |
---|---|
mAccessint |
アクセスVehiclePropertyAccess |
エリアタイプint |
|
mChangeModeint |
変更モードVehiclePropertyChangeMode |
mConfigArrayArrayList<Integer> |
configArrayvec<int32_t> |
mConfigStringString |
configStringstring |
mMaxSampleRatefloat |
maxSampleRatefloat |
mMinSampleRatefloat |
最小サンプルレートfloat |
mPropertyIdint |
小道具int32_t |
mサポートエリアSparseArray<AreaConfig<T>> mSupportedAreas |
エリア構成vec<VehicleAreaConfig> |
mタイプClass<T> |
mType は、車両プロパティの定義に従って計算されます。Class<?> clazz = getJavaClass(p.prop & VehiclePropertyType.MASK)
PropertyHalServiceIds
PropertyHalService によってサポートされる車両プロパティを定義します。このクラスは、読み取りおよび書き込み権限をプロパティ ID にバインドします。車両属性の許可定義を取得するためのインターフェイス コード パスを提供します
。packages/services/Car/service/src/com/android/car/hal/PropertyHalServiceIds.java
public class PropertyHalServiceIds {
// Index (key is propertyId, and the value is readPermission, writePermission
private final SparseArray<Pair<String, String>> mProps;
public PropertyHalServiceIds() {
mProps = new SparseArray<>();
// Add propertyId and read/write permissions
// 在构造函数中绑定权限
mProps.put(VehicleProperty.DOOR_POS, new Pair<>(
Car.PERMISSION_CONTROL_CAR_DOORS,
Car.PERMISSION_CONTROL_CAR_DOORS));
//......
}
}
-
getReadPermission()
読み取り権限を取得、戻り値は文字列public String getReadPermission(int propId) { Pair<String, String> p = mProps.get(propId); if (p != null) { // Property ID exists. Return read permission. if (p.first == null) { Log.e(TAG, "propId is not available for reading : 0x" + toHexString(propId)); } return p.first; } else if (isVendorProperty(propId)) { // if property is vendor property and do not have specific permission. return Car.PERMISSION_VENDOR_EXTENSION; } else { return null; } }
-
getWritePermission()
書き込み権限を取得、戻り値は文字列public String getWritePermission(int propId) { Pair<String, String> p = mProps.get(propId); if (p != null) { // Property ID exists. Return write permission. if (p.second == null) { Log.e(TAG, "propId is not writable : 0x" + toHexString(propId)); } return p.second; } else if (isVendorProperty(propId)) { // if property is vendor property and do not have specific permission. return Car.PERMISSION_VENDOR_EXTENSION; } else { return null; } }
-
isSupportedProperty()
車両属性がPropertyHalService
既知のリストにあるかどうかを確認しますpublic boolean isSupportedProperty(int propId) { // Property is in the list of supported properties return mProps.get(propId) != null || isVendorProperty(propId); }
private static boolean isVendorProperty(int propId) { return (propId & VehiclePropertyGroup.MASK) == VehiclePropertyGroup.VENDOR; }
要約する
親切 | 例証する |
---|---|
カーサービス | 車の主なサービス |
ICarImpl | 特定の Car の実装クラス |
ビークルハル | IVehicleCallback インターフェイスを実装し、各サブサービスを維持するクラス |
プロパティハルサービス | HAL層で取得したデータを加工し、FW層で利用する型に変換 |
HalClient | IVehileインターフェースを保持し、エージェントが実際に動作 |
PropertyHalServiceIds | サポートされている属性と権限を定義する |
車のプロパティユーティリティ | ツールクラス、FWレイヤーとHALレイヤーのデータを変換 |
車のプロパティ構成 | 車両属性構成情報 |
車プロパティ サービス | 車両プロパティによって制御されるサブサービス |
クライアント | 車両プロパティの通知を購読するためのクラス |
CarService
作为主服务,通过ICarImpl
类实现对子服务CarPropertyService
的创建以及对VehicleHal
的初始化。VehicleHal
中完成对子服务们的初始化,并通过传入的IVehicle
对象使得PropertyHalService
获取系统支持的车辆属性,完成初始化操作。在PropertyHalService
中创建HalClient
对象完成对IVehicle
接口的实际调用,并将从HAL层获取的数据类型转化成FW层使用数据类型。CarPropertyService
持有PropertyHalService
的引用,完成上下层的数据交互操作。对于APPLICATION注册的Listener,CarPropertyService
使用Client
对象进行维护,当订阅的数据发生变化进行通知,当首次注册时,会主动获取值并进行一次通知操作。
关联关系:CarPropertyManager --> ICarProperty --> CarPropertyService --> PropertyHalService --> VehicleHal
|
| --------------------- | ----------------------------------------------- |
| CarService | Car的主服务 |
| ICarImpl | 具体Car的实现类 |
| VehicleHal | 实现IVehicleCallback接口的类,并维护各个子服务 |
| PropertyHalService | 处理HAL层获取到的数据并将其转化成FW层使用的类型 |
| HalClient | 持有IVehile接口,代理实际操作 |
| PropertyHalServiceIds | 定义支持的属性以及权限 |
| CarPropertyUtils | 工具类,转化FW层和HAL层数据 |
| CarPropertyConfig | 车辆属性配置信息 |
| CarPropertyService | 车辆属性控制的子服务 |
| Client | 车辆车辆属性订阅通知的类 |
CarService
主なサービスとして、サブサービスの作成とサブサービスの初期化はICarImpl
クラスによって実現されます。でサブサービスの初期化を完了し、受信オブジェクトを介してシステムでサポートされている車両属性を取得して、初期化操作を完了します。その中にオブジェクトを作成してインターフェイスへの実際の呼び出しを完了し、HAL 層から取得したデータ型を FW 層で使用されるデータ型に変換します。保持された参照は、上位層と下位層のデータ相互作用操作を完了します。APPLICATION で登録された Listener は、オブジェクトを使用してメンテナンスを行い、サブスクライブされたデータが変更されたときに通知され、初回登録時にアクティブに値を取得して通知操作を実行します。CarPropertyService
VehicleHal
VehicleHal
IVehicle
PropertyHalService
PropertyHalService
HalClient
IVehicle
CarPropertyService
PropertyHalService
CarPropertyService
Client
関係: CarPropertyManager --> ICarProperty --> CarPropertyService --> PropertyHalService --> VehicleHal