Android车载开发初窥

  • Post author:
  • Post category:其他




背景

众所周知,互联网行业发展的并不愉快,导致互联网行业就业形势不太理想,“开猿节流”的事情时有发生,所以很多小伙伴开启了车载android的学习,我也不例外。



AutoMovie和auto:

车载Android系统,又称Android Automotive, 是一个基于 Android 平台扩展后,适用于现代汽车的智能操作系统,可以直接运行为Android系统开发的应用。Android Automotive并非Android的分支或并行开发版本。它与手机和平板电脑等设备上搭载的Android使用相同的代码库,位于同一个存储区中。Android Automotive与Android最大的区别在于,Android Automotive增加了对汽车特定要求、功能和技术的支持。auto则是类似于carplay一样app



AutoMoive架构

这个就是AndroidAutoMovie的架构图,总体来说关于android的部分在Framework中添加了大量的车机服务,并且在sdk中提供了api供我们调用,而在底层则添加了嵌入式操作系统相关的架构。关于底层我们只是做一些简单的了解,我们先来看看应用层和Framework层,先来看看这个车机服务是咋起来的那车机服务是咋起的呢?答案还是

在Systemserver里,

private void startOtherServices() {    
    ...   if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
                traceBeginAndSlog("StartCarServiceHelperService");
                mSystemServiceManager.startService(CAR_SERVICE_HELPER_SERVICE_CLASS);
                traceEnd();
            }
    ... }


Systemserver通过SystemServiceManager来管理的,所以CAR_SERVICE_HELPER_SERVICE_CLASS同样也被它管理,我们来跟下代码

public SystemService startService(String className) {
        final Class<SystemService> serviceClass;
        try {
            serviceClass = (Class<SystemService>)Class.forName(className);
        } catch (ClassNotFoundException ex) {
            Slog.i(TAG, "Starting " + className);
            throw new RuntimeException("Failed to create service " + className
                    + ": 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", ex);
        }
        return startService(serviceClass);
    }

    /**
     * Creates and starts a system service. The class must be a subclass of
     * {@link com.android.server.SystemService}.
     *
     * @param serviceClass A Java class that implements the SystemService interface.
     * @return The service instance, never null.
     * @throws RuntimeException if the service fails to start.
     */
    @SuppressWarnings("unchecked")
    public <T extends SystemService> T startService(Class<T> serviceClass) {
        try {
            final String name = serviceClass.getName();
            Slog.i(TAG, "Starting " + name);
            Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartService " + name);

            // Create the service.
            if (!SystemService.class.isAssignableFrom(serviceClass)) {
                throw new RuntimeException("Failed to create " + name
                        + ": service must extend " + SystemService.class.getName());
            }
            final T service;
            try {
                Constructor<T> constructor = serviceClass.getConstructor(Context.class);
                service = constructor.newInstance(mContext);//反射获取对象
            } catch (InstantiationException ex) {
                throw new RuntimeException("Failed to create service " + name
                        + ": service could not be instantiated", ex);
            } catch (IllegalAccessException ex) {
                throw new RuntimeException("Failed to create service " + name
                        + ": service must have a public constructor with a Context argument", ex);
            } catch (NoSuchMethodException ex) {
                throw new RuntimeException("Failed to create service " + name
                        + ": service must have a public constructor with a Context argument", ex);
            } catch (InvocationTargetException ex) {
                throw new RuntimeException("Failed to create service " + name
                        + ": service constructor threw an exception", ex);
            }

            startService(service);
            return service;
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
        }
    }

    public void startService(@NonNull final SystemService service) {
        // Register it.
        mServices.add(service);
        // Start it.
        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");
    }

我们通过上面的代码可以看到,它最终是调了 CarServiceHelperService.onStart()这个方法,我们继续跟代码

    @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");
    }


这个方法里,启动一个包名为com.android.car并绑定得到一个binder远端代理,这样就完成了carService的启动,我们不难发现它就是个单独的app,写到这,我突然不免意思到,这个跟前公司智能android机顶盒的流程,简直如出一辙啊,cable线的直播电视app开发中,由中间件适配硬件,提供hal层给Framework调用,我们也是整了一个服务类的apk,这个通过抽象接口调用底层,并且提供binder给应用层绑定,那应用层咋绑定呢,也是通过一个jar包来做和服务类apk通讯,app只需要调用jar包中的api就够了,好了好像跑偏了,言归正传,我们继续说这个单独app,这个源码在哪里呢?/packages/services/Car/service,我们跟进去看一下它的代码

public class CarService extends Service {

    private static final long WAIT_FOR_VEHICLE_HAL_TIMEOUT_MS = 10_000;

    private static final boolean IS_USER_BUILD = "user".equals(Build.TYPE);

    private static final String IVHAL_20 =
            android.hardware.automotive.vehicle.V2_0.IVehicle.kInterfaceName;
    private static final String IVHAL_21 =
            android.hardware.automotive.vehicle.V2_1.IVehicle.kInterfaceName;

    private CanBusErrorNotifier mCanBusErrorNotifier;
    private ICarImpl mICarImpl; //提供服务的远端stub
    private IVehicle mVehicle; //就理解为跟硬件打交道的抽象接口吧



    private final VehicleDeathRecipient mVehicleDeathRecipient = new VehicleDeathRecipient();

    @Override
    public void onCreate() {
        Log.i(CarLog.TAG_SERVICE, "Service onCreate");
        mCanBusErrorNotifier = new CanBusErrorNotifier(this /* context */);
        mVehicle = getVehicle(null /* Any Vehicle HAL interface name */);

        if (mVehicle == null) {
            throw new IllegalStateException("Vehicle HAL service is not available.");
        }
        try {
            mVehicleInterfaceName = mVehicle.interfaceDescriptor();
        } catch (RemoteException e) {
            throw new IllegalStateException("Unable to get Vehicle HAL interface descriptor", e);
        }

        Log.i(CarLog.TAG_SERVICE, "Connected to " + mVehicleInterfaceName);

        mICarImpl = new ICarImpl(this, mVehicle, SystemInterface.getDefault(this),
                mCanBusErrorNotifier);
        mICarImpl.init();
        SystemProperties.set("boot.car_service_created", "1");

        linkToDeath(mVehicle, mVehicleDeathRecipient);

        super.onCreate();
    }

  

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // keep it alive.
        return START_STICKY;
    }

    @Override
    public IBinder onBind(Intent intent) {
        return mICarImpl;
    } }

通过代码,我们不难发现mICarImpl应该是实现了stub的远端服务,我们跟下它的代码

public class ICarImpl extends ICar.Stub {
    private final CarServiceBase[] mAllServices;

    /** Test only service. Populate it only when necessary. */
    @GuardedBy("this")
    private CarTestService mCarTestService;

    public ICarImpl(Context serviceContext, IVehicle vehicle, SystemInterface systemInterface,
            CanBusErrorNotifier errorNotifier) {
        mContext = serviceContext;
        mHal = new VehicleHal(vehicle);
        mSystemActivityMonitoringService = new SystemActivityMonitoringService(serviceContext);
        mCarPowerManagementService = new CarPowerManagementService(
                mHal.getPowerHal(), systemInterface);
        mCarSensorService = new CarSensorService(serviceContext, mHal.getSensorHal());
        mCarPackageManagerService = new CarPackageManagerService(serviceContext, mCarSensorService,
                mSystemActivityMonitoringService);
        mCarInputService = new CarInputService(serviceContext, mHal.getInputHal());
        mCarProjectionService = new CarProjectionService(serviceContext, mCarInputService);
        mGarageModeService = new GarageModeService(mContext, mCarPowerManagementService);
        mCarInfoService = new CarInfoService(serviceContext, mHal.getInfoHal());
        mAppFocusService = new AppFocusService(serviceContext, mSystemActivityMonitoringService);
        mCarAudioService = new CarAudioService(serviceContext, mHal.getAudioHal(),
                mCarInputService, errorNotifier);
        mCarCabinService = new CarCabinService(serviceContext, mHal.getCabinHal());
        mCarHvacService = new CarHvacService(serviceContext, mHal.getHvacHal());
        mCarRadioService = new CarRadioService(serviceContext, mHal.getRadioHal());
        mCarNightService = new CarNightService(serviceContext, mCarSensorService);
        mInstrumentClusterService = new InstrumentClusterService(serviceContext,
                mAppFocusService, mCarInputService);
        mSystemStateControllerService = new SystemStateControllerService(serviceContext,
                mCarPowerManagementService, mCarAudioService, this);
        mCarVendorExtensionService = new CarVendorExtensionService(serviceContext,
                mHal.getVendorExtensionHal());
        mPerUserCarServiceHelper = new PerUserCarServiceHelper(serviceContext);
        mCarBluetoothService = new CarBluetoothService(serviceContext, mCarCabinService,
                mCarSensorService, mPerUserCarServiceHelper);
        if (FeatureConfiguration.ENABLE_VEHICLE_MAP_SERVICE) {
            mVmsSubscriberService = new VmsSubscriberService(serviceContext, mHal.getVmsHal());
            mVmsPublisherService = new VmsPublisherService(serviceContext, mHal.getVmsHal());
        }
        if (FeatureConfiguration.ENABLE_DIAGNOSTIC) {
            mCarDiagnosticService = new CarDiagnosticService(serviceContext,
                    mHal.getDiagnosticHal());
        }

        // Be careful with order. Service depending on other service should be inited later.
        List<CarServiceBase> allServices = new ArrayList<>(Arrays.asList(
                mSystemActivityMonitoringService,
                mCarPowerManagementService,
                mCarSensorService,
                mCarPackageManagerService,
                mCarInputService,
                mGarageModeService,
                mCarInfoService,
                mAppFocusService,
                mCarAudioService,
                mCarCabinService,
                mCarHvacService,
                mCarRadioService,
                mCarNightService,
                mInstrumentClusterService,
                mCarProjectionService,
                mSystemStateControllerService,
                mCarVendorExtensionService,
                mCarBluetoothService,
                mPerUserCarServiceHelper
        ));
        if (FeatureConfiguration.ENABLE_VEHICLE_MAP_SERVICE) {
            allServices.add(mVmsSubscriberService);
            allServices.add(mVmsPublisherService);
        }
        if (FeatureConfiguration.ENABLE_DIAGNOSTIC) {
            allServices.add(mCarDiagnosticService);
        }
        mAllServices = allServices.toArray(new CarServiceBase[0]);
    }

    public void init() {
        mHal.init();
        for (CarServiceBase service : mAllServices) {
            service.init();
        }
    }

    public void release() {
        // release done in opposite order from init
        for (int i = mAllServices.length - 1; i >= 0; i--) {
            mAllServices[i].release();
        }
        mHal.release();
    }

    public void vehicleHalReconnected(IVehicle vehicle) {
        mHal.vehicleHalReconnected(vehicle);
        for (CarServiceBase service : mAllServices) {
            service.vehicleHalReconnected();
        }
    }

    //提供对外服务获取api
    @Override
    public IBinder getCarService(String serviceName) {
        switch (serviceName) {
            case Car.AUDIO_SERVICE:
                return mCarAudioService;
            case Car.SENSOR_SERVICE:
                return mCarSensorService;
            case Car.INFO_SERVICE:
                return mCarInfoService;
            case Car.APP_FOCUS_SERVICE:
                return mAppFocusService;
            case Car.PACKAGE_SERVICE:
                return mCarPackageManagerService;
            case Car.CABIN_SERVICE:
                assertCabinPermission(mContext);
                return mCarCabinService;
            case Car.DIAGNOSTIC_SERVICE:
                FeatureUtil.assertFeature(FeatureConfiguration.ENABLE_DIAGNOSTIC);
                if (FeatureConfiguration.ENABLE_DIAGNOSTIC) {
                    assertAnyDiagnosticPermission(mContext);
                    return mCarDiagnosticService;
                }
            case Car.HVAC_SERVICE:
                assertHvacPermission(mContext);
                return mCarHvacService;
            case Car.RADIO_SERVICE:
                assertRadioPermission(mContext);
                return mCarRadioService;
            case Car.CAR_NAVIGATION_SERVICE:
                assertNavigationManagerPermission(mContext);
                IInstrumentClusterNavigation navService =
                        mInstrumentClusterService.getNavigationService();
                return navService == null ? null : navService.asBinder();
            case Car.PROJECTION_SERVICE:
                assertProjectionPermission(mContext);
                return mCarProjectionService;
            case Car.VENDOR_EXTENSION_SERVICE:
                assertVendorExtensionPermission(mContext);
                return mCarVendorExtensionService;
            case Car.VMS_SUBSCRIBER_SERVICE:
                FeatureUtil.assertFeature(FeatureConfiguration.ENABLE_VEHICLE_MAP_SERVICE);
                if (FeatureConfiguration.ENABLE_VEHICLE_MAP_SERVICE) {
                    assertVmsSubscriberPermission(mContext);
                    return mVmsSubscriberService;
                }
            case Car.TEST_SERVICE: {
                assertPermission(mContext, Car.PERMISSION_CAR_TEST_SERVICE);
                synchronized (this) {
                    if (mCarTestService == null) {
                        mCarTestService = new CarTestService(mContext, this);
                    }
                    return mCarTestService;
                }
            }
            default:
                Log.w(CarLog.TAG_SERVICE, "getCarService for unknown service:" + serviceName);
                return null;
        }
    } }



这么多service看的眼睛都花了,不过确实是在这里面管理添加并缓存的,并且Car还把硬件抽象相关的vehicle传过来了,那各种服务拿到这个硬件接口,不就是可以操作硬件了嘛。以上就是carservice的启动过程。用一张图来表述各个功能模块



最后

如果想要成为架构师或想突破20~30K薪资范畴,那就不要局限在编码,业务,要会选型、扩展,提升编程思维。此外,良好的职业规划也很重要,学习的习惯很重要,但是最重要的还是要能持之以恒,任何不能坚持落实的计划都是空谈。

如果你没有方向,这里给大家分享一套由阿里高级架构师编写的《Android八大模块进阶笔记》,帮大家将杂乱、零散、碎片化的知识进行体系化的整理,让大家系统而高效地掌握Android开发的各个知识点。

在这里插入图片描述

相对于我们平时看的碎片化内容,这份笔记的知识点更系统化,更容易理解和记忆,是严格按照知识体系编排的。



全套视频资料:


一、面试合集

在这里插入图片描述


二、源码解析合集


在这里插入图片描述


三、开源框架合集


在这里插入图片描述


欢迎大家一键三连支持,若需要文中资料,直接扫描文末CSDN官方认证微信卡片免费领取↓↓↓




版权声明:本文为xiaokangss原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。