Android 车载应用开发指南 - CarService 详解(下)
车载应用正在改变人们的出行体验。从导航到娱乐、从安全到信息服务,车载应用的开发已成为汽车智能化发展的重要组成部分。而对于开发者来说,如何将自己的应用程序无缝集成到车载系统中,利用汽车的硬件和服务能力,是一个极具挑战性的话题
那么,在Android平台上开发车载应用时,CarService究竟扮演了什么样的角色?它的功能和使用方法有哪些关键点?
随着车联网技术的普及,车载应用的种类和功能也在迅速增加,从简单的导航和音乐播放,到智能语音助手、驾驶行为分析等多样化的服务。CarService作为Android车载应用开发的基础组件,为开发者提供了与车辆深度交互的能力。在未来,车载应用的智能化、个性化将进一步提升驾驶体验,并成为汽车产品竞争的重要元素。
03 CarService 实现原理
想要弄清楚CarService实现方式,首先需要搞明白CarService的启动流程。
CarService 启动流程主要分为以下四个步骤:
-
SystemServer 启动 CarServiceHelperService 服务
-
在调用 startService() 后,CarServiceHelperService 的onStart() 方法通过 bindService 的方式启动 CarService(一个系统级别的 APK,位于 system/priv-app)
-
启动 CarService 后首先调用 onCreate(),创建 ICarImpl 对象并初始化,在此时创建了一系列 Car 相关的核心服务,并遍历 init 初始化
-
然后调用 onBind 将该 ICarImpl 对象返回给CarServiceHelperService,CarServiceHelperService 在内部的一个 Binder 对象 ICarServiceHelperImpl传递给 CarService,建立双向跨进程
3.1 启动 CarServiceHelperService 服务
SystemServer会在startOtherServices()方法中让SystemServiceManager先通过反射的形式创建出StartCarServiceHelperService对象。
-
源码路径:frameworks/base/services/java/com/android/server/SystemServer.java
private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
...
// 仅在 automotive 中启动
if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
t.traceBegin("StartCarServiceHelperService");
final SystemService cshs = mSystemServiceManager
.startService(CAR_SERVICE_HELPER_SERVICE_CLASS);
if (cshs instanceof Dumpable) {
mDumper.addDumpable((Dumpable) cshs);
}
if (cshs instanceof DevicePolicySafetyChecker) {
dpms.setDevicePolicySafetyChecker((DevicePolicySafetyChecker) cshs);
}
t.traceEnd();
}
...
}
然后在SystemServiceManager中调用StartCarServiceHelperService的onStart()方法。
CarServiceHelperService是CarService的 SystemService 端的配套服务。
-
源码路径:
frameworks/base/services/core/java/com/android/server/SystemServiceManager.java
public SystemService startService(String className) {
final Class<SystemService> serviceClass = loadClassFromLoader(className,
this.getClass().getClassLoader());
return startService(serviceClass);
}
public void startService(@NonNull final SystemService service) {
// Register it.
mServices.add(service);
long time = SystemClock.elapsedRealtime();
try {
service.onStart();
} catch (RuntimeException ex) {
throw new RuntimeException("Failed to start service " + service.getClass().getName()
+ ": onStart threw an exception", ex);
}
warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onStart");
}
3.2 绑定 CarService 服务
-
源码路径:frameworks/opt/car/services/src/com/android/internal/car/CarServiceHelperService.java
private static final String CAR_SERVICE_INTERFACE = "android.car.ICar";
@Override
public void onStart() {
EventLog.writeEvent(EventLogTags.CAR_HELPER_START);
IntentFilter filter = new IntentFilter(Intent.ACTION_REBOOT);
filter.addAction(Intent.ACTION_SHUTDOWN);
mContext.registerReceiverForAllUsers(mShutdownEventReceiver, filter, null, null);
mCarWatchdogDaemonHelper.addOnConnectionChangeListener(mConnectionListener);
mCarWatchdogDaemonHelper.connect();
Intent intent = new Intent();
intent.setPackage("com.android.car"); // 绑定包名,设置广播仅对该包有效
intent.setAction(CAR_SERVICE_INTERFACE); // 绑定 action,表明想要启动能够响应设置的这个 action 的活动,并在清单文件 AndroidManifest.xml 中设置 action 属性
// 绑定后回调
if (!mContext.bindServiceAsUser(intent, mCarServiceConnection, Context.BIND_AUTO_CREATE,
mHandler, UserHandle.SYSTEM)) {
Slogf.wtf(TAG, "cannot start car service");
}
loadNativeLibrary();
}
-
源码路径:packages/services/Car/service/AndroidManifest.xml
sharedUserId 是系统级别的,类似 SystemUI,它编译出来同样是一个 APK 文件
-
设备文件路径:/system/priv-app/CarService/CarService.apk
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
package="com.android.car"
coreApp="true"
android:sharedUserId="android.uid.system">
......
<application android:label="@string/app_title"
android:directBootAware="true"
android:allowBackup="false"
android:persistent="true">
<service android:name=".CarService"
android:singleUser="true"
android:exported="true">
<intent-filter>
<action android:name="android.car.ICar"/>
</intent-filter>
</service>
......
</application>
3.3 CarService 初始化
CarService进入启动时序后,会在onCreate()方法中进行一系列自身的初始化操作,步骤如下:
1)通过 HIDL 接口获取到 HAL 层的 IHwBinder 对象IVehicle,与 AIDL 的用法类似,必须持有 IHwBinder 对象我们才可以与 Vehicle HAL 层进行通信。
2)创建 ICarImpl 对象,并调用init方法,它就是ICar.aidl接口的实现类,我们需要通过它才能拿到其他的 Service 的 IBinder 对象。
3)将ICar.aidl的实现类添加到 ServiceManager 中。
4)设定 SystemProperty,将CarService设定为创建完成状态,只有包含CarService在内的所有的核心 Service 都完成初始化,才能结束开机动画并发送开机广播。
-
源码路径:packages/services/Car/service/src/com/android/car/CarService.java
@Override
public void onCreate() {
LimitedTimingsTraceLog initTiming = new LimitedTimingsTraceLog(CAR_SERVICE_INIT_TIMING_TAG,
Trace.TRACE_TAG_SYSTEM_SERVER, CAR_SERVICE_INIT_TIMING_MIN_DURATION_MS);
initTiming.traceBegin("CarService.onCreate");
initTiming.traceBegin("getVehicle");
// 获取 hal 层的 Vehicle service
mVehicle = getVehicle();
initTiming.traceEnd();
...
//创建 ICarImpl 实例
mICarImpl = new ICarImpl(this,
mVehicle,
SystemInterface.Builder.defaultSystemInterface(this).build(),
mVehicleInterfaceName);
//然后调用 ICarImpl 的 init 初始化方法
mICarImpl.init();
linkToDeath(mVehicle, mVehicleDeathRecipient);
//将该 service 注册到 ServiceManager
ServiceManager.addService("car_service", mICarImpl);
//设置 boot.car_service_created 属性
SystemProperties.set("boot.car_service_created", "1");
super.onCreate();
initTiming.traceEnd(); // "CarService.onCreate"
}
@Nullable
private static IVehicle getVehicle() {
final String instanceName = SystemProperties.get("ro.vehicle.hal", "default");
try {
//该 service 启动文件 hardware/interfaces/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-service.rc
return android.hardware.automotive.vehicle.V2_0.IVehicle.getService(instanceName);
} catch (RemoteException e) {
Slog.e(CarLog.TAG_SERVICE, "Failed to get IVehicle/" + instanceName + " service", e);
} catch (NoSuchElementException e) {
Slog.e(CarLog.TAG_SERVICE, "IVehicle/" + instanceName + " service not registered yet");
}
return null;
}
接着再看ICarImpl的实现,如下所示:
1)创建各个核心服务对象
2)把服务对象缓存到 CarLocalServices 中,这里主要是为了方便 Service 之间的相互访问
-
源码路径:
/packages/services/Car/service/src/com/android/car/ICarImpl.java
@VisibleForTesting
ICarImpl(Context serviceContext, IVehicle vehicle, SystemInterface systemInterface,
String vehicleInterfaceName,
@Nullable CarUserService carUserService,
@Nullable CarWatchdogService carWatchdogService,
@Nullable ICarPowerPolicySystemNotification powerPolicyDaemon) {
...
mContext = serviceContext;
mSystemInterface = systemInterface;
CarLocalServices.addService(SystemInterface.class, mSystemInterface);
//创建 VehicleHal 对象
mHal = constructWithTrace(t, VehicleHal.class,
() -> new VehicleHal(serviceContext, vehicle));
...
// 创建核心服务对象,并缓存到 CarLocalServices
mCarPropertyService = constructWithTrace(t, CarPropertyService.class, () -> new CarPropertyService(serviceContext, mHal.getPropertyHal()));
mCarDrivingStateService = constructWithTrace(t, CarDrivingStateService.class,() -> new CarDrivingStateService(serviceContext, mCarPropertyService));
mCarUXRestrictionsService = constructWithTrace(t, CarUxRestrictionsManagerService.class, () -> new CarUxRestrictionsManagerService(serviceContext, mCarDrivingStateService, mCarPropertyService));
...
// 将创建的服务对象依次添加到一个 list 中保存起来
List<CarServiceBase> allServices = new ArrayList<>();
allServices.add(mFeatureController);
allServices.add(mCarUXRestrictionsService); // mCarUserService depends on it
allServices.add(mCarUserService);
allServices.add(mSystemActivityMonitoringService);
allServices.add(mCarPowerManagementService);
allServices.add(mCarPropertyService);
allServices.add(mCarDrivingStateService);
allServices.add(mCarOccupantZoneService);
addServiceIfNonNull(allServices, mOccupantAwarenessService);
allServices.add(mCarPackageManagerService);
allServices.add(mCarInputService);
allServices.add(mGarageModeService);
...
}
@MainThread
void init() {
LimitedTimingsTraceLog t = new LimitedTimingsTraceLog(CAR_SERVICE_INIT_TIMING_TAG,
Trace.TRACE_TAG_SYSTEM_SERVER, CAR_SERVICE_INIT_TIMING_MIN_DURATION_MS);
t.traceBegin("ICarImpl.init");
t.traceBegin("VHAL.init");
mHal.init();
t.traceEnd();
t.traceBegin("CarService.initAllServices");
//启动的所有服务遍历调用 init 初始化(各个都继承了 CarServiceBase)
for (CarServiceBase service : mAllServices) {
t.traceBegin(service.getClass().getSimpleName());
service.init();
t.traceEnd();
}
t.traceEnd(); // "CarService.initAllServices"
t.traceEnd(); // "ICarImpl.init"
}
然后将上面 onCreate() 创建的 mICarImpl 对象返回:
-
onBind() 回调方法会继续传递通过 bindService() 传递来的 intent 对象(即上面的bindServiceAsUser方法)
-
onUnbind() 会处理传递给 unbindService() 的 intent 对象。如果 service 允许绑定,onBind() 会返回客户端与服务互相联系的通信句柄
-
源码路径:
/packages/services/Car/service/src/com/android/car/CarService.java
@Override
public IBinder onBind(Intent intent) {
return mICarImpl;
}
所以此处的 mICarImpl 会作为 IBinder 返回给CarServiceHelperService.java - bindServiceAsUser方法中的参数 mCarServiceConnection(回调)
3.4 回调 ServiceConnection
-
ICarImpl 初始化完毕,会作为 IBinder 返回给CarServiceHelperService.java - bindServiceAsUser方法中绑定此服务的 mCarServiceConnection(回调)
mCarServiceConnection 初始化如下:
-
其中返回的 ICarImpl 被保存在了 CarServiceHelperService 的 mCarService
-
mCarService.transact 跨进程通信,调用 ICar.aidl 中定义的第一个方法 setCarServiceHelper
-
源码路径:
/frameworks/opt/car/services/src/com/android/internal/car/CarServiceHelperService.java
private static final String CAR_SERVICE_INTERFACE = "android.car.ICar";
private IBinder mCarService;
private final ICarServiceHelperImpl mHelper = new ICarServiceHelperImpl();
private final ServiceConnection mCarServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
if (DBG) {
Slogf.d(TAG, "onServiceConnected: %s", iBinder);
}
handleCarServiceConnection(iBinder);
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
handleCarServiceCrash();
}
};
@VisibleForTesting
void handleCarServiceConnection(IBinder iBinder) {
synchronized (mLock) {
if (mCarServiceBinder == iBinder) {
return; // already connected.
}
Slogf.i(TAG, "car service binder changed, was %s new: %s", mCarServiceBinder, iBinder);
//1. 返回的 ICarImpl 被保存在了 CarServiceHelperService 的 mCarServiceBinder
mCarServiceBinder = iBinder;
Slogf.i(TAG, "**CarService connected**");
}
sendSetSystemServerConnectionsCall();
...
}
private void sendSetSystemServerConnectionsCall() {
Parcel data = Parcel.obtain();
data.writeInterfaceToken(CAR_SERVICE_INTERFACE);
data.writeStrongBinder(mHelper.asBinder());
//将 ICarServiceHelperImpl 类型的对象作为数据跨进程传递
data.writeStrongBinder(mCarServiceConnectedCallback.asBinder());
IBinder binder;
synchronized (mLock) {
binder = mCarServiceBinder;
}
int code = IBinder.FIRST_CALL_TRANSACTION;
try {
//2. 跨进程传输
//对端是 mCarService 即 ICarImpl,调用 binder 的 transact 进行跨进程通信
//其 code 代表需要调用的对端方法,data 为携带的传输数据
//FIRST_CALL_TRANSACTION = 0x00000001,即调用对端 ICar.aidl 中定义的第一个方法 setCarServiceHelper
if (VERBOSE) Slogf.v(TAG, "calling one-way binder transaction with code %d", code);
// oneway void setSystemServerConnections(in IBinder helper, in IBinder receiver) = 0;
binder.transact(code, data, null, Binder.FLAG_ONEWAY);
if (VERBOSE) Slogf.v(TAG, "finished one-way binder transaction with code %d", code);
}
...
}
跨进程 setSystemServerConnections
@Override
public void setSystemServerConnections(IBinder helper, IBinder receiver) {
Bundle bundle;
try {
EventLog.writeEvent(EventLogTags.CAR_SERVICE_SET_CAR_SERVICE_HELPER,
Binder.getCallingPid());
assertCallingFromSystemProcess();
//将 ICarServiceHelper 的代理端保存在 ICarImpl 内部 mICarServiceHelper
ICarServiceHelper carServiceHelper = ICarServiceHelper.Stub.asInterface(helper);
synchronized (mLock) {
mICarServiceHelper = carServiceHelper;
}
//同时也传给了 SystemInterface
//此时他们有能力跨进程访问 CarServiceHelperService
mSystemInterface.setCarServiceHelper(carServiceHelper);
mCarOccupantZoneService.setCarServiceHelper(carServiceHelper);
mCarUserService.setCarServiceHelper(carServiceHelper);
...
}
3.5 小结
CarService的启动时序如下所示:
04 总结
本文讲解了CarService的总体结构、使用方法及启动流程。
CarService中实现的功能非常庞大,可以说相比传统手机端的 Android 系统,AAOS 中独特且最重要的部分都在 Framework 的CarService中。
-
首先 CarService 是一个系统级别的服务 APK,类似 SystemUI,其在开机时由 SystemServer 通过 CarServiceHelperService 启动。
-
CarServiceHelperService 通过绑定服务的方式启动 CarService,启动之后创建了一个 Binder 对象 ICarImpl,并通过 onBind 返回给 system_server 进程。
-
ICarImpl 构造方法中创建了一系列和汽车相关的核心服务,并依次启动这些服务即调用各自 init 方法。ICarImpl 返回给 CarServiceHelperService 之后,CarServiceHelperService 也将其内部的一个 Binder 对象(ICarServiceHelperImpl)传递到了 CarService 进程,自此 CarService 和 system_server 两个进程建立了双向 Binder 通信。
-
ICarImpl 返回给 CarServiceHelperService 之后,CarServiceHelperService 也将其内部的一个 Binder 对象(ICarServiceHelperImpl)传递到了 CarService 进程,自此 CarService 和 system_server 两个进程建立了双向 Binder 通信。
CarService为Android车载应用开发者提供了一个强大而灵活的平台,让应用程序能够充分利用汽车的硬件和服务能力,打造更加智能化和便捷的驾驶体验。掌握CarService的使用,是车载应用开发中的重要一环,也是实现车载生态系统中创新应用的关键。
“在车载应用的世界里,技术的每一次进步,都是为了让行驶的每一公里更加安全、便捷和愉悦。”
✦
END
✦
链接:https://juejin.cn/post/7353827463632404517 本文为转载,转载文章所包含的文字来源于作者。如因内容或版权等问题,请联系进行删除