文章大概的说了一点Car模块的binder交互,说的比较乱,只适合我个人研读。🐶🐶🐶

套路1:

服务的aidl 设置get() set() callback() register(IIoStatsListener listener)

管理类怎么写?

首先管理类需要让第三方使用到所有服务端的接口以及回调功能,所以我们要提供注册的功能以及解注册的功能。
既然要提供接口回调,那么就需要在管理类中写接口,将服务端的回调函数通过接口传给使用的第三方。

  • 首先需要将服务端的binder实例化,使用内部类引用外部类使用软引用。然后通过handler将服务端传来的数据发出去。通过加入的服务端集合遍历,将所有的数据回调出去。
  • 在register函数里面,因为要注册回调。所以我们需要实例化ListenerToService ,因为只有在null的情况下才去去new一个对象,
    所以需要判断是否为空。
  • 因为有多个listener所以一般都是将listener加入到一个集合中。
  • unregisterListener 里面先判断在回调集合中是否已经删除了这个监听,如果没有删除就直接移除。
private static final class ListenerToService extends IIoStatsListener.Stub {
        private final WeakReference<CarStorageMonitoringManager> mManager;

        ListenerToService(CarStorageMonitoringManager manager) {
            mManager = new WeakReference<>(manager);
        }

        @Override
        public void onSnapshot(IoStats snapshot) {
            CarStorageMonitoringManager manager = mManager.get();
            if (manager != null) {
                manager.mMessageHandler.sendEvents(Collections.singletonList(snapshot));
            }
        }
    }

public CarStorageMonitoringManager(IBinder service, Handler handler) {
        mService = ICarStorageMonitoring.Stub.asInterface(service);
        mMessageHandler = new SingleMessageHandler<IoStats>(handler, MSG_IO_STATS_EVENT) {
            @Override
            protected void handleEvent(IoStats event) {
                for (IoStatsListener listener : mListeners) {
                    listener.onSnapshot(event);
                }
            }
        };
    }
    
public void registerListener(IoStatsListener listener) throws CarNotConnectedException {
        try {
            if (mListeners.isEmpty()) {
                if (mListenerToService == null) {
                    mListenerToService = new ListenerToService(this);
                }
                mService.registerListener(mListenerToService);
            }
            mListeners.add(listener);
        } catch (IllegalStateException e) {
            checkCarNotConnectedExceptionFromCarService(e);
        } catch (RemoteException e) {
            throw new CarNotConnectedException();
        }
    }
public void unregisterListener(IoStatsListener listener) throws CarNotConnectedException {
        try {
            if (!mListeners.remove(listener)) {
                return;
            }
            if (mListeners.isEmpty()) {
                mService.unregisterListener(mListenerToService);
                mListenerToService = null;
            }
        } catch (IllegalStateException e) {
            checkCarNotConnectedExceptionFromCarService(e);
        } catch (RemoteException e) {
            throw new CarNotConnectedException();
        }
    }

服务端怎么写?

  • 要继承服务的aidl
  • 复写aidl中的方法,在类的构造方法中可以实例化一些需要的类和方法。
  • 服务端的回调,可以通过RemoteCallbackList来处理,实例化后,在register方法中注册RemoteCallbackList。这样做的好处是极大的简化了回调带来的多余代码。
1.CarStorageMonitoringService extends ICarStorageMonitoring.Stub
2.private final RemoteCallbackList<IIoStatsListener> mListeners = new RemoteCallbackList<>();
3.注册回调
 @Override
    public void registerListener(IIoStatsListener listener) {
        mListeners.register(listener);
    }
    @Override
    public void unregisterListener(IIoStatsListener listener) {
        mListeners.unregister(listener);
    }
4.通过RemoteCallbackList将数据发送给注册端
private void dispatchNewIoEvent(IoStats delta) {
        final int listenersCount = mListeners.beginBroadcast();
        IntStream.range(0, listenersCount).forEach(
            i -> {
                try {
                    mListeners.getBroadcastItem(i).onSnapshot(delta);
                } catch (RemoteException e) {
                    Log.w(TAG, "failed to dispatch snapshot", e);
                }
            });
        mListeners.finishBroadcast();
    }

套路二

服务端怎么写?

先看看callback 的aidl 怎么写。

interface IVehicleCallback {
    oneway onPropertyEvent(vec<VehiclePropValue> propValues);
    oneway onPropertySet(VehiclePropValue propValue);
    oneway onPropertySetError(StatusCode errorCode,
                              int32_t propId,
                              int32_t areaId);
};

java端这样写:

1. VehicleHal extends IVehicleCallback.Stub 
2. 因为callback都是通过服务端进行注册的,所以这里面使用构造方法传入service
public VehicleHal(IVehicle vehicle) {
....
mHalClient = new HalClient(vehicle, mHandlerThread.getLooper(), this /*IVehicleCallback*/);
....
}
3.注册,反注册
mHalClient.subscribe(opts);
mHalClient.unsubscribe(property);
4.将callback 回调出去。因为有很多模块使用这个回调。所以在添加回调的时候,先将使用这个集合的回调加进去。然后遍历就知道有多少个服务要使用这个callback了。
private final SparseArray<HalServiceBase> mServicesToDispatch = new SparseArray<>();
5.通过遍历,将数据分发给各个service 然后清空集合。下次在来数据的时候,重新执行。
for (HalServiceBase s : mServicesToDispatch) {
            s.handleHalEvents(s.getDispatchList());
            s.getDispatchList().clear();
        }
 6.看一下服务类注册callback的类mhalClient,构造方法传入了callback,提供了处理aidl里面的接口能力,但是具体的工作还是VehicleHal来实现的。
 
 HalClient(IVehicle vehicle, Looper looper, IVehicleCallback callback) {
        mVehicle = vehicle;
        Handler handler = new CallbackHandler(looper, callback);
        mInternalCallback = new VehicleCallback(handler);
    }
 7.public void subscribe(SubscribeOptions... options) throws RemoteException {
        mVehicle.subscribe(mInternalCallback, new ArrayList<>(Arrays.asList(options)));
    }

    public void unsubscribe(int prop) throws RemoteException {
        mVehicle.unsubscribe(mInternalCallback, prop);
    }
 8.看看具体需要使用到callback 与一些接口的服务类是怎么处理的。
 PropertyHalService extends HalServiceBase
  public PropertyHalService(VehicleHal vehicleHal) {}
  9. public CarPropertyValue getProperty(int mgrPropId, int areaId) {
   value = mVehicleHal.get(halPropId, areaId); 
  }
  10. 通过HalServiceBase这个抽象类,handleHalEvents会接收所有的来自于VehicleHal的回调。
	因为不同的service模块可能接收的id都不一样,所以再回调的是时候,先判断用户需要的ID,过滤出自己需要的id,然后回调到接口里面。
	if (listener != null) {
            for (VehiclePropValue v : values) {
            .....
             listener.onPropertyChange(mEventsToDispatch);
            mEventsToDispatch.clear();
            .....
            }
            }

前面的10步我们看到了hal service 把底层的数据交给了base类。那么最后需要在各个具体的服务类里面去完成释放给客户端的任务.

CarPropertyService extends ICarProperty.Stub
        implements CarServiceBase, PropertyHalService.PropertyHalListener {
		
		1.首先在构造方法传入了PropertyHalService
		 public CarPropertyService(Context context, PropertyHalService hal) {
        mHal = hal;
        mContext = context;
    }
		2.然后是注册回调,根据id ,率进行注册。
		这里面没有用remotecallbacklist 而是直接new了一个client 来管理客户端的绑定解绑以及客户端死亡回调再次释放资源。
registerListener(int propId, float rate, ICarPropertyEventListener listener)
3.套路来了,所有的客户端注册都可以这样写!
实现客户端的死亡回调
private class Client implements IBinder.DeathRecipient {
//客户传入的listener
        private final ICarPropertyEventListener mListener;
        //binder
        private final IBinder mListenerBinder;
        private final SparseArray<Float> mRateMap = new SparseArray<Float>();   // key is propId

        Client(ICarPropertyEventListener listener) {
            mListener = listener;
            mListenerBinder = listener.asBinder();

            try {
            //注册死亡回调
                mListenerBinder.linkToDeath(this, 0);
            } catch (RemoteException e) {
                Log.e(TAG, "Failed to link death for recipient. " + e);
                throw new IllegalStateException(Car.CAR_NOT_CONNECTED_EXCEPTION_MSG);
            }
            //使用map 映射 每个客户端binder 对应一个client对象
            mClientMap.put(mListenerBinder, this);
        }
		//速率表
        void addProperty(int propId, float rate) {
            mRateMap.put(propId, rate);
        }

        /**
         * Client died. Remove the listener from HAL service and unregister if this is the last
         * client.
         */
        @Override
        public void binderDied() {
            if (DBG) {
                Log.d(TAG, "binderDied " + mListenerBinder);
            }
			//如果客户端挂了,那么就执行解绑操作,释放资源
            for (int i = 0; i < mRateMap.size(); i++) {
                int propId = mRateMap.keyAt(i);
                CarPropertyService.this.unregisterListenerBinderLocked(propId, mListenerBinder);
            }
            //同时删除map集合里面的值
            this.release();
        }

        ICarPropertyEventListener getListener() {
            return mListener;
        }

        IBinder getListenerBinder() {
            return mListenerBinder;
        }

        float getRate(int propId) {
            // Return 0 if no key found, since that is the slowest rate.
            return mRateMap.get(propId, (float) 0);
        }

        void release() {
            mListenerBinder.unlinkToDeath(this, 0);
            mClientMap.remove(mListenerBinder);
        }

        void removeProperty(int propId) {
            mRateMap.remove(propId);
            if (mRateMap.size() == 0) {
                // Last property was released, remove the client.
                this.release();
            }
        }
    }
4.将套路用到register方法里面,这个注册主要是马上将一部分值回调给注册的客户端。
 private final Map<IBinder, Client> mClientMap = new ConcurrentHashMap<>();
registerListener(int propId, float rate, ICarPropertyEventListener listener){
IBinder listenerBinder = listener.asBinder();
synchronized (mLock) {
            // 通过binder获取每个客户端的实例
            Client client = mClientMap.get(listenerBinder);
            if (client == null) {
            //新建一个
                client = new Client(listener);
            }
            //添加id 对应的速率 映射
            client.addProperty(propId, rate);
            // Insert the client into the propId --> clients map
            //每个property id 对应的多个client端
            List<Client> clients = mPropIdClientMap.get(propId);
            if (clients == null) {
                clients = new CopyOnWriteArrayList<Client>();
                mPropIdClientMap.put(propId, clients);
            }
            if (!clients.contains(client)) {
                clients.add(client);
            }
            // 注册hal 服务的listener
            if (!mListenerIsSet) {
                mHal.setListener(this);
            }
            // 如果速率有更新那么从hal 服务那里更新订阅服务
            if (rate > mHal.getSampleRate(propId)) {
                mHal.subscribeProperty(propId, rate);
            }
        }
        //注册回调的时候,会给每个id值 get一个然后回调出去值
List<CarPropertyEvent> events = new LinkedList<CarPropertyEvent>();
        for (int areaId : mConfigs.get(propId).getAreaIds()) {
            CarPropertyValue value = mHal.getProperty(propId, areaId);
            CarPropertyEvent event = new CarPropertyEvent(
                    CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE, value);
            events.add(event);
        }
        try {
            listener.onEvent(events);
        } catch (RemoteException ex) {
            Log.e(TAG, "onEvent calling failed: " + ex);
        }

}

5.看看来自hal service 的接口处理的id值更新

  @Override
    public void onPropertyChange(List<CarPropertyEvent> events) {
    //局部变量
        Map<IBinder, Pair<ICarPropertyEventListener, List<CarPropertyEvent>>> eventsToDispatch =
                new HashMap<>();
		//遍历集合获取id
        for (CarPropertyEvent event : events) {
            int propId = event.getCarPropertyValue().getPropertyId();
            //通过id这个key 找到client集合
            List<Client> clients = mPropIdClientMap.get(propId);
            //如果是空的那么就是没有注册者注册过这个id,跳过继续循环
            if (clients == null) {
                Log.e(TAG, "onPropertyChange: no listener registered for propId=0x"
                        + toHexString(propId));
                continue;
            }
			//遍历客户端的集合
            for (Client c : clients) {
            //每个客户端对应一个binder
                IBinder listenerBinder = c.getListenerBinder();
                //通过pair对 寻找 这个客户端binder对应的所有的property id 的集合
                Pair<ICarPropertyEventListener, List<CarPropertyEvent>> p =
                        eventsToDispatch.get(listenerBinder);
                        //如果没有
                if (p == null) {
                    // Initialize the linked list for the listener
                    //frist 是binder second new了一个链表CarPropertyEvent
                    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 {
            //first里面是listener,所以调用listener的方法将second里面的数据发出去。形成对应的关系。牛逼的设计!!!
                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);
            }
        }
    }

客户端管理类怎么写?

上面用了大量的篇幅说明了,hal到服务端的套路。那么客户端也不可能直接用服务端的数据,需要管理起来,让客户端不必要都去一个一个实现其服务端的aidl ,那就很麻烦了,而且对多客户端很不友好,所以就有了manager。

1.先看看客户端的构造方法
//首先要传入binder 这个是客户端必须要给的。
public CarPropertyManager(IBinder service, Handler handler, boolean dbg, String tag) {}
2.
public boolean registerListener(CarPropertyEventListener listener, int propertyId, float rate)
            throws CarNotConnectedException {
        synchronized (mActivePropertyListener) {
            if (mCarPropertyEventToService == null) {
            //把这个manager传入到CarPropertyEventListenerToService,顺便实例化,可以接收监听的操作了
                mCarPropertyEventToService = new CarPropertyEventListenerToService(this);
            }
            //是否需要更新服务
            boolean needsServerUpdate = false;
            CarPropertyListeners listeners;
            listeners = mActivePropertyListener.get(propertyId);
            if (listeners == null) {
            //这个类对数据进行了处理,比如时间的新旧,速率变化
                listeners = new CarPropertyListeners(rate);
                mActivePropertyListener.put(propertyId, listeners);
                needsServerUpdate = true;
            }
            if (listeners.addAndUpdateRate(listener, rate)) {
                needsServerUpdate = true;
            }
            if (needsServerUpdate) {
            //直接通过服务重新注册
                if (!registerOrUpdatePropertyListener(propertyId, rate)) {
                    return false;
                }
            }
        }
        return true;
    }
}

 private class CarPropertyEventListenerToService extends ICarPropertyEventListener.Stub{
        private final WeakReference<CarPropertyManager> mMgr;

        CarPropertyEventListenerToService(CarPropertyManager mgr) {
            mMgr = new WeakReference<>(mgr);
        }

        @Override
        public void onEvent(List<CarPropertyEvent> events) throws RemoteException {
            CarPropertyManager manager = mMgr.get();
            if (manager != null) {
                manager.handleEvent(events);
            }
        }
    }

套路三

准备在下一个篇幅去记录,这种方法其实比较好用,使用的场景是通过服务来获取资源数据。