blob: c33d5ecc5d1643179ff30dca02177284ca4d5ca4 [file] [log] [blame]
Terry Wangfebbead2019-10-17 17:05:18 -07001/*
sidchhabraa7c8f8a2020-01-16 18:38:17 -08002 * Copyright (C) 2020 The Android Open Source Project
Terry Wangfebbead2019-10-17 17:05:18 -07003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package com.android.server.appsearch;
17
Terry Wangdbd1dca2020-11-03 17:03:56 -080018import static android.app.appsearch.AppSearchResult.throwableToFailedResult;
Terry Wange201dc02021-04-16 01:03:20 -070019import static android.os.Process.INVALID_UID;
Terry Wangdbd1dca2020-11-03 17:03:56 -080020
Xiaoyu Jinf8cc2012021-03-12 11:00:54 -080021import android.annotation.ElapsedRealtimeLong;
sidchhabraa7c8f8a2020-01-16 18:38:17 -080022import android.annotation.NonNull;
Alexander Dorokhine18465842020-01-21 01:08:57 -080023import android.app.appsearch.AppSearchBatchResult;
Terry Wang623e3b02021-02-02 20:27:33 -080024import android.app.appsearch.AppSearchMigrationHelper;
Alexander Dorokhine969f4462020-03-05 15:54:19 -080025import android.app.appsearch.AppSearchResult;
Alexander Dorokhine92ce3532020-10-06 01:39:36 -070026import android.app.appsearch.AppSearchSchema;
Alexander Dorokhinec66d67c2020-10-08 13:44:04 -070027import android.app.appsearch.GenericDocument;
Alexander Dorokhine9795b512021-03-23 22:06:59 -070028import android.app.appsearch.GetSchemaResponse;
Alexander Dorokhineab789062021-01-11 21:00:00 -080029import android.app.appsearch.PackageIdentifier;
Terry Wang26b9e5c2020-10-23 02:05:01 -070030import android.app.appsearch.SearchResultPage;
Alexander Dorokhinec9fc9602020-10-06 01:39:50 -070031import android.app.appsearch.SearchSpec;
Terry Wang623e3b02021-02-02 20:27:33 -080032import android.app.appsearch.SetSchemaResponse;
Cassie Wang8f0df492021-03-24 09:23:18 -070033import android.app.appsearch.StorageInfo;
Alexander Dorokhined5e8eda2021-05-04 13:24:47 -070034import android.app.appsearch.aidl.AppSearchBatchResultParcel;
35import android.app.appsearch.aidl.AppSearchResultParcel;
36import android.app.appsearch.aidl.IAppSearchBatchResultCallback;
37import android.app.appsearch.aidl.IAppSearchManager;
38import android.app.appsearch.aidl.IAppSearchResultCallback;
Alexander Dorokhine4d051632021-06-18 10:48:58 -070039import android.app.appsearch.exceptions.AppSearchException;
Terry Wang12dc6c02021-03-31 19:26:16 -070040import android.content.BroadcastReceiver;
Terry Wangfebbead2019-10-17 17:05:18 -070041import android.content.Context;
Terry Wang12dc6c02021-03-31 19:26:16 -070042import android.content.Intent;
43import android.content.IntentFilter;
Alexander Dorokhinea5d0d322021-05-10 15:59:31 -070044import android.content.pm.PackageInfo;
Yang Yu0fcd51a2021-04-23 11:25:44 -070045import android.content.pm.PackageManager;
Yang Yu0fcd51a2021-04-23 11:25:44 -070046import android.content.pm.PackageStats;
Alexander Dorokhine270d4f12020-01-15 17:24:35 -080047import android.os.Binder;
Alexander Dorokhine92ce3532020-10-06 01:39:36 -070048import android.os.Bundle;
Terry Wang623e3b02021-02-02 20:27:33 -080049import android.os.ParcelFileDescriptor;
Terry Wangdbd1dca2020-11-03 17:03:56 -080050import android.os.RemoteException;
Xiaoyu Jinf8cc2012021-03-12 11:00:54 -080051import android.os.SystemClock;
Cassie Wang0c62d992021-01-15 14:39:30 -080052import android.os.UserHandle;
Pinyao Tingd5c2ed92021-03-18 14:51:54 -070053import android.os.UserManager;
Alexander Dorokhineab789062021-01-11 21:00:00 -080054import android.util.ArrayMap;
Cassie Wang9ba9ae12021-02-01 16:39:37 -080055import android.util.ArraySet;
Terry Wangdbd1dca2020-11-03 17:03:56 -080056import android.util.Log;
Terry Wangfebbead2019-10-17 17:05:18 -070057
Cassie Wang15c86972021-02-09 13:43:25 -080058import com.android.internal.annotations.GuardedBy;
Alexander Dorokhinea5d0d322021-05-10 15:59:31 -070059import com.android.server.LocalManagerRegistry;
Terry Wangfebbead2019-10-17 17:05:18 -070060import com.android.server.SystemService;
Xiaoyu Jinf8cc2012021-03-12 11:00:54 -080061import com.android.server.appsearch.external.localstorage.stats.CallStats;
Alexander Dorokhine14816e22021-07-12 10:53:24 -070062import com.android.server.appsearch.external.localstorage.stats.OptimizeStats;
Alexander Dorokhine44c04972021-06-22 12:32:15 -070063import com.android.server.appsearch.external.localstorage.visibilitystore.VisibilityStore;
Xiaoyu Jin10329472021-06-23 16:50:03 -070064import com.android.server.appsearch.stats.StatsCollector;
Alexander Dorokhine5c416772021-06-04 09:05:00 -070065import com.android.server.appsearch.util.PackageUtil;
Alexander Dorokhinea5d0d322021-05-10 15:59:31 -070066import com.android.server.usage.StorageStatsManagerLocal;
67import com.android.server.usage.StorageStatsManagerLocal.StorageStatsAugmenter;
Alexander Dorokhinefd07eba2020-01-13 20:22:20 -080068
Alexander Dorokhinec77f4442021-04-14 09:26:06 -070069import com.google.android.icing.proto.PersistType;
70
Terry Wang623e3b02021-02-02 20:27:33 -080071import java.io.DataInputStream;
72import java.io.DataOutputStream;
73import java.io.EOFException;
74import java.io.FileInputStream;
75import java.io.FileOutputStream;
Alexander Dorokhine6a99f942020-12-04 02:57:22 -080076import java.util.ArrayList;
Alexander Dorokhine18465842020-01-21 01:08:57 -080077import java.util.List;
Alexander Dorokhineab789062021-01-11 21:00:00 -080078import java.util.Map;
Alexander Dorokhined18f8842021-01-20 15:26:13 -080079import java.util.Objects;
Cassie Wang9ba9ae12021-02-01 16:39:37 -080080import java.util.Set;
Terry Wange04ceab2021-03-29 19:25:12 -070081import java.util.concurrent.Executor;
Terry Wangd2186e52021-04-14 13:19:45 -070082import java.util.concurrent.LinkedBlockingQueue;
Terry Wange04ceab2021-03-29 19:25:12 -070083import java.util.concurrent.ThreadPoolExecutor;
84import java.util.concurrent.TimeUnit;
Alexander Dorokhine18465842020-01-21 01:08:57 -080085
Alexander Dorokhine5d2bb0b2021-06-24 22:58:46 -070086/**
87 * The main service implementation which contains AppSearch's platform functionality.
88 * @hide
89 */
Terry Wangfebbead2019-10-17 17:05:18 -070090public class AppSearchManagerService extends SystemService {
Alexander Dorokhineebd37742020-09-22 15:02:26 -070091 private static final String TAG = "AppSearchManagerService";
Terry Wang12dc6c02021-03-31 19:26:16 -070092 private final Context mContext;
Yang Yu0fcd51a2021-04-23 11:25:44 -070093 private PackageManager mPackageManager;
Pinyao Tingd5c2ed92021-03-18 14:51:54 -070094 private UserManager mUserManager;
Alexander Dorokhine4d051632021-06-18 10:48:58 -070095 private AppSearchUserInstanceManager mAppSearchUserInstanceManager;
Terry Wangfebbead2019-10-17 17:05:18 -070096
Terry Wange04ceab2021-03-29 19:25:12 -070097 // Never call shutdownNow(). It will cancel the futures it's returned. And since
98 // Executor#execute won't return anything, we will hang forever waiting for the execution.
99 // AppSearch multi-thread execution is guarded by Read & Write Lock in AppSearchImpl, all
100 // mutate requests will need to gain write lock and query requests need to gain read lock.
101 private static final Executor EXECUTOR = new ThreadPoolExecutor(/*corePoolSize=*/1,
102 Runtime.getRuntime().availableProcessors(), /*keepAliveTime*/ 60L, TimeUnit.SECONDS,
Terry Wangd2186e52021-04-14 13:19:45 -0700103 new LinkedBlockingQueue<>());
Terry Wange04ceab2021-03-29 19:25:12 -0700104
Alexander Dorokhinebea55602021-05-19 13:59:45 -0700105 // Cache of unlocked users so we don't have to query UserManager service each time. The "locked"
106 // suffix refers to the fact that access to the field should be locked; unrelated to the
107 // unlocked status of users.
108 @GuardedBy("mUnlockedUsersLocked")
109 private final Set<UserHandle> mUnlockedUsersLocked = new ArraySet<>();
Cassie Wang9ba9ae12021-02-01 16:39:37 -0800110
Terry Wangfebbead2019-10-17 17:05:18 -0700111 public AppSearchManagerService(Context context) {
112 super(context);
Terry Wang12dc6c02021-03-31 19:26:16 -0700113 mContext = context;
Terry Wangfebbead2019-10-17 17:05:18 -0700114 }
115
116 @Override
117 public void onStart() {
118 publishBinderService(Context.APP_SEARCH_SERVICE, new Stub());
Yang Yu0fcd51a2021-04-23 11:25:44 -0700119 mPackageManager = getContext().getPackageManager();
Alexander Dorokhine4d051632021-06-18 10:48:58 -0700120 mAppSearchUserInstanceManager = AppSearchUserInstanceManager.getInstance();
Terry Wang12dc6c02021-03-31 19:26:16 -0700121 mUserManager = mContext.getSystemService(UserManager.class);
122 registerReceivers();
Alexander Dorokhinea5d0d322021-05-10 15:59:31 -0700123 LocalManagerRegistry.getManager(StorageStatsManagerLocal.class)
Yang Yu0fcd51a2021-04-23 11:25:44 -0700124 .registerStorageStatsAugmenter(new AppSearchStorageStatsAugmenter(), TAG);
Terry Wang12dc6c02021-03-31 19:26:16 -0700125 }
126
Xiaoyu Jin10329472021-06-23 16:50:03 -0700127 @Override
128 public void onBootPhase(/* @BootPhase */ int phase) {
129 if (phase == PHASE_BOOT_COMPLETED) {
130 StatsCollector.getInstance(mContext, EXECUTOR);
131 }
132 }
133
Terry Wang12dc6c02021-03-31 19:26:16 -0700134 private void registerReceivers() {
Alexander Dorokhine5c416772021-06-04 09:05:00 -0700135 mContext.registerReceiverForAllUsers(
136 new UserActionReceiver(),
137 new IntentFilter(Intent.ACTION_USER_REMOVED),
138 /*broadcastPermission=*/ null,
Terry Wang12dc6c02021-03-31 19:26:16 -0700139 /*scheduler=*/ null);
Terry Wange201dc02021-04-16 01:03:20 -0700140
141 //TODO(b/145759910) Add a direct callback when user clears the data instead of relying on
142 // broadcasts
143 IntentFilter packageChangedFilter = new IntentFilter();
144 packageChangedFilter.addAction(Intent.ACTION_PACKAGE_FULLY_REMOVED);
145 packageChangedFilter.addAction(Intent.ACTION_PACKAGE_DATA_CLEARED);
146 packageChangedFilter.addDataScheme("package");
147 packageChangedFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
Alexander Dorokhine5c416772021-06-04 09:05:00 -0700148 mContext.registerReceiverForAllUsers(
149 new PackageChangedReceiver(),
150 packageChangedFilter,
151 /*broadcastPermission=*/ null,
Terry Wange201dc02021-04-16 01:03:20 -0700152 /*scheduler=*/ null);
Terry Wang12dc6c02021-03-31 19:26:16 -0700153 }
154
155 private class UserActionReceiver extends BroadcastReceiver {
156 @Override
157 public void onReceive(@NonNull Context context, @NonNull Intent intent) {
Alexander Dorokhinebea55602021-05-19 13:59:45 -0700158 Objects.requireNonNull(context);
159 Objects.requireNonNull(intent);
160
Terry Wang12dc6c02021-03-31 19:26:16 -0700161 switch (intent.getAction()) {
162 case Intent.ACTION_USER_REMOVED:
Alexander Dorokhine5c416772021-06-04 09:05:00 -0700163 UserHandle userHandle = intent.getParcelableExtra(Intent.EXTRA_USER);
164 if (userHandle == null) {
165 Log.e(TAG, "Extra "
166 + Intent.EXTRA_USER + " is missing in the intent: " + intent);
Terry Wang12dc6c02021-03-31 19:26:16 -0700167 return;
168 }
Alexander Dorokhine5c416772021-06-04 09:05:00 -0700169 handleUserRemoved(userHandle);
Terry Wang12dc6c02021-03-31 19:26:16 -0700170 break;
171 default:
Terry Wange201dc02021-04-16 01:03:20 -0700172 Log.e(TAG, "Received unknown intent: " + intent);
Terry Wang12dc6c02021-03-31 19:26:16 -0700173 }
174 }
175 }
176
177 /**
178 * Handles user removed action.
179 *
180 * <p>Only need to clear the AppSearchImpl instance. The data of AppSearch is saved in the
181 * "credential encrypted" system directory of each user. That directory will be auto-deleted
182 * when a user is removed.
183 *
Alexander Dorokhinebea55602021-05-19 13:59:45 -0700184 * @param userHandle The multi-user handle of the user that need to be removed.
Terry Wang12dc6c02021-03-31 19:26:16 -0700185 *
186 * @see android.os.Environment#getDataSystemCeDirectory
187 */
Alexander Dorokhinebea55602021-05-19 13:59:45 -0700188 private void handleUserRemoved(@NonNull UserHandle userHandle) {
Terry Wang12dc6c02021-03-31 19:26:16 -0700189 try {
Alexander Dorokhine4d051632021-06-18 10:48:58 -0700190 mAppSearchUserInstanceManager.closeAndRemoveUserInstance(userHandle);
Alexander Dorokhinebea55602021-05-19 13:59:45 -0700191 Log.i(TAG, "Removed AppSearchImpl instance for: " + userHandle);
Terry Wang12dc6c02021-03-31 19:26:16 -0700192 } catch (Throwable t) {
Alexander Dorokhinebea55602021-05-19 13:59:45 -0700193 Log.e(TAG, "Unable to remove data for: " + userHandle, t);
Terry Wange201dc02021-04-16 01:03:20 -0700194 }
195 }
196
197 private class PackageChangedReceiver extends BroadcastReceiver {
198 @Override
199 public void onReceive(@NonNull Context context, @NonNull Intent intent) {
Alexander Dorokhinebea55602021-05-19 13:59:45 -0700200 Objects.requireNonNull(context);
201 Objects.requireNonNull(intent);
202
Terry Wange201dc02021-04-16 01:03:20 -0700203 switch (intent.getAction()) {
204 case Intent.ACTION_PACKAGE_FULLY_REMOVED:
205 case Intent.ACTION_PACKAGE_DATA_CLEARED:
206 String packageName = intent.getData().getSchemeSpecificPart();
207 if (packageName == null) {
208 Log.e(TAG, "Package name is missing in the intent: " + intent);
209 return;
210 }
211 int uid = intent.getIntExtra(Intent.EXTRA_UID, INVALID_UID);
212 if (uid == INVALID_UID) {
213 Log.e(TAG, "uid is missing in the intent: " + intent);
214 return;
215 }
216 handlePackageRemoved(packageName, uid);
217 break;
218 default:
219 Log.e(TAG, "Received unknown intent: " + intent);
220 }
221 }
222 }
223
Alexander Dorokhinebea55602021-05-19 13:59:45 -0700224 private void handlePackageRemoved(@NonNull String packageName, int uid) {
225 UserHandle userHandle = UserHandle.getUserHandleForUid(uid);
Terry Wange201dc02021-04-16 01:03:20 -0700226 try {
Alexander Dorokhinebea55602021-05-19 13:59:45 -0700227 if (isUserLocked(userHandle)) {
Terry Wanga9e6e212021-04-23 15:51:37 -0700228 // We cannot access a locked user's directry and remove package data from it.
229 // We should remove those uninstalled package data when the user is unlocking.
Terry Wange201dc02021-04-16 01:03:20 -0700230 return;
231 }
Terry Wanga9e6e212021-04-23 15:51:37 -0700232 // Only clear the package's data if AppSearch exists for this user.
Alexander Dorokhine4d051632021-06-18 10:48:58 -0700233 if (AppSearchUserInstanceManager.getAppSearchDir(userHandle).exists()) {
Cassie Wang84e33a02021-06-18 14:13:31 -0700234 Context userContext = mContext.createContextAsUser(userHandle, /*flags=*/ 0);
Alexander Dorokhine4d051632021-06-18 10:48:58 -0700235 AppSearchUserInstance instance =
236 mAppSearchUserInstanceManager.getOrCreateUserInstance(
Cassie Wang84e33a02021-06-18 14:13:31 -0700237 userContext, userHandle, AppSearchConfig.getInstance(EXECUTOR));
Terry Wange201dc02021-04-16 01:03:20 -0700238 //TODO(b/145759910) clear visibility setting for package.
Alexander Dorokhine4d051632021-06-18 10:48:58 -0700239 instance.getAppSearchImpl().clearPackageData(packageName);
240 instance.getLogger().removeCachedUidForPackage(packageName);
Terry Wange201dc02021-04-16 01:03:20 -0700241 }
242 } catch (Throwable t) {
243 Log.e(TAG, "Unable to remove data for package: " + packageName, t);
Terry Wang12dc6c02021-03-31 19:26:16 -0700244 }
Terry Wangfebbead2019-10-17 17:05:18 -0700245 }
246
Cassie Wang9ba9ae12021-02-01 16:39:37 -0800247 @Override
Pinyao Tingd5c2ed92021-03-18 14:51:54 -0700248 public void onUserUnlocking(@NonNull TargetUser user) {
Alexander Dorokhinebea55602021-05-19 13:59:45 -0700249 Objects.requireNonNull(user);
Terry Wanga9e6e212021-04-23 15:51:37 -0700250 UserHandle userHandle = user.getUserHandle();
Alexander Dorokhinebea55602021-05-19 13:59:45 -0700251 synchronized (mUnlockedUsersLocked) {
Terry Wanga9e6e212021-04-23 15:51:37 -0700252 mUnlockedUsersLocked.add(userHandle);
Cassie Wang15c86972021-02-09 13:43:25 -0800253 }
Terry Wanga9e6e212021-04-23 15:51:37 -0700254 EXECUTOR.execute(() -> {
255 try {
256 // Only clear the package's data if AppSearch exists for this user.
Alexander Dorokhine4d051632021-06-18 10:48:58 -0700257 if (AppSearchUserInstanceManager.getAppSearchDir(userHandle).exists()) {
Cassie Wang84e33a02021-06-18 14:13:31 -0700258 Context userContext = mContext.createContextAsUser(userHandle, /*flags=*/ 0);
Alexander Dorokhine4d051632021-06-18 10:48:58 -0700259 AppSearchUserInstance instance =
260 mAppSearchUserInstanceManager.getOrCreateUserInstance(
Cassie Wang84e33a02021-06-18 14:13:31 -0700261 userContext, userHandle, AppSearchConfig.getInstance(EXECUTOR));
262 List<PackageInfo> installedPackageInfos = userContext
Terry Wanga9e6e212021-04-23 15:51:37 -0700263 .getPackageManager()
264 .getInstalledPackages(/*flags=*/0);
265 Set<String> packagesToKeep = new ArraySet<>(installedPackageInfos.size());
266 for (int i = 0; i < installedPackageInfos.size(); i++) {
267 packagesToKeep.add(installedPackageInfos.get(i).packageName);
268 }
269 packagesToKeep.add(VisibilityStore.PACKAGE_NAME);
270 //TODO(b/145759910) clear visibility setting for package.
Alexander Dorokhine4d051632021-06-18 10:48:58 -0700271 instance.getAppSearchImpl().prunePackageData(packagesToKeep);
Terry Wanga9e6e212021-04-23 15:51:37 -0700272 }
273 } catch (Throwable t) {
274 Log.e(TAG, "Unable to prune packages for " + user, t);
275 }
276 });
Cassie Wang9ba9ae12021-02-01 16:39:37 -0800277 }
278
Terry Wangde9f3382021-04-28 19:45:07 -0700279 @Override
280 public void onUserStopping(@NonNull TargetUser user) {
Alexander Dorokhinebea55602021-05-19 13:59:45 -0700281 Objects.requireNonNull(user);
282
283 synchronized (mUnlockedUsersLocked) {
284 UserHandle userHandle = user.getUserHandle();
285 mUnlockedUsersLocked.remove(userHandle);
Terry Wangde9f3382021-04-28 19:45:07 -0700286 try {
Alexander Dorokhine4d051632021-06-18 10:48:58 -0700287 mAppSearchUserInstanceManager.closeAndRemoveUserInstance(userHandle);
Terry Wangde9f3382021-04-28 19:45:07 -0700288 } catch (Throwable t) {
289 Log.e(TAG, "Error handling user stopping.", t);
290 }
291 }
292 }
293
Alexander Dorokhinebea55602021-05-19 13:59:45 -0700294 private void verifyUserUnlocked(@NonNull UserHandle callingUser) {
295 if (isUserLocked(callingUser)) {
296 throw new IllegalStateException(callingUser + " is locked or not running.");
Terry Wange201dc02021-04-16 01:03:20 -0700297 }
298 }
299
Alexander Dorokhinebea55602021-05-19 13:59:45 -0700300 private boolean isUserLocked(@NonNull UserHandle callingUser) {
301 synchronized (mUnlockedUsersLocked) {
Yang Yu0fcd51a2021-04-23 11:25:44 -0700302 // First, check the local copy.
Alexander Dorokhinebea55602021-05-19 13:59:45 -0700303 if (mUnlockedUsersLocked.contains(callingUser)) {
Terry Wange201dc02021-04-16 01:03:20 -0700304 return false;
Yang Yu0fcd51a2021-04-23 11:25:44 -0700305 }
306 // If the local copy says the user is locked, check with UM for the actual state,
307 // since the user might just have been unlocked.
Alexander Dorokhinebea55602021-05-19 13:59:45 -0700308 return !mUserManager.isUserUnlockingOrUnlocked(callingUser);
Yang Yu0fcd51a2021-04-23 11:25:44 -0700309 }
310 }
311
Terry Wangfebbead2019-10-17 17:05:18 -0700312 private class Stub extends IAppSearchManager.Stub {
Alexander Dorokhinefd07eba2020-01-13 20:22:20 -0800313 @Override
Alexander Dorokhine969f4462020-03-05 15:54:19 -0800314 public void setSchema(
Cassie Wang0c62d992021-01-15 14:39:30 -0800315 @NonNull String packageName,
Terry Wang6413aee2020-10-07 03:04:58 -0700316 @NonNull String databaseName,
Alexander Dorokhine92ce3532020-10-06 01:39:36 -0700317 @NonNull List<Bundle> schemaBundles,
Alexander Dorokhine315cca62021-03-04 12:34:41 -0800318 @NonNull List<String> schemasNotDisplayedBySystem,
Alexander Dorokhine4d051632021-06-18 10:48:58 -0700319 @NonNull Map<String, List<Bundle>> schemasVisibleToPackagesBundles,
Alexander Dorokhine969f4462020-03-05 15:54:19 -0800320 boolean forceOverride,
Alexander Dorokhine9795b512021-03-23 22:06:59 -0700321 int schemaVersion,
Alexander Dorokhinebea55602021-05-19 13:59:45 -0700322 @NonNull UserHandle userHandle,
Xiaoyu Jinc5a75772021-05-09 20:12:44 -0700323 @ElapsedRealtimeLong long binderCallStartTimeMillis,
Terry Wangdbd1dca2020-11-03 17:03:56 -0800324 @NonNull IAppSearchResultCallback callback) {
Alexander Dorokhine5258ad22021-04-15 10:59:55 -0700325 Objects.requireNonNull(packageName);
326 Objects.requireNonNull(databaseName);
327 Objects.requireNonNull(schemaBundles);
Alexander Dorokhinebea55602021-05-19 13:59:45 -0700328 Objects.requireNonNull(schemasNotDisplayedBySystem);
Alexander Dorokhine4d051632021-06-18 10:48:58 -0700329 Objects.requireNonNull(schemasVisibleToPackagesBundles);
Alexander Dorokhinebea55602021-05-19 13:59:45 -0700330 Objects.requireNonNull(userHandle);
Alexander Dorokhine5258ad22021-04-15 10:59:55 -0700331 Objects.requireNonNull(callback);
Alexander Dorokhinebea55602021-05-19 13:59:45 -0700332
Xiaoyu Jinc5a75772021-05-09 20:12:44 -0700333 long totalLatencyStartTimeMillis = SystemClock.elapsedRealtime();
Terry Wangf2093072020-11-30 04:47:19 -0800334 int callingUid = Binder.getCallingUid();
Terry Wange04ceab2021-03-29 19:25:12 -0700335 EXECUTOR.execute(() -> {
Xiaoyu Jinc5a75772021-05-09 20:12:44 -0700336 @AppSearchResult.ResultCode int statusCode = AppSearchResult.RESULT_OK;
Alexander Dorokhine4d051632021-06-18 10:48:58 -0700337 AppSearchUserInstance instance = null;
Xiaoyu Jinc5a75772021-05-09 20:12:44 -0700338 int operationSuccessCount = 0;
339 int operationFailureCount = 0;
Terry Wange04ceab2021-03-29 19:25:12 -0700340 try {
Cassie Wangd51ed162021-07-29 22:22:30 +0000341 verifyCaller(callingUid, packageName);
342
343 // Obtain the user where the client wants to run the operations in. This should
344 // end up being the same as userHandle, assuming it is not a special user and
345 // the client is allowed to run operations in that user.
346 UserHandle targetUser = handleIncomingUser(userHandle, callingUid);
Cassie Wang2feb34d2021-07-22 18:55:19 +0000347 verifyUserUnlocked(targetUser);
Cassie Wangd51ed162021-07-29 22:22:30 +0000348
Terry Wange04ceab2021-03-29 19:25:12 -0700349 List<AppSearchSchema> schemas = new ArrayList<>(schemaBundles.size());
350 for (int i = 0; i < schemaBundles.size(); i++) {
351 schemas.add(new AppSearchSchema(schemaBundles.get(i)));
Alexander Dorokhineab789062021-01-11 21:00:00 -0800352 }
Alexander Dorokhine15d0ae42021-06-18 14:28:34 -0700353 Map<String, List<PackageIdentifier>> schemasVisibleToPackages =
Alexander Dorokhine4d051632021-06-18 10:48:58 -0700354 new ArrayMap<>(schemasVisibleToPackagesBundles.size());
Terry Wange04ceab2021-03-29 19:25:12 -0700355 for (Map.Entry<String, List<Bundle>> entry :
Alexander Dorokhine4d051632021-06-18 10:48:58 -0700356 schemasVisibleToPackagesBundles.entrySet()) {
Terry Wange04ceab2021-03-29 19:25:12 -0700357 List<PackageIdentifier> packageIdentifiers =
358 new ArrayList<>(entry.getValue().size());
359 for (int i = 0; i < entry.getValue().size(); i++) {
360 packageIdentifiers.add(
361 new PackageIdentifier(entry.getValue().get(i)));
362 }
Alexander Dorokhine15d0ae42021-06-18 14:28:34 -0700363 schemasVisibleToPackages.put(entry.getKey(), packageIdentifiers);
Terry Wange04ceab2021-03-29 19:25:12 -0700364 }
Cassie Wang2feb34d2021-07-22 18:55:19 +0000365 instance = mAppSearchUserInstanceManager.getUserInstance(targetUser);
Alexander Dorokhine4d051632021-06-18 10:48:58 -0700366 SetSchemaResponse setSchemaResponse = instance.getAppSearchImpl().setSchema(
Terry Wange04ceab2021-03-29 19:25:12 -0700367 packageName,
368 databaseName,
369 schemas,
Alexander Dorokhine4d051632021-06-18 10:48:58 -0700370 instance.getVisibilityStore(),
Terry Wange04ceab2021-03-29 19:25:12 -0700371 schemasNotDisplayedBySystem,
Alexander Dorokhine15d0ae42021-06-18 14:28:34 -0700372 schemasVisibleToPackages,
Terry Wange04ceab2021-03-29 19:25:12 -0700373 forceOverride,
374 schemaVersion);
Xiaoyu Jinc5a75772021-05-09 20:12:44 -0700375 ++operationSuccessCount;
Terry Wange04ceab2021-03-29 19:25:12 -0700376 invokeCallbackOnResult(callback,
377 AppSearchResult.newSuccessfulResult(setSchemaResponse.getBundle()));
Terry Wangf4d219b2021-07-01 19:11:39 -0700378
379 // setSchema will sync the schemas in the request to AppSearch, any existing
380 // schemas which is not included in the request will be delete if we force
381 // override incompatible schemas. And all documents of these types will be
382 // deleted as well. We should checkForOptimize for these deletion.
383 checkForOptimize(instance);
Terry Wange04ceab2021-03-29 19:25:12 -0700384 } catch (Throwable t) {
Xiaoyu Jinc5a75772021-05-09 20:12:44 -0700385 ++operationFailureCount;
386 statusCode = throwableToFailedResult(t).getResultCode();
Terry Wange04ceab2021-03-29 19:25:12 -0700387 invokeCallbackOnError(callback, t);
Xiaoyu Jinc5a75772021-05-09 20:12:44 -0700388 } finally {
Alexander Dorokhine4d051632021-06-18 10:48:58 -0700389 if (instance != null) {
Xiaoyu Jinc5a75772021-05-09 20:12:44 -0700390 int estimatedBinderLatencyMillis =
391 2 * (int) (totalLatencyStartTimeMillis - binderCallStartTimeMillis);
392 int totalLatencyMillis =
393 (int) (SystemClock.elapsedRealtime() - totalLatencyStartTimeMillis);
Alexander Dorokhine4d051632021-06-18 10:48:58 -0700394 instance.getLogger().logStats(new CallStats.Builder()
Alexander Dorokhine82a38722021-06-09 16:35:22 -0700395 .setPackageName(packageName)
396 .setDatabase(databaseName)
397 .setStatusCode(statusCode)
398 .setTotalLatencyMillis(totalLatencyMillis)
Xiaoyu Jinc5a75772021-05-09 20:12:44 -0700399 .setCallType(CallStats.CALL_TYPE_SET_SCHEMA)
400 // TODO(b/173532925) check the existing binder call latency chart
401 // is good enough for us:
402 // http://dashboards/view/_72c98f9a_91d9_41d4_ab9a_bc14f79742b4
403 .setEstimatedBinderLatencyMillis(estimatedBinderLatencyMillis)
404 .setNumOperationsSucceeded(operationSuccessCount)
Alexander Dorokhine82a38722021-06-09 16:35:22 -0700405 .setNumOperationsFailed(operationFailureCount)
406 .build());
Xiaoyu Jinc5a75772021-05-09 20:12:44 -0700407 }
Alexander Dorokhineab789062021-01-11 21:00:00 -0800408 }
Terry Wange04ceab2021-03-29 19:25:12 -0700409 });
Alexander Dorokhine179c8b82020-01-11 00:17:48 -0800410 }
411
412 @Override
Terry Wang83a24932020-12-09 21:00:18 -0800413 public void getSchema(
Cassie Wang0c62d992021-01-15 14:39:30 -0800414 @NonNull String packageName,
Terry Wang83a24932020-12-09 21:00:18 -0800415 @NonNull String databaseName,
Alexander Dorokhinebea55602021-05-19 13:59:45 -0700416 @NonNull UserHandle userHandle,
Terry Wang83a24932020-12-09 21:00:18 -0800417 @NonNull IAppSearchResultCallback callback) {
Alexander Dorokhine5258ad22021-04-15 10:59:55 -0700418 Objects.requireNonNull(packageName);
419 Objects.requireNonNull(databaseName);
Alexander Dorokhinebea55602021-05-19 13:59:45 -0700420 Objects.requireNonNull(userHandle);
Alexander Dorokhine5258ad22021-04-15 10:59:55 -0700421 Objects.requireNonNull(callback);
Alexander Dorokhinebea55602021-05-19 13:59:45 -0700422
Cassie Wangb0d60122021-03-30 12:38:46 -0700423 int callingUid = Binder.getCallingUid();
Terry Wange04ceab2021-03-29 19:25:12 -0700424 EXECUTOR.execute(() -> {
425 try {
Cassie Wangd51ed162021-07-29 22:22:30 +0000426 verifyCaller(callingUid, packageName);
427
428 // Obtain the user where the client wants to run the operations in. This should
429 // end up being the same as userHandle, assuming it is not a special user and
430 // the client is allowed to run operations in that user.
431 UserHandle targetUser = handleIncomingUser(userHandle, callingUid);
Cassie Wang2feb34d2021-07-22 18:55:19 +0000432 verifyUserUnlocked(targetUser);
Cassie Wangd51ed162021-07-29 22:22:30 +0000433
Alexander Dorokhine4d051632021-06-18 10:48:58 -0700434 AppSearchUserInstance instance =
Cassie Wang2feb34d2021-07-22 18:55:19 +0000435 mAppSearchUserInstanceManager.getUserInstance(targetUser);
Alexander Dorokhine4d051632021-06-18 10:48:58 -0700436 GetSchemaResponse response =
437 instance.getAppSearchImpl().getSchema(packageName, databaseName);
Terry Wange04ceab2021-03-29 19:25:12 -0700438 invokeCallbackOnResult(
439 callback,
440 AppSearchResult.newSuccessfulResult(response.getBundle()));
441 } catch (Throwable t) {
442 invokeCallbackOnError(callback, t);
443 }
444 });
Alexander Dorokhine9795b512021-03-23 22:06:59 -0700445 }
446
447 @Override
448 public void getNamespaces(
449 @NonNull String packageName,
450 @NonNull String databaseName,
Alexander Dorokhinebea55602021-05-19 13:59:45 -0700451 @NonNull UserHandle userHandle,
Alexander Dorokhine9795b512021-03-23 22:06:59 -0700452 @NonNull IAppSearchResultCallback callback) {
Alexander Dorokhine5258ad22021-04-15 10:59:55 -0700453 Objects.requireNonNull(packageName);
454 Objects.requireNonNull(databaseName);
Alexander Dorokhinebea55602021-05-19 13:59:45 -0700455 Objects.requireNonNull(userHandle);
Alexander Dorokhine5258ad22021-04-15 10:59:55 -0700456 Objects.requireNonNull(callback);
Alexander Dorokhinebea55602021-05-19 13:59:45 -0700457
Cassie Wangb0d60122021-03-30 12:38:46 -0700458 int callingUid = Binder.getCallingUid();
Terry Wange04ceab2021-03-29 19:25:12 -0700459 EXECUTOR.execute(() -> {
460 try {
Cassie Wangd51ed162021-07-29 22:22:30 +0000461 verifyCaller(callingUid, packageName);
462
463 // Obtain the user where the client wants to run the operations in. This should
464 // end up being the same as userHandle, assuming it is not a special user and
465 // the client is allowed to run operations in that user.
466 UserHandle targetUser = handleIncomingUser(userHandle, callingUid);
Cassie Wang2feb34d2021-07-22 18:55:19 +0000467 verifyUserUnlocked(targetUser);
Cassie Wangd51ed162021-07-29 22:22:30 +0000468
Alexander Dorokhine4d051632021-06-18 10:48:58 -0700469 AppSearchUserInstance instance =
Cassie Wang2feb34d2021-07-22 18:55:19 +0000470 mAppSearchUserInstanceManager.getUserInstance(targetUser);
Alexander Dorokhine4d051632021-06-18 10:48:58 -0700471 List<String> namespaces =
472 instance.getAppSearchImpl().getNamespaces(packageName, databaseName);
473 invokeCallbackOnResult(
474 callback, AppSearchResult.newSuccessfulResult(namespaces));
Terry Wange04ceab2021-03-29 19:25:12 -0700475 } catch (Throwable t) {
476 invokeCallbackOnError(callback, t);
477 }
478 });
Terry Wang83a24932020-12-09 21:00:18 -0800479 }
480
481 @Override
Alexander Dorokhine18465842020-01-21 01:08:57 -0800482 public void putDocuments(
Cassie Wang0c62d992021-01-15 14:39:30 -0800483 @NonNull String packageName,
Terry Wang6413aee2020-10-07 03:04:58 -0700484 @NonNull String databaseName,
Alexander Dorokhinec66d67c2020-10-08 13:44:04 -0700485 @NonNull List<Bundle> documentBundles,
Alexander Dorokhinebea55602021-05-19 13:59:45 -0700486 @NonNull UserHandle userHandle,
Xiaoyu Jinf8cc2012021-03-12 11:00:54 -0800487 @ElapsedRealtimeLong long binderCallStartTimeMillis,
Terry Wangdbd1dca2020-11-03 17:03:56 -0800488 @NonNull IAppSearchBatchResultCallback callback) {
Alexander Dorokhine5258ad22021-04-15 10:59:55 -0700489 Objects.requireNonNull(packageName);
490 Objects.requireNonNull(databaseName);
491 Objects.requireNonNull(documentBundles);
Alexander Dorokhinebea55602021-05-19 13:59:45 -0700492 Objects.requireNonNull(userHandle);
Alexander Dorokhine5258ad22021-04-15 10:59:55 -0700493 Objects.requireNonNull(callback);
Alexander Dorokhinebea55602021-05-19 13:59:45 -0700494
Xiaoyu Jinef66a422021-05-09 17:38:59 -0700495 long totalLatencyStartTimeMillis = SystemClock.elapsedRealtime();
Terry Wangf2093072020-11-30 04:47:19 -0800496 int callingUid = Binder.getCallingUid();
Terry Wange04ceab2021-03-29 19:25:12 -0700497 EXECUTOR.execute(() -> {
Xiaoyu Jinf8cc2012021-03-12 11:00:54 -0800498 @AppSearchResult.ResultCode int statusCode = AppSearchResult.RESULT_OK;
Alexander Dorokhine4d051632021-06-18 10:48:58 -0700499 AppSearchUserInstance instance = null;
Xiaoyu Jinf8cc2012021-03-12 11:00:54 -0800500 int operationSuccessCount = 0;
501 int operationFailureCount = 0;
Terry Wange04ceab2021-03-29 19:25:12 -0700502 try {
Cassie Wangd51ed162021-07-29 22:22:30 +0000503 verifyCaller(callingUid, packageName);
504
505 // Obtain the user where the client wants to run the operations in. This should
506 // end up being the same as userHandle, assuming it is not a special user and
507 // the client is allowed to run operations in that user.
508 UserHandle targetUser = handleIncomingUser(userHandle, callingUid);
Cassie Wang2feb34d2021-07-22 18:55:19 +0000509 verifyUserUnlocked(targetUser);
Cassie Wangd51ed162021-07-29 22:22:30 +0000510
Terry Wange04ceab2021-03-29 19:25:12 -0700511 AppSearchBatchResult.Builder<String, Void> resultBuilder =
512 new AppSearchBatchResult.Builder<>();
Cassie Wang2feb34d2021-07-22 18:55:19 +0000513 instance = mAppSearchUserInstanceManager.getUserInstance(targetUser);
Terry Wange04ceab2021-03-29 19:25:12 -0700514 for (int i = 0; i < documentBundles.size(); i++) {
515 GenericDocument document = new GenericDocument(documentBundles.get(i));
516 try {
Alexander Dorokhine4d051632021-06-18 10:48:58 -0700517 instance.getAppSearchImpl().putDocument(
518 packageName, databaseName, document, instance.getLogger());
519 resultBuilder.setSuccess(document.getId(), /*value=*/ null);
Xiaoyu Jinf8cc2012021-03-12 11:00:54 -0800520 ++operationSuccessCount;
Terry Wange04ceab2021-03-29 19:25:12 -0700521 } catch (Throwable t) {
Alexander Dorokhine4d051632021-06-18 10:48:58 -0700522 resultBuilder.setResult(document.getId(), throwableToFailedResult(t));
Xiaoyu Jinf8cc2012021-03-12 11:00:54 -0800523 AppSearchResult<Void> result = throwableToFailedResult(t);
Alexander Dorokhine17f79372021-04-21 11:23:09 -0700524 resultBuilder.setResult(document.getId(), result);
Xiaoyu Jinc5a75772021-05-09 20:12:44 -0700525 // Since we can only include one status code in the atom,
526 // for failures, we would just save the one for the last failure
Xiaoyu Jinf8cc2012021-03-12 11:00:54 -0800527 statusCode = result.getResultCode();
528 ++operationFailureCount;
Terry Wange04ceab2021-03-29 19:25:12 -0700529 }
Alexander Dorokhine18465842020-01-21 01:08:57 -0800530 }
Alexander Dorokhinec77f4442021-04-14 09:26:06 -0700531 // Now that the batch has been written. Persist the newly written data.
Alexander Dorokhine4d051632021-06-18 10:48:58 -0700532 instance.getAppSearchImpl().persistToDisk(PersistType.Code.LITE);
Terry Wange04ceab2021-03-29 19:25:12 -0700533 invokeCallbackOnResult(callback, resultBuilder.build());
Terry Wangf4d219b2021-07-01 19:11:39 -0700534
535 // The existing documents with same ID will be deleted, so there may be some
536 // resources that could be released after optimize().
537 checkForOptimize(instance, /*mutateBatchSize=*/ documentBundles.size());
Terry Wange04ceab2021-03-29 19:25:12 -0700538 } catch (Throwable t) {
Xiaoyu Jinc5a75772021-05-09 20:12:44 -0700539 ++operationFailureCount;
540 statusCode = throwableToFailedResult(t).getResultCode();
Terry Wange04ceab2021-03-29 19:25:12 -0700541 invokeCallbackOnError(callback, t);
Xiaoyu Jinf8cc2012021-03-12 11:00:54 -0800542 } finally {
Alexander Dorokhine4d051632021-06-18 10:48:58 -0700543 if (instance != null) {
Xiaoyu Jinc410c4f2021-05-09 14:15:50 -0700544 int estimatedBinderLatencyMillis =
545 2 * (int) (totalLatencyStartTimeMillis - binderCallStartTimeMillis);
546 int totalLatencyMillis =
547 (int) (SystemClock.elapsedRealtime() - totalLatencyStartTimeMillis);
Alexander Dorokhine4d051632021-06-18 10:48:58 -0700548 instance.getLogger().logStats(new CallStats.Builder()
Alexander Dorokhine82a38722021-06-09 16:35:22 -0700549 .setPackageName(packageName)
550 .setDatabase(databaseName)
551 .setStatusCode(statusCode)
552 .setTotalLatencyMillis(totalLatencyMillis)
Xiaoyu Jinf8cc2012021-03-12 11:00:54 -0800553 .setCallType(CallStats.CALL_TYPE_PUT_DOCUMENTS)
554 // TODO(b/173532925) check the existing binder call latency chart
555 // is good enough for us:
556 // http://dashboards/view/_72c98f9a_91d9_41d4_ab9a_bc14f79742b4
Xiaoyu Jinc410c4f2021-05-09 14:15:50 -0700557 .setEstimatedBinderLatencyMillis(estimatedBinderLatencyMillis)
Xiaoyu Jinf8cc2012021-03-12 11:00:54 -0800558 .setNumOperationsSucceeded(operationSuccessCount)
Alexander Dorokhine82a38722021-06-09 16:35:22 -0700559 .setNumOperationsFailed(operationFailureCount)
560 .build());
Xiaoyu Jinf8cc2012021-03-12 11:00:54 -0800561 }
Alexander Dorokhine18465842020-01-21 01:08:57 -0800562 }
Terry Wange04ceab2021-03-29 19:25:12 -0700563 });
Alexander Dorokhinefd07eba2020-01-13 20:22:20 -0800564 }
Alexander Dorokhine969f4462020-03-05 15:54:19 -0800565
Alexander Dorokhine69a8d9f2020-03-06 10:43:16 -0800566 @Override
Terry Wangf2093072020-11-30 04:47:19 -0800567 public void getDocuments(
Cassie Wang0c62d992021-01-15 14:39:30 -0800568 @NonNull String packageName,
Terry Wangf2093072020-11-30 04:47:19 -0800569 @NonNull String databaseName,
570 @NonNull String namespace,
Alexander Dorokhine17f79372021-04-21 11:23:09 -0700571 @NonNull List<String> ids,
Alexander Dorokhine87cdd152021-01-20 15:41:25 -0800572 @NonNull Map<String, List<String>> typePropertyPaths,
Alexander Dorokhinebea55602021-05-19 13:59:45 -0700573 @NonNull UserHandle userHandle,
Xiaoyu Jinc5a75772021-05-09 20:12:44 -0700574 @ElapsedRealtimeLong long binderCallStartTimeMillis,
Terry Wangdbd1dca2020-11-03 17:03:56 -0800575 @NonNull IAppSearchBatchResultCallback callback) {
Alexander Dorokhine5258ad22021-04-15 10:59:55 -0700576 Objects.requireNonNull(packageName);
577 Objects.requireNonNull(databaseName);
578 Objects.requireNonNull(namespace);
Alexander Dorokhine17f79372021-04-21 11:23:09 -0700579 Objects.requireNonNull(ids);
Alexander Dorokhinebea55602021-05-19 13:59:45 -0700580 Objects.requireNonNull(typePropertyPaths);
581 Objects.requireNonNull(userHandle);
Alexander Dorokhine5258ad22021-04-15 10:59:55 -0700582 Objects.requireNonNull(callback);
Alexander Dorokhinebea55602021-05-19 13:59:45 -0700583
Xiaoyu Jinc5a75772021-05-09 20:12:44 -0700584 long totalLatencyStartTimeMillis = SystemClock.elapsedRealtime();
Terry Wangf2093072020-11-30 04:47:19 -0800585 int callingUid = Binder.getCallingUid();
Terry Wange04ceab2021-03-29 19:25:12 -0700586 EXECUTOR.execute(() -> {
Xiaoyu Jinc5a75772021-05-09 20:12:44 -0700587 @AppSearchResult.ResultCode int statusCode = AppSearchResult.RESULT_OK;
Alexander Dorokhine4d051632021-06-18 10:48:58 -0700588 AppSearchUserInstance instance = null;
Xiaoyu Jinc5a75772021-05-09 20:12:44 -0700589 int operationSuccessCount = 0;
590 int operationFailureCount = 0;
Terry Wange04ceab2021-03-29 19:25:12 -0700591 try {
Cassie Wangd51ed162021-07-29 22:22:30 +0000592 verifyCaller(callingUid, packageName);
593
594 // Obtain the user where the client wants to run the operations in. This should
595 // end up being the same as userHandle, assuming it is not a special user and
596 // the client is allowed to run operations in that user.
597 UserHandle targetUser = handleIncomingUser(userHandle, callingUid);
Cassie Wang2feb34d2021-07-22 18:55:19 +0000598 verifyUserUnlocked(targetUser);
Cassie Wangd51ed162021-07-29 22:22:30 +0000599
Terry Wange04ceab2021-03-29 19:25:12 -0700600 AppSearchBatchResult.Builder<String, Bundle> resultBuilder =
601 new AppSearchBatchResult.Builder<>();
Cassie Wang2feb34d2021-07-22 18:55:19 +0000602 instance = mAppSearchUserInstanceManager.getUserInstance(targetUser);
Alexander Dorokhine17f79372021-04-21 11:23:09 -0700603 for (int i = 0; i < ids.size(); i++) {
604 String id = ids.get(i);
Terry Wange04ceab2021-03-29 19:25:12 -0700605 try {
Alexander Dorokhine4d051632021-06-18 10:48:58 -0700606 GenericDocument document = instance.getAppSearchImpl().getDocument(
607 packageName,
608 databaseName,
609 namespace,
610 id,
611 typePropertyPaths);
Xiaoyu Jinc5a75772021-05-09 20:12:44 -0700612 ++operationSuccessCount;
Alexander Dorokhine17f79372021-04-21 11:23:09 -0700613 resultBuilder.setSuccess(id, document.getBundle());
Terry Wange04ceab2021-03-29 19:25:12 -0700614 } catch (Throwable t) {
Xiaoyu Jinc5a75772021-05-09 20:12:44 -0700615 // Since we can only include one status code in the atom,
616 // for failures, we would just save the one for the last failure
617 AppSearchResult<Bundle> result = throwableToFailedResult(t);
618 resultBuilder.setResult(id, result);
619 statusCode = result.getResultCode();
620 ++operationFailureCount;
Terry Wange04ceab2021-03-29 19:25:12 -0700621 }
Alexander Dorokhinea95f44f2020-03-06 13:53:14 -0800622 }
Terry Wange04ceab2021-03-29 19:25:12 -0700623 invokeCallbackOnResult(callback, resultBuilder.build());
624 } catch (Throwable t) {
Xiaoyu Jinc5a75772021-05-09 20:12:44 -0700625 ++operationFailureCount;
626 statusCode = throwableToFailedResult(t).getResultCode();
Terry Wange04ceab2021-03-29 19:25:12 -0700627 invokeCallbackOnError(callback, t);
Xiaoyu Jinc5a75772021-05-09 20:12:44 -0700628 } finally {
Alexander Dorokhine4d051632021-06-18 10:48:58 -0700629 if (instance != null) {
Xiaoyu Jinc5a75772021-05-09 20:12:44 -0700630 int estimatedBinderLatencyMillis =
631 2 * (int) (totalLatencyStartTimeMillis - binderCallStartTimeMillis);
632 int totalLatencyMillis =
633 (int) (SystemClock.elapsedRealtime() - totalLatencyStartTimeMillis);
Alexander Dorokhine4d051632021-06-18 10:48:58 -0700634 instance.getLogger().logStats(new CallStats.Builder()
Alexander Dorokhine82a38722021-06-09 16:35:22 -0700635 .setPackageName(packageName)
636 .setDatabase(databaseName)
637 .setStatusCode(statusCode)
638 .setTotalLatencyMillis(totalLatencyMillis)
Xiaoyu Jinc5a75772021-05-09 20:12:44 -0700639 .setCallType(CallStats.CALL_TYPE_GET_DOCUMENTS)
640 // TODO(b/173532925) check the existing binder call latency chart
641 // is good enough for us:
642 // http://dashboards/view/_72c98f9a_91d9_41d4_ab9a_bc14f79742b4
643 .setEstimatedBinderLatencyMillis(estimatedBinderLatencyMillis)
644 .setNumOperationsSucceeded(operationSuccessCount)
Alexander Dorokhine82a38722021-06-09 16:35:22 -0700645 .setNumOperationsFailed(operationFailureCount)
646 .build());
Xiaoyu Jinc5a75772021-05-09 20:12:44 -0700647 }
Alexander Dorokhine69a8d9f2020-03-06 10:43:16 -0800648 }
Terry Wange04ceab2021-03-29 19:25:12 -0700649 });
Alexander Dorokhine69a8d9f2020-03-06 10:43:16 -0800650 }
651
sidchhabraa7c8f8a2020-01-16 18:38:17 -0800652 @Override
Alexander Dorokhinee708e182020-03-06 15:30:34 -0800653 public void query(
Cassie Wang0c62d992021-01-15 14:39:30 -0800654 @NonNull String packageName,
Terry Wang6413aee2020-10-07 03:04:58 -0700655 @NonNull String databaseName,
Alexander Dorokhinec9fc9602020-10-06 01:39:50 -0700656 @NonNull String queryExpression,
657 @NonNull Bundle searchSpecBundle,
Alexander Dorokhinebea55602021-05-19 13:59:45 -0700658 @NonNull UserHandle userHandle,
Xiaoyu Jinef66a422021-05-09 17:38:59 -0700659 @ElapsedRealtimeLong long binderCallStartTimeMillis,
Alexander Dorokhined48f2362020-10-20 17:40:49 -0700660 @NonNull IAppSearchResultCallback callback) {
Alexander Dorokhine5258ad22021-04-15 10:59:55 -0700661 Objects.requireNonNull(packageName);
662 Objects.requireNonNull(databaseName);
663 Objects.requireNonNull(queryExpression);
664 Objects.requireNonNull(searchSpecBundle);
Alexander Dorokhinebea55602021-05-19 13:59:45 -0700665 Objects.requireNonNull(userHandle);
Alexander Dorokhine5258ad22021-04-15 10:59:55 -0700666 Objects.requireNonNull(callback);
Alexander Dorokhinebea55602021-05-19 13:59:45 -0700667
Xiaoyu Jinef66a422021-05-09 17:38:59 -0700668 long totalLatencyStartTimeMillis = SystemClock.elapsedRealtime();
Terry Wangf2093072020-11-30 04:47:19 -0800669 int callingUid = Binder.getCallingUid();
Terry Wange04ceab2021-03-29 19:25:12 -0700670 EXECUTOR.execute(() -> {
Xiaoyu Jinef66a422021-05-09 17:38:59 -0700671 @AppSearchResult.ResultCode int statusCode = AppSearchResult.RESULT_OK;
Alexander Dorokhine4d051632021-06-18 10:48:58 -0700672 AppSearchUserInstance instance = null;
Xiaoyu Jinef66a422021-05-09 17:38:59 -0700673 int operationSuccessCount = 0;
674 int operationFailureCount = 0;
Terry Wange04ceab2021-03-29 19:25:12 -0700675 try {
Cassie Wangd51ed162021-07-29 22:22:30 +0000676 verifyCaller(callingUid, packageName);
677
678 // Obtain the user where the client wants to run the operations in. This should
679 // end up being the same as userHandle, assuming it is not a special user and
680 // the client is allowed to run operations in that user.
681 UserHandle targetUser = handleIncomingUser(userHandle, callingUid);
Cassie Wang2feb34d2021-07-22 18:55:19 +0000682 verifyUserUnlocked(targetUser);
Cassie Wangd51ed162021-07-29 22:22:30 +0000683
Cassie Wang2feb34d2021-07-22 18:55:19 +0000684 instance = mAppSearchUserInstanceManager.getUserInstance(targetUser);
Alexander Dorokhine4d051632021-06-18 10:48:58 -0700685 SearchResultPage searchResultPage = instance.getAppSearchImpl().query(
686 packageName,
687 databaseName,
688 queryExpression,
689 new SearchSpec(searchSpecBundle),
690 instance.getLogger());
Xiaoyu Jinef66a422021-05-09 17:38:59 -0700691 ++operationSuccessCount;
Terry Wange04ceab2021-03-29 19:25:12 -0700692 invokeCallbackOnResult(
693 callback,
694 AppSearchResult.newSuccessfulResult(searchResultPage.getBundle()));
695 } catch (Throwable t) {
Xiaoyu Jinef66a422021-05-09 17:38:59 -0700696 ++operationFailureCount;
697 statusCode = throwableToFailedResult(t).getResultCode();
Terry Wange04ceab2021-03-29 19:25:12 -0700698 invokeCallbackOnError(callback, t);
Xiaoyu Jinef66a422021-05-09 17:38:59 -0700699 } finally {
Alexander Dorokhine4d051632021-06-18 10:48:58 -0700700 if (instance != null) {
Xiaoyu Jinef66a422021-05-09 17:38:59 -0700701 int estimatedBinderLatencyMillis =
702 2 * (int) (totalLatencyStartTimeMillis - binderCallStartTimeMillis);
703 int totalLatencyMillis =
704 (int) (SystemClock.elapsedRealtime() - totalLatencyStartTimeMillis);
Alexander Dorokhine4d051632021-06-18 10:48:58 -0700705 instance.getLogger().logStats(new CallStats.Builder()
Alexander Dorokhine82a38722021-06-09 16:35:22 -0700706 .setPackageName(packageName)
707 .setDatabase(databaseName)
708 .setStatusCode(statusCode)
709 .setTotalLatencyMillis(totalLatencyMillis)
Xiaoyu Jinef66a422021-05-09 17:38:59 -0700710 .setCallType(CallStats.CALL_TYPE_SEARCH)
711 // TODO(b/173532925) check the existing binder call latency chart
712 // is good enough for us:
713 // http://dashboards/view/_72c98f9a_91d9_41d4_ab9a_bc14f79742b4
714 .setEstimatedBinderLatencyMillis(estimatedBinderLatencyMillis)
715 .setNumOperationsSucceeded(operationSuccessCount)
Alexander Dorokhine82a38722021-06-09 16:35:22 -0700716 .setNumOperationsFailed(operationFailureCount)
717 .build());
Xiaoyu Jinef66a422021-05-09 17:38:59 -0700718 }
Terry Wange04ceab2021-03-29 19:25:12 -0700719 }
720 });
Alexander Dorokhined48f2362020-10-20 17:40:49 -0700721 }
722
Terry Wangf2093072020-11-30 04:47:19 -0800723 @Override
Terry Wangbfbfcac2020-11-06 15:46:44 -0800724 public void globalQuery(
Cassie Wang0c62d992021-01-15 14:39:30 -0800725 @NonNull String packageName,
Terry Wangbfbfcac2020-11-06 15:46:44 -0800726 @NonNull String queryExpression,
727 @NonNull Bundle searchSpecBundle,
Alexander Dorokhinebea55602021-05-19 13:59:45 -0700728 @NonNull UserHandle userHandle,
Xiaoyu Jinef66a422021-05-09 17:38:59 -0700729 @ElapsedRealtimeLong long binderCallStartTimeMillis,
Terry Wangbfbfcac2020-11-06 15:46:44 -0800730 @NonNull IAppSearchResultCallback callback) {
Alexander Dorokhine5258ad22021-04-15 10:59:55 -0700731 Objects.requireNonNull(packageName);
732 Objects.requireNonNull(queryExpression);
733 Objects.requireNonNull(searchSpecBundle);
Alexander Dorokhinebea55602021-05-19 13:59:45 -0700734 Objects.requireNonNull(userHandle);
Alexander Dorokhine5258ad22021-04-15 10:59:55 -0700735 Objects.requireNonNull(callback);
Alexander Dorokhinebea55602021-05-19 13:59:45 -0700736
Xiaoyu Jinef66a422021-05-09 17:38:59 -0700737 long totalLatencyStartTimeMillis = SystemClock.elapsedRealtime();
Terry Wangf2093072020-11-30 04:47:19 -0800738 int callingUid = Binder.getCallingUid();
Terry Wange04ceab2021-03-29 19:25:12 -0700739 EXECUTOR.execute(() -> {
Xiaoyu Jinef66a422021-05-09 17:38:59 -0700740 @AppSearchResult.ResultCode int statusCode = AppSearchResult.RESULT_OK;
Alexander Dorokhine4d051632021-06-18 10:48:58 -0700741 AppSearchUserInstance instance = null;
Xiaoyu Jinef66a422021-05-09 17:38:59 -0700742 int operationSuccessCount = 0;
743 int operationFailureCount = 0;
Terry Wange04ceab2021-03-29 19:25:12 -0700744 try {
Cassie Wangd51ed162021-07-29 22:22:30 +0000745 verifyCaller(callingUid, packageName);
746
747 // Obtain the user where the client wants to run the operations in. This should
748 // end up being the same as userHandle, assuming it is not a special user and
749 // the client is allowed to run operations in that user.
750 UserHandle targetUser = handleIncomingUser(userHandle, callingUid);
Cassie Wang2feb34d2021-07-22 18:55:19 +0000751 verifyUserUnlocked(targetUser);
Cassie Wangd51ed162021-07-29 22:22:30 +0000752
Cassie Wang2feb34d2021-07-22 18:55:19 +0000753 instance = mAppSearchUserInstanceManager.getUserInstance(targetUser);
Alexander Dorokhine4d051632021-06-18 10:48:58 -0700754
755 boolean callerHasSystemAccess =
756 instance.getVisibilityStore().doesCallerHaveSystemAccess(packageName);
757 SearchResultPage searchResultPage = instance.getAppSearchImpl().globalQuery(
758 queryExpression,
759 new SearchSpec(searchSpecBundle),
760 packageName,
761 instance.getVisibilityStore(),
762 callingUid,
763 callerHasSystemAccess,
764 instance.getLogger());
Xiaoyu Jinef66a422021-05-09 17:38:59 -0700765 ++operationSuccessCount;
Terry Wange04ceab2021-03-29 19:25:12 -0700766 invokeCallbackOnResult(
767 callback,
768 AppSearchResult.newSuccessfulResult(searchResultPage.getBundle()));
Xiaoyu Jinef66a422021-05-09 17:38:59 -0700769 } catch (Throwable t) {
770 ++operationFailureCount;
771 statusCode = throwableToFailedResult(t).getResultCode();
Terry Wange04ceab2021-03-29 19:25:12 -0700772 invokeCallbackOnError(callback, t);
Xiaoyu Jinef66a422021-05-09 17:38:59 -0700773 } finally {
Alexander Dorokhine4d051632021-06-18 10:48:58 -0700774 if (instance != null) {
Xiaoyu Jinef66a422021-05-09 17:38:59 -0700775 int estimatedBinderLatencyMillis =
776 2 * (int) (totalLatencyStartTimeMillis - binderCallStartTimeMillis);
777 int totalLatencyMillis =
778 (int) (SystemClock.elapsedRealtime() - totalLatencyStartTimeMillis);
Alexander Dorokhine4d051632021-06-18 10:48:58 -0700779 instance.getLogger().logStats(new CallStats.Builder()
Alexander Dorokhine82a38722021-06-09 16:35:22 -0700780 .setPackageName(packageName)
781 .setStatusCode(statusCode)
782 .setTotalLatencyMillis(totalLatencyMillis)
Xiaoyu Jinef66a422021-05-09 17:38:59 -0700783 .setCallType(CallStats.CALL_TYPE_GLOBAL_SEARCH)
784 // TODO(b/173532925) check the existing binder call latency chart
785 // is good enough for us:
786 // http://dashboards/view/_72c98f9a_91d9_41d4_ab9a_bc14f79742b4
787 .setEstimatedBinderLatencyMillis(estimatedBinderLatencyMillis)
788 .setNumOperationsSucceeded(operationSuccessCount)
Alexander Dorokhine82a38722021-06-09 16:35:22 -0700789 .setNumOperationsFailed(operationFailureCount)
790 .build());
Xiaoyu Jinef66a422021-05-09 17:38:59 -0700791 }
Terry Wange04ceab2021-03-29 19:25:12 -0700792 }
793 });
Terry Wangbfbfcac2020-11-06 15:46:44 -0800794 }
795
Alexander Dorokhined48f2362020-10-20 17:40:49 -0700796 @Override
Cassie Wang0c62d992021-01-15 14:39:30 -0800797 public void getNextPage(
Cassie Wang84e33a02021-06-18 14:13:31 -0700798 @NonNull String packageName,
Cassie Wang0c62d992021-01-15 14:39:30 -0800799 long nextPageToken,
Alexander Dorokhinebea55602021-05-19 13:59:45 -0700800 @NonNull UserHandle userHandle,
Alexander Dorokhined48f2362020-10-20 17:40:49 -0700801 @NonNull IAppSearchResultCallback callback) {
Cassie Wang84e33a02021-06-18 14:13:31 -0700802 Objects.requireNonNull(packageName);
Alexander Dorokhinebea55602021-05-19 13:59:45 -0700803 Objects.requireNonNull(userHandle);
Alexander Dorokhine5258ad22021-04-15 10:59:55 -0700804 Objects.requireNonNull(callback);
Alexander Dorokhinebea55602021-05-19 13:59:45 -0700805
Terry Wangf2093072020-11-30 04:47:19 -0800806 int callingUid = Binder.getCallingUid();
Terry Wange04ceab2021-03-29 19:25:12 -0700807 EXECUTOR.execute(() -> {
808 try {
Cassie Wangd51ed162021-07-29 22:22:30 +0000809 verifyCaller(callingUid, packageName);
810
811 // Obtain the user where the client wants to run the operations in. This should
812 // end up being the same as userHandle, assuming it is not a special user and
813 // the client is allowed to run operations in that user.
814 UserHandle targetUser = handleIncomingUser(userHandle, callingUid);
Cassie Wang2feb34d2021-07-22 18:55:19 +0000815 verifyUserUnlocked(targetUser);
Cassie Wangd51ed162021-07-29 22:22:30 +0000816
Alexander Dorokhine4d051632021-06-18 10:48:58 -0700817 AppSearchUserInstance instance =
Cassie Wang2feb34d2021-07-22 18:55:19 +0000818 mAppSearchUserInstanceManager.getUserInstance(targetUser);
Alexander Dorokhine4d051632021-06-18 10:48:58 -0700819 SearchResultPage searchResultPage =
Alexander Dorokhined7e39892021-07-02 14:50:05 -0700820 instance.getAppSearchImpl().getNextPage(packageName, nextPageToken);
Terry Wange04ceab2021-03-29 19:25:12 -0700821 invokeCallbackOnResult(
822 callback,
823 AppSearchResult.newSuccessfulResult(searchResultPage.getBundle()));
824 } catch (Throwable t) {
825 invokeCallbackOnError(callback, t);
826 }
827 });
Alexander Dorokhined48f2362020-10-20 17:40:49 -0700828 }
829
830 @Override
Cassie Wang84e33a02021-06-18 14:13:31 -0700831 public void invalidateNextPageToken(@NonNull String packageName, long nextPageToken,
832 @NonNull UserHandle userHandle) {
833 Objects.requireNonNull(packageName);
Alexander Dorokhinebea55602021-05-19 13:59:45 -0700834 Objects.requireNonNull(userHandle);
835
Terry Wangf2093072020-11-30 04:47:19 -0800836 int callingUid = Binder.getCallingUid();
Terry Wange04ceab2021-03-29 19:25:12 -0700837 EXECUTOR.execute(() -> {
838 try {
Cassie Wangd51ed162021-07-29 22:22:30 +0000839 verifyCaller(callingUid, packageName);
840
841 // Obtain the user where the client wants to run the operations in. This should
842 // end up being the same as userHandle, assuming it is not a special user and
843 // the client is allowed to run operations in that user.
844 UserHandle targetUser = handleIncomingUser(userHandle, callingUid);
Cassie Wang2feb34d2021-07-22 18:55:19 +0000845 verifyUserUnlocked(targetUser);
Cassie Wangd51ed162021-07-29 22:22:30 +0000846
Alexander Dorokhine4d051632021-06-18 10:48:58 -0700847 AppSearchUserInstance instance =
Cassie Wang2feb34d2021-07-22 18:55:19 +0000848 mAppSearchUserInstanceManager.getUserInstance(targetUser);
Alexander Dorokhined7e39892021-07-02 14:50:05 -0700849 instance.getAppSearchImpl().invalidateNextPageToken(packageName, nextPageToken);
Terry Wange04ceab2021-03-29 19:25:12 -0700850 } catch (Throwable t) {
851 Log.e(TAG, "Unable to invalidate the query page token", t);
852 }
853 });
sidchhabraa7c8f8a2020-01-16 18:38:17 -0800854 }
Alexander Dorokhine969f4462020-03-05 15:54:19 -0800855
Alexander Dorokhinef6c66ae2020-03-09 14:47:25 -0700856 @Override
Terry Wang623e3b02021-02-02 20:27:33 -0800857 public void writeQueryResultsToFile(
858 @NonNull String packageName,
859 @NonNull String databaseName,
860 @NonNull ParcelFileDescriptor fileDescriptor,
861 @NonNull String queryExpression,
862 @NonNull Bundle searchSpecBundle,
Alexander Dorokhinebea55602021-05-19 13:59:45 -0700863 @NonNull UserHandle userHandle,
Terry Wang623e3b02021-02-02 20:27:33 -0800864 @NonNull IAppSearchResultCallback callback) {
Alexander Dorokhinebea55602021-05-19 13:59:45 -0700865 Objects.requireNonNull(packageName);
866 Objects.requireNonNull(databaseName);
867 Objects.requireNonNull(fileDescriptor);
868 Objects.requireNonNull(queryExpression);
869 Objects.requireNonNull(searchSpecBundle);
870 Objects.requireNonNull(userHandle);
871 Objects.requireNonNull(callback);
872
Terry Wang623e3b02021-02-02 20:27:33 -0800873 int callingUid = Binder.getCallingUid();
Terry Wange04ceab2021-03-29 19:25:12 -0700874 EXECUTOR.execute(() -> {
875 try {
Cassie Wangd51ed162021-07-29 22:22:30 +0000876 verifyCaller(callingUid, packageName);
877
878 // Obtain the user where the client wants to run the operations in. This should
879 // end up being the same as userHandle, assuming it is not a special user and
880 // the client is allowed to run operations in that user.
881 UserHandle targetUser = handleIncomingUser(userHandle, callingUid);
Cassie Wang2feb34d2021-07-22 18:55:19 +0000882 verifyUserUnlocked(targetUser);
Cassie Wangd51ed162021-07-29 22:22:30 +0000883
Alexander Dorokhine4d051632021-06-18 10:48:58 -0700884 AppSearchUserInstance instance =
Cassie Wang2feb34d2021-07-22 18:55:19 +0000885 mAppSearchUserInstanceManager.getUserInstance(targetUser);
Terry Wange04ceab2021-03-29 19:25:12 -0700886 // we don't need to append the file. The file is always brand new.
887 try (DataOutputStream outputStream = new DataOutputStream(
888 new FileOutputStream(fileDescriptor.getFileDescriptor()))) {
Alexander Dorokhine4d051632021-06-18 10:48:58 -0700889 SearchResultPage searchResultPage = instance.getAppSearchImpl().query(
Terry Wange04ceab2021-03-29 19:25:12 -0700890 packageName,
891 databaseName,
892 queryExpression,
Alexander Dorokhine7cbc4712021-04-27 14:47:39 -0700893 new SearchSpec(searchSpecBundle),
894 /*logger=*/ null);
Terry Wange04ceab2021-03-29 19:25:12 -0700895 while (!searchResultPage.getResults().isEmpty()) {
896 for (int i = 0; i < searchResultPage.getResults().size(); i++) {
897 AppSearchMigrationHelper.writeBundleToOutputStream(
898 outputStream, searchResultPage.getResults().get(i)
899 .getGenericDocument().getBundle());
900 }
Alexander Dorokhine4d051632021-06-18 10:48:58 -0700901 searchResultPage = instance.getAppSearchImpl().getNextPage(
Alexander Dorokhined7e39892021-07-02 14:50:05 -0700902 packageName, searchResultPage.getNextPageToken());
Terry Wang623e3b02021-02-02 20:27:33 -0800903 }
Terry Wang623e3b02021-02-02 20:27:33 -0800904 }
Terry Wange04ceab2021-03-29 19:25:12 -0700905 invokeCallbackOnResult(callback, AppSearchResult.newSuccessfulResult(null));
906 } catch (Throwable t) {
907 invokeCallbackOnError(callback, t);
Terry Wang623e3b02021-02-02 20:27:33 -0800908 }
Terry Wange04ceab2021-03-29 19:25:12 -0700909 });
Terry Wang623e3b02021-02-02 20:27:33 -0800910 }
911
912 @Override
913 public void putDocumentsFromFile(
914 @NonNull String packageName,
915 @NonNull String databaseName,
916 @NonNull ParcelFileDescriptor fileDescriptor,
Alexander Dorokhinebea55602021-05-19 13:59:45 -0700917 @NonNull UserHandle userHandle,
Terry Wang623e3b02021-02-02 20:27:33 -0800918 @NonNull IAppSearchResultCallback callback) {
Alexander Dorokhinebea55602021-05-19 13:59:45 -0700919 Objects.requireNonNull(packageName);
920 Objects.requireNonNull(databaseName);
921 Objects.requireNonNull(fileDescriptor);
922 Objects.requireNonNull(userHandle);
923 Objects.requireNonNull(callback);
924
Terry Wang623e3b02021-02-02 20:27:33 -0800925 int callingUid = Binder.getCallingUid();
Terry Wange04ceab2021-03-29 19:25:12 -0700926 EXECUTOR.execute(() -> {
927 try {
Cassie Wangd51ed162021-07-29 22:22:30 +0000928 verifyCaller(callingUid, packageName);
929
930 // Obtain the user where the client wants to run the operations in. This should
931 // end up being the same as userHandle, assuming it is not a special user and
932 // the client is allowed to run operations in that user.
933 UserHandle targetUser = handleIncomingUser(userHandle, callingUid);
Cassie Wang2feb34d2021-07-22 18:55:19 +0000934 verifyUserUnlocked(targetUser);
Cassie Wangd51ed162021-07-29 22:22:30 +0000935
Alexander Dorokhine4d051632021-06-18 10:48:58 -0700936 AppSearchUserInstance instance =
Cassie Wang2feb34d2021-07-22 18:55:19 +0000937 mAppSearchUserInstanceManager.getUserInstance(targetUser);
Terry Wang623e3b02021-02-02 20:27:33 -0800938
Terry Wange04ceab2021-03-29 19:25:12 -0700939 GenericDocument document;
940 ArrayList<Bundle> migrationFailureBundles = new ArrayList<>();
941 try (DataInputStream inputStream = new DataInputStream(
942 new FileInputStream(fileDescriptor.getFileDescriptor()))) {
943 while (true) {
944 try {
945 document = AppSearchMigrationHelper
946 .readDocumentFromInputStream(inputStream);
947 } catch (EOFException e) {
948 // nothing wrong, we just finish the reading.
949 break;
950 }
951 try {
Alexander Dorokhine4d051632021-06-18 10:48:58 -0700952 instance.getAppSearchImpl().putDocument(
953 packageName, databaseName, document, /*logger=*/ null);
Terry Wange04ceab2021-03-29 19:25:12 -0700954 } catch (Throwable t) {
Alexander Dorokhine17f79372021-04-21 11:23:09 -0700955 migrationFailureBundles.add(new SetSchemaResponse.MigrationFailure(
956 document.getNamespace(),
957 document.getId(),
958 document.getSchemaType(),
959 AppSearchResult.throwableToFailedResult(t))
960 .getBundle());
Terry Wange04ceab2021-03-29 19:25:12 -0700961 }
Terry Wang623e3b02021-02-02 20:27:33 -0800962 }
963 }
Alexander Dorokhine4d051632021-06-18 10:48:58 -0700964 instance.getAppSearchImpl().persistToDisk(PersistType.Code.FULL);
Terry Wange04ceab2021-03-29 19:25:12 -0700965 invokeCallbackOnResult(callback,
966 AppSearchResult.newSuccessfulResult(migrationFailureBundles));
967 } catch (Throwable t) {
968 invokeCallbackOnError(callback, t);
Terry Wang623e3b02021-02-02 20:27:33 -0800969 }
Terry Wange04ceab2021-03-29 19:25:12 -0700970 });
Terry Wang623e3b02021-02-02 20:27:33 -0800971 }
972
973 @Override
Alexander Dorokhined18f8842021-01-20 15:26:13 -0800974 public void reportUsage(
975 @NonNull String packageName,
976 @NonNull String databaseName,
977 @NonNull String namespace,
Alexander Dorokhine17f79372021-04-21 11:23:09 -0700978 @NonNull String documentId,
Alexander Dorokhined18f8842021-01-20 15:26:13 -0800979 long usageTimeMillis,
Alexander Dorokhine9795b512021-03-23 22:06:59 -0700980 boolean systemUsage,
Alexander Dorokhinebea55602021-05-19 13:59:45 -0700981 @NonNull UserHandle userHandle,
Alexander Dorokhined18f8842021-01-20 15:26:13 -0800982 @NonNull IAppSearchResultCallback callback) {
Alexander Dorokhinebea55602021-05-19 13:59:45 -0700983 Objects.requireNonNull(packageName);
Alexander Dorokhined18f8842021-01-20 15:26:13 -0800984 Objects.requireNonNull(databaseName);
985 Objects.requireNonNull(namespace);
Alexander Dorokhine17f79372021-04-21 11:23:09 -0700986 Objects.requireNonNull(documentId);
Alexander Dorokhinebea55602021-05-19 13:59:45 -0700987 Objects.requireNonNull(userHandle);
Alexander Dorokhined18f8842021-01-20 15:26:13 -0800988 Objects.requireNonNull(callback);
Alexander Dorokhinebea55602021-05-19 13:59:45 -0700989
Alexander Dorokhined18f8842021-01-20 15:26:13 -0800990 int callingUid = Binder.getCallingUid();
Terry Wange04ceab2021-03-29 19:25:12 -0700991 EXECUTOR.execute(() -> {
992 try {
Cassie Wangd51ed162021-07-29 22:22:30 +0000993 verifyCaller(callingUid, packageName);
994
995 // Obtain the user where the client wants to run the operations in. This should
996 // end up being the same as userHandle, assuming it is not a special user and
997 // the client is allowed to run operations in that user.
998 UserHandle targetUser = handleIncomingUser(userHandle, callingUid);
Cassie Wang2feb34d2021-07-22 18:55:19 +0000999 verifyUserUnlocked(targetUser);
Cassie Wangd51ed162021-07-29 22:22:30 +00001000
Alexander Dorokhine4d051632021-06-18 10:48:58 -07001001 AppSearchUserInstance instance =
Cassie Wang2feb34d2021-07-22 18:55:19 +00001002 mAppSearchUserInstanceManager.getUserInstance(targetUser);
Alexander Dorokhine9795b512021-03-23 22:06:59 -07001003
Alexander Dorokhine4d051632021-06-18 10:48:58 -07001004 if (systemUsage
1005 && !instance.getVisibilityStore()
1006 .doesCallerHaveSystemAccess(packageName)) {
1007 throw new AppSearchException(
1008 AppSearchResult.RESULT_SECURITY_ERROR,
1009 packageName + " does not have access to report system usage");
Terry Wange04ceab2021-03-29 19:25:12 -07001010 }
1011
Alexander Dorokhine4d051632021-06-18 10:48:58 -07001012 instance.getAppSearchImpl().reportUsage(
Alexander Dorokhine17f79372021-04-21 11:23:09 -07001013 packageName, databaseName, namespace, documentId,
Terry Wange04ceab2021-03-29 19:25:12 -07001014 usageTimeMillis, systemUsage);
1015 invokeCallbackOnResult(
Alexander Dorokhine4d051632021-06-18 10:48:58 -07001016 callback, AppSearchResult.newSuccessfulResult(/*value=*/ null));
Terry Wange04ceab2021-03-29 19:25:12 -07001017 } catch (Throwable t) {
1018 invokeCallbackOnError(callback, t);
Alexander Dorokhine9795b512021-03-23 22:06:59 -07001019 }
Terry Wange04ceab2021-03-29 19:25:12 -07001020 });
Alexander Dorokhined18f8842021-01-20 15:26:13 -08001021 }
1022
1023 @Override
Alexander Dorokhine17f79372021-04-21 11:23:09 -07001024 public void removeByDocumentId(
Cassie Wang0c62d992021-01-15 14:39:30 -08001025 @NonNull String packageName,
Terry Wangf2093072020-11-30 04:47:19 -08001026 @NonNull String databaseName,
1027 @NonNull String namespace,
Alexander Dorokhine17f79372021-04-21 11:23:09 -07001028 @NonNull List<String> ids,
Alexander Dorokhinebea55602021-05-19 13:59:45 -07001029 @NonNull UserHandle userHandle,
Xiaoyu Jinc5a75772021-05-09 20:12:44 -07001030 @ElapsedRealtimeLong long binderCallStartTimeMillis,
Terry Wangdbd1dca2020-11-03 17:03:56 -08001031 @NonNull IAppSearchBatchResultCallback callback) {
Alexander Dorokhine5258ad22021-04-15 10:59:55 -07001032 Objects.requireNonNull(packageName);
1033 Objects.requireNonNull(databaseName);
Alexander Dorokhinebea55602021-05-19 13:59:45 -07001034 Objects.requireNonNull(namespace);
Alexander Dorokhine17f79372021-04-21 11:23:09 -07001035 Objects.requireNonNull(ids);
Alexander Dorokhinebea55602021-05-19 13:59:45 -07001036 Objects.requireNonNull(userHandle);
Alexander Dorokhine5258ad22021-04-15 10:59:55 -07001037 Objects.requireNonNull(callback);
Alexander Dorokhinebea55602021-05-19 13:59:45 -07001038
Xiaoyu Jinc5a75772021-05-09 20:12:44 -07001039 long totalLatencyStartTimeMillis = SystemClock.elapsedRealtime();
Terry Wangf2093072020-11-30 04:47:19 -08001040 int callingUid = Binder.getCallingUid();
Terry Wange04ceab2021-03-29 19:25:12 -07001041 EXECUTOR.execute(() -> {
Xiaoyu Jinc5a75772021-05-09 20:12:44 -07001042 @AppSearchResult.ResultCode int statusCode = AppSearchResult.RESULT_OK;
Alexander Dorokhine4d051632021-06-18 10:48:58 -07001043 AppSearchUserInstance instance = null;
Xiaoyu Jinc5a75772021-05-09 20:12:44 -07001044 int operationSuccessCount = 0;
1045 int operationFailureCount = 0;
Terry Wange04ceab2021-03-29 19:25:12 -07001046 try {
Cassie Wangd51ed162021-07-29 22:22:30 +00001047 verifyCaller(callingUid, packageName);
1048
1049 // Obtain the user where the client wants to run the operations in. This should
1050 // end up being the same as userHandle, assuming it is not a special user and
1051 // the client is allowed to run operations in that user.
1052 UserHandle targetUser = handleIncomingUser(userHandle, callingUid);
Cassie Wang2feb34d2021-07-22 18:55:19 +00001053 verifyUserUnlocked(targetUser);
Cassie Wangd51ed162021-07-29 22:22:30 +00001054
Terry Wange04ceab2021-03-29 19:25:12 -07001055 AppSearchBatchResult.Builder<String, Void> resultBuilder =
1056 new AppSearchBatchResult.Builder<>();
Cassie Wang2feb34d2021-07-22 18:55:19 +00001057 instance = mAppSearchUserInstanceManager.getUserInstance(targetUser);
Alexander Dorokhine17f79372021-04-21 11:23:09 -07001058 for (int i = 0; i < ids.size(); i++) {
1059 String id = ids.get(i);
Terry Wange04ceab2021-03-29 19:25:12 -07001060 try {
Alexander Dorokhine4d051632021-06-18 10:48:58 -07001061 instance.getAppSearchImpl().remove(
Alexander Dorokhinea4b5bab2021-05-20 14:24:50 -07001062 packageName,
1063 databaseName,
1064 namespace,
1065 id,
1066 /*removeStatsBuilder=*/ null);
Xiaoyu Jinc5a75772021-05-09 20:12:44 -07001067 ++operationSuccessCount;
Alexander Dorokhine17f79372021-04-21 11:23:09 -07001068 resultBuilder.setSuccess(id, /*result= */ null);
Terry Wange04ceab2021-03-29 19:25:12 -07001069 } catch (Throwable t) {
Xiaoyu Jinc5a75772021-05-09 20:12:44 -07001070 AppSearchResult<Void> result = throwableToFailedResult(t);
1071 resultBuilder.setResult(id, result);
1072 // Since we can only include one status code in the atom,
1073 // for failures, we would just save the one for the last failure
1074 statusCode = result.getResultCode();
1075 ++operationFailureCount;
Terry Wange04ceab2021-03-29 19:25:12 -07001076 }
Alexander Dorokhineff82fba2020-03-09 16:35:24 -07001077 }
Alexander Dorokhinec77f4442021-04-14 09:26:06 -07001078 // Now that the batch has been written. Persist the newly written data.
Alexander Dorokhine4d051632021-06-18 10:48:58 -07001079 instance.getAppSearchImpl().persistToDisk(PersistType.Code.LITE);
Terry Wange04ceab2021-03-29 19:25:12 -07001080 invokeCallbackOnResult(callback, resultBuilder.build());
Terry Wangf4d219b2021-07-01 19:11:39 -07001081
1082 checkForOptimize(instance, ids.size());
Terry Wange04ceab2021-03-29 19:25:12 -07001083 } catch (Throwable t) {
Xiaoyu Jinc5a75772021-05-09 20:12:44 -07001084 ++operationFailureCount;
1085 statusCode = throwableToFailedResult(t).getResultCode();
Terry Wange04ceab2021-03-29 19:25:12 -07001086 invokeCallbackOnError(callback, t);
Xiaoyu Jinc5a75772021-05-09 20:12:44 -07001087 } finally {
Alexander Dorokhine4d051632021-06-18 10:48:58 -07001088 if (instance != null) {
Xiaoyu Jinc5a75772021-05-09 20:12:44 -07001089 int estimatedBinderLatencyMillis =
1090 2 * (int) (totalLatencyStartTimeMillis - binderCallStartTimeMillis);
1091 int totalLatencyMillis =
1092 (int) (SystemClock.elapsedRealtime() - totalLatencyStartTimeMillis);
Alexander Dorokhine4d051632021-06-18 10:48:58 -07001093 instance.getLogger().logStats(new CallStats.Builder()
Alexander Dorokhine82a38722021-06-09 16:35:22 -07001094 .setPackageName(packageName)
1095 .setDatabase(databaseName)
1096 .setStatusCode(statusCode)
1097 .setTotalLatencyMillis(totalLatencyMillis)
Xiaoyu Jinc5a75772021-05-09 20:12:44 -07001098 .setCallType(CallStats.CALL_TYPE_REMOVE_DOCUMENTS_BY_ID)
1099 // TODO(b/173532925) check the existing binder call latency chart
1100 // is good enough for us:
1101 // http://dashboards/view/_72c98f9a_91d9_41d4_ab9a_bc14f79742b4
1102 .setEstimatedBinderLatencyMillis(estimatedBinderLatencyMillis)
1103 .setNumOperationsSucceeded(operationSuccessCount)
Alexander Dorokhine82a38722021-06-09 16:35:22 -07001104 .setNumOperationsFailed(operationFailureCount)
1105 .build());
Xiaoyu Jinc5a75772021-05-09 20:12:44 -07001106 }
Alexander Dorokhineff82fba2020-03-09 16:35:24 -07001107 }
Terry Wange04ceab2021-03-29 19:25:12 -07001108 });
Alexander Dorokhineff82fba2020-03-09 16:35:24 -07001109 }
1110
1111 @Override
Terry Wang26b9e5c2020-10-23 02:05:01 -07001112 public void removeByQuery(
Cassie Wang0c62d992021-01-15 14:39:30 -08001113 @NonNull String packageName,
Terry Wang26b9e5c2020-10-23 02:05:01 -07001114 @NonNull String databaseName,
1115 @NonNull String queryExpression,
1116 @NonNull Bundle searchSpecBundle,
Alexander Dorokhinebea55602021-05-19 13:59:45 -07001117 @NonNull UserHandle userHandle,
Xiaoyu Jinc5a75772021-05-09 20:12:44 -07001118 @ElapsedRealtimeLong long binderCallStartTimeMillis,
Alexander Dorokhine178366b2020-10-20 17:40:49 -07001119 @NonNull IAppSearchResultCallback callback) {
Xiaoyu Jinc5a75772021-05-09 20:12:44 -07001120 // TODO(b/173532925) log CallStats once we have CALL_TYPE_REMOVE_BY_QUERY added
Alexander Dorokhine5258ad22021-04-15 10:59:55 -07001121 Objects.requireNonNull(packageName);
1122 Objects.requireNonNull(databaseName);
1123 Objects.requireNonNull(queryExpression);
1124 Objects.requireNonNull(searchSpecBundle);
Alexander Dorokhinebea55602021-05-19 13:59:45 -07001125 Objects.requireNonNull(userHandle);
Alexander Dorokhine5258ad22021-04-15 10:59:55 -07001126 Objects.requireNonNull(callback);
Alexander Dorokhinebea55602021-05-19 13:59:45 -07001127
Xiaoyu Jinc5a75772021-05-09 20:12:44 -07001128 long totalLatencyStartTimeMillis = SystemClock.elapsedRealtime();
Terry Wangf2093072020-11-30 04:47:19 -08001129 int callingUid = Binder.getCallingUid();
Terry Wange04ceab2021-03-29 19:25:12 -07001130 EXECUTOR.execute(() -> {
Xiaoyu Jinc5a75772021-05-09 20:12:44 -07001131 @AppSearchResult.ResultCode int statusCode = AppSearchResult.RESULT_OK;
Alexander Dorokhine4d051632021-06-18 10:48:58 -07001132 AppSearchUserInstance instance = null;
Xiaoyu Jinc5a75772021-05-09 20:12:44 -07001133 int operationSuccessCount = 0;
1134 int operationFailureCount = 0;
Terry Wange04ceab2021-03-29 19:25:12 -07001135 try {
Cassie Wangd51ed162021-07-29 22:22:30 +00001136 verifyCaller(callingUid, packageName);
1137
1138 // Obtain the user where the client wants to run the operations in. This should
1139 // end up being the same as userHandle, assuming it is not a special user and
1140 // the client is allowed to run operations in that user.
1141 UserHandle targetUser = handleIncomingUser(userHandle, callingUid);
Cassie Wang2feb34d2021-07-22 18:55:19 +00001142 verifyUserUnlocked(targetUser);
Cassie Wangd51ed162021-07-29 22:22:30 +00001143
Cassie Wang2feb34d2021-07-22 18:55:19 +00001144 instance = mAppSearchUserInstanceManager.getUserInstance(targetUser);
Alexander Dorokhine4d051632021-06-18 10:48:58 -07001145 instance.getAppSearchImpl().removeByQuery(
Terry Wange04ceab2021-03-29 19:25:12 -07001146 packageName,
1147 databaseName,
1148 queryExpression,
Alexander Dorokhinea4b5bab2021-05-20 14:24:50 -07001149 new SearchSpec(searchSpecBundle),
1150 /*removeStatsBuilder=*/ null);
Alexander Dorokhinec77f4442021-04-14 09:26:06 -07001151 // Now that the batch has been written. Persist the newly written data.
Alexander Dorokhine4d051632021-06-18 10:48:58 -07001152 instance.getAppSearchImpl().persistToDisk(PersistType.Code.LITE);
Xiaoyu Jinc5a75772021-05-09 20:12:44 -07001153 ++operationSuccessCount;
Terry Wange04ceab2021-03-29 19:25:12 -07001154 invokeCallbackOnResult(callback, AppSearchResult.newSuccessfulResult(null));
Terry Wangf4d219b2021-07-01 19:11:39 -07001155
1156 checkForOptimize(instance);
Terry Wange04ceab2021-03-29 19:25:12 -07001157 } catch (Throwable t) {
Xiaoyu Jinc5a75772021-05-09 20:12:44 -07001158 ++operationFailureCount;
1159 statusCode = throwableToFailedResult(t).getResultCode();
Terry Wange04ceab2021-03-29 19:25:12 -07001160 invokeCallbackOnError(callback, t);
Xiaoyu Jinc5a75772021-05-09 20:12:44 -07001161 } finally {
Alexander Dorokhine4d051632021-06-18 10:48:58 -07001162 if (instance != null) {
Xiaoyu Jinc5a75772021-05-09 20:12:44 -07001163 int estimatedBinderLatencyMillis =
1164 2 * (int) (totalLatencyStartTimeMillis - binderCallStartTimeMillis);
1165 int totalLatencyMillis =
1166 (int) (SystemClock.elapsedRealtime() - totalLatencyStartTimeMillis);
Alexander Dorokhine4d051632021-06-18 10:48:58 -07001167 instance.getLogger().logStats(new CallStats.Builder()
Alexander Dorokhine82a38722021-06-09 16:35:22 -07001168 .setPackageName(packageName)
1169 .setDatabase(databaseName)
1170 .setStatusCode(statusCode)
1171 .setTotalLatencyMillis(totalLatencyMillis)
Xiaoyu Jinc5a75772021-05-09 20:12:44 -07001172 .setCallType(CallStats.CALL_TYPE_REMOVE_DOCUMENTS_BY_SEARCH)
1173 // TODO(b/173532925) check the existing binder call latency chart
1174 // is good enough for us:
1175 // http://dashboards/view/_72c98f9a_91d9_41d4_ab9a_bc14f79742b4
1176 .setEstimatedBinderLatencyMillis(estimatedBinderLatencyMillis)
1177 .setNumOperationsSucceeded(operationSuccessCount)
Alexander Dorokhine82a38722021-06-09 16:35:22 -07001178 .setNumOperationsFailed(operationFailureCount)
1179 .build());
Xiaoyu Jinc5a75772021-05-09 20:12:44 -07001180 }
Terry Wange04ceab2021-03-29 19:25:12 -07001181 }
1182 });
Alexander Dorokhinef6c66ae2020-03-09 14:47:25 -07001183 }
1184
Terry Wangdbd1dca2020-11-03 17:03:56 -08001185 @Override
Cassie Wang8f0df492021-03-24 09:23:18 -07001186 public void getStorageInfo(
1187 @NonNull String packageName,
1188 @NonNull String databaseName,
Alexander Dorokhinebea55602021-05-19 13:59:45 -07001189 @NonNull UserHandle userHandle,
Cassie Wang8f0df492021-03-24 09:23:18 -07001190 @NonNull IAppSearchResultCallback callback) {
Alexander Dorokhine5258ad22021-04-15 10:59:55 -07001191 Objects.requireNonNull(packageName);
1192 Objects.requireNonNull(databaseName);
Alexander Dorokhinebea55602021-05-19 13:59:45 -07001193 Objects.requireNonNull(userHandle);
Alexander Dorokhine5258ad22021-04-15 10:59:55 -07001194 Objects.requireNonNull(callback);
Alexander Dorokhinebea55602021-05-19 13:59:45 -07001195
Cassie Wang8f0df492021-03-24 09:23:18 -07001196 int callingUid = Binder.getCallingUid();
Terry Wange04ceab2021-03-29 19:25:12 -07001197 EXECUTOR.execute(() -> {
1198 try {
Cassie Wangd51ed162021-07-29 22:22:30 +00001199 verifyCaller(callingUid, packageName);
1200
1201 // Obtain the user where the client wants to run the operations in. This should
1202 // end up being the same as userHandle, assuming it is not a special user and
1203 // the client is allowed to run operations in that user.
1204 UserHandle targetUser = handleIncomingUser(userHandle, callingUid);
Cassie Wang2feb34d2021-07-22 18:55:19 +00001205 verifyUserUnlocked(targetUser);
Cassie Wangd51ed162021-07-29 22:22:30 +00001206
Alexander Dorokhine4d051632021-06-18 10:48:58 -07001207 AppSearchUserInstance instance =
Cassie Wang2feb34d2021-07-22 18:55:19 +00001208 mAppSearchUserInstanceManager.getUserInstance(targetUser);
Alexander Dorokhine4d051632021-06-18 10:48:58 -07001209 StorageInfo storageInfo = instance.getAppSearchImpl()
1210 .getStorageInfoForDatabase(packageName, databaseName);
Terry Wange04ceab2021-03-29 19:25:12 -07001211 Bundle storageInfoBundle = storageInfo.getBundle();
1212 invokeCallbackOnResult(
1213 callback, AppSearchResult.newSuccessfulResult(storageInfoBundle));
1214 } catch (Throwable t) {
1215 invokeCallbackOnError(callback, t);
1216 }
1217 });
Cassie Wang8f0df492021-03-24 09:23:18 -07001218 }
1219
1220 @Override
Alexander Dorokhinebea55602021-05-19 13:59:45 -07001221 public void persistToDisk(
Cassie Wang84e33a02021-06-18 14:13:31 -07001222 @NonNull String packageName,
Alexander Dorokhinebea55602021-05-19 13:59:45 -07001223 @NonNull UserHandle userHandle,
Xiaoyu Jinc5a75772021-05-09 20:12:44 -07001224 @ElapsedRealtimeLong long binderCallStartTimeMillis) {
Cassie Wang84e33a02021-06-18 14:13:31 -07001225 Objects.requireNonNull(packageName);
Alexander Dorokhinebea55602021-05-19 13:59:45 -07001226 Objects.requireNonNull(userHandle);
1227
Xiaoyu Jinc5a75772021-05-09 20:12:44 -07001228 long totalLatencyStartTimeMillis = SystemClock.elapsedRealtime();
Cassie Wangb0d60122021-03-30 12:38:46 -07001229 int callingUid = Binder.getCallingUid();
Terry Wange04ceab2021-03-29 19:25:12 -07001230 EXECUTOR.execute(() -> {
Xiaoyu Jinc5a75772021-05-09 20:12:44 -07001231 @AppSearchResult.ResultCode int statusCode = AppSearchResult.RESULT_OK;
Alexander Dorokhine4d051632021-06-18 10:48:58 -07001232 AppSearchUserInstance instance = null;
Xiaoyu Jinc5a75772021-05-09 20:12:44 -07001233 int operationSuccessCount = 0;
1234 int operationFailureCount = 0;
Terry Wange04ceab2021-03-29 19:25:12 -07001235 try {
Cassie Wangd51ed162021-07-29 22:22:30 +00001236 verifyCaller(callingUid, packageName);
1237
1238 // Obtain the user where the client wants to run the operations in. This should
1239 // end up being the same as userHandle, assuming it is not a special user and
1240 // the client is allowed to run operations in that user.
1241 UserHandle targetUser = handleIncomingUser(userHandle, callingUid);
Cassie Wang2feb34d2021-07-22 18:55:19 +00001242 verifyUserUnlocked(targetUser);
Cassie Wangd51ed162021-07-29 22:22:30 +00001243
Cassie Wang2feb34d2021-07-22 18:55:19 +00001244 instance = mAppSearchUserInstanceManager.getUserInstance(targetUser);
Alexander Dorokhine4d051632021-06-18 10:48:58 -07001245 instance.getAppSearchImpl().persistToDisk(PersistType.Code.FULL);
Xiaoyu Jinc5a75772021-05-09 20:12:44 -07001246 ++operationSuccessCount;
Terry Wange04ceab2021-03-29 19:25:12 -07001247 } catch (Throwable t) {
Xiaoyu Jinc5a75772021-05-09 20:12:44 -07001248 ++operationFailureCount;
1249 statusCode = throwableToFailedResult(t).getResultCode();
Terry Wange04ceab2021-03-29 19:25:12 -07001250 Log.e(TAG, "Unable to persist the data to disk", t);
Xiaoyu Jinc5a75772021-05-09 20:12:44 -07001251 } finally {
Alexander Dorokhine4d051632021-06-18 10:48:58 -07001252 if (instance != null) {
Xiaoyu Jinc5a75772021-05-09 20:12:44 -07001253 int estimatedBinderLatencyMillis =
1254 2 * (int) (totalLatencyStartTimeMillis - binderCallStartTimeMillis);
1255 int totalLatencyMillis =
1256 (int) (SystemClock.elapsedRealtime() - totalLatencyStartTimeMillis);
Alexander Dorokhine4d051632021-06-18 10:48:58 -07001257 instance.getLogger().logStats(new CallStats.Builder()
Alexander Dorokhine82a38722021-06-09 16:35:22 -07001258 .setStatusCode(statusCode)
1259 .setTotalLatencyMillis(totalLatencyMillis)
Xiaoyu Jinc5a75772021-05-09 20:12:44 -07001260 .setCallType(CallStats.CALL_TYPE_FLUSH)
1261 // TODO(b/173532925) check the existing binder call latency chart
1262 // is good enough for us:
1263 // http://dashboards/view/_72c98f9a_91d9_41d4_ab9a_bc14f79742b4
1264 .setEstimatedBinderLatencyMillis(estimatedBinderLatencyMillis)
1265 .setNumOperationsSucceeded(operationSuccessCount)
Alexander Dorokhine82a38722021-06-09 16:35:22 -07001266 .setNumOperationsFailed(operationFailureCount)
1267 .build());
Xiaoyu Jinc5a75772021-05-09 20:12:44 -07001268 }
Terry Wange04ceab2021-03-29 19:25:12 -07001269 }
1270 });
Terry Wang2da17852020-12-16 19:59:08 -08001271 }
1272
1273 @Override
Alexander Dorokhinebea55602021-05-19 13:59:45 -07001274 public void initialize(
Cassie Wang84e33a02021-06-18 14:13:31 -07001275 @NonNull String packageName,
Alexander Dorokhinebea55602021-05-19 13:59:45 -07001276 @NonNull UserHandle userHandle,
Xiaoyu Jinc410c4f2021-05-09 14:15:50 -07001277 @ElapsedRealtimeLong long binderCallStartTimeMillis,
1278 @NonNull IAppSearchResultCallback callback) {
Cassie Wang84e33a02021-06-18 14:13:31 -07001279 Objects.requireNonNull(packageName);
Alexander Dorokhinebea55602021-05-19 13:59:45 -07001280 Objects.requireNonNull(userHandle);
Alexander Dorokhine5258ad22021-04-15 10:59:55 -07001281 Objects.requireNonNull(callback);
Alexander Dorokhinebea55602021-05-19 13:59:45 -07001282
Xiaoyu Jinc410c4f2021-05-09 14:15:50 -07001283 long totalLatencyStartTimeMillis = SystemClock.elapsedRealtime();
Terry Wangf2093072020-11-30 04:47:19 -08001284 int callingUid = Binder.getCallingUid();
Cassie Wang84e33a02021-06-18 14:13:31 -07001285
Terry Wange04ceab2021-03-29 19:25:12 -07001286 EXECUTOR.execute(() -> {
Xiaoyu Jinc410c4f2021-05-09 14:15:50 -07001287 @AppSearchResult.ResultCode int statusCode = AppSearchResult.RESULT_OK;
Alexander Dorokhine4d051632021-06-18 10:48:58 -07001288 AppSearchUserInstance instance = null;
Xiaoyu Jinc410c4f2021-05-09 14:15:50 -07001289 int operationSuccessCount = 0;
1290 int operationFailureCount = 0;
Terry Wange04ceab2021-03-29 19:25:12 -07001291 try {
Cassie Wangd51ed162021-07-29 22:22:30 +00001292 verifyCaller(callingUid, packageName);
1293
1294 // Obtain the user where the client wants to run the operations in. This should
1295 // end up being the same as userHandle, assuming it is not a special user and
1296 // the client is allowed to run operations in that user.
1297 UserHandle targetUser = handleIncomingUser(userHandle, callingUid);
1298 verifyUserUnlocked(targetUser);
1299
Cassie Wang2feb34d2021-07-22 18:55:19 +00001300 Context targetUserContext = mContext.createContextAsUser(targetUser,
1301 /*flags=*/ 0);
Alexander Dorokhine4d051632021-06-18 10:48:58 -07001302 instance = mAppSearchUserInstanceManager.getOrCreateUserInstance(
Cassie Wang2feb34d2021-07-22 18:55:19 +00001303 targetUserContext, targetUser, AppSearchConfig.getInstance(EXECUTOR));
Xiaoyu Jinc410c4f2021-05-09 14:15:50 -07001304 ++operationSuccessCount;
Terry Wange04ceab2021-03-29 19:25:12 -07001305 invokeCallbackOnResult(callback, AppSearchResult.newSuccessfulResult(null));
1306 } catch (Throwable t) {
Xiaoyu Jinc410c4f2021-05-09 14:15:50 -07001307 ++operationFailureCount;
1308 statusCode = throwableToFailedResult(t).getResultCode();
Terry Wange04ceab2021-03-29 19:25:12 -07001309 invokeCallbackOnError(callback, t);
Xiaoyu Jinc410c4f2021-05-09 14:15:50 -07001310 } finally {
Alexander Dorokhine4d051632021-06-18 10:48:58 -07001311 if (instance != null) {
Xiaoyu Jinc410c4f2021-05-09 14:15:50 -07001312 int estimatedBinderLatencyMillis =
1313 2 * (int) (totalLatencyStartTimeMillis - binderCallStartTimeMillis);
1314 int totalLatencyMillis =
1315 (int) (SystemClock.elapsedRealtime() - totalLatencyStartTimeMillis);
Alexander Dorokhine4d051632021-06-18 10:48:58 -07001316 instance.getLogger().logStats(new CallStats.Builder()
Alexander Dorokhine82a38722021-06-09 16:35:22 -07001317 .setStatusCode(statusCode)
1318 .setTotalLatencyMillis(totalLatencyMillis)
Xiaoyu Jinc410c4f2021-05-09 14:15:50 -07001319 .setCallType(CallStats.CALL_TYPE_INITIALIZE)
1320 // TODO(b/173532925) check the existing binder call latency chart
1321 // is good enough for us:
1322 // http://dashboards/view/_72c98f9a_91d9_41d4_ab9a_bc14f79742b4
1323 .setEstimatedBinderLatencyMillis(estimatedBinderLatencyMillis)
1324 .setNumOperationsSucceeded(operationSuccessCount)
Alexander Dorokhine82a38722021-06-09 16:35:22 -07001325 .setNumOperationsFailed(operationFailureCount)
1326 .build());
Xiaoyu Jinc410c4f2021-05-09 14:15:50 -07001327 }
Terry Wange04ceab2021-03-29 19:25:12 -07001328 }
1329 });
Terry Wangdbd1dca2020-11-03 17:03:56 -08001330 }
1331
Alexander Dorokhine8c5ba912020-12-14 22:58:12 -08001332 /** Invokes the {@link IAppSearchResultCallback} with the result. */
Cassie Wang0c62d992021-01-15 14:39:30 -08001333 private void invokeCallbackOnResult(
1334 IAppSearchResultCallback callback, AppSearchResult<?> result) {
Terry Wangdbd1dca2020-11-03 17:03:56 -08001335 try {
Alexander Dorokhined5e8eda2021-05-04 13:24:47 -07001336 callback.onResult(new AppSearchResultParcel<>(result));
Terry Wangdbd1dca2020-11-03 17:03:56 -08001337 } catch (RemoteException e) {
Terry Wang2da17852020-12-16 19:59:08 -08001338 Log.e(TAG, "Unable to send result to the callback", e);
Alexander Dorokhine969f4462020-03-05 15:54:19 -08001339 }
Terry Wangdbd1dca2020-11-03 17:03:56 -08001340 }
Alexander Dorokhine969f4462020-03-05 15:54:19 -08001341
Alexander Dorokhine8c5ba912020-12-14 22:58:12 -08001342 /** Invokes the {@link IAppSearchBatchResultCallback} with the result. */
Cassie Wang0c62d992021-01-15 14:39:30 -08001343 private void invokeCallbackOnResult(
Alexander Dorokhined5e8eda2021-05-04 13:24:47 -07001344 IAppSearchBatchResultCallback callback, AppSearchBatchResult<String, ?> result) {
Terry Wangdbd1dca2020-11-03 17:03:56 -08001345 try {
Alexander Dorokhined5e8eda2021-05-04 13:24:47 -07001346 callback.onResult(new AppSearchBatchResultParcel<>(result));
Terry Wangdbd1dca2020-11-03 17:03:56 -08001347 } catch (RemoteException e) {
Terry Wang2da17852020-12-16 19:59:08 -08001348 Log.e(TAG, "Unable to send result to the callback", e);
Alexander Dorokhine969f4462020-03-05 15:54:19 -08001349 }
Terry Wangdbd1dca2020-11-03 17:03:56 -08001350 }
1351
1352 /**
Alexander Dorokhine8c5ba912020-12-14 22:58:12 -08001353 * Invokes the {@link IAppSearchResultCallback} with an throwable.
Terry Wangdbd1dca2020-11-03 17:03:56 -08001354 *
Alexander Dorokhine8c5ba912020-12-14 22:58:12 -08001355 * <p>The throwable is convert to a {@link AppSearchResult};
Terry Wangdbd1dca2020-11-03 17:03:56 -08001356 */
1357 private void invokeCallbackOnError(IAppSearchResultCallback callback, Throwable throwable) {
Alexander Dorokhined5e8eda2021-05-04 13:24:47 -07001358 AppSearchResult<?> result = throwableToFailedResult(throwable);
Terry Wangdbd1dca2020-11-03 17:03:56 -08001359 try {
Alexander Dorokhined5e8eda2021-05-04 13:24:47 -07001360 callback.onResult(new AppSearchResultParcel<>(result));
Terry Wangdbd1dca2020-11-03 17:03:56 -08001361 } catch (RemoteException e) {
Terry Wang2da17852020-12-16 19:59:08 -08001362 Log.e(TAG, "Unable to send result to the callback", e);
Terry Wangdbd1dca2020-11-03 17:03:56 -08001363 }
1364 }
1365
1366 /**
Alexander Dorokhine8c5ba912020-12-14 22:58:12 -08001367 * Invokes the {@link IAppSearchBatchResultCallback} with an unexpected internal throwable.
Terry Wangdbd1dca2020-11-03 17:03:56 -08001368 *
Alexander Dorokhineb5d34b12021-04-15 00:32:15 -07001369 * <p>The throwable is converted to {@link AppSearchResult}.
Terry Wangdbd1dca2020-11-03 17:03:56 -08001370 */
Cassie Wang0c62d992021-01-15 14:39:30 -08001371 private void invokeCallbackOnError(
Alexander Dorokhineb5d34b12021-04-15 00:32:15 -07001372 @NonNull IAppSearchBatchResultCallback callback, @NonNull Throwable throwable) {
Alexander Dorokhined5e8eda2021-05-04 13:24:47 -07001373 AppSearchResult<?> result = throwableToFailedResult(throwable);
Terry Wangdbd1dca2020-11-03 17:03:56 -08001374 try {
Alexander Dorokhined5e8eda2021-05-04 13:24:47 -07001375 callback.onSystemError(new AppSearchResultParcel<>(result));
Terry Wangdbd1dca2020-11-03 17:03:56 -08001376 } catch (RemoteException e) {
Terry Wang2da17852020-12-16 19:59:08 -08001377 Log.e(TAG, "Unable to send error to the callback", e);
Terry Wangdbd1dca2020-11-03 17:03:56 -08001378 }
Alexander Dorokhine969f4462020-03-05 15:54:19 -08001379 }
Terry Wangfebbead2019-10-17 17:05:18 -07001380 }
Terry Wangf2093072020-11-30 04:47:19 -08001381
Alexander Dorokhinebea55602021-05-19 13:59:45 -07001382 /**
1383 * Helper for dealing with incoming user arguments to system service calls.
1384 *
Cassie Wang2feb34d2021-07-22 18:55:19 +00001385 * @param targetUserHandle The user which the caller is requesting to execute as.
Alexander Dorokhine5c416772021-06-04 09:05:00 -07001386 * @param callingUid The actual uid of the caller as determined by Binder.
Alexander Dorokhinebea55602021-05-19 13:59:45 -07001387 * @return the user handle that the call should run as. Will always be a concrete user.
1388 */
Alexander Dorokhinebea55602021-05-19 13:59:45 -07001389 @NonNull
Cassie Wang2feb34d2021-07-22 18:55:19 +00001390 private UserHandle handleIncomingUser(@NonNull UserHandle targetUserHandle, int callingUid) {
1391 UserHandle callingUserHandle = UserHandle.getUserHandleForUid(callingUid);
1392 if (callingUserHandle.equals(targetUserHandle)) {
1393 return targetUserHandle;
Alexander Dorokhine5c416772021-06-04 09:05:00 -07001394 }
Cassie Wang4bff4ff2021-07-16 13:03:19 -07001395
Alexander Dorokhine5c416772021-06-04 09:05:00 -07001396 // Duplicates UserController#ensureNotSpecialUser
Cassie Wang2feb34d2021-07-22 18:55:19 +00001397 if (targetUserHandle.getIdentifier() < 0) {
Alexander Dorokhine5c416772021-06-04 09:05:00 -07001398 throw new IllegalArgumentException(
Cassie Wang2feb34d2021-07-22 18:55:19 +00001399 "Call does not support special user " + targetUserHandle);
Alexander Dorokhine5c416772021-06-04 09:05:00 -07001400 }
Cassie Wang4bff4ff2021-07-16 13:03:19 -07001401
Alexander Dorokhine5c416772021-06-04 09:05:00 -07001402 throw new SecurityException(
Cassie Wang2feb34d2021-07-22 18:55:19 +00001403 "Requested user, " + targetUserHandle + ", is not the same as the calling user, "
1404 + callingUserHandle + ".");
Terry Wangf2093072020-11-30 04:47:19 -08001405 }
Yang Yu0fcd51a2021-04-23 11:25:44 -07001406
Cassie Wang84e33a02021-06-18 14:13:31 -07001407 /**
Cassie Wangd51ed162021-07-29 22:22:30 +00001408 * Verify various aspects of the calling user.
Cassie Wang84e33a02021-06-18 14:13:31 -07001409 *
Cassie Wangd51ed162021-07-29 22:22:30 +00001410 * @param callingUid Uid of the caller, usually retrieved from Binder for authenticity.
1411 * @param claimedCallingPackage Package name the caller claims to be.
1412 */
1413 private void verifyCaller(int callingUid, @NonNull String claimedCallingPackage) {
1414 // Obtain the user where the client is running in. Note that this could be different from
1415 // the userHandle where the client wants to run the AppSearch operation in.
1416 UserHandle callingUserHandle = UserHandle.getUserHandleForUid(callingUid);
1417 Context callingUserContext = mContext.createContextAsUser(callingUserHandle,
1418 /*flags=*/ 0);
1419
1420 verifyCallingPackage(callingUserContext, callingUid, claimedCallingPackage);
1421 verifyNotInstantApp(callingUserContext, claimedCallingPackage);
1422 }
1423
1424 /**
1425 * Check that the caller's supposed package name matches the uid making the call.
1426 *
1427 * @throws SecurityException if the package name and uid don't match.
1428 */
1429 private void verifyCallingPackage(
1430 @NonNull Context actualCallingUserContext,
1431 int actualCallingUid,
1432 @NonNull String claimedCallingPackage) {
1433 int claimedCallingUid = PackageUtil.getPackageUid(
1434 actualCallingUserContext, claimedCallingPackage);
1435 if (claimedCallingUid == INVALID_UID) {
1436 throw new SecurityException(
1437 "Specified calling package [" + claimedCallingPackage + "] not found");
1438 }
1439 if (claimedCallingUid != actualCallingUid) {
1440 throw new SecurityException(
1441 "Specified calling package ["
1442 + claimedCallingPackage
1443 + "] does not match the calling uid "
1444 + actualCallingUid);
1445 }
1446 }
1447
1448 /**
1449 * Ensure instant apps can't make calls to AppSearch.
1450 *
Cassie Wang84e33a02021-06-18 14:13:31 -07001451 * @throws SecurityException if the caller is an instant app.
1452 */
1453 private void verifyNotInstantApp(@NonNull Context userContext, @NonNull String packageName) {
1454 PackageManager callingPackageManager = userContext.getPackageManager();
1455 if (callingPackageManager.isInstantApp(packageName)) {
1456 throw new SecurityException("Caller not allowed to create AppSearch session"
1457 + "; userHandle=" + userContext.getUser() + ", callingPackage=" + packageName);
1458 }
1459 }
1460
Yang Yu0fcd51a2021-04-23 11:25:44 -07001461 // TODO(b/179160886): Cache the previous storage stats.
1462 private class AppSearchStorageStatsAugmenter implements StorageStatsAugmenter {
1463 @Override
Alexander Dorokhinea5d0d322021-05-10 15:59:31 -07001464 public void augmentStatsForPackageForUser(
Yang Yu0fcd51a2021-04-23 11:25:44 -07001465 @NonNull PackageStats stats,
1466 @NonNull String packageName,
Alexander Dorokhinea5d0d322021-05-10 15:59:31 -07001467 @NonNull UserHandle userHandle,
1468 boolean canCallerAccessAllStats) {
Yang Yu0fcd51a2021-04-23 11:25:44 -07001469 Objects.requireNonNull(stats);
1470 Objects.requireNonNull(packageName);
Alexander Dorokhinea5d0d322021-05-10 15:59:31 -07001471 Objects.requireNonNull(userHandle);
Alexander Dorokhinebea55602021-05-19 13:59:45 -07001472
Yang Yu0fcd51a2021-04-23 11:25:44 -07001473 try {
Alexander Dorokhinebea55602021-05-19 13:59:45 -07001474 verifyUserUnlocked(userHandle);
Cassie Wang84e33a02021-06-18 14:13:31 -07001475 Context userContext = mContext.createContextAsUser(userHandle, /*flags=*/ 0);
Alexander Dorokhine4d051632021-06-18 10:48:58 -07001476 AppSearchUserInstance instance =
1477 mAppSearchUserInstanceManager.getOrCreateUserInstance(
Cassie Wang84e33a02021-06-18 14:13:31 -07001478 userContext, userHandle, AppSearchConfig.getInstance(EXECUTOR));
Alexander Dorokhine4d051632021-06-18 10:48:58 -07001479 stats.dataSize += instance.getAppSearchImpl()
1480 .getStorageInfoForPackage(packageName).getSizeBytes();
Yang Yu0fcd51a2021-04-23 11:25:44 -07001481 } catch (Throwable t) {
1482 Log.e(
1483 TAG,
Alexander Dorokhinebea55602021-05-19 13:59:45 -07001484 "Unable to augment storage stats for "
1485 + userHandle
Yang Yu0fcd51a2021-04-23 11:25:44 -07001486 + " packageName "
1487 + packageName,
1488 t);
1489 }
1490 }
1491
1492 @Override
1493 public void augmentStatsForUid(
Alexander Dorokhinea5d0d322021-05-10 15:59:31 -07001494 @NonNull PackageStats stats, int uid, boolean canCallerAccessAllStats) {
Yang Yu0fcd51a2021-04-23 11:25:44 -07001495 Objects.requireNonNull(stats);
Alexander Dorokhinebea55602021-05-19 13:59:45 -07001496
1497 UserHandle userHandle = UserHandle.getUserHandleForUid(uid);
Yang Yu0fcd51a2021-04-23 11:25:44 -07001498 try {
Alexander Dorokhinebea55602021-05-19 13:59:45 -07001499 verifyUserUnlocked(userHandle);
Yang Yu0fcd51a2021-04-23 11:25:44 -07001500 String[] packagesForUid = mPackageManager.getPackagesForUid(uid);
1501 if (packagesForUid == null) {
1502 return;
1503 }
Cassie Wang84e33a02021-06-18 14:13:31 -07001504 Context userContext = mContext.createContextAsUser(userHandle, /*flags=*/ 0);
Alexander Dorokhine4d051632021-06-18 10:48:58 -07001505 AppSearchUserInstance instance =
1506 mAppSearchUserInstanceManager.getOrCreateUserInstance(
Cassie Wang84e33a02021-06-18 14:13:31 -07001507 userContext, userHandle, AppSearchConfig.getInstance(EXECUTOR));
Alexander Dorokhinea5d0d322021-05-10 15:59:31 -07001508 for (int i = 0; i < packagesForUid.length; i++) {
Alexander Dorokhine4d051632021-06-18 10:48:58 -07001509 stats.dataSize += instance.getAppSearchImpl()
1510 .getStorageInfoForPackage(packagesForUid[i]).getSizeBytes();
Yang Yu0fcd51a2021-04-23 11:25:44 -07001511 }
1512 } catch (Throwable t) {
1513 Log.e(TAG, "Unable to augment storage stats for uid " + uid, t);
1514 }
1515 }
Alexander Dorokhinea5d0d322021-05-10 15:59:31 -07001516
1517 @Override
1518 public void augmentStatsForUser(
1519 @NonNull PackageStats stats, @NonNull UserHandle userHandle) {
1520 // TODO(b/179160886): this implementation could incur many jni calls and a lot of
1521 // in-memory processing from getStorageInfoForPackage. Instead, we can just compute the
1522 // size of the icing dir (or use the overall StorageInfo without interpolating it).
1523 Objects.requireNonNull(stats);
1524 Objects.requireNonNull(userHandle);
Alexander Dorokhinebea55602021-05-19 13:59:45 -07001525
Alexander Dorokhinea5d0d322021-05-10 15:59:31 -07001526 try {
Alexander Dorokhinebea55602021-05-19 13:59:45 -07001527 verifyUserUnlocked(userHandle);
1528 List<PackageInfo> packagesForUser = mPackageManager.getInstalledPackagesAsUser(
1529 /*flags=*/0, userHandle.getIdentifier());
Alexander Dorokhinea5d0d322021-05-10 15:59:31 -07001530 if (packagesForUser == null) {
1531 return;
1532 }
Cassie Wang84e33a02021-06-18 14:13:31 -07001533 Context userContext = mContext.createContextAsUser(userHandle, /*flags=*/ 0);
Alexander Dorokhine4d051632021-06-18 10:48:58 -07001534 AppSearchUserInstance instance =
1535 mAppSearchUserInstanceManager.getOrCreateUserInstance(
Cassie Wang84e33a02021-06-18 14:13:31 -07001536 userContext, userHandle, AppSearchConfig.getInstance(EXECUTOR));
Alexander Dorokhinea5d0d322021-05-10 15:59:31 -07001537 for (int i = 0; i < packagesForUser.size(); i++) {
1538 String packageName = packagesForUser.get(i).packageName;
Alexander Dorokhine4d051632021-06-18 10:48:58 -07001539 stats.dataSize += instance.getAppSearchImpl()
1540 .getStorageInfoForPackage(packageName).getSizeBytes();
Alexander Dorokhinea5d0d322021-05-10 15:59:31 -07001541 }
1542 } catch (Throwable t) {
Alexander Dorokhinebea55602021-05-19 13:59:45 -07001543 Log.e(TAG, "Unable to augment storage stats for " + userHandle, t);
Alexander Dorokhinea5d0d322021-05-10 15:59:31 -07001544 }
1545 }
Yang Yu0fcd51a2021-04-23 11:25:44 -07001546 }
Terry Wangf4d219b2021-07-01 19:11:39 -07001547
1548 private void checkForOptimize(AppSearchUserInstance instance, int mutateBatchSize) {
1549 EXECUTOR.execute(() -> {
Alexander Dorokhine14816e22021-07-12 10:53:24 -07001550 long totalLatencyStartMillis = SystemClock.elapsedRealtime();
1551 OptimizeStats.Builder builder = new OptimizeStats.Builder();
Terry Wangf4d219b2021-07-01 19:11:39 -07001552 try {
Alexander Dorokhine14816e22021-07-12 10:53:24 -07001553 instance.getAppSearchImpl().checkForOptimize(mutateBatchSize, builder);
Terry Wangf4d219b2021-07-01 19:11:39 -07001554 } catch (AppSearchException e) {
1555 Log.w(TAG, "Error occurred when check for optimize", e);
Alexander Dorokhine14816e22021-07-12 10:53:24 -07001556 } finally {
1557 OptimizeStats oStats = builder
1558 .setTotalLatencyMillis(
1559 (int) (SystemClock.elapsedRealtime() - totalLatencyStartMillis))
1560 .build();
1561 if (oStats.getOriginalDocumentCount() > 0) {
1562 // see if optimize has been run by checking originalDocumentCount
1563 instance.getLogger().logStats(oStats);
1564 }
Terry Wangf4d219b2021-07-01 19:11:39 -07001565 }
1566 });
1567 }
1568
1569 private void checkForOptimize(AppSearchUserInstance instance) {
1570 EXECUTOR.execute(() -> {
Alexander Dorokhine14816e22021-07-12 10:53:24 -07001571 long totalLatencyStartMillis = SystemClock.elapsedRealtime();
1572 OptimizeStats.Builder builder = new OptimizeStats.Builder();
Terry Wangf4d219b2021-07-01 19:11:39 -07001573 try {
Alexander Dorokhine14816e22021-07-12 10:53:24 -07001574 instance.getAppSearchImpl().checkForOptimize(builder);
Terry Wangf4d219b2021-07-01 19:11:39 -07001575 } catch (AppSearchException e) {
1576 Log.w(TAG, "Error occurred when check for optimize", e);
Alexander Dorokhine14816e22021-07-12 10:53:24 -07001577 } finally {
1578 OptimizeStats oStats = builder
1579 .setTotalLatencyMillis(
1580 (int) (SystemClock.elapsedRealtime() - totalLatencyStartMillis))
1581 .build();
1582 if (oStats.getOriginalDocumentCount() > 0) {
1583 // see if optimize has been run by checking originalDocumentCount
1584 instance.getLogger().logStats(oStats);
1585 }
Terry Wangf4d219b2021-07-01 19:11:39 -07001586 }
1587 });
1588 }
Terry Wangfebbead2019-10-17 17:05:18 -07001589}