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

Commit adf80b4a authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Automerger Merge Worker
Browse files

Merge "fix app prediction service doesn't clean-up properly." into rvc-qpr-dev...

Merge "fix app prediction service doesn't clean-up properly." into rvc-qpr-dev am: 4cb7d8c8 am: e548482d

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/12221409

Change-Id: I5ec77ed5785cd9ac1d2be7007bdff9cad94b0fb3
parents feb7f133 e548482d
Loading
Loading
Loading
Loading
+3 −1
Original line number Original line Diff line number Diff line
@@ -83,6 +83,8 @@ public final class AppPredictor {
    private final AppPredictionSessionId mSessionId;
    private final AppPredictionSessionId mSessionId;
    private final ArrayMap<Callback, CallbackWrapper> mRegisteredCallbacks = new ArrayMap<>();
    private final ArrayMap<Callback, CallbackWrapper> mRegisteredCallbacks = new ArrayMap<>();


    private final IBinder mToken = new Binder();

    /**
    /**
     * Creates a new Prediction client.
     * Creates a new Prediction client.
     * <p>
     * <p>
@@ -98,7 +100,7 @@ public final class AppPredictor {
        mSessionId = new AppPredictionSessionId(
        mSessionId = new AppPredictionSessionId(
                context.getPackageName() + ":" + UUID.randomUUID().toString(), context.getUserId());
                context.getPackageName() + ":" + UUID.randomUUID().toString(), context.getUserId());
        try {
        try {
            mPredictionManager.createPredictionSession(predictionContext, mSessionId);
            mPredictionManager.createPredictionSession(predictionContext, mSessionId, mToken);
        } catch (RemoteException e) {
        } catch (RemoteException e) {
            Log.e(TAG, "Failed to create predictor", e);
            Log.e(TAG, "Failed to create predictor", e);
            e.rethrowAsRuntimeException();
            e.rethrowAsRuntimeException();
+1 −1
Original line number Original line Diff line number Diff line
@@ -29,7 +29,7 @@ import android.content.pm.ParceledListSlice;
interface IPredictionManager {
interface IPredictionManager {


    void createPredictionSession(in AppPredictionContext context,
    void createPredictionSession(in AppPredictionContext context,
            in AppPredictionSessionId sessionId);
            in AppPredictionSessionId sessionId, in IBinder token);


    void notifyAppTargetEvent(in AppPredictionSessionId sessionId, in AppTargetEvent event);
    void notifyAppTargetEvent(in AppPredictionSessionId sessionId, in AppTargetEvent event);


+4 −3
Original line number Original line Diff line number Diff line
@@ -34,6 +34,7 @@ import android.app.prediction.IPredictionManager;
import android.content.Context;
import android.content.Context;
import android.content.pm.ParceledListSlice;
import android.content.pm.ParceledListSlice;
import android.os.Binder;
import android.os.Binder;
import android.os.IBinder;
import android.os.ResultReceiver;
import android.os.ResultReceiver;
import android.os.ShellCallback;
import android.os.ShellCallback;
import android.util.Slog;
import android.util.Slog;
@@ -108,9 +109,9 @@ public class AppPredictionManagerService extends


        @Override
        @Override
        public void createPredictionSession(@NonNull AppPredictionContext context,
        public void createPredictionSession(@NonNull AppPredictionContext context,
                @NonNull AppPredictionSessionId sessionId) {
                @NonNull AppPredictionSessionId sessionId, @NonNull IBinder token) {
            runForUserLocked("createPredictionSession", sessionId,
            runForUserLocked("createPredictionSession", sessionId, (service) ->
                    (service) -> service.onCreatePredictionSessionLocked(context, sessionId));
                    service.onCreatePredictionSessionLocked(context, sessionId, token));
        }
        }


        @Override
        @Override
+84 −51
Original line number Original line Diff line number Diff line
@@ -30,6 +30,7 @@ import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ParceledListSlice;
import android.content.pm.ParceledListSlice;
import android.content.pm.ServiceInfo;
import android.content.pm.ServiceInfo;
import android.os.IBinder;
import android.os.RemoteCallbackList;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.RemoteException;
import android.provider.DeviceConfig;
import android.provider.DeviceConfig;
@@ -44,8 +45,6 @@ import com.android.server.LocalServices;
import com.android.server.infra.AbstractPerUserSystemService;
import com.android.server.infra.AbstractPerUserSystemService;
import com.android.server.people.PeopleServiceInternal;
import com.android.server.people.PeopleServiceInternal;


import java.util.function.Consumer;

/**
/**
 * Per-user instance of {@link AppPredictionManagerService}.
 * Per-user instance of {@link AppPredictionManagerService}.
 */
 */
@@ -112,17 +111,24 @@ public class AppPredictionPerUserService extends
     */
     */
    @GuardedBy("mLock")
    @GuardedBy("mLock")
    public void onCreatePredictionSessionLocked(@NonNull AppPredictionContext context,
    public void onCreatePredictionSessionLocked(@NonNull AppPredictionContext context,
            @NonNull AppPredictionSessionId sessionId) {
            @NonNull AppPredictionSessionId sessionId, @NonNull IBinder token) {
        if (!mSessionInfos.containsKey(sessionId)) {
        final boolean usesPeopleService = DeviceConfig.getBoolean(NAMESPACE_SYSTEMUI,
            mSessionInfos.put(sessionId, new AppPredictionSessionInfo(sessionId, context,
                PREDICT_USING_PEOPLE_SERVICE_PREFIX + context.getUiSurface(), false);
                    DeviceConfig.getBoolean(NAMESPACE_SYSTEMUI,
        final boolean serviceExists = resolveService(sessionId, false,
                            PREDICT_USING_PEOPLE_SERVICE_PREFIX + context.getUiSurface(), false),
                usesPeopleService, s -> s.onCreatePredictionSession(context, sessionId));
                    this::removeAppPredictionSessionInfo));
        if (serviceExists && !mSessionInfos.containsKey(sessionId)) {
            final AppPredictionSessionInfo sessionInfo = new AppPredictionSessionInfo(
                    sessionId, context, usesPeopleService, token, () -> {
                synchronized (mLock) {
                    onDestroyPredictionSessionLocked(sessionId);
                }
            });
            if (sessionInfo.linkToDeath()) {
                mSessionInfos.put(sessionId, sessionInfo);
            } else {
                // destroy the session if calling process is already dead
                onDestroyPredictionSessionLocked(sessionId);
            }
            }
        final boolean serviceExists = resolveService(sessionId, s ->
                s.onCreatePredictionSession(context, sessionId), true);
        if (!serviceExists) {
            mSessionInfos.remove(sessionId);
        }
        }
    }
    }


@@ -132,7 +138,10 @@ public class AppPredictionPerUserService extends
    @GuardedBy("mLock")
    @GuardedBy("mLock")
    public void notifyAppTargetEventLocked(@NonNull AppPredictionSessionId sessionId,
    public void notifyAppTargetEventLocked(@NonNull AppPredictionSessionId sessionId,
            @NonNull AppTargetEvent event) {
            @NonNull AppTargetEvent event) {
        resolveService(sessionId, s -> s.notifyAppTargetEvent(sessionId, event), false);
        final AppPredictionSessionInfo sessionInfo = mSessionInfos.get(sessionId);
        if (sessionInfo == null) return;
        resolveService(sessionId, false, sessionInfo.mUsesPeopleService,
                s -> s.notifyAppTargetEvent(sessionId, event));
    }
    }


    /**
    /**
@@ -141,8 +150,10 @@ public class AppPredictionPerUserService extends
    @GuardedBy("mLock")
    @GuardedBy("mLock")
    public void notifyLaunchLocationShownLocked(@NonNull AppPredictionSessionId sessionId,
    public void notifyLaunchLocationShownLocked(@NonNull AppPredictionSessionId sessionId,
            @NonNull String launchLocation, @NonNull ParceledListSlice targetIds) {
            @NonNull String launchLocation, @NonNull ParceledListSlice targetIds) {
        resolveService(sessionId, s ->
        final AppPredictionSessionInfo sessionInfo = mSessionInfos.get(sessionId);
                s.notifyLaunchLocationShown(sessionId, launchLocation, targetIds), false);
        if (sessionInfo == null) return;
        resolveService(sessionId, false, sessionInfo.mUsesPeopleService,
                s -> s.notifyLaunchLocationShown(sessionId, launchLocation, targetIds));
    }
    }


    /**
    /**
@@ -151,7 +162,10 @@ public class AppPredictionPerUserService extends
    @GuardedBy("mLock")
    @GuardedBy("mLock")
    public void sortAppTargetsLocked(@NonNull AppPredictionSessionId sessionId,
    public void sortAppTargetsLocked(@NonNull AppPredictionSessionId sessionId,
            @NonNull ParceledListSlice targets, @NonNull IPredictionCallback callback) {
            @NonNull ParceledListSlice targets, @NonNull IPredictionCallback callback) {
        resolveService(sessionId, s -> s.sortAppTargets(sessionId, targets, callback), true);
        final AppPredictionSessionInfo sessionInfo = mSessionInfos.get(sessionId);
        if (sessionInfo == null) return;
        resolveService(sessionId, true, sessionInfo.mUsesPeopleService,
                s -> s.sortAppTargets(sessionId, targets, callback));
    }
    }


    /**
    /**
@@ -160,10 +174,12 @@ public class AppPredictionPerUserService extends
    @GuardedBy("mLock")
    @GuardedBy("mLock")
    public void registerPredictionUpdatesLocked(@NonNull AppPredictionSessionId sessionId,
    public void registerPredictionUpdatesLocked(@NonNull AppPredictionSessionId sessionId,
            @NonNull IPredictionCallback callback) {
            @NonNull IPredictionCallback callback) {
        final boolean serviceExists = resolveService(sessionId, s ->
                s.registerPredictionUpdates(sessionId, callback), false);
        final AppPredictionSessionInfo sessionInfo = mSessionInfos.get(sessionId);
        final AppPredictionSessionInfo sessionInfo = mSessionInfos.get(sessionId);
        if (serviceExists && sessionInfo != null) {
        if (sessionInfo == null) return;
        final boolean serviceExists = resolveService(sessionId, false,
                sessionInfo.mUsesPeopleService,
                s -> s.registerPredictionUpdates(sessionId, callback));
        if (serviceExists) {
            sessionInfo.addCallbackLocked(callback);
            sessionInfo.addCallbackLocked(callback);
        }
        }
    }
    }
@@ -174,10 +190,12 @@ public class AppPredictionPerUserService extends
    @GuardedBy("mLock")
    @GuardedBy("mLock")
    public void unregisterPredictionUpdatesLocked(@NonNull AppPredictionSessionId sessionId,
    public void unregisterPredictionUpdatesLocked(@NonNull AppPredictionSessionId sessionId,
            @NonNull IPredictionCallback callback) {
            @NonNull IPredictionCallback callback) {
        final boolean serviceExists = resolveService(sessionId, s ->
                s.unregisterPredictionUpdates(sessionId, callback), false);
        final AppPredictionSessionInfo sessionInfo = mSessionInfos.get(sessionId);
        final AppPredictionSessionInfo sessionInfo = mSessionInfos.get(sessionId);
        if (serviceExists && sessionInfo != null) {
        if (sessionInfo == null) return;
        final boolean serviceExists = resolveService(sessionId, false,
                sessionInfo.mUsesPeopleService,
                s -> s.unregisterPredictionUpdates(sessionId, callback));
        if (serviceExists) {
            sessionInfo.removeCallbackLocked(callback);
            sessionInfo.removeCallbackLocked(callback);
        }
        }
    }
    }
@@ -187,7 +205,10 @@ public class AppPredictionPerUserService extends
     */
     */
    @GuardedBy("mLock")
    @GuardedBy("mLock")
    public void requestPredictionUpdateLocked(@NonNull AppPredictionSessionId sessionId) {
    public void requestPredictionUpdateLocked(@NonNull AppPredictionSessionId sessionId) {
        resolveService(sessionId, s -> s.requestPredictionUpdate(sessionId), true);
        final AppPredictionSessionInfo sessionInfo = mSessionInfos.get(sessionId);
        if (sessionInfo == null) return;
        resolveService(sessionId, true, sessionInfo.mUsesPeopleService,
                s -> s.requestPredictionUpdate(sessionId));
    }
    }


    /**
    /**
@@ -195,12 +216,14 @@ public class AppPredictionPerUserService extends
     */
     */
    @GuardedBy("mLock")
    @GuardedBy("mLock")
    public void onDestroyPredictionSessionLocked(@NonNull AppPredictionSessionId sessionId) {
    public void onDestroyPredictionSessionLocked(@NonNull AppPredictionSessionId sessionId) {
        final boolean serviceExists = resolveService(sessionId, s ->
        if (isDebug()) {
                s.onDestroyPredictionSession(sessionId), false);
            Slog.d(TAG, "onDestroyPredictionSessionLocked(): sessionId=" + sessionId);
        final AppPredictionSessionInfo sessionInfo = mSessionInfos.get(sessionId);
        if (serviceExists && sessionInfo != null) {
            sessionInfo.destroy();
        }
        }
        final AppPredictionSessionInfo sessionInfo = mSessionInfos.remove(sessionId);
        if (sessionInfo == null) return;
        resolveService(sessionId, false, sessionInfo.mUsesPeopleService,
                s -> s.onDestroyPredictionSession(sessionId));
        sessionInfo.destroy();
    }
    }


    @Override
    @Override
@@ -291,27 +314,18 @@ public class AppPredictionPerUserService extends
        }
        }


        for (AppPredictionSessionInfo sessionInfo : mSessionInfos.values()) {
        for (AppPredictionSessionInfo sessionInfo : mSessionInfos.values()) {
            sessionInfo.resurrectSessionLocked(this);
            sessionInfo.resurrectSessionLocked(this, sessionInfo.mToken);
        }
    }

    private void removeAppPredictionSessionInfo(AppPredictionSessionId sessionId) {
        if (isDebug()) {
            Slog.d(TAG, "removeAppPredictionSessionInfo(): sessionId=" + sessionId);
        }
        synchronized (mLock) {
            mSessionInfos.remove(sessionId);
        }
        }
    }
    }


    @GuardedBy("mLock")
    @GuardedBy("mLock")
    @Nullable
    @Nullable
    protected boolean resolveService(@NonNull final AppPredictionSessionId sessionId,
    protected boolean resolveService(
            @NonNull final AbstractRemoteService.AsyncRequest<IPredictionService> cb,
            @NonNull final AppPredictionSessionId sessionId,
            boolean sendImmediately) {
            boolean sendImmediately,
        final AppPredictionSessionInfo sessionInfo = mSessionInfos.get(sessionId);
            boolean usesPeopleService,
        if (sessionInfo == null) return false;
            @NonNull final AbstractRemoteService.AsyncRequest<IPredictionService> cb) {
        if (sessionInfo.mUsesPeopleService) {
        if (usesPeopleService) {
            final IPredictionService service =
            final IPredictionService service =
                    LocalServices.getService(PeopleServiceInternal.class);
                    LocalServices.getService(PeopleServiceInternal.class);
            if (service != null) {
            if (service != null) {
@@ -368,7 +382,9 @@ public class AppPredictionPerUserService extends
        private final AppPredictionContext mPredictionContext;
        private final AppPredictionContext mPredictionContext;
        private final boolean mUsesPeopleService;
        private final boolean mUsesPeopleService;
        @NonNull
        @NonNull
        private final Consumer<AppPredictionSessionId> mRemoveSessionInfoAction;
        final IBinder mToken;
        @NonNull
        final IBinder.DeathRecipient mDeathRecipient;


        private final RemoteCallbackList<IPredictionCallback> mCallbacks =
        private final RemoteCallbackList<IPredictionCallback> mCallbacks =
                new RemoteCallbackList<IPredictionCallback>() {
                new RemoteCallbackList<IPredictionCallback>() {
@@ -388,14 +404,16 @@ public class AppPredictionPerUserService extends
                @NonNull final AppPredictionSessionId id,
                @NonNull final AppPredictionSessionId id,
                @NonNull final AppPredictionContext predictionContext,
                @NonNull final AppPredictionContext predictionContext,
                final boolean usesPeopleService,
                final boolean usesPeopleService,
                @NonNull final Consumer<AppPredictionSessionId> removeSessionInfoAction) {
                @NonNull final IBinder token,
                @NonNull final IBinder.DeathRecipient deathRecipient) {
            if (DEBUG) {
            if (DEBUG) {
                Slog.d(TAG, "Creating AppPredictionSessionInfo for session Id=" + id);
                Slog.d(TAG, "Creating AppPredictionSessionInfo for session Id=" + id);
            }
            }
            mSessionId = id;
            mSessionId = id;
            mPredictionContext = predictionContext;
            mPredictionContext = predictionContext;
            mUsesPeopleService = usesPeopleService;
            mUsesPeopleService = usesPeopleService;
            mRemoveSessionInfoAction = removeSessionInfoAction;
            mToken = token;
            mDeathRecipient = deathRecipient;
        }
        }


        void addCallbackLocked(IPredictionCallback callback) {
        void addCallbackLocked(IPredictionCallback callback) {
@@ -414,23 +432,38 @@ public class AppPredictionPerUserService extends
            mCallbacks.unregister(callback);
            mCallbacks.unregister(callback);
        }
        }


        boolean linkToDeath() {
            try {
                mToken.linkToDeath(mDeathRecipient, 0);
            } catch (RemoteException e) {
                if (DEBUG) {
                    Slog.w(TAG, "Caller is dead before session can be started, sessionId: "
                            + mSessionId);
                }
                return false;
            }
            return true;
        }

        void destroy() {
        void destroy() {
            if (DEBUG) {
            if (DEBUG) {
                Slog.d(TAG, "Removing all callbacks for session Id=" + mSessionId
                Slog.d(TAG, "Removing all callbacks for session Id=" + mSessionId
                        + " and " + mCallbacks.getRegisteredCallbackCount() + " callbacks.");
                        + " and " + mCallbacks.getRegisteredCallbackCount() + " callbacks.");
            }
            }
            if (mToken != null) {
                mToken.unlinkToDeath(mDeathRecipient, 0);
            }
            mCallbacks.kill();
            mCallbacks.kill();
            mRemoveSessionInfoAction.accept(mSessionId);
        }
        }


        void resurrectSessionLocked(AppPredictionPerUserService service) {
        void resurrectSessionLocked(AppPredictionPerUserService service, IBinder token) {
            int callbackCount = mCallbacks.getRegisteredCallbackCount();
            int callbackCount = mCallbacks.getRegisteredCallbackCount();
            if (DEBUG) {
            if (DEBUG) {
                Slog.d(TAG, "Resurrecting remote service (" + service.getRemoteServiceLocked()
                Slog.d(TAG, "Resurrecting remote service (" + service.getRemoteServiceLocked()
                        + ") for session Id=" + mSessionId + " and "
                        + ") for session Id=" + mSessionId + " and "
                        + callbackCount + " callbacks.");
                        + callbackCount + " callbacks.");
            }
            }
            service.onCreatePredictionSessionLocked(mPredictionContext, mSessionId);
            service.onCreatePredictionSessionLocked(mPredictionContext, mSessionId, token);
            mCallbacks.broadcast(
            mCallbacks.broadcast(
                    callback -> service.registerPredictionUpdatesLocked(mSessionId, callback));
                    callback -> service.registerPredictionUpdatesLocked(mSessionId, callback));
        }
        }