Split getAppSearchImpl and createAppSearchImpl in AppSearchImpl

User could never call an uninitialized SearchSession, so convert and
propagate the initialize error in getAppSearchImpl to user
for every call is unnecessary.

Test: presubmit
Bug: 162450968
Change-Id: Ie2b3c7c0a56852d7e517c616960c19b7b9e9ad35
diff --git a/service/java/com/android/server/appsearch/AppSearchManagerService.java b/service/java/com/android/server/appsearch/AppSearchManagerService.java
index a45fa39..68c9069 100644
--- a/service/java/com/android/server/appsearch/AppSearchManagerService.java
+++ b/service/java/com/android/server/appsearch/AppSearchManagerService.java
@@ -119,8 +119,7 @@
                     }
                     schemasPackageAccessible.put(entry.getKey(), packageIdentifiers);
                 }
-                AppSearchImpl impl =
-                        mImplInstanceManager.getAppSearchImpl(getContext(), callingUserId);
+                AppSearchImpl impl = mImplInstanceManager.getAppSearchImpl(callingUserId);
                 impl.setSchema(
                         packageName,
                         databaseName,
@@ -153,7 +152,7 @@
                 verifyUserUnlocked(callingUserId);
                 verifyCallingPackage(callingUid, packageName);
                 AppSearchImpl impl =
-                        mImplInstanceManager.getAppSearchImpl(getContext(), callingUserId);
+                        mImplInstanceManager.getAppSearchImpl(callingUserId);
                 List<AppSearchSchema> schemas = impl.getSchema(packageName, databaseName);
                 List<Bundle> schemaBundles = new ArrayList<>(schemas.size());
                 for (int i = 0; i < schemas.size(); i++) {
@@ -188,7 +187,7 @@
                 AppSearchBatchResult.Builder<String, Void> resultBuilder =
                         new AppSearchBatchResult.Builder<>();
                 AppSearchImpl impl =
-                        mImplInstanceManager.getAppSearchImpl(getContext(), callingUserId);
+                        mImplInstanceManager.getAppSearchImpl(callingUserId);
                 for (int i = 0; i < documentBundles.size(); i++) {
                     GenericDocument document = new GenericDocument(documentBundles.get(i));
                     try {
@@ -231,7 +230,7 @@
                 AppSearchBatchResult.Builder<String, Bundle> resultBuilder =
                         new AppSearchBatchResult.Builder<>();
                 AppSearchImpl impl =
-                        mImplInstanceManager.getAppSearchImpl(getContext(), callingUserId);
+                        mImplInstanceManager.getAppSearchImpl(callingUserId);
                 for (int i = 0; i < uris.size(); i++) {
                     String uri = uris.get(i);
                     try {
@@ -276,7 +275,7 @@
                 verifyUserUnlocked(callingUserId);
                 verifyCallingPackage(callingUid, packageName);
                 AppSearchImpl impl =
-                        mImplInstanceManager.getAppSearchImpl(getContext(), callingUserId);
+                        mImplInstanceManager.getAppSearchImpl(callingUserId);
                 SearchResultPage searchResultPage =
                         impl.query(
                                 packageName,
@@ -311,7 +310,7 @@
                 verifyUserUnlocked(callingUserId);
                 verifyCallingPackage(callingUid, packageName);
                 AppSearchImpl impl =
-                        mImplInstanceManager.getAppSearchImpl(getContext(), callingUserId);
+                        mImplInstanceManager.getAppSearchImpl(callingUserId);
                 SearchResultPage searchResultPage =
                         impl.globalQuery(
                                 queryExpression,
@@ -342,7 +341,7 @@
             try {
                 verifyUserUnlocked(callingUserId);
                 AppSearchImpl impl =
-                        mImplInstanceManager.getAppSearchImpl(getContext(), callingUserId);
+                        mImplInstanceManager.getAppSearchImpl(callingUserId);
                 SearchResultPage searchResultPage = impl.getNextPage(nextPageToken);
                 invokeCallbackOnResult(
                         callback,
@@ -362,7 +361,7 @@
             try {
                 verifyUserUnlocked(callingUserId);
                 AppSearchImpl impl =
-                        mImplInstanceManager.getAppSearchImpl(getContext(), callingUserId);
+                        mImplInstanceManager.getAppSearchImpl(callingUserId);
                 impl.invalidateNextPageToken(nextPageToken);
             } catch (Throwable t) {
                 Log.e(TAG, "Unable to invalidate the query page token", t);
@@ -390,7 +389,7 @@
             try {
                 verifyUserUnlocked(callingUserId);
                 AppSearchImpl impl =
-                        mImplInstanceManager.getAppSearchImpl(getContext(), callingUserId);
+                        mImplInstanceManager.getAppSearchImpl(callingUserId);
                 impl.reportUsage(packageName, databaseName, namespace, uri, usageTimeMillis);
                 invokeCallbackOnResult(
                         callback, AppSearchResult.newSuccessfulResult(/*result=*/ null));
@@ -422,7 +421,7 @@
                 AppSearchBatchResult.Builder<String, Void> resultBuilder =
                         new AppSearchBatchResult.Builder<>();
                 AppSearchImpl impl =
-                        mImplInstanceManager.getAppSearchImpl(getContext(), callingUserId);
+                        mImplInstanceManager.getAppSearchImpl(callingUserId);
                 for (int i = 0; i < uris.size(); i++) {
                     String uri = uris.get(i);
                     try {
@@ -460,7 +459,7 @@
                 verifyUserUnlocked(callingUserId);
                 verifyCallingPackage(callingUid, packageName);
                 AppSearchImpl impl =
-                        mImplInstanceManager.getAppSearchImpl(getContext(), callingUserId);
+                        mImplInstanceManager.getAppSearchImpl(callingUserId);
                 impl.removeByQuery(
                         packageName,
                         databaseName,
@@ -482,7 +481,7 @@
             try {
                 verifyUserUnlocked(callingUserId);
                 AppSearchImpl impl =
-                        mImplInstanceManager.getAppSearchImpl(getContext(), callingUserId);
+                        mImplInstanceManager.getAppSearchImpl(callingUserId);
                 impl.persistToDisk();
             } catch (Throwable t) {
                 Log.e(TAG, "Unable to persist the data to disk", t);
@@ -499,7 +498,7 @@
             final long callingIdentity = Binder.clearCallingIdentity();
             try {
                 verifyUserUnlocked(callingUserId);
-                mImplInstanceManager.getAppSearchImpl(getContext(), callingUserId);
+                mImplInstanceManager.getOrCreateAppSearchImpl(getContext(), callingUserId);
                 invokeCallbackOnResult(callback, AppSearchResult.newSuccessfulResult(null));
             } catch (Throwable t) {
                 invokeCallbackOnError(callback, t);
@@ -571,6 +570,7 @@
         private void invokeCallbackOnError(
                 IAppSearchBatchResultCallback callback, Throwable throwable) {
             try {
+                //TODO(b/175067650) verify ParcelableException could propagate throwable correctly.
                 callback.onSystemError(new ParcelableException(throwable));
             } catch (RemoteException e) {
                 Log.e(TAG, "Unable to send error to the callback", e);
diff --git a/service/java/com/android/server/appsearch/ImplInstanceManager.java b/service/java/com/android/server/appsearch/ImplInstanceManager.java
index 82319d4..8c953d1 100644
--- a/service/java/com/android/server/appsearch/ImplInstanceManager.java
+++ b/service/java/com/android/server/appsearch/ImplInstanceManager.java
@@ -74,7 +74,7 @@
     }
 
     /**
-     * Gets an instance of AppSearchImpl for the given user.
+     * Gets an instance of AppSearchImpl for the given user, or creates one if none exists.
      *
      * <p>If no AppSearchImpl instance exists for the unlocked user, Icing will be initialized and
      * one will be created.
@@ -84,7 +84,7 @@
      * @return An initialized {@link AppSearchImpl} for this user
      */
     @NonNull
-    public AppSearchImpl getAppSearchImpl(
+    public AppSearchImpl getOrCreateAppSearchImpl(
             @NonNull Context context, @UserIdInt int userId) throws AppSearchException {
         synchronized (mInstancesLocked) {
             AppSearchImpl instance = mInstancesLocked.get(userId);
@@ -96,6 +96,32 @@
         }
     }
 
+
+    /**
+     * Gets an instance of AppSearchImpl for the given user.
+     *
+     * <p>This method should only be called by an initialized SearchSession, which has been already
+     * created the AppSearchImpl instance for the given user.
+     *
+     * @param userId The multi-user userId of the device user calling AppSearch
+     * @return An initialized {@link AppSearchImpl} for this user
+     * @throws IllegalStateException if {@link AppSearchImpl} haven't created for the given user.
+     */
+    @NonNull
+    public AppSearchImpl getAppSearchImpl(@UserIdInt int userId) {
+        synchronized (mInstancesLocked) {
+            AppSearchImpl instance = mInstancesLocked.get(userId);
+            if (instance == null) {
+                // Impossible scenario, user cannot call an uninitialized SearchSession,
+                // getInstance should always find the instance for the given user and never try to
+                // create an instance for this user again.
+                throw new IllegalStateException(
+                        "AppSearchImpl has never been created for this user: " + userId);
+            }
+            return instance;
+        }
+    }
+
     private AppSearchImpl createImpl(@NonNull Context context, @UserIdInt int userId)
             throws AppSearchException {
         File appSearchDir = getAppSearchDir(context, userId);
@@ -104,6 +130,7 @@
 
     private static File getAppSearchDir(@NonNull Context context, @UserIdInt int userId) {
         // See com.android.internal.app.ChooserActivity::getPinnedSharedPrefs
+        //TODO(b/177685938):Switch from getDataUserCePackageDirectory to getDataSystemCeDirectory
         File userCeDir =
                 Environment.getDataUserCePackageDirectory(
                         StorageManager.UUID_PRIVATE_INTERNAL, userId, context.getPackageName());
diff --git a/testing/Android.bp b/testing/Android.bp
index eb072af..3c5082e 100644
--- a/testing/Android.bp
+++ b/testing/Android.bp
@@ -30,5 +30,8 @@
         "guava",
         "truth-prebuilt",
     ],
-    visibility: ["//cts/tests/appsearch"],
+    visibility: [
+        "//cts/tests/appsearch",
+        "//vendor:__subpackages__",
+    ],
 }