OSDN Git Service

Use RemoteCallbackList to store registered callbacks
authorMehdi Alizadeh <mett@google.com>
Sat, 15 Jun 2019 00:28:14 +0000 (17:28 -0700)
committerMehdi Alizadeh <mett@google.com>
Wed, 19 Jun 2019 22:35:25 +0000 (15:35 -0700)
Bug: 134680085
Test: Verified no errors in logcat while closing the ShareSheet
Test: Enable debug flag and verify the logs by killing the client and the servicer
Kill launcher: adb shell killall com.google.android.apps.nexuslauncher
Kill service: adb shell killall com.google.android.as

Change-Id: I706bd0f7224f24bd774ed009babc5f73e12629ca

services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java

index 10ba9a5..03c4542 100644 (file)
@@ -28,7 +28,7 @@ import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ParceledListSlice;
 import android.content.pm.ServiceInfo;
-import android.os.IBinder;
+import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.service.appprediction.AppPredictionService;
 import android.util.ArrayMap;
@@ -37,7 +37,7 @@ import android.util.Slog;
 import com.android.internal.annotations.GuardedBy;
 import com.android.server.infra.AbstractPerUserSystemService;
 
-import java.util.ArrayList;
+import java.util.function.Consumer;
 
 /**
  * Per-user instance of {@link AppPredictionManagerService}.
@@ -108,15 +108,10 @@ public class AppPredictionPerUserService extends
         if (service != null) {
             service.onCreatePredictionSession(context, sessionId);
 
-            mSessionInfos.put(sessionId, new AppPredictionSessionInfo(sessionId, context, () -> {
-                synchronized (mLock) {
-                    AppPredictionSessionInfo sessionInfo = mSessionInfos.get(sessionId);
-                    if (sessionInfo != null) {
-                        sessionInfo.removeAllCallbacksLocked();
-                        mSessionInfos.remove(sessionId);
-                    }
-                }
-            }));
+            if (!mSessionInfos.containsKey(sessionId)) {
+                mSessionInfos.put(sessionId, new AppPredictionSessionInfo(sessionId, context,
+                        this::removeAppPredictionSessionInfo));
+            }
         }
     }
 
@@ -212,8 +207,7 @@ public class AppPredictionPerUserService extends
 
             AppPredictionSessionInfo sessionInfo = mSessionInfos.get(sessionId);
             if (sessionInfo != null) {
-                sessionInfo.removeAllCallbacksLocked();
-                mSessionInfos.remove(sessionId);
+                sessionInfo.destroy();
             }
         }
     }
@@ -273,6 +267,15 @@ public class AppPredictionPerUserService extends
         }
     }
 
+    private void removeAppPredictionSessionInfo(AppPredictionSessionId sessionId) {
+        if (isDebug()) {
+            Slog.d(TAG, "removeAppPredictionSessionInfo(): sessionId=" + sessionId);
+        }
+        synchronized (mLock) {
+            mSessionInfos.remove(sessionId);
+        }
+    }
+
     @GuardedBy("mLock")
     @Nullable
     private RemoteAppPredictionService getRemoteServiceLocked() {
@@ -295,55 +298,71 @@ public class AppPredictionPerUserService extends
     }
 
     private static final class AppPredictionSessionInfo {
+        private static final boolean DEBUG = false;  // Do not submit with true
+
         private final AppPredictionSessionId mSessionId;
-        private final AppPredictionContext mContext;
-        private final ArrayList<IPredictionCallback> mCallbacks = new ArrayList<>();
-        private final IBinder.DeathRecipient mBinderDeathHandler;
+        private final AppPredictionContext mPredictionContext;
+        private final Consumer<AppPredictionSessionId> mRemoveSessionInfoAction;
+
+        private final RemoteCallbackList<IPredictionCallback> mCallbacks =
+                new RemoteCallbackList<IPredictionCallback>() {
+                    @Override
+                    public void onCallbackDied(IPredictionCallback callback) {
+                        if (DEBUG) {
+                            Slog.d(TAG, "Binder died for session Id=" + mSessionId
+                                    + " and callback=" + callback.asBinder());
+                        }
+                        if (mCallbacks.getRegisteredCallbackCount() == 0) {
+                            destroy();
+                        }
+                    }
+                };
 
-        AppPredictionSessionInfo(AppPredictionSessionId id, AppPredictionContext context,
-                IBinder.DeathRecipient binderDeathHandler) {
+        AppPredictionSessionInfo(AppPredictionSessionId id, AppPredictionContext predictionContext,
+                Consumer<AppPredictionSessionId> removeSessionInfoAction) {
+            if (DEBUG) {
+                Slog.d(TAG, "Creating AppPredictionSessionInfo for session Id=" + id);
+            }
             mSessionId = id;
-            mContext = context;
-            mBinderDeathHandler = binderDeathHandler;
+            mPredictionContext = predictionContext;
+            mRemoveSessionInfoAction = removeSessionInfoAction;
         }
 
         void addCallbackLocked(IPredictionCallback callback) {
-            if (mBinderDeathHandler != null) {
-                try {
-                    callback.asBinder().linkToDeath(mBinderDeathHandler, 0);
-                } catch (RemoteException e) {
-                    Slog.e(TAG, "Failed to link to death: " + e);
-                }
+            if (DEBUG) {
+                Slog.d(TAG, "Storing callback for session Id=" + mSessionId
+                        + " and callback=" + callback.asBinder());
             }
-            mCallbacks.add(callback);
+            mCallbacks.register(callback);
         }
 
         void removeCallbackLocked(IPredictionCallback callback) {
-            if (mBinderDeathHandler != null) {
-                callback.asBinder().unlinkToDeath(mBinderDeathHandler, 0);
+            if (DEBUG) {
+                Slog.d(TAG, "Removing callback for session Id=" + mSessionId
+                        + " and callback=" + callback.asBinder());
             }
-            mCallbacks.remove(callback);
+            mCallbacks.unregister(callback);
         }
 
-        void removeAllCallbacksLocked() {
-            if (mBinderDeathHandler != null) {
-                for (IPredictionCallback callback : mCallbacks) {
-                    callback.asBinder().unlinkToDeath(mBinderDeathHandler, 0);
-                }
+        void destroy() {
+            if (DEBUG) {
+                Slog.d(TAG, "Removing all callbacks for session Id=" + mSessionId
+                        + " and " + mCallbacks.getRegisteredCallbackCount() + " callbacks.");
             }
-            mCallbacks.clear();
+            mCallbacks.kill();
+            mRemoveSessionInfoAction.accept(mSessionId);
         }
 
         void resurrectSessionLocked(AppPredictionPerUserService service) {
-            if (service.isDebug()) {
+            int callbackCount = mCallbacks.getRegisteredCallbackCount();
+            if (DEBUG) {
                 Slog.d(TAG, "Resurrecting remote service (" + service.getRemoteServiceLocked()
                         + ") for session Id=" + mSessionId + " and "
-                        + mCallbacks.size() + " callbacks.");
-            }
-            service.onCreatePredictionSessionLocked(mContext, mSessionId);
-            for (IPredictionCallback callback : mCallbacks) {
-                service.registerPredictionUpdatesLocked(mSessionId, callback);
+                        + callbackCount + " callbacks.");
             }
+            service.onCreatePredictionSessionLocked(mPredictionContext, mSessionId);
+            mCallbacks.broadcast(
+                    callback -> service.registerPredictionUpdatesLocked(mSessionId, callback));
         }
     }
 }