Merge "fix app prediction service doesn't clean-up properly." into rvc-qpr-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
4cb7d8c878
@@ -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();
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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));
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user