SafeParcelable Requests in AppSearch - PersistToDiskAidlRequest.

Bug: 275629842
Test: atest CtsAppSearchTestCases CtsAppSearchHostTestCases AppSearchServicesTests AppSearchCoreTests ContactsIndexerTests
Change-Id: I7917663140be8fb47f8621db2d0a3a4a05fddd92
diff --git a/framework/java/android/app/appsearch/AppSearchSession.java b/framework/java/android/app/appsearch/AppSearchSession.java
index ba5c3a5..c3dffde 100644
--- a/framework/java/android/app/appsearch/AppSearchSession.java
+++ b/framework/java/android/app/appsearch/AppSearchSession.java
@@ -31,6 +31,7 @@
 import android.app.appsearch.aidl.IAppSearchManager;
 import android.app.appsearch.aidl.IAppSearchResultCallback;
 import android.app.appsearch.aidl.InitializeAidlRequest;
+import android.app.appsearch.aidl.PersistToDiskAidlRequest;
 import android.app.appsearch.aidl.SetSchemaAidlRequest;
 import android.app.appsearch.exceptions.AppSearchException;
 import android.app.appsearch.safeparcel.GenericDocumentParcel;
@@ -834,9 +835,10 @@
         if (mIsMutated && !mIsClosed) {
             try {
                 mService.persistToDisk(
-                        mCallerAttributionSource,
-                        mUserHandle,
-                        /*binderCallStartTimeMillis=*/ SystemClock.elapsedRealtime());
+                        new PersistToDiskAidlRequest(
+                                mCallerAttributionSource,
+                                mUserHandle,
+                                /*binderCallStartTimeMillis=*/ SystemClock.elapsedRealtime()));
                 mIsClosed = true;
             } catch (RemoteException e) {
                 Log.e(TAG, "Unable to close the AppSearchSession", e);
diff --git a/framework/java/android/app/appsearch/GlobalSearchSession.java b/framework/java/android/app/appsearch/GlobalSearchSession.java
index 8aed280..f2dd1c9 100644
--- a/framework/java/android/app/appsearch/GlobalSearchSession.java
+++ b/framework/java/android/app/appsearch/GlobalSearchSession.java
@@ -25,6 +25,7 @@
 import android.app.appsearch.aidl.IAppSearchManager;
 import android.app.appsearch.aidl.IAppSearchObserverProxy;
 import android.app.appsearch.aidl.IAppSearchResultCallback;
+import android.app.appsearch.aidl.PersistToDiskAidlRequest;
 import android.app.appsearch.exceptions.AppSearchException;
 import android.app.appsearch.observer.DocumentChangeInfo;
 import android.app.appsearch.observer.ObserverCallback;
@@ -418,9 +419,10 @@
         if (mIsMutated && !mIsClosed) {
             try {
                 mService.persistToDisk(
-                        mCallerAttributionSource,
-                        mUserHandle,
-                        /*binderCallStartTimeMillis=*/ SystemClock.elapsedRealtime());
+                        new PersistToDiskAidlRequest(
+                                mCallerAttributionSource,
+                                mUserHandle,
+                                /*binderCallStartTimeMillis=*/ SystemClock.elapsedRealtime()));
                 mIsClosed = true;
             } catch (RemoteException e) {
                 Log.e(TAG, "Unable to close the GlobalSearchSession", e);
diff --git a/framework/java/android/app/appsearch/aidl/IAppSearchManager.aidl b/framework/java/android/app/appsearch/aidl/IAppSearchManager.aidl
index 32e74ec..3fe1c92 100644
--- a/framework/java/android/app/appsearch/aidl/IAppSearchManager.aidl
+++ b/framework/java/android/app/appsearch/aidl/IAppSearchManager.aidl
@@ -27,6 +27,7 @@
 import android.app.appsearch.aidl.GetSchemaAidlRequest;
 import android.app.appsearch.aidl.GetNamespacesAidlRequest;
 import android.app.appsearch.aidl.InitializeAidlRequest;
+import android.app.appsearch.aidl.PersistToDiskAidlRequest;
 import android.app.appsearch.aidl.SetSchemaAidlRequest;
 import android.app.appsearch.observer.ObserverSpec;
 import android.app.appsearch.stats.SchemaMigrationStats;
@@ -414,14 +415,10 @@
     /**
      * Persists all update/delete requests to the disk.
      *
-     * @param callerAttributionSource The permission identity of the package to persist to disk for
-     * @param userHandle Handle of the calling user
-     * @param binderCallStartTimeMillis start timestamp of binder call in Millis
+     * @param request {@link PersistToDiskAidlRequest} contains the input parameters for set schema
+     *     operation.
      */
-    void persistToDisk(
-        in AppSearchAttributionSource callerAttributionSource,
-        in UserHandle userHandle,
-        in long binderCallStartTimeMillis) = 17;
+    void persistToDisk(in PersistToDiskAidlRequest request) = 17;
 
     /**
      * Adds an observer to monitor changes within the databases owned by {@code observedPackage} if
diff --git a/framework/java/android/app/appsearch/aidl/PersistToDiskAidlRequest.aidl b/framework/java/android/app/appsearch/aidl/PersistToDiskAidlRequest.aidl
new file mode 100644
index 0000000..5b463ab
--- /dev/null
+++ b/framework/java/android/app/appsearch/aidl/PersistToDiskAidlRequest.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright 2024, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.app.appsearch.aidl;
+
+/** {@hide} */
+parcelable PersistToDiskAidlRequest;
\ No newline at end of file
diff --git a/framework/java/android/app/appsearch/aidl/PersistToDiskAidlRequest.java b/framework/java/android/app/appsearch/aidl/PersistToDiskAidlRequest.java
new file mode 100644
index 0000000..c8d13e6
--- /dev/null
+++ b/framework/java/android/app/appsearch/aidl/PersistToDiskAidlRequest.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.appsearch.aidl;
+
+import android.annotation.NonNull;
+import android.app.appsearch.AppSearchSession;
+import android.app.appsearch.safeparcel.AbstractSafeParcelable;
+import android.app.appsearch.safeparcel.SafeParcelable;
+import android.os.Parcel;
+import android.os.UserHandle;
+
+import java.util.Objects;
+
+/**
+ * Encapsulates a request to make a binder call to persist all update/delete requests to the disk.
+ * @hide
+ */
+@SafeParcelable.Class(creator = "PersistToDiskAidlRequestCreator")
+public class PersistToDiskAidlRequest extends AbstractSafeParcelable {
+    @NonNull
+    public static final PersistToDiskAidlRequestCreator CREATOR =
+            new PersistToDiskAidlRequestCreator();
+
+    @NonNull
+    @Field(id = 1, getter = "getCallerAttributionSource")
+    private final AppSearchAttributionSource mCallerAttributionSource;
+    @NonNull
+    @Field(id = 2, getter = "getUserHandle")
+    private final UserHandle mUserHandle;
+    @Field(id = 3, getter = "getBinderCallStartTimeMillis")
+    private final long mBinderCallStartTimeMillis;
+
+    @Constructor
+    public PersistToDiskAidlRequest(
+            @Param(id = 1) @NonNull AppSearchAttributionSource callerAttributionSource,
+            @Param(id = 2) @NonNull UserHandle userHandle,
+            @Param(id = 3) @NonNull long binderCallStartTimeMillis) {
+        mCallerAttributionSource = Objects.requireNonNull(callerAttributionSource);
+        mUserHandle = Objects.requireNonNull(userHandle);
+        mBinderCallStartTimeMillis = binderCallStartTimeMillis;
+    }
+
+    @NonNull
+    public AppSearchAttributionSource getCallerAttributionSource() {
+        return mCallerAttributionSource;
+    }
+
+    @NonNull
+    public UserHandle getUserHandle() {
+        return mUserHandle;
+    }
+
+    public long getBinderCallStartTimeMillis() {
+        return mBinderCallStartTimeMillis;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        PersistToDiskAidlRequestCreator.writeToParcel(this, dest, flags);
+    }
+}
diff --git a/service/java/com/android/server/appsearch/AppSearchManagerService.java b/service/java/com/android/server/appsearch/AppSearchManagerService.java
index fbb46a7..d2bb029 100644
--- a/service/java/com/android/server/appsearch/AppSearchManagerService.java
+++ b/service/java/com/android/server/appsearch/AppSearchManagerService.java
@@ -57,6 +57,7 @@
 import android.app.appsearch.aidl.IAppSearchObserverProxy;
 import android.app.appsearch.aidl.IAppSearchResultCallback;
 import android.app.appsearch.aidl.InitializeAidlRequest;
+import android.app.appsearch.aidl.PersistToDiskAidlRequest;
 import android.app.appsearch.aidl.SetSchemaAidlRequest;
 import android.app.appsearch.exceptions.AppSearchException;
 import android.app.appsearch.observer.ObserverSpec;
@@ -1992,22 +1993,19 @@
         }
 
         @Override
-        public void persistToDisk(
-                @NonNull AppSearchAttributionSource callerAttributionSource,
-                @NonNull UserHandle userHandle,
-                @ElapsedRealtimeLong long binderCallStartTimeMillis) {
-            Objects.requireNonNull(callerAttributionSource);
-            Objects.requireNonNull(userHandle);
+        public void persistToDisk(@NonNull PersistToDiskAidlRequest request) {
+            Objects.requireNonNull(request);
 
             long totalLatencyStartTimeMillis = SystemClock.elapsedRealtime();
             try {
                 UserHandle targetUser = mServiceImplHelper.verifyIncomingCall(
-                        callerAttributionSource, userHandle);
-                String callingPackageName =
-                        Objects.requireNonNull(callerAttributionSource.getPackageName());
+                        request.getCallerAttributionSource(), request.getUserHandle());
+                String callingPackageName = Objects.requireNonNull(
+                        request.getCallerAttributionSource().getPackageName());
                 if (checkCallDenied(callingPackageName, /* callingDatabaseName= */ null,
-                        CallStats.CALL_TYPE_FLUSH, targetUser, binderCallStartTimeMillis,
-                        totalLatencyStartTimeMillis, /* numOperations= */ 1)) {
+                        CallStats.CALL_TYPE_FLUSH, targetUser,
+                        request.getBinderCallStartTimeMillis(), totalLatencyStartTimeMillis,
+                        /* numOperations= */ 1)) {
                     return;
                 }
                 boolean callAccepted = mServiceImplHelper.executeLambdaForUserNoCallbackAsync(
@@ -2032,7 +2030,7 @@
                         if (instance != null) {
                             int estimatedBinderLatencyMillis =
                                     2 * (int) (totalLatencyStartTimeMillis
-                                            - binderCallStartTimeMillis);
+                                            - request.getBinderCallStartTimeMillis());
                             int totalLatencyMillis =
                                     (int) (SystemClock.elapsedRealtime()
                                             - totalLatencyStartTimeMillis);
@@ -2054,9 +2052,9 @@
                 if (!callAccepted) {
                     logRateLimitedOrCallDeniedCallStats(
                             callingPackageName, /* callingDatabaseName= */ null,
-                            CallStats.CALL_TYPE_FLUSH, targetUser, binderCallStartTimeMillis,
-                            totalLatencyStartTimeMillis, /* numOperations= */ 1,
-                            RESULT_RATE_LIMITED);
+                            CallStats.CALL_TYPE_FLUSH, targetUser,
+                            request.getBinderCallStartTimeMillis(), totalLatencyStartTimeMillis,
+                            /* numOperations= */ 1, RESULT_RATE_LIMITED);
                 }
             } catch (RuntimeException e) {
                 Log.e(TAG, "Unable to persist the data to disk", e);
diff --git a/testing/mockingservicestests/src/com/android/server/appsearch/AppSearchManagerServiceTest.java b/testing/mockingservicestests/src/com/android/server/appsearch/AppSearchManagerServiceTest.java
index d69c243..60ceab9 100644
--- a/testing/mockingservicestests/src/com/android/server/appsearch/AppSearchManagerServiceTest.java
+++ b/testing/mockingservicestests/src/com/android/server/appsearch/AppSearchManagerServiceTest.java
@@ -66,6 +66,7 @@
 import android.app.appsearch.aidl.IAppSearchObserverProxy;
 import android.app.appsearch.aidl.IAppSearchResultCallback;
 import android.app.appsearch.aidl.InitializeAidlRequest;
+import android.app.appsearch.aidl.PersistToDiskAidlRequest;
 import android.app.appsearch.aidl.SetSchemaAidlRequest;
 import android.app.appsearch.observer.ObserverSpec;
 import android.app.appsearch.stats.SchemaMigrationStats;
@@ -558,8 +559,9 @@
     @Test
     public void testPersistToDiskStatsLogging() throws Exception {
         mAppSearchManagerServiceStub.persistToDisk(
-                AppSearchAttributionSource.createAttributionSource(mContext), mUserHandle,
-                BINDER_CALL_START_TIME);
+                new PersistToDiskAidlRequest(
+                        AppSearchAttributionSource.createAttributionSource(mContext), mUserHandle,
+                        BINDER_CALL_START_TIME));
         verifyCallStats(mContext.getPackageName(), CallStats.CALL_TYPE_FLUSH);
     }
 
@@ -1427,8 +1429,9 @@
 
     private void verifyPersistToDiskResult(int resultCode) throws Exception {
         mAppSearchManagerServiceStub.persistToDisk(
-                AppSearchAttributionSource.createAttributionSource(mContext), mUserHandle,
-                BINDER_CALL_START_TIME);
+                new PersistToDiskAidlRequest(
+                        AppSearchAttributionSource.createAttributionSource(mContext), mUserHandle,
+                        BINDER_CALL_START_TIME));
         verifyCallResult(resultCode, CallStats.CALL_TYPE_FLUSH, /* result= */ null);
     }