Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 41c0c360 authored by Mehdi Alizadeh's avatar Mehdi Alizadeh Committed by android-build-merger
Browse files

Merge "Use RemoteCallbackList to store registered callbacks" into qt-dev am: 60f7b58a

am: b97947dc

Change-Id: I24476106afe4a48489db7758ca3990c2cdec6c32
parents cbe2ec23 b97947dc
Loading
Loading
Loading
Loading
+61 −42
Original line number Diff line number Diff line
@@ -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,16 +108,11 @@ 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));
        }
    }
}