Fix the flaky CarAppFocusManagerTest.
- AppFocusService is changing mFocusOwners in the main-thread at
requestAppFocus(), which can create the race-condition in the
consecutive abandonAppFocus() call.
Bug: 176244434
Test: atest android.car.cts.CarAppFocusManagerTest --iterations 100
Change-Id: I05642cad90277ea7f5c0f9e4666e115ce3bf61f0
diff --git a/service/src/com/android/car/AppFocusService.java b/service/src/com/android/car/AppFocusService.java
index 7c4c752..674d7ff 100644
--- a/service/src/com/android/car/AppFocusService.java
+++ b/service/src/com/android/car/AppFocusService.java
@@ -164,7 +164,8 @@
+ appType + "," + ownerInfo);
}
}
- updateFocusOwner(appType, info);
+ mFocusOwners.put(appType, info);
+ dispatchAcquireFocusOwnerLocked(appType, info, mFocusOwnershipCallbacks);
}
info.addOwnedAppType(appType);
mDispatchHandler.requestAppFocusOwnershipGrantDispatch(
@@ -214,9 +215,7 @@
if (DBG) {
Slog.i(CarLog.TAG_APP_FOCUS, "abandoning focus " + appType + "," + info);
}
- for (FocusOwnershipCallback ownershipCallback : mFocusOwnershipCallbacks) {
- ownershipCallback.onFocusAbandoned(appType, info.mUid, info.mPid);
- }
+ dispatchAbandonFocusOwnerLocked(appType, info, mFocusOwnershipCallbacks);
for (BinderInterfaceContainer.BinderInterface<IAppFocusListener> client :
mAllChangeClients.getInterfaces()) {
ClientInfo clientInfo = (ClientInfo) client;
@@ -323,17 +322,24 @@
}
}
- private void updateFocusOwner(int appType, OwnershipClientInfo owner) {
- CarServiceUtils.runOnMain(() -> {
- List<FocusOwnershipCallback> focusOwnershipCallbacks;
- synchronized (mLock) {
- mFocusOwners.put(appType, owner);
- focusOwnershipCallbacks = new ArrayList<>(mFocusOwnershipCallbacks);
- }
- for (FocusOwnershipCallback callback : focusOwnershipCallbacks) {
- callback.onFocusAcquired(appType, owner.getUid(), owner.getPid());
- }
- });
+ private void dispatchAcquireFocusOwnerLocked(int appType, OwnershipClientInfo owner,
+ List<FocusOwnershipCallback> focusOwnershipCallbacks) {
+ // Dispatches each callback separately, not to make the copy of mFocusOwnershipCallbacks.
+ for (int i = focusOwnershipCallbacks.size() - 1; i >= 0; --i) {
+ FocusOwnershipCallback callback = focusOwnershipCallbacks.get(i);
+ mDispatchHandler.post(
+ () -> callback.onFocusAcquired(appType, owner.getUid(), owner.getPid()));
+ }
+ }
+
+ private void dispatchAbandonFocusOwnerLocked(int appType, OwnershipClientInfo owner,
+ List<FocusOwnershipCallback> focusOwnershipCallbacks) {
+ // Dispatches each callback separately, not to make the copy of mFocusOwnershipCallbacks.
+ for (int i = focusOwnershipCallbacks.size() - 1; i >= 0; --i) {
+ FocusOwnershipCallback callback = focusOwnershipCallbacks.get(i);
+ mDispatchHandler.post(
+ () -> callback.onFocusAbandoned(appType, owner.getUid(), owner.getPid()));
+ }
}
private void dispatchAppFocusOwnershipLoss(IAppFocusOwnershipCallback callback, int appType) {