AIDL 调用过程详解

目的:不同进程间的的IPC 通信

代码示例:

/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.car;

import android.content.Intent;

import android.car.ICarConnectionListener;

/** @hide */
interface ICar {
    IBinder getCarService(in String serviceName) = 0;
    int getCarConnectionType() = 1;
}

声明了两个接口 getCarService 和getCarConnectionType

接口的实现在什么地方呢?

 * Copyright (C) 2015 The Android Open Source Project

package com.android.car;

import android.car.Car;

public class ICarImpl extends ICar.Stub {

    public static final String INTERNAL_INPUT_SERVICE =  "internal_input";

    // load jni for all services here
    static {
        System.loadLibrary("jni_car_service");
    }

    @GuardedBy("ICarImpl.class")
    private static ICarImpl sInstance = null;

    private final Context mContext;
    private final VehicleHal mHal;

    private final CarPowerManagementService mCarPowerManagementService;
    private final CarPackageManagerService mCarPackageManagerService;
    private final CarInputService mCarInputService;
    private final CarSensorService mCarSensorService;
    private final CarInfoService mCarInfoService;
    private final CarAudioService mCarAudioService;
    private final CarProjectionService mCarProjectionService;
    private final CarCameraService mCarCameraService;
    private final CarHvacService mCarHvacService;
    private final CarRadioService mCarRadioService;
    private final CarNightService mCarNightService;
    private final AppContextService mAppContextService;
    private final GarageModeService mGarageModeService;
    private final CarNavigationService mCarNavigationService;
    private final InstrumentClusterService mInstrumentClusterService;

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

    public synchronized static ICarImpl getInstance(Context serviceContext) {
        if (sInstance == null) {
            sInstance = new ICarImpl(serviceContext);
            sInstance.init();
        }
        return sInstance;
    }

    public synchronized static void releaseInstance() {
        if (sInstance == null) {
            return;
        }
        sInstance.release();
        sInstance = null;
    }

    public ICarImpl(Context serviceContext) {
        mContext = serviceContext;
        mHal = VehicleHal.getInstance();
        mCarPowerManagementService = new CarPowerManagementService(serviceContext);
        mCarInputService = new CarInputService(serviceContext);
        mCarProjectionService = new CarProjectionService(serviceContext, mCarInputService);
        mGarageModeService = new GarageModeService(mContext, mCarPowerManagementService);
        mCarInfoService = new CarInfoService(serviceContext);
        mAppContextService = new AppContextService(serviceContext);
        mCarSensorService = new CarSensorService(serviceContext);
        mCarAudioService = new CarAudioService(serviceContext);
        mCarHvacService = new CarHvacService(serviceContext);
        mCarRadioService = new CarRadioService(serviceContext);
        mCarCameraService = new CarCameraService(serviceContext);
        mCarNightService = new CarNightService(serviceContext);
        mCarPackageManagerService = new CarPackageManagerService(serviceContext);
        mInstrumentClusterService = new InstrumentClusterService(serviceContext);
        mCarNavigationService = new CarNavigationService(
                serviceContext, mAppContextService, mInstrumentClusterService);

        // Be careful with order. Service depending on other service should be inited later.
        mAllServices = new CarServiceBase[] {
                mCarPowerManagementService,
                mCarPackageManagerService,
                mCarInputService,
                mGarageModeService,
                mCarInfoService,
                mAppContextService,
                mCarSensorService,
                mCarAudioService,
                mCarHvacService,
                mCarRadioService,
                mCarCameraService,
                mCarNightService,
                mInstrumentClusterService,
                mCarProjectionService,
                mCarNavigationService,
                };
    }

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

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

    /** Only for CarTestService */
    void startMocking() {
        reinitServices();
    }

    /** Only for CarTestService */
    void stopMocking() {
        reinitServices();
    }

    /** Reset all services when starting / stopping vehicle hal mocking */
    private void reinitServices() {
        for (int i = mAllServices.length - 1; i >= 0; i--) {
            mAllServices[i].release();
        }
        for (CarServiceBase service: mAllServices) {
            service.init();
        }
    }

    @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_CONTEXT_SERVICE:
                return mAppContextService;
            case Car.PACKAGE_SERVICE:
                return mCarPackageManagerService;
            case Car.CAMERA_SERVICE:
                assertCameraPermission(mContext);
                return mCarCameraService;
            case Car.HVAC_SERVICE:
                assertHvacPermission(mContext);
                return mCarHvacService;
            case Car.RADIO_SERVICE:
                assertRadioPermission(mContext);
                return mCarRadioService;
            case Car.CAR_NAVIGATION_SERVICE:
                assertNavigationManagerPermission(mContext);
                return mCarNavigationService;
            case Car.PROJECTION_SERVICE:
                assertProjectionPermission(mContext);
                return mCarProjectionService;
            case Car.TEST_SERVICE: {
                assertVehicleHalMockPermission(mContext);
                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;
        }
    }

    @Override
    public int getCarConnectionType() {
        if (!isInMocking()) {
            return Car.CONNECTION_TYPE_EMBEDDED;
        } else {
            return Car.CONNECTION_TYPE_EMBEDDED_MOCKING;
        }
    }

    public CarServiceBase getCarInternalService(String serviceName) {
        switch (serviceName) {
            case INTERNAL_INPUT_SERVICE:
                return mCarInputService;
            default:
                Log.w(CarLog.TAG_SERVICE, "getCarInternalService for unknown service:" +
                        serviceName);
                return null;
        }
    }

    /**
     * Whether mocking underlying HAL or not.
     * @return
     */
    public synchronized boolean isInMocking() {
        if (mCarTestService == null) {
            return false;
        }
        return mCarTestService.isInMocking();
    }

    public static void assertVehicleHalMockPermission(Context context) {
        if (context.checkCallingOrSelfPermission(Car.PERMISSION_MOCK_VEHICLE_HAL)
                != PackageManager.PERMISSION_GRANTED) {
            throw new SecurityException("requires CAR_MOCK_VEHICLE_HAL permission");
        }
    }

    public static void assertCameraPermission(Context context) {
        if (context.checkCallingOrSelfPermission(Car.PERMISSION_CAR_CAMERA)
                != PackageManager.PERMISSION_GRANTED) {
            throw new SecurityException(
                    "requires " + Car.PERMISSION_CAR_CAMERA);
        }
    }

    public static void assertNavigationManagerPermission(Context context) {
        if (context.checkCallingOrSelfPermission(Car.PERMISSION_CAR_NAVIGATION_MANAGER)
                != PackageManager.PERMISSION_GRANTED) {
            throw new SecurityException(
                    "requires " + Car.PERMISSION_CAR_NAVIGATION_MANAGER);
        }
    }

    public static void assertHvacPermission(Context context) {
        if (context.checkCallingOrSelfPermission(Car.PERMISSION_CAR_HVAC)
                != PackageManager.PERMISSION_GRANTED) {
            throw new SecurityException(
                    "requires " + Car.PERMISSION_CAR_HVAC);
        }
    }

    private static void assertRadioPermission(Context context) {
        if (context.checkCallingOrSelfPermission(Car.PERMISSION_CAR_RADIO)
            != PackageManager.PERMISSION_GRANTED) {
            throw new SecurityException(
                "requires permission " + Car.PERMISSION_CAR_RADIO);
        }
    }

    public static void assertProjectionPermission(Context context) {
        if (context.checkCallingOrSelfPermission(Car.PERMISSION_CAR_PROJECTION)
                != PackageManager.PERMISSION_GRANTED) {
            throw new SecurityException(
                    "requires " + Car.PERMISSION_CAR_PROJECTION);
        }
    }

    void dump(PrintWriter writer) {
        writer.println("*Dump all services*");
        for (CarServiceBase service: mAllServices) {
            service.dump(writer);
        }
        CarTestService testService = mCarTestService;
        if (testService != null) {
            testService.dump(writer);
        }
    }
}

如何确认这个代码就是ICar 接口的实现呢?
ICarImpl extends ICar.Stub
ICarImpl 继承了服务器端ICar.Stub

现在需要如何使用这个接口呢?

 mService = ICar.Stub.asInterface(service);

*在连接Service的时候,服务端的Stub(Binder)以参数的形式传过来了–IBinder service,然后我们通过asInterface()方法获取它的实例对象。
我们从android对aidl文件自动生成的java类中可以看到asInterface()这个接口的实现,大概的意思就是:
如果客户端和服务端在同一个进程下,那么asInterface()将返回Stub对象本身,否则返回Stub.Proxy对象。
也就是说asInterface()返回的对象有两种可能(实际上有三种,还有一种是null),Stub和Stub.Proxy。它们有什么区别呢?
如果在同一个进程下的话,那么asInterface()将返回服务端的Stub对象本身,因为此时根本不需要跨进称通信,那么直接调用Stub对象的接口就可以了,返回的实现就是服务端的Stub实现,也就是根本没有跨进程通信;
如果不是同一个进程,那么asInterface()返回是Stub.Proxy对象,该对象持有着远程的Binder引用,因为现在需要跨进程通信,所以如果调用Stub.Proxy的接口的话,那么它们都将是IPC调用,它会通过调用transact方法去与服务端通信。
以上就是两者的区别。*

Created with Raphaël 2.1.0 IPC Communication Client Client Server Server Binder

猜你喜欢

转载自blog.csdn.net/iccome/article/details/74744886
今日推荐