CarPropertyService

2025-08-01

获取Property值

获取Property值的步骤

获取Property直到VehicleStub的步骤

sequenceDiagram
autonumber
participant U as SomeMethod
participant CPM as CarPropertyManager
participant CPS as CarPropertyService
participant PHS as PropertyHalService
participant VH as VehicleHal
participant VS as VehicleStub
U->>+CPM:getProperty
CPM->>+CPS:getProperty
CPS->>+PHS:getProperty
PHS->>+VH:get
VH->>VH:getValueWithRetry
VH->>+VS:get
VS-->>-VH: HalPropValue
VH-->>-PHS: HalPropValue
PHS-->>-CPS : CarPropertyValue
CPS-->>-CPM: CarPropertyValue
CPM-->>-U : CarPropertyValue

第1步 执行getProperty方法:

public <E> CarPropertyValue<E> getProperty(int propertyId, int areaId) {
    ...
    try {
        CarPropertyValue<E> carPropertyValue = (CarPropertyValue<E>) (runSyncOperation(() -> {
            return mService.getProperty(propertyId, areaId);
        }));
        ...
        return carPropertyValue;
    }
    ...
}

,方法指定了相应的(propertyId, areaId),并返回一个泛型类CarPropertyValue的实例。在方法中,通过同步操作使用了mService.getProperty方法调用了CarPropertyServicegetProperty方法

第2步 执行CarPropertyService::getProperty方法:

public CarPropertyValue getProperty(int propertyId, int areaId)
        throws IllegalArgumentException, ServiceSpecificException {
    ...
    try {
        return runSyncOperationCheckLimit(() -> {
            return mPropertyHalService.getProperty(propertyId, areaId);
        });
    }
    ...
}

,仍然通过一个同步操作执行了PropertyHalServicegetProperty方法

第3步 执行PropertyHalService::getProperty方法:

public CarPropertyValue getProperty(int mgrPropId, int areaId)
        throws IllegalArgumentException, ServiceSpecificException {
    int halPropId = managerToHalPropId(mgrPropId);

    HalPropValue halPropValue;
    HalPropConfig halPropConfig;
    //从cache中获取isStaticAndSystemPropertyLocked的property
    synchronized (mLock) {
        halPropConfig = mHalPropIdToPropConfig.get(halPropId);
        if (isStaticAndSystemPropertyLocked(mgrPropId)) {
            CarPropertyValue carPropertyValue = mStaticPropertyIdAreaIdCache.get(mgrPropId,
                    areaId);
            if (carPropertyValue != null) {
                ...
                return carPropertyValue;
            }
        }
    }
    //从VehicleHal中获取,并将isStaticAndSystemPropertyLocked的property存入cache
    halPropValue = mVehicleHal.get(halPropId, areaId);
    try {
        CarPropertyValue result = halPropValue.toCarPropertyValue(mgrPropId, halPropConfig);
        synchronized (mLock) {
            if (!isStaticAndSystemPropertyLocked(mgrPropId)) {
                return result;
            }
            mStaticPropertyIdAreaIdCache.put(mgrPropId, areaId, result);
            return result;
        }
    }
}

,在这一步,PropertyHalService主要干了如下几件事:

  1. car property id 到 hal property id 的转换,以及 hal property value 到 car property value 的转换
  2. 对于满足isStaticAndSystemPropertyLocked的property读写mStaticPropertyIdAreaIdCache
  3. VehicleHal中通过get获取property值

第4步 执行VehicleHal::get方法:

public HalPropValue get(int propertyId, int areaId)
        throws IllegalArgumentException, ServiceSpecificException {
    ...
    return getValueWithRetry(mPropValueBuilder.build(propertyId, areaId));
}

调用了getValueWithRetry方法

第5步 执行getValueWithRetry方法:

private HalPropValue getValueWithRetry(HalPropValue value) {
    return getValueWithRetry(value, /* maxRetries= */ 0);
}

调用了另一个getValueWithRetry方法:

private HalPropValue getValueWithRetry(HalPropValue value, int maxRetries) {
    HalPropValue result;
    ...
    try {
        result = invokeRetriable((requestValue) -> {
        ...
            try {
                return mVehicleStub.get(requestValue);
            } 
            ...
        }, "get", value, mMaxDurationForRetryMs, mSleepBetweenRetryMs, maxRetries);
    } 
    ...
    return result;
}

,方法调用了

private static HalPropValue invokeRetriable(RetriableAction action,
        String operation, HalPropValue requestValue, long maxDurationForRetryMs,
        long sleepBetweenRetryMs, int maxRetries)
        throws ServiceSpecificException, IllegalArgumentException {
    Retrier retrier = new Retrier(action, operation, requestValue, maxDurationForRetryMs,
            sleepBetweenRetryMs, maxRetries);
    HalPropValue result = retrier.invokeAction();
    ...
    return result;
}

,传入的参数包括lambda形式的action,对应的value以及与重试相关的参数,并调用了retrier.invokeAction方法:

HalPropValue invokeAction()
        throws ServiceSpecificException, IllegalArgumentException {
    mRetryCount++;
    try {
        return mAction.run(mRequestValue);
    }
    ...
}

,调用了lambda表达式中定义的run方法,最终调用了mVehicleStub.get方法

获取Property从VehicleStub到VHAL的步骤

sequenceDiagram
participant VehicleHal
participant AVS as AidlVehicleStub
participant Pool as PendingSyncRequestPool
participant H as AsyncRequestsHandler
participant GSVC as GetSetValuesCallback
participant VHAL

VehicleHal->>+AVS: get
AVS->>+AVS: getOrSetSync
AVS->>+Pool:addRequest
Pool-->>- AVS: AndroidFuture
AVS-->>+H: sendRequestToVhal
H-->>+VHAL: getValues
par VHAL中获取值并调用callback
VHAL->>+GSVC: onGetValues
deactivate VHAL
GSVC->>+GSVC: onGetSetValues
GSVC->>+GSVC: completePendingSyncRequestLocked
GSVC->>+Pool: finishRequestIfFound
Pool-->>-GSVC: AndroidFuture
create participant AndroidFuture
GSVC-->>AndroidFuture: commit
deactivate GSVC
deactivate GSVC
and AidlVehicleStub同步获取结果
AVS->>AndroidFuture: get
AndroidFuture->>AndroidFuture: 等待commit
AndroidFuture-->>AVS: HalPropValue
end
destroy AndroidFuture

第6步 执行AidlVehicleStub::get方法:

public HalPropValue get(HalPropValue requestedPropValue)
        throws RemoteException, ServiceSpecificException {
    long currentTime = System.currentTimeMillis();
    HalPropValue halPropValue = getOrSetSync(requestedPropValue,
            mPendingSyncGetValueRequestPool, new AsyncGetRequestsHandler(),
            (result) -> {
                ... 
                return mPropValueBuilder.build(result.prop);
            });
    ...
    return halPropValue;
}

,调用了getOrSetSync方法:

private <VhalResultType> HalPropValue getOrSetSync(
        HalPropValue requestedPropValue,
        PendingSyncRequestPool<VhalResultType> pendingSyncRequestPool,
        AsyncRequestsHandler requestsHandler,
        Function<VhalResultType, HalPropValue> resultHandler)
        throws RemoteException, ServiceSpecificException {
    ...
    long vhalRequestId = mRequestId.getAndIncrement();

    //异步调用
    AndroidFuture<VhalResultType> resultFuture = pendingSyncRequestPool.addRequest(
            vhalRequestId);

    requestsHandler.allocateVhalRequestSize(1);
    requestsHandler.addVhalRequest(vhalRequestId, requestedPropValue);
    requestsHandler.sendRequestsToVhal(mAidlVehicle, mGetSetValuesCallback);

    boolean gotResult = false;

    //同步获取异步调用的结果
    try {
        ...
        VhalResultType result = resultFuture.get(mSyncOpTimeoutInMs,
                TimeUnit.MILLISECONDS);
        gotResult = true;
        return resultHandler.apply(result);
    } 
    ...
}

,方法通过requestsHandler向VHAL发送一个异步请求,并通过resultFuture.get这个同步方法获取结果并返回,在向VHAL发送一个异步请求时,传入了一个mGetSetValuesCallback,查看其定义:

...
private final GetSetValuesCallback mGetSetValuesCallback;
...
mGetSetValuesCallback = new GetSetValuesCallback();
...
private final class GetSetValuesCallback extends IVehicleCallback.Stub {

    @Override
    public void onGetValues(GetValueResults responses) throws RemoteException {
        AidlVehicleStub.this.onGetValues(responses);
    }
    ...
}

,VHAL在执行完获取property值的操作后会调用这个callback的onGetValues方法

第7步 执行requestHandler.sendRequestToVhal方法,根据第6步传入的参数,可以看到requestHandlerAsyncGetRequestHandler的实例:

public void sendRequestsToVhal(IVehicle iVehicle, GetSetValuesCallback callbackForVhal)
        throws RemoteException, ServiceSpecificException {
    ...
    GetValueRequests largeParcelableRequest = new GetValueRequests();
    largeParcelableRequest.payloads = mVhalRequestItems;
    largeParcelableRequest = (GetValueRequests) LargeParcelable.toLargeParcelable(
            largeParcelableRequest, () -> {
                GetValueRequests newRequests = new GetValueRequests();
                newRequests.payloads = new GetValueRequest[0];
                return newRequests;
    });

    try {
        ...
        iVehicle.getValues(callbackForVhal, largeParcelableRequest);
    } finally {
        LargeParcelable.closeFd(largeParcelableRequest.sharedMemoryFd);
        ...
    }
}

,通过binder调用了VHAL层的getValues方法

第8步 VHAL在执行完获取property值的操作后通过binder调用callback的onGetValues方法:

private void onGetValues(GetValueResults responses) {
    GetValueResults origResponses = (GetValueResults)
            LargeParcelable.reconstructStableAIDLParcelable(responses,
                    /* keepSharedMemory= */ false);
    ...
    onGetSetValues(origResponses.payloads, new AsyncGetResultsHandler(mPropValueBuilder),
            mPendingSyncGetValueRequestPool);
}

,调用了onGetSetValues方法

第9步 执行onGetSetValues方法:

private <VhalResultType> void onGetSetValues(VhalResultType[] vhalResults,
        AsyncResultsHandler asyncResultsHandler,
        PendingSyncRequestPool<VhalResultType> pendingSyncRequestPool) {
    synchronized (mLock) {
        for (VhalResultType result : vhalResults) {
            long vhalRequestId = asyncResultsHandler.getVhalRequestId(result);
            //由于是同步调用,于是mPendingAsyncRequestPool不存在该条requestId
            if (!mPendingAsyncRequestPool.contains(vhalRequestId)) {
                    completePendingSyncRequestLocked(pendingSyncRequestPool, vhalRequestId, result);
                    continue;
            }
            ...
        }
    }
}

第10步 这一步执行completePendingSyncRequestLocked方法:

private <VhalResultType> void completePendingSyncRequestLocked(
        PendingSyncRequestPool<VhalResultType> pendingSyncRequestPool, long vhalRequestId,
        VhalResultType result) {
    ...
    AndroidFuture<VhalResultType> pendingRequest =
            pendingSyncRequestPool.finishRequestIfFound(vhalRequestId);
    ...
    pendingRequest.complete(result);
    ...
}

,这一步首先调用finishRequestIfFound方法,设置相应的requestId的状态为执行完毕

第11步 执行finishRequestIfFound方法:

@Nullable AndroidFuture<VhalResultType> finishRequestIfFound(long vhalRequestId) {
    synchronized (mSyncRequestPoolLock) {
        AndroidFuture<VhalResultType> pendingRequest =
                mPendingRequestsByVhalRequestId.get(vhalRequestId);
        mPendingRequestsByVhalRequestId.remove(vhalRequestId);
        return pendingRequest;
    }
}

,这一步会从mPendingRequestsByVhalRequestId移除相应的key并返回一个AndroidFuture

第12步 这一步通过AndroidFuturecomplete方法设置result

第9步 在执行完sendRequestToVhal方法后,调用了resultFuture.get方法用来同步获取result

设置Property

第1步 执行setProperty方法:

public <E> void setProperty(@NonNull Class<E> clazz, int propertyId, int areaId,
        @NonNull E val) {
    ...
    try {
        runSyncOperation(() -> {
            mService.setProperty(new CarPropertyValue<>(propertyId, areaId, val),
                    mCarPropertyEventToService);
            return null;
        });
    }
    ...
}

订阅Property

要订阅CarProperty属性,需要实现一个CarPropertyEventCallback接口的实例:

private final CarPropertyManager.CarPropertyEventCallback XXX = new CarPropertyManager.CarPropertyEventCallback() {
    @Override
    public void onChangeEvent(CarPropertyValue carPropertyValue) {
        ...
    }
};

,其中定义了一个回调函数onChangeEvent,用于根据改变后的Property值进行相应的操作

下图展示了订阅Property事件所使用的类与一些成员对象:

arch

注册call back

时序图

sequenceDiagram
autonumber
participant someMethod
participant CPM as CarPropertyManager
participant CPS as CarPropertyService
participant PHS as PropertyHalService
Participant VH as VehicleHal
Participant SC as AidlVehicleStub.AidlSubscriptionClient
Participant VHAL

someMethod ->> CPM : subscribePropertyEvents
activate CPM
CPM->>CPM: subscribePropertyEventsInternal
activate CPM
CPM->>CPM: applySubscriptionChangesLocked
activate CPM
CPM->>CPM: registerLocked
activate CPM
CPM->> CPS: registerListener 
Note over CPM, CPS: binder
deactivate CPM
deactivate CPM
deactivate CPM
deactivate CPM
activate CPS
CPS->>CPS: applyStagedChangesLocked;
activate CPS
CPS->>PHS: subscribeProperty
deactivate CPS
deactivate CPS
activate PHS
PHS->>PHS: updateSubscriptionRateLocked
activate PHS
PHS->>VH: subscribeProperty
deactivate PHS
deactivate PHS
activate VH
VH->>SC: subscribeProperty
activate SC
deactivate VH
SC->>VHAL: subscribeProperty
Note over SC, VHAL : binder
deactivate SC

详细步骤

第1步 一个车辆设置的方法中使用subscribePropertyEvents方法注册一个callback,通常包含下述四种方法:

//不指定area id,不指定update rate
public boolean subscribePropertyEvents(int propertyId,
        @NonNull CarPropertyEventCallback carPropertyEventCallback) {
    return subscribePropertyEvents(List.of(
            new Subscription.Builder(propertyId).setUpdateRateHz(DEFAULT_UPDATE_RATE_HZ)
            .build()), /* callbackExecutor= */ null, carPropertyEventCallback);
}

//不指定area id,指定update rate
public boolean subscribePropertyEvents(int propertyId,
        @FloatRange(from = 0.0, to = 100.0) float updateRateHz,
        @NonNull CarPropertyEventCallback carPropertyEventCallback) {
    return subscribePropertyEvents(List.of(
            new Subscription.Builder(propertyId).setUpdateRateHz(updateRateHz).build()),
            /* callbackExecutor= */ null, carPropertyEventCallback);
}

//指定area id,不指定update rate
public boolean subscribePropertyEvents(int propertyId, int areaId,
        @NonNull CarPropertyEventCallback carPropertyEventCallback) {
    return subscribePropertyEvents(List.of(
            new Subscription.Builder(propertyId).addAreaId(areaId).setUpdateRateHz(1f)
                    .build()),
            /* callbackExecutor= */ null, carPropertyEventCallback);
}

//指定area id,指定update rate
public boolean subscribePropertyEvents(int propertyId, int areaId,
        @FloatRange(from = 0.0, to = 100.0) float updateRateHz,
        @NonNull CarPropertyEventCallback carPropertyEventCallback) {
    Subscription subscription = new Subscription.Builder(propertyId).addAreaId(areaId)
            .setUpdateRateHz(updateRateHz).build();
    return subscribePropertyEvents(List.of(subscription), /* callbackExecutor= */ null,
            carPropertyEventCallback);
}

,一些参数的含义如下表: |参数| |含义| |-|-|-| |propertyId|必选|需要监听的属性id| |areaId|可选|车辆区域id| |updateRateHz|可选,不选时设置为默认值|监听的频率| |carPropertyEventCallback|必选|监听的回调入口|

,无论是哪种方法,最终都会被构造成一个Subscription类的实例,并调用下面的subscribePropertyEvents方法:

public boolean subscribePropertyEvents(@NonNull List<Subscription> subscriptions,
        @Nullable @CallbackExecutor Executor callbackExecutor,
        @NonNull CarPropertyEventCallback carPropertyEventCallback) {
    requireNonNull(subscriptions);
    List<CarSubscription> subscribeOptions = convertToCarSubscribeOptions(subscriptions);
    return subscribePropertyEventsInternal(subscribeOptions, callbackExecutor,
            carPropertyEventCallback);
}

在上述方法中,首先会调用convertToCarSubscirbeOptions方法,将Subcription转化成CarSubscription

private List<CarSubscription> convertToCarSubscribeOptions(List<Subscription> subscriptions) {
    List<CarSubscription> carSubscribeOptions = new ArrayList<>();
    for (int i = 0; i < subscriptions.size(); i++) {
        Subscription clientOption = subscriptions.get(i);
        CarSubscription internalOption = new CarSubscription();
        internalOption.propertyId = clientOption.getPropertyId();
        internalOption.areaIds = clientOption.getAreaIds();
        internalOption.updateRateHz = clientOption.getUpdateRateHz();
        internalOption.enableVariableUpdateRate = clientOption.isVariableUpdateRateEnabled();
        internalOption.resolution = clientOption.getResolution();
        carSubscribeOptions.add(internalOption);
    }
    return carSubscribeOptions;
}

,在执行完convertToCarSubscripbeOptions方法后,调用subscribePropertyEventsInternal方法

第2步 执行subscribePropertyEventsInternal方法:

private boolean subscribePropertyEventsInternal(List<CarSubscription> subscribeOptions,
        @Nullable @CallbackExecutor Executor callbackExecutor,
        CarPropertyEventCallback carPropertyEventCallback) {
    ...

    //初始化回调函数的Executor,若为空则设置为Car car的main executor
    if (callbackExecutor == null) {
        callbackExecutor = mExecutor;
    }

    List<CarSubscription> sanitizedSubscribeOptions;

    ...

    List<CarSubscription> updatedSubscribeOptions;

    synchronized (mLock) {

        CarPropertyEventCallbackController cpeCallbackController =
                mCpeCallbackToCpeCallbackController.get(carPropertyEventCallback);
        ...

        mSubscriptionManager.stageNewOptions(carPropertyEventCallback, sanitizedSubscribeOptions);
        /**
         * 这一步向CarPropertyService注册carPropertyEventCallback
         **/
        var maybeUpdatedCarSubscriptions = applySubscriptionChangesLocked();
        ...
        updatedSubscribeOptions = maybeUpdatedCarSubscriptions.get();

        //给callback指定一个controller
        if (cpeCallbackController == null) {
            cpeCallbackController =
                    new CarPropertyEventCallbackController(carPropertyEventCallback,
                            callbackExecutor);
            mCpeCallbackToCpeCallbackController.put(carPropertyEventCallback,
                    cpeCallbackController);
        }

        //向controller中添加要监听的property
        for (int i = 0; i < sanitizedSubscribeOptions.size(); i++) {
            CarSubscription option = sanitizedSubscribeOptions.get(i);
            int propertyId = option.propertyId;
            float sanitizedUpdateRateHz = option.updateRateHz;
            int[] areaIds = option.areaIds;

            //如果监听类型是变化时回调
            if (sanitizedUpdateRateHz == 0) {
                cpeCallbackController.addOnChangeProperty(propertyId, areaIds);
            } else {
            //如果监听类型是定时回调
                cpeCallbackController.addContinuousProperty(propertyId, areaIds,
                        sanitizedUpdateRateHz, option.enableVariableUpdateRate,
                        option.resolution);
            }
            //添加controller到Property的controller set中
            ArraySet<CarPropertyEventCallbackController> cpeCallbackControllerSet =
                    mPropIdToCpeCallbackControllerList.get(propertyId);
            if (cpeCallbackControllerSet == null) {
                cpeCallbackControllerSet = new ArraySet<>();
                mPropIdToCpeCallbackControllerList.put(propertyId, cpeCallbackControllerSet);
            }
            cpeCallbackControllerSet.add(cpeCallbackController);
        }
    }
    ...
    return true;
}

方法主要完成如下动作:

  • 设置回调的执行线程池
  • 创建一个CarPropertyEventCallbackController,指定对应的call back,对controller进行设置并加入到相应的map或者set中
  • 调用applySubscriptionChangesLocked方法向CarPropertyService中注册call back

CarPropertyManager,维护了两个map,分别是mCpeCallbackToCpeCallbackControllermPropIdToCpeCallbackControllerList

cpe map

如上图所示,mCpeCallbackToCpeCallbackController保存了call back到controller的映射关系,以CarPropertyEventCallback为入口,映射为一个CarPropertyCallbackController对象

mPropIdToCpeCallbackControllerList保存了propertyIdcpeCallbackControllerSet的映射,而cpeCallbackControllerSet是一个ArraySet类的实例,其中保存了不同的CarPropertyEventCallbackController对象

第3步 执行applySubscriptionChangesLocked方法:

@GuardedBy("mLock")
private Optional<List<CarSubscription>> applySubscriptionChangesLocked() {
    List<CarSubscription> updatedCarSubscriptions = new ArrayList<>();
    List<Integer> propertiesToUnsubscribe = new ArrayList<>();

    mSubscriptionManager.diffBetweenCurrentAndStage(updatedCarSubscriptions,
            propertiesToUnsubscribe);

    ...

    try {
        //需要注册的subscription
        if (!updatedCarSubscriptions.isEmpty()) {
            if (!registerLocked(updatedCarSubscriptions)) {
                ...
                mSubscriptionManager.dropCommit();
                return Optional.empty();
            }
        }

        ...
    } 
    ...

    mSubscriptionManager.commit();
    return Optional.of(updatedCarSubscriptions);
}

,调用了registerLocked方法

第4步,调用registerLocked方法,该方法通过binder调用CarPropertyServiceregisterListener方法

private boolean registerLocked(List<CarSubscription> options) {
    try {
        mService.registerListener(options, mCarPropertyEventToService);
    } 
    ...
}

,方法向CarPropertyService注册了一个mCarPropertyEventToService对象,其定义如下:

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

    CarPropertyEventListenerToService(CarPropertyManager carPropertyManager) {
        mCarPropertyManager = new WeakReference<>(carPropertyManager);
    }

    @Override
    public void onEvent(List<CarPropertyEvent> carPropertyEvents) throws RemoteException {
        CarPropertyManager carPropertyManager = mCarPropertyManager.get();
        if (carPropertyManager != null) {
            carPropertyManager.handleEvents(carPropertyEvents);
        }
    }
}

,可以看到,其继承了ICarPropertyEventListener.Stub,说明registerListener方法向CarPropertyService传递了一个binder对象

第5步 调用CarPropertyService::registerListener方法:

public void registerListener(List<CarSubscription> carSubscriptions,
        ICarPropertyEventListener carPropertyEventListener)
        throws IllegalArgumentException, ServiceSpecificException {
    ...
    List<CarSubscription> sanitizedOptions =
            validateAndSanitizeSubscriptions(carSubscriptions);
    CarPropertyServiceClient finalClient;
    synchronized (mLock) {
        //创建一个client对象
        CarPropertyServiceClient client = getOrCreateClientForBinderLocked(
                carPropertyEventListener);
        if (client == null) {
            return;
        }
        ...
        //写入stage
        mSubscriptionManager.stageNewOptions(client, sanitizedOptions);

        //stage写入current
        try {
            applyStagedChangesLocked();
        } 
        ...
        mSubscriptionManager.commit();
        //设置client监听的property
        for (int i = 0; i < sanitizedOptions.size(); i++) {
            CarSubscription option = sanitizedOptions.get(i);
            if (option.updateRateHz != 0) {
                client.addContinuousProperty(
                        option.propertyId, option.areaIds, option.updateRateHz,
                        option.enableVariableUpdateRate, option.resolution);
            } else {
                client.addOnChangeProperty(option.propertyId, option.areaIds);
            }
        }
        finalClient = client;
    }
    ...
}

,在方法中,创建了一个CarPropertyServiceClient对象与传入的carPropertyEventListener对应 ,在CarPropertyService中,存在一个map:mClientMap,保存了carPropertyEventListener.mRemoteCarPropertyServiceClient的映射 client map

第6步 执行applyStagedChangesLocked方法:

void applyStagedChangesLocked() throws ServiceSpecificException {
    List<CarSubscription> filteredSubscriptions = new ArrayList<>();
    List<Integer> propertyIdsToUnsubscribe = new ArrayList<>();
    mSubscriptionManager.diffBetweenCurrentAndStage(/* out */ filteredSubscriptions,
            /* out */ propertyIdsToUnsubscribe);
    ...
    if (!filteredSubscriptions.isEmpty()) {
        try {
            mPropertyHalService.subscribeProperty(filteredSubscriptions);
        } 
        ...
    }
    ...
}

,调用了PropertyHalService::susbscribeProperty方法

第7步 执行PropertyHalService::susbscribeProperty方法:

public void subscribeProperty(List<CarSubscription> carSubscriptions)
        throws ServiceSpecificException {
    synchronized (mLock) {
        for (int i = 0; i < carSubscriptions.size(); i++) {
            ...
            mSubManager.stageNewOptions(new ClientType(CAR_PROP_SVC_REQUEST_ID),
                    List.of(newCarSubscription(halPropId, areaIds, updateRateHz,
                    carSubscription.enableVariableUpdateRate, carSubscription.resolution)));
        }
        try {
            updateSubscriptionRateLocked();
        }
        ...
    }
}

,调用了updateSubscriptionRateLocked方法

第8步 执行updateSubscriptionRateLocked方法:

private void updateSubscriptionRateLocked() throws ServiceSpecificException {
    ArrayList<CarSubscription> diffSubscribeOptions = new ArrayList<>();
    List<Integer> propIdsToUnsubscribe = new ArrayList<>();
    mSubManager.diffBetweenCurrentAndStage(diffSubscribeOptions, propIdsToUnsubscribe);
    try {
        if (!diffSubscribeOptions.isEmpty()) {
            ...
            mVehicleHal.subscribeProperty(this, toHalSubscribeOptions(diffSubscribeOptions));
        }
        ...
        mSubManager.commit();
    }
    ...
}

,调用了VehicleHal::subscribeProperty方法,传入的参数包含this,观察PropertyHalService的定义:

public class PropertyHalService extends HalServiceBase 

,继承了HalServiceBase

第9步 执行VehicleHal::subscribeProperty方法,方法创建了一个数组SubscribeOptions[] subscribeOptions用于记录监听选项

public void subscribeProperty(HalServiceBase service, List<HalSubscribeOptions>
        halSubscribeOptions) throws IllegalArgumentException, ServiceSpecificException {
    synchronized (mLock) {
        PairSparseArray<RateInfo> previousState = cloneState(mRateInfoByPropIdAreaId);
        SubscribeOptions[] subscribeOptions = createVhalSubscribeOptionsLocked(
                service, halSubscribeOptions);
        ...
        try {
            mSubscriptionClient.subscribe(subscribeOptions);
        }
        ...
    }
}

,然后调用了mSubscriptionClient.subscribe方法,mSubscriptionClient的定义与赋值语句如下:

private final SubscriptionClient mSubscriptionClient;
mVehicleStub = vehicle;
mSubscriptionClient = vehicle.newSubscriptionClient(this);

,传入的参数为this,观察VehicleHal的类定义:

public class VehicleHal implements VehicleHalCallback, CarSystemService

,可以看到,其实现了VehicleHalCallBack接口 ,SubscriptionClient类定义如下:

public abstract class VehicleStub {
    public interface SubscriptionClient {
        void subscribe(SubscribeOptions[] options) throws RemoteException, ServiceSpecificException;
        void unsubscribe(int prop) throws RemoteException, ServiceSpecificException;
        void registerSupportedValuesChange(List<PropIdAreaId> propIdAreaIds);
        void unregisterSupportedValuesChange(List<PropIdAreaId> propIdAreaIds);
    }
    ...
}

,如果使用AIDL与HAL层交互,则mVehicleStubAidlVehicleStub类的实例,有:

public SubscriptionClient newSubscriptionClient(VehicleHalCallback callback) {
    return new AidlSubscriptionClient(callback, mPropValueBuilder);
}

private class AidlSubscriptionClient extends IVehicleCallback.Stub
        implements SubscriptionClient {
    private final VehicleHalCallback mCallback;
    private final HalPropValueBuilder mBuilder;

    AidlSubscriptionClient(VehicleHalCallback callback, HalPropValueBuilder builder) {
        mCallback = callback;
        mBuilder = builder;
    }
    ...
}

,可以看到AidlSubscriptionClient继承了IVehicleCallback#Stub类,并实现了SubscriptionClient接口

第10步 执行AidlSubscriptionClient::subscribe方法,调用了mAidlVehicle.subscribe方法

public void subscribe(SubscribeOptions[] options)
        throws RemoteException, ServiceSpecificException {
    mAidlVehicle.subscribe(this, options, /* maxSharedMemoryFileCount= */ 2);
}

mAidlVehicle的定义如下:

private final IVehicle mAidlVehicle;

IVehicle为AIDL自动生成的接口,对应的AIDL定义如下:

interface IVehicle {
    const long INVALID_MEMORY_ID = 0;
    const int MAX_SHARED_MEMORY_FILES_PER_CLIENT = 3;
    ...
    void subscribe(in IVehicleCallback callback, in SubscribeOptions[] options,
            int maxSharedMemoryFileCount);
}

,说明使用binder调用了VHAL层的subscribe方法

VHAL

观察IVehicle.aidl内容:

interface IVehicle {
    void subscribe(in IVehicleCallback callback, in SubscribeOptions[] options,
            int maxSharedMemoryFileCount);
    ...
}

,其中定义了订阅property的接口。观察IVehicleCallback.aidl内容:

interface IVehicleCallback {
    oneway void onPropertyEvent(in VehiclePropValues propValues, int sharedMemoryFileCount);
    ...
}

,可以看到,其中定义了一个oneway的调用onPropertyEvent,用于返回执行callback方法

回调call back

在VHAL和car system service中的步骤

sequenceDiagram

participant CPL as CarPropertyEventListenerToService
participant CPSC as CarPropertyServiceClient
participant CPS as CarPropertyService
participant PHS as PropertyHalService
Participant VH as VehicleHal
Participant SC as AidlVehicleStub.AidlSubscriptionClient
Participant VHAL

note over SC, VHAL : binder
activate SC
VHAL->>SC: onPropertyEvent
activate VH
SC->>VH: onPropertyEvent
deactivate SC
activate VH
VH->>VH: handleOnPropertyEvent
activate PHS
VH->>PHS: onHalEvents
deactivate VH
deactivate VH
activate CPS
PHS->>CPS : onPropertyChange
deactivate PHS
activate CPSC
CPS->> CPSC: onEvents
deactivate CPS
activate CPSC 
CPSC->>CPSC: onFilteredEvents
activate CPL
CPSC->>CPL: onEvents
note over CPSC, CPL : binder
deactivate CPSC
deactivate CPSC

第1步 对于VHAL而言,AidlSubscriptionClient是一个实现了IVehicleCallback接口的远程binder对象,通过binder调用其onPropertyEvent方法:

public void onPropertyEvent(VehiclePropValues propValues, int sharedMemoryFileCount)
        throws RemoteException {
    VehiclePropValues origPropValues = (VehiclePropValues)
            LargeParcelable.reconstructStableAIDLParcelable(propValues,
                    /* keepSharedMemory= */ false);
    ArrayList<HalPropValue> values = new ArrayList<>(origPropValues.payloads.length);
    for (VehiclePropValue value : origPropValues.payloads) {
        values.add(mBuilder.build(value));
    }
    mCallback.onPropertyEvent(values);
}

,方法首先将VehiclePropValues转换成了HalPropValue的列表,然后调用了mCallback.onPropertyEvent方法

第2步 对于AidlSubscriptionClient而言,VehicleHal是一个VehicleHalCallback类型的对象mCallback,于是,执行其onPropertyEvent方法:

public void onPropertyEvent(ArrayList<HalPropValue> propValues) {
    mHandler.post(() -> handleOnPropertyEvent(propValues));
}

,通过handler线程的looper执行handleOnPropertyEvent方法

第3步 执行handleOnPropertyEvent方法:

private void handleOnPropertyEvent(List<HalPropValue> propValues) {
    synchronized (mLock) {
        //将service需要接收的property value加入到service的dispatch list中
        //将需要通知的service加入到mServicesToDispatch列表
        for (int i = 0; i < propValues.size(); i++) {
            HalPropValue v = propValues.get(i);
            int propId = v.getPropId();
            HalServiceBase service = mPropertyHandlers.get(propId);
            ...
            service.getDispatchList().add(v);
            mServicesToDispatch.add(service);
            ...
        }
    }
    //回调service的onHalEvents方法,并清空对应的dispatch list
    for (HalServiceBase s : mServicesToDispatch) {
        s.onHalEvents(s.getDispatchList());
        s.getDispatchList().clear();
    }
    //清空 mServicesToDispatch
    mServicesToDispatch.clear();
}

,可以看到,方法从mPropertyHandlers中获取了propertyId对应的HalServiceBase,并将property的新值放入到其dispatch list中,查看mPropertyHandlers的定义:

private final SparseArray<HalServiceBase> mPropertyHandlers = new SparseArray<>();

,可以看到其是一个SpraseArray类型的对象,存储了propertyIdHalServiceBase的映射。然后,方法会调用每个HalServiceBaseonHalEvents方法进行回调,并对dispatch list 和 mServicesToDispatch进行清空

第4步对于VehicleHal而言,PropertyHalService是一个HalServiceBase的实例,执行其onHalEvents方法:

public void onHalEvents(List<HalPropValue> halPropValues) {

    List<CarPropertyEvent> eventsToDispatch = new ArrayList<>();

    ...
    Map<VehicleStubCallback, List<GetSetValueResultWrapper>> callbackToSetValueResults =
            new ArrayMap<>();

    synchronized (mLock) {
        for (HalPropValue halPropValue : halPropValues) {
            ...
            //获取propId并从hal的propId转换为manager的propId
            int halPropId = halPropValue.getPropId();
            ...
            int mgrPropId = halToManagerPropId(halPropId);
            ...
            try {
                //将halPropertyValue转换为carPropertyValue
                CarPropertyValue<?> carPropertyValue = halPropValue.toCarPropertyValue(
                        mgrPropId, halPropConfig);
                //创建一个Event对象
                CarPropertyEvent carPropertyEvent = new CarPropertyEvent(
                        CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE, carPropertyValue);
                eventsToDispatch.add(carPropertyEvent);
                ...
            }
            ...
        }
        ...
    }

    PropertyHalListener propertyHalListener;
    synchronized (mLock) {
        propertyHalListener = mPropertyHalListener;
    }
    //执行回调
    if (propertyHalListener != null) {
        propertyHalListener.onPropertyChange(eventsToDispatch);
    }
    ...
}

,将VHAL的property转换为对应的Car property并调用propertyHalListener.onPropertyChange方法执行回调,其中propertyHalListenermPropertyHalListener为同一引用,都指向了CarPropertyServicePropertyHalService视其为PropertyHalListener的一个实例)

第5步 执行onPropertyChange方法:

public void onPropertyChange(List<CarPropertyEvent> events) {
    Map<CarPropertyServiceClient, List<CarPropertyEvent>> eventsToDispatch = new ArrayMap<>();
    synchronized (mLock) {
        for (int i = 0; i < events.size(); i++) {
            CarPropertyEvent event = events.get(i);
            int propId = event.getCarPropertyValue().getPropertyId();
            int areaId = event.getCarPropertyValue().getAreaId();

            //获取与(propId, areaId)对应的CarPropertyServiceCLient实例
            Set<CarPropertyServiceClient> clients = mSubscriptionManager.getClients(
                    propId, areaId);
            ...
            //将CarPropertyServiceCLient实例与event列表的对应关系保存到eventsToDispatch中
            for (CarPropertyServiceClient client : clients) {
                List<CarPropertyEvent> eventsForClient = eventsToDispatch.get(client);
                if (eventsForClient == null) {
                    eventsToDispatch.put(client, new ArrayList<CarPropertyEvent>());
                }
                eventsToDispatch.get(client).add(event);
            }
        }
    }
    //执行回调
    for (CarPropertyServiceClient client : eventsToDispatch.keySet()) {
        try {
            client.onEvent(eventsToDispatch.get(client));
        }
        ...
    }
}

,获取(propId, areaId)对应的CarPropertyServiceClient后,将event与client的对应关系存储到一个map中,然后调用client.onEvent方法执行回调

第6步 执行CarPropertyServiceClient::onEvent方法:

public void onEvent(List<CarPropertyEvent> events) throws RemoteException {
    List<CarPropertyEvent> filteredEvents = new ArrayList<>();
    ...
    onFilteredEvents(filteredEvents);
}

,调用了onFilteredEvents方法

第7步 执行onFilteredEvents方法:

public void onFilteredEvents(List<CarPropertyEvent> events) throws RemoteException {
    if (!events.isEmpty()) {
        mListener.onEvent(events);
    }
}

mListener保存了对CarPropertyManagermCarPropertyToService的binder引用,通过binder调用了其onEvent方法

在CarPropertyManager中的步骤

sequenceDiagram
participant CPEC as CarPropertyEventCallback
participant CECC as CarPropertyEventCallbackController
participant Handler as SingleMessageHandler
participant CPM as CarPropertyManager
participant CPL as CarPropertyEventListenerToService
participant CPSC as CarPropertyServiceClient

activate CPL
CPSC->>CPL: onEvents
activate CPM
CPL->>CPM: handleEvents
alt 在binder线程中执行
activate Handler
CPM->>Handler: sendEvents
activate CPM
Handler->>CPM: handleOnPropertyEvents
deactivate Handler
else
activate CPM
CPM->>CPM:handleOnPropertyEvents
end
activate CPM 
CPM->>CPM: dispatchToClients
activate CECC
CPM->>CECC: onEvent
deactivate CPM
deactivate CPM
deactivate CPM
CECC ->> CPEC: onChangeEvent
deactivate CECC

第8步 执行CarPropertyManager#CarPropertyEventListenerToService::onEvent方法:

public void onEvent(List<CarPropertyEvent> carPropertyEvents) throws RemoteException {
    CarPropertyManager carPropertyManager = mCarPropertyManager.get();
    if (carPropertyManager != null) {
        carPropertyManager.handleEvents(carPropertyEvents);
    }
}

,方法调用了CarPropertyManagerhandleEvents方法

第9步 执行handleEvents方法:

private void handleEvents(List<CarPropertyEvent> carPropertyEvents) {
    if (mHandler == null) {
        ...
        return;
    }
    if (mFeatureFlags.handlePropertyEventsInBinderThread()) {
        handleCarPropertyEvents(carPropertyEvents);
    } else {
        mHandler.sendEvents(carPropertyEvents);
    }
}

,分为两种情况,如果设置在binder线程中执行回调,则直接调用handleCarPropertyEvents方法,否则,执行mHandler.sendEvents发送事件

第10步 观察mHandler的定义:

mHandler = new SingleMessageHandler<>(eventHandler.getLooper(), MSG_GENERIC_EVENT) {
    @Override
    protected void handleEvent(CarPropertyEvent carPropertyEvent) {
        handleCarPropertyEvents(List.of(carPropertyEvent));
    }
};

,可以看到其最终也调用到了handleCarProperyEvents方法:

private void handleCarPropertyEvents(List<CarPropertyEvent> carPropertyEvents) {
    SparseArray<List<CarPropertyEvent>> carPropertyEventsByPropertyId = new SparseArray<>();
    ...

    var eventsDispatchList = new EventDispatchList();


    //根据property id将CarPropertyEventCallbackController与event集合对应起来,并加入到`eventsDispatchList`中
    synchronized (mLock) {
        for (int i = 0; i < carPropertyEventsByPropertyId.size(); i++) {
            int propertyId = carPropertyEventsByPropertyId.keyAt(i);
            List<CarPropertyEvent> eventsForPropertyId =
                    carPropertyEventsByPropertyId.valueAt(i);
            ArraySet<CarPropertyEventCallbackController> cpeCallbackControllerSet =
                    mPropIdToCpeCallbackControllerList.get(propertyId);
            if (cpeCallbackControllerSet == null) {
                ...
                return;
            }
            for (int j = 0; j < cpeCallbackControllerSet.size(); j++) {
                var callback = cpeCallbackControllerSet.valueAt(j);
                eventsDispatchList.addEvents(callback, eventsForPropertyId);
            }
        }
    }

    ...
    //执行回调
    eventsDispatchList.dispatchToClients();
}

,并调用了EventDispatchList::dispatchToClients方法

第11步 执行dispatchToClients方法:

public void dispatchToClients() {
    for (int i = 0; i < mEventsByClient.size(); i++) {
        ...
        dispatchToClient(mEventsByClient.keyAt(i), mEventsByClient.valueAt(i));
    }
    mEventsByClient.clear();
}

,调用了另一个dispatchToClient方法:

private static class EventDispatchList extends
        DispatchList<CarPropertyEventCallbackController, CarPropertyEvent> {
    @Override
    protected void dispatchToClient(CarPropertyEventCallbackController client,
            List<CarPropertyEvent> events) {
        for (int j = 0; j < events.size(); j++) {
            client.onEvent(events.get(j));
        }
    }
}

,调用了CarPropertyEventCallbackControlleronEvent方法

第12步 执行CarPropertyEventCallbackControlleronEvent方法:

public void onEvent(CarPropertyEvent carPropertyEvent) {
    ...
    CarPropertyEvent updatedCarPropertyEvent;
    ...
    switch (updatedCarPropertyEvent.getEventType()) {
        case CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE:
            mExecutor.execute(() -> mCarPropertyEventCallback.onChangeEvent(carPropertyValue));
            break;
        case CarPropertyEvent.PROPERTY_EVENT_ERROR:
            ...
        default:
            ...
    }
}

,可以看到,在这一步中,通过在注册call back时设置的回调函数执行线程池mExecutor执行CarPropertyEventCallbackonChangeEvent方法

SubscriptionManager:Property订阅管理(API $\geq$ 35)

结合上述流程可以看到,在CarPropertyManagerCarPropertySerivcePropertyHalService中,都使用了SubscriptionManager,用于管理Property订阅的状态,使用的流程如下:

flowchart LR
A[stageNewOptions]-->B[使用diffBetweenCurrentAndStage获取新的订阅和需要取消的订阅]-->D[执行订阅更新的操作]-->C[commit]

SubscriptionManager中,定义了两个map和一个set:

public final class SubscriptionManager<ClientType> {
    ...
    PairSparseArray<RateInfoForClients<ClientType>> mCurrentRateInfoByClientByPropIdAreaId =
        new PairSparseArray<>();
    PairSparseArray<RateInfoForClients<ClientType>> mStagedRateInfoByClientByPropIdAreaId =
        new PairSparseArray<>();
    ArraySet<int[]> mStagedAffectedPropIdAreaIds = new ArraySet<>();
    ...
}

,其中,mCurrentRateInfoByClientByPropIdAreaIdmStagedRateInfoByClientByPropIdAreaId记录了ProperId & areaIdRateInfoForClients的映射关系,RateInfoClients的定义如下:

private static final class RateInfoForClients<ClientType> {
    private final ArrayMap<ClientType, RateInfo> mRateInfoByClient;
    private final TreeSet<Float> mUpdateRatesHz;
    private final ArrayMap<Float, Integer> mClientCountByUpdateRateHz;
    private final TreeSet<Float> mResolutions;
    private final ArrayMap<Float, Integer> mClientCountByResolution;
    ...
}

,通过一个map映射了ClientTypeRateInfo,一个map记录了不同频率下的ClientType数,一个map记录了不同resolution下的ClientType数,并使用两个Treeset记录了不同的频率和resolution

subscription manager

stageNewOptions

public void stageNewOptions(ClientType client, List<CarSubscription> options) {
    cloneCurrentToStageIfClean();
    for (int i = 0; i < options.size(); i++) {
        CarSubscription option = options.get(i);
        int propertyId = option.propertyId;
        for (int areaId : option.areaIds) {
            mStagedAffectedPropIdAreaIds.add(new int[]{propertyId, areaId});
            if (mStagedRateInfoByClientByPropIdAreaId.get(propertyId, areaId) == null) {
                mStagedRateInfoByClientByPropIdAreaId.put(propertyId, areaId,
                        new RateInfoForClients<>());
            }
            mStagedRateInfoByClientByPropIdAreaId.get(propertyId, areaId).add(
                    client, option.updateRateHz, option.enableVariableUpdateRate,
                    option.resolution);
        }
    }
}

,首先通过

private void cloneCurrentToStageIfClean() {
    if (!mStagedAffectedPropIdAreaIds.isEmpty()) {
        return;
    }

    mStagedRateInfoByClientByPropIdAreaId = new PairSparseArray<>();
    for (int i = 0; i < mCurrentRateInfoByClientByPropIdAreaId.size(); i++) {
        int[] keyPair = mCurrentRateInfoByClientByPropIdAreaId.keyPairAt(i);
        mStagedRateInfoByClientByPropIdAreaId.put(keyPair[0], keyPair[1],
                new RateInfoForClients<>(
                        mCurrentRateInfoByClientByPropIdAreaId.valueAt(i)));
    }
}

mCurrentRateInfoByClientByPropIdAreaId中的数据拷贝到空的mStagedRateInfoByClientByPropIdAreaId中,然后根据options中的内容插入到mStagedRateInfoByClientByPropIdAreaId

diffBetweenCurrentAndStage

public void diffBetweenCurrentAndStage(List<CarSubscription> outDiffSubscriptions,
        List<Integer> outPropertyIdsToUnsubscribe) {
    //如果没有staged则直接返回
    if (mStagedAffectedPropIdAreaIds.isEmpty()) {
        ...
        return;
    }
    ArraySet<Integer> possiblePropIdsToUnsubscribe = new ArraySet<>();
    PairSparseArray<RateInfo> diffRateInfoByPropIdAreaId = new PairSparseArray<>();
    for (int i = 0; i < mStagedAffectedPropIdAreaIds.size(); i++) {
        int[] propIdAreaId = mStagedAffectedPropIdAreaIds.valueAt(i);
        int propertyId = propIdAreaId[0];
        int areaId = propIdAreaId[1];

        //如果staged的map中没有记录(propertyId, areaId)对应的内容,则加入可能取消订阅的属性列表
        if (!mStagedRateInfoByClientByPropIdAreaId.contains(propertyId, areaId)) {
            ...
            possiblePropIdsToUnsubscribe.add(propertyId);
            continue;
        }

        RateInfo newCombinedRateInfo = mStagedRateInfoByClientByPropIdAreaId
                .get(propertyId, areaId).getCombinedRateInfo();

        //如果在current的map中没有记录(propertyId, areaId)对应的内容
        // 或者记录的rateInfo与staged中的rateInfo不同
        // 则是需要改变订阅状态的propertyId
        if (!mCurrentRateInfoByClientByPropIdAreaId.contains(propertyId, areaId)
                || !(mCurrentRateInfoByClientByPropIdAreaId
                        .get(propertyId, areaId).getCombinedRateInfo()
                        .equals(newCombinedRateInfo))) {
            ...
            diffRateInfoByPropIdAreaId.put(propertyId, areaId, newCombinedRateInfo);
            continue;
        }
    }
    outDiffSubscriptions.addAll(getCarSubscription(diffRateInfoByPropIdAreaId));
    //当且仅当一个propertyId下所有的areaId都被取消订阅,才取消对propertyId的订阅
    for (int i = 0; i < possiblePropIdsToUnsubscribe.size(); i++) {
        int possiblePropIdToUnsubscribe = possiblePropIdsToUnsubscribe.valueAt(i);
        if (mStagedRateInfoByClientByPropIdAreaId.getSecondKeysForFirstKey(
                possiblePropIdToUnsubscribe).isEmpty()) {
            ...
            outPropertyIdsToUnsubscribe.add(possiblePropIdToUnsubscribe);
        }
    }
}

方法diffBetweenCurrentAndStage用于比较currentstaged中的不同并更新两个列表:outDiffSubscriptionsoutPropertyIdsToUnsubscribe,前者用于记录需要改变订阅状态的propertyId,后者用于记录需要取消订阅的propertyId,相关的判断条件如下:

flowchart LR
subgraph 取消订阅
direction LR
    A["(propertyId, areaId)在mStagedAffectedPropIdAreaIds中不在mStagedRateInfoByClientByPropIdAreaId中"]-->B[" propertyId下的所有areaId都取消了订阅"]-->C["propertyId加入到outPropertyIdsToUnsubscribe中"]
end
subgraph 改变订阅
direction LR
    E["(propertyId, areaId)不在mCurrentRateInfoByClientByPropIdAreaId中"]-->F["包装成susbscription"]-->G["将subscription加入到outDiffSubscriptions中"]
    H["staged中的rateInfo与current中的不同"]-->F
end

commit 和 dropCommit

public void commit() {
    if (mStagedAffectedPropIdAreaIds.isEmpty()) {
        ...
        return;
    }
    mCurrentRateInfoByClientByPropIdAreaId = mStagedRateInfoByClientByPropIdAreaId;
    mStagedAffectedPropIdAreaIds.clear();
}

public void dropCommit() {
    if (mStagedAffectedPropIdAreaIds.isEmpty()) {
        ...
        return;
    }
    mStagedRateInfoByClientByPropIdAreaId = mCurrentRateInfoByClientByPropIdAreaId;
    mStagedAffectedPropIdAreaIds.clear();
}

commit方法将 mStagedRateInfoByClientByPropIdAreaId写入mCurrentRateInfoByClientByPropIdAreaId并清空mStagedAffectedPropIdAreaIds,相反,dropCommit方法将mCurrentRateInfoByClientByPropIdAreaId写入 mStagedRateInfoByClientByPropIdAreaId并清空mStagedAffectedPropIdAreaIds