IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    Android Automotive之CarService模块裁剪

    FranzKafka95发表于 2024-02-28 04:53:28
    love 0
    Read Time:3 Minute, 45 Second

    近期在移植适配Android14的过程中,发现系统在启动阶段老是在Console中打印类似的日志:

    [   13.303945] servicemanager: Could not find android.hardware.automotive.IEvsEnumerator/default in the VINTF manifest.

    出现这份日志时,我第一时间检查了对应的服务,确实没有集成相应的EVS HAL实现。但本身这些实现在Android12.1中也没有,在Android12.1启动过程中却并不会有相关的错误日志。从日志信息来看,可能还与其他配置相关联。跟随着日志中的线索,简单了解了一下VINTF配置,即使在清理完VINTF配置后仍存在这类错误,这说明问题的根因并不在这里。

    当我使用adb进入Android系统并通过logcat查看日志时,发现CarService会频繁打印与CarEvsService相关联的日志,并提示未能成功连接EVS HAL服务,问题就出现在这里。

    在我的这篇文章中,详细介绍了EVS的框架,其除了在Native层拥有三个服务(EVS HAL,EVS Manager,EVS APP)之外,在CarService中还提供了一个CarEvsManager与CarEvsService;在CarEvsService中便会尝试连接EVS Manager;我们在系统启动阶段看到的日志信息,就是由于CarEvsService启动后无法连接到EVS Manager导致的。

    那么问题来了,如果我们的系统在定制时没有集成相关的框架能力,如何在CarService中也对相应的模块进行屏蔽呢。针对这个问题,我们首先需要对CarService进行分析。

    CarService简介

    CarService是Android Automotive所提供的核心服务,众多的Automotive特性都依赖于该服务;Android12.1中CarService源码位于/packages/services/Car/service/,Android14.0中源码位于packages/services/Car/service-builtin,编译产物均为CarService.apk.

    编译时与Car相关的所有编译配置都在packages/services/Car/car_product/buil/car.mk中,在该makefile中又include了car_base.mk,关于CarService的整体应用框架,如下图所示:

    CarService所提供的绝大部分功能位于androi.car库,其源码位置/packages/services/Car/car-lib,在该目录下的Android.bp通过java_library字段定义了名为android.car的Java库,从而供应用使用。

    在CarService中,包含了众多的子Service,如下所示:

    我们在使用CarService时,可以通过其提供的getCarManager获取对应的子Manager,从而连接对应的子Service;如下所示:

    CarEvsManager evsManager = (CarEvsManager) car.getCarManager(Car.CAR_EVS_SERVICE);

    CarService启动

    CarService在Android Automotive中属于系统级别服务,由SystemServer拉起,拉起过程中主要依赖于CarServiceHelperService服务,首先我们看看如何在SystemServer中启动CarServiceHelperService:

    // 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(@NonNull TimingsTraceAndSlog t) {
    ……
    	if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
                    t.traceBegin("StartCarServiceHelperService");
                    mSystemServiceManager.startService(CAR_SERVICE_HELPER_SERVICE_CLASS);
                    t.traceEnd();
                }
         }
    

    这里我们可以看到CarServiceHelperService的启动是在system_server中startOtherServices中进行,调用的是SystemServiceManager.java中提供的startService方法。

    /**
     * Starts a service by class name.
     *
     * @return The service instance.
     */
    public SystemService startService(String className) {
    	final Class<SystemService> serviceClass = loadClassFromLoader(className,
    	this.getClass().getClassLoader());
    	return startService(serviceClass);
    }
    
    /*
     * Loads and initializes a class from the given classLoader. Returns the class.
     */
    @SuppressWarnings("unchecked")
    private static Class<SystemService> loadClassFromLoader(String className,ClassLoader classLoader) {
        try {
            return (Class<SystemService>) Class.forName(className, true, classLoader);
        } catch (ClassNotFoundException ex) {
            throw new RuntimeException("Failed to create service " + className
                    + " from class loader " + classLoader.toString() + ": service class not "
                    + "found, usually indicates that the caller should "
                    + "have called PackageManager.hasSystemFeature() to check whether the "
                    + "feature is available on this device before trying to start the "
                    + "services that implement it. Also ensure that the correct path for the "
        }
    }

    这里通过classLoader拿到CarServiceHelperService的class对象,进而通过startService重载调用对应service的onStart方法:

    //frameworks/base/services/core/java/com/android/server/SystemServiceManager.java
    //startService重载,通过调用对应service的onStart方法启动对应的Service
    public void startService(@NonNull final SystemService service) {
        // Register it.将对应的service对象保存至mService所对应的list中
        mServices.add(service);
        // Start it.
        long time = SystemClock.elapsedRealtime();
    try {
            //通过onStart进行启动
            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");
    }

    接下来我们进入CarServiceHelperService,看看其onStart具体做了哪些事情:

    //frameworks/opt/car/services/src/com/android/internal/car/CarServiceHelperService.java
    @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);
           //通过intent启动car service
    	if (!mContext.bindServiceAsUser(intent, mCarServiceConnection, Context.BIND_AUTO_CREATE,mHandler, UserHandle.SYSTEM)) {
    		Slogf.wtf(TAG, "cannot start car service");
    	}
    	loadNativeLibrary();
    }

    这里我们可以看到,CarServiceHelperService的onStart中会通过intent去启动我们的CarService,其对应的包名为com.android.car,通过Context.BIND_AUTO_CREATE标志来自启动服务(会自动调用服务的onCreate方法)。

    紧接着我们来分析CarService的onBind,其内部实现很简单,就是返回了一个名为mICarImpl的实例对象,该实例对象是在CarService类的onCreate进行实例化的:

    @Override
    public void onCreate() {
    	.....
           //获取Vehicle服务对象
    	mVehicle = getVehicle();
          //CarService实现 实例化
    	mICarImpl = new ICarImpl(this,
    	mVehicle,
    	SystemInterface.Builder.defaultSystemInterface(this).build(),
    	mVehicleInterfaceName);
           //通过init方法进行初始化
    	mICarImpl.init();
    	linkToDeath(mVehicle, mVehicleDeathRecipient);
           //添加到servicemanager
    	ServiceManager.addService("car_service", mICarImpl);
    	SystemProperties.set("boot.car_service_created", "1");
    	super.onCreate();
    }

    接着我们来到ICarImpl类的实现,看看其init方法:

    @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");
           //初始化各个子service,调用各子service的init方法
    	for (CarServiceBase service : mAllServices) {
    		t.traceBegin(service.getClass().getSimpleName());
    		service.init();
    		t.traceEnd();
    	}
    	t.traceEnd(); // "CarService.initAllServices"
    	t.traceEnd(); // "ICarImpl.init"
    }

    这里我们可以看到,CarService启动时会通过for循环去调用每个子service的init方法,从而完成启动过程中的初始化;其中mAllService是一个数组,其包含的元素为CarService中对应的各个子service实例,由此完成CarService的初始化流程

    在了解完其启动流程后,我们自然会想到mAllService数组内的元素到底是从哪里来的呢,这也是我们进行CarService模块裁剪的关键。

    CarFeatureController

    在CarService中,CarFeatureController用于解析配置,从而控制初始化阶段需要进程初始化的子服务;比如CarEvsService的初始化就依赖于CarFeatureController:

    if (mFeatureController.isFeatureEnabled(Car.CAR_EVS_SERVICE)) {
        mCarEvsService = constructWithTrace(t, CarEvsService.class,
        () -> new CarEvsService(serviceContext, mHal.getEvsHal(), mCarPropertyService));
    } else {
        mCarEvsService = null;
    }
    CarFeatureController由ICarImpl进行实例化:
    mFeatureController = constructWithTrace(t, CarFeatureController.class,
        () -> new CarFeatureController(serviceContext, defaultEnabledFeatures,
        disabledFromVhal, mSystemInterface.getSystemCarDir()));

    其中defaultEnabledFeatures代表CarService中默认支持的特性,可以通过/packages/services/Car/service/res/values/config.xml进行配置:

    defaultEnabledFeatures = res.getStringArray(R.array.config_allowed_optional_car_features);

    在Android12与14中,其具体配置如下:

    <string-array translatable="false" name="config_allowed_optional_car_features">
          <item>car_navigation_service</item>
          <item>cluster_service</item>
          <item>com.android.car.user.CarUserNoticeService</item>
          <item>diagnostic</item>
          <item>storage_monitoring</item>
          <item>vehicle_map_service</item>
          <item>car_evs_service</item>
          <item>car_telemetry_service</item>
    </string-array>

    在CarFeatureController初始化时,会传入默认支持的feature特性,还会读取一个名为car_feature_config.txt的配置文件(如果存在),在CarFeatureController中,其内部成员变量mEnabledFeatures是一个HashSet,用于存储记录需要支持的特性,这些特性都有相对应的子Service;这些特性分为强制的(MANDATORY_FEATURES)和可选的(OPTIONAL_FEATURES)两种;最后完整支持的feature都会被记录在SUPPORT_FEATURES内;

    所以当我们需要对CarService进行模块裁剪时,我们需要先确认该模块是否是optional的,如果是optional的模块,我们可以通过修改原生配置或者Overlay原生配置的方式覆盖config.xml中关于config_allowed_optional_car_features的配置;如果是原生强制支持的特性,可以通过修改源码或者定制car_feature_config.txt的配置来实现。

    操作实践

    在我遇到的场景里,CarEvsService属于可选项,为了避免对原生系统造成侵入式修改,我选择使用Overlay的形式来做定制化配置,具体步骤分为如下几步:

    1.在device目录下创建Overlay的配置文件夹,放入Overlay的配置

    2.在device.mk中通过DEVICE_PACKAGE_OVERLAYS配置Overlay

    3.重新进行编译打包,测试验证

    关于Overlay的更多细节,可以参考我的文章,希望对各位有所帮助~

    Happy
    Happy
    0 0 %
    Sad
    Sad
    0 0 %
    Excited
    Excited
    0 0 %
    Sleepy
    Sleepy
    0 0 %
    Angry
    Angry
    0 0 %
    Surprise
    Surprise
    0 0 %

    The post Android Automotive之CarService模块裁剪 first appeared on FranzKafka Blog.



沪ICP备19023445号-2号
友情链接