diff --git a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java index b6b7fded7ecde..777f9fe00bcad 100644 --- a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java +++ b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java @@ -234,6 +234,18 @@ public class AppSearchManagerService extends SystemService { } } + @Override + public void onUserStopping(@NonNull TargetUser user) { + synchronized (mUnlockedUserIdsLocked) { + mUnlockedUserIdsLocked.remove(user.getUserIdentifier()); + try { + mImplInstanceManager.closeAndRemoveAppSearchImplForUser(user.getUserIdentifier()); + } catch (Throwable t) { + Log.e(TAG, "Error handling user stopping.", t); + } + } + } + private void verifyUserUnlocked(int callingUserId) { if (isUserLocked(callingUserId)) { throw new IllegalStateException("User " + callingUserId + " is locked or not running."); diff --git a/apex/appsearch/service/java/com/android/server/appsearch/ImplInstanceManager.java b/apex/appsearch/service/java/com/android/server/appsearch/ImplInstanceManager.java index 94ee830f8e742..b815de48569f8 100644 --- a/apex/appsearch/service/java/com/android/server/appsearch/ImplInstanceManager.java +++ b/apex/appsearch/service/java/com/android/server/appsearch/ImplInstanceManager.java @@ -117,10 +117,28 @@ public final class ImplInstanceManager { */ public void removeAppSearchImplForUser(@UserIdInt int userId) { synchronized (mInstancesLocked) { + // no need to close and persist data to disk since we are removing them now. mInstancesLocked.remove(userId); } } + /** + * Close and remove an instance of {@link AppSearchImpl} for the given user. + * + *

All mutation apply to this {@link AppSearchImpl} will be persisted to disk. + * + * @param userId The multi-user userId of the user that need to be removed. + */ + public void closeAndRemoveAppSearchImplForUser(@UserIdInt int userId) { + synchronized (mInstancesLocked) { + AppSearchImpl appSearchImpl = mInstancesLocked.get(userId); + if (appSearchImpl != null) { + appSearchImpl.close(); + mInstancesLocked.remove(userId); + } + } + } + /** * Gets an instance of AppSearchImpl for the given user. * diff --git a/apex/appsearch/testing/java/com/android/server/appsearch/testing/AppSearchSessionShimImpl.java b/apex/appsearch/testing/java/com/android/server/appsearch/testing/AppSearchSessionShimImpl.java index 941cea9bc97a9..71b4f36a71279 100644 --- a/apex/appsearch/testing/java/com/android/server/appsearch/testing/AppSearchSessionShimImpl.java +++ b/apex/appsearch/testing/java/com/android/server/appsearch/testing/AppSearchSessionShimImpl.java @@ -17,6 +17,7 @@ package com.android.server.appsearch.testing; import android.annotation.NonNull; +import android.annotation.UserIdInt; import android.app.appsearch.AppSearchBatchResult; import android.app.appsearch.AppSearchManager; import android.app.appsearch.AppSearchResult; @@ -37,6 +38,7 @@ import android.app.appsearch.SetSchemaResponse; import android.app.appsearch.StorageInfo; import android.app.appsearch.exceptions.AppSearchException; import android.content.Context; +import android.os.UserHandle; import androidx.test.core.app.ApplicationProvider; @@ -58,18 +60,29 @@ public class AppSearchSessionShimImpl implements AppSearchSessionShim { private final AppSearchSession mAppSearchSession; private final ExecutorService mExecutor; + /** Creates the SearchSessionShim with given SearchContext. */ @NonNull public static ListenableFuture createSearchSession( @NonNull AppSearchManager.SearchContext searchContext) { - return createSearchSession(searchContext, Executors.newCachedThreadPool()); + Context context = ApplicationProvider.getApplicationContext(); + return createSearchSession(context, searchContext, Executors.newCachedThreadPool()); } - /** Creates the SearchSession with given ExecutorService. */ + /** Creates the SearchSessionShim with given SearchContext for the given user. */ @NonNull public static ListenableFuture createSearchSession( + @NonNull AppSearchManager.SearchContext searchContext, @UserIdInt int userId) { + Context context = ApplicationProvider.getApplicationContext() + .createContextAsUser(new UserHandle(userId), /*flags=*/ 0); + return createSearchSession(context, searchContext, Executors.newCachedThreadPool()); + } + + /** Creates the SearchSession with given Context and ExecutorService. */ + @NonNull + public static ListenableFuture createSearchSession( + @NonNull Context context, @NonNull AppSearchManager.SearchContext searchContext, @NonNull ExecutorService executor) { - Context context = ApplicationProvider.getApplicationContext(); AppSearchManager appSearchManager = context.getSystemService(AppSearchManager.class); SettableFuture> future = SettableFuture.create(); appSearchManager.createSearchSession(searchContext, executor, future::set);