blob: a4188a2733b869db2202b38678ad1d0e852f1441 [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 Wang12dc6c02021-03-31 19:26:16 -070020import static android.os.UserHandle.USER_NULL;
Terry Wangdbd1dca2020-11-03 17:03:56 -080021
Xiaoyu Jinf8cc2012021-03-12 11:00:54 -080022import android.annotation.ElapsedRealtimeLong;
sidchhabraa7c8f8a2020-01-16 18:38:17 -080023import android.annotation.NonNull;
Terry Wangf2093072020-11-30 04:47:19 -080024import android.annotation.UserIdInt;
25import android.app.ActivityManager;
Alexander Dorokhine18465842020-01-21 01:08:57 -080026import android.app.appsearch.AppSearchBatchResult;
Terry Wang623e3b02021-02-02 20:27:33 -080027import android.app.appsearch.AppSearchMigrationHelper;
Alexander Dorokhine969f4462020-03-05 15:54:19 -080028import android.app.appsearch.AppSearchResult;
Alexander Dorokhine92ce3532020-10-06 01:39:36 -070029import android.app.appsearch.AppSearchSchema;
Alexander Dorokhinec66d67c2020-10-08 13:44:04 -070030import android.app.appsearch.GenericDocument;
Alexander Dorokhine9795b512021-03-23 22:06:59 -070031import android.app.appsearch.GetSchemaResponse;
Terry Wangdbd1dca2020-11-03 17:03:56 -080032import android.app.appsearch.IAppSearchBatchResultCallback;
Terry Wangfebbead2019-10-17 17:05:18 -070033import android.app.appsearch.IAppSearchManager;
Terry Wangdbd1dca2020-11-03 17:03:56 -080034import android.app.appsearch.IAppSearchResultCallback;
Alexander Dorokhineab789062021-01-11 21:00:00 -080035import android.app.appsearch.PackageIdentifier;
Terry Wang26b9e5c2020-10-23 02:05:01 -070036import android.app.appsearch.SearchResultPage;
Alexander Dorokhinec9fc9602020-10-06 01:39:50 -070037import android.app.appsearch.SearchSpec;
Terry Wang623e3b02021-02-02 20:27:33 -080038import android.app.appsearch.SetSchemaResponse;
Cassie Wang8f0df492021-03-24 09:23:18 -070039import android.app.appsearch.StorageInfo;
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;
Yang Yu0fcd51a2021-04-23 11:25:44 -070044import android.content.pm.PackageManager;
Cassie Wang0c62d992021-01-15 14:39:30 -080045import android.content.pm.PackageManagerInternal;
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;
Cassie Wang0c62d992021-01-15 14:39:30 -080059import com.android.server.LocalServices;
Terry Wangfebbead2019-10-17 17:05:18 -070060import com.android.server.SystemService;
Alexander Dorokhinef660d8f2020-10-29 22:37:00 -070061import com.android.server.appsearch.external.localstorage.AppSearchImpl;
Xiaoyu Jinf8cc2012021-03-12 11:00:54 -080062import com.android.server.appsearch.external.localstorage.stats.CallStats;
63import com.android.server.appsearch.stats.LoggerInstanceManager;
64import com.android.server.appsearch.stats.PlatformLogger;
Yang Yu0fcd51a2021-04-23 11:25:44 -070065import com.android.server.usage.StorageStatsManagerInternal;
66import com.android.server.usage.StorageStatsManagerInternal.StorageStatsAugmenter;
Alexander Dorokhinefd07eba2020-01-13 20:22:20 -080067
Alexander Dorokhinec77f4442021-04-14 09:26:06 -070068import com.google.android.icing.proto.PersistType;
69
Terry Wang623e3b02021-02-02 20:27:33 -080070import java.io.DataInputStream;
71import java.io.DataOutputStream;
72import java.io.EOFException;
73import java.io.FileInputStream;
74import java.io.FileOutputStream;
Alexander Dorokhine6a99f942020-12-04 02:57:22 -080075import java.util.ArrayList;
Alexander Dorokhine18465842020-01-21 01:08:57 -080076import java.util.List;
Alexander Dorokhineab789062021-01-11 21:00:00 -080077import java.util.Map;
Alexander Dorokhined18f8842021-01-20 15:26:13 -080078import java.util.Objects;
Cassie Wang9ba9ae12021-02-01 16:39:37 -080079import java.util.Set;
Terry Wange04ceab2021-03-29 19:25:12 -070080import java.util.concurrent.Executor;
Terry Wangd2186e52021-04-14 13:19:45 -070081import java.util.concurrent.LinkedBlockingQueue;
Terry Wange04ceab2021-03-29 19:25:12 -070082import java.util.concurrent.ThreadPoolExecutor;
83import java.util.concurrent.TimeUnit;
Alexander Dorokhine18465842020-01-21 01:08:57 -080084
Cassie Wang0c62d992021-01-15 14:39:30 -080085/** TODO(b/142567528): add comments when implement this class */
Terry Wangfebbead2019-10-17 17:05:18 -070086public class AppSearchManagerService extends SystemService {
Alexander Dorokhineebd37742020-09-22 15:02:26 -070087 private static final String TAG = "AppSearchManagerService";
Terry Wang12dc6c02021-03-31 19:26:16 -070088 private final Context mContext;
Yang Yu0fcd51a2021-04-23 11:25:44 -070089 private PackageManager mPackageManager;
Cassie Wang0c62d992021-01-15 14:39:30 -080090 private PackageManagerInternal mPackageManagerInternal;
Cassie Wang21c2d6a2021-01-20 23:59:55 -080091 private ImplInstanceManager mImplInstanceManager;
Pinyao Tingd5c2ed92021-03-18 14:51:54 -070092 private UserManager mUserManager;
Xiaoyu Jinf8cc2012021-03-12 11:00:54 -080093 private LoggerInstanceManager mLoggerInstanceManager;
Terry Wangfebbead2019-10-17 17:05:18 -070094
Terry Wange04ceab2021-03-29 19:25:12 -070095 // Never call shutdownNow(). It will cancel the futures it's returned. And since
96 // Executor#execute won't return anything, we will hang forever waiting for the execution.
97 // AppSearch multi-thread execution is guarded by Read & Write Lock in AppSearchImpl, all
98 // mutate requests will need to gain write lock and query requests need to gain read lock.
99 private static final Executor EXECUTOR = new ThreadPoolExecutor(/*corePoolSize=*/1,
100 Runtime.getRuntime().availableProcessors(), /*keepAliveTime*/ 60L, TimeUnit.SECONDS,
Terry Wangd2186e52021-04-14 13:19:45 -0700101 new LinkedBlockingQueue<>());
Terry Wange04ceab2021-03-29 19:25:12 -0700102
Cassie Wang15c86972021-02-09 13:43:25 -0800103 // Cache of unlocked user ids so we don't have to query UserManager service each time. The
104 // "locked" suffix refers to the fact that access to the field should be locked; unrelated to
105 // the unlocked status of user ids.
106 @GuardedBy("mUnlockedUserIdsLocked")
107 private final Set<Integer> mUnlockedUserIdsLocked = new ArraySet<>();
Cassie Wang9ba9ae12021-02-01 16:39:37 -0800108
Terry Wangfebbead2019-10-17 17:05:18 -0700109 public AppSearchManagerService(Context context) {
110 super(context);
Terry Wang12dc6c02021-03-31 19:26:16 -0700111 mContext = context;
Terry Wangfebbead2019-10-17 17:05:18 -0700112 }
113
114 @Override
115 public void onStart() {
116 publishBinderService(Context.APP_SEARCH_SERVICE, new Stub());
Yang Yu0fcd51a2021-04-23 11:25:44 -0700117 mPackageManager = getContext().getPackageManager();
Cassie Wang0c62d992021-01-15 14:39:30 -0800118 mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
Terry Wang12dc6c02021-03-31 19:26:16 -0700119 mImplInstanceManager = ImplInstanceManager.getInstance(mContext);
120 mUserManager = mContext.getSystemService(UserManager.class);
Xiaoyu Jinf8cc2012021-03-12 11:00:54 -0800121 mLoggerInstanceManager = LoggerInstanceManager.getInstance();
Terry Wang12dc6c02021-03-31 19:26:16 -0700122 registerReceivers();
Yang Yu0fcd51a2021-04-23 11:25:44 -0700123 LocalServices.getService(StorageStatsManagerInternal.class)
124 .registerStorageStatsAugmenter(new AppSearchStorageStatsAugmenter(), TAG);
Terry Wang12dc6c02021-03-31 19:26:16 -0700125 }
126
127 private void registerReceivers() {
128 mContext.registerReceiverAsUser(new UserActionReceiver(), UserHandle.ALL,
129 new IntentFilter(Intent.ACTION_USER_REMOVED), /*broadcastPermission=*/ null,
130 /*scheduler=*/ null);
Terry Wange201dc02021-04-16 01:03:20 -0700131
132 //TODO(b/145759910) Add a direct callback when user clears the data instead of relying on
133 // broadcasts
134 IntentFilter packageChangedFilter = new IntentFilter();
135 packageChangedFilter.addAction(Intent.ACTION_PACKAGE_FULLY_REMOVED);
136 packageChangedFilter.addAction(Intent.ACTION_PACKAGE_DATA_CLEARED);
137 packageChangedFilter.addDataScheme("package");
138 packageChangedFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
139 mContext.registerReceiverAsUser(new PackageChangedReceiver(), UserHandle.ALL,
140 packageChangedFilter, /*broadcastPermission=*/ null,
141 /*scheduler=*/ null);
Terry Wang12dc6c02021-03-31 19:26:16 -0700142 }
143
144 private class UserActionReceiver extends BroadcastReceiver {
145 @Override
146 public void onReceive(@NonNull Context context, @NonNull Intent intent) {
147 switch (intent.getAction()) {
148 case Intent.ACTION_USER_REMOVED:
Terry Wange201dc02021-04-16 01:03:20 -0700149 int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
Terry Wang12dc6c02021-03-31 19:26:16 -0700150 if (userId == USER_NULL) {
Terry Wange201dc02021-04-16 01:03:20 -0700151 Log.e(TAG, "userId is missing in the intent: " + intent);
Terry Wang12dc6c02021-03-31 19:26:16 -0700152 return;
153 }
154 handleUserRemoved(userId);
155 break;
156 default:
Terry Wange201dc02021-04-16 01:03:20 -0700157 Log.e(TAG, "Received unknown intent: " + intent);
Terry Wang12dc6c02021-03-31 19:26:16 -0700158 }
159 }
160 }
161
162 /**
163 * Handles user removed action.
164 *
165 * <p>Only need to clear the AppSearchImpl instance. The data of AppSearch is saved in the
166 * "credential encrypted" system directory of each user. That directory will be auto-deleted
167 * when a user is removed.
168 *
169 * @param userId The multi-user userId of the user that need to be removed.
170 *
171 * @see android.os.Environment#getDataSystemCeDirectory
172 */
173 private void handleUserRemoved(@UserIdInt int userId) {
174 try {
175 mImplInstanceManager.removeAppSearchImplForUser(userId);
Xiaoyu Jinf8cc2012021-03-12 11:00:54 -0800176 mLoggerInstanceManager.removePlatformLoggerForUser(userId);
Terry Wange201dc02021-04-16 01:03:20 -0700177 Log.i(TAG, "Removed AppSearchImpl instance for user: " + userId);
Terry Wang12dc6c02021-03-31 19:26:16 -0700178 } catch (Throwable t) {
Terry Wange201dc02021-04-16 01:03:20 -0700179 Log.e(TAG, "Unable to remove data for user: " + userId, t);
180 }
181 }
182
183 private class PackageChangedReceiver extends BroadcastReceiver {
184 @Override
185 public void onReceive(@NonNull Context context, @NonNull Intent intent) {
186 switch (intent.getAction()) {
187 case Intent.ACTION_PACKAGE_FULLY_REMOVED:
188 case Intent.ACTION_PACKAGE_DATA_CLEARED:
189 String packageName = intent.getData().getSchemeSpecificPart();
190 if (packageName == null) {
191 Log.e(TAG, "Package name is missing in the intent: " + intent);
192 return;
193 }
194 int uid = intent.getIntExtra(Intent.EXTRA_UID, INVALID_UID);
195 if (uid == INVALID_UID) {
196 Log.e(TAG, "uid is missing in the intent: " + intent);
197 return;
198 }
199 handlePackageRemoved(packageName, uid);
200 break;
201 default:
202 Log.e(TAG, "Received unknown intent: " + intent);
203 }
204 }
205 }
206
207 private void handlePackageRemoved(String packageName, int uid) {
208 int userId = UserHandle.getUserId(uid);
209 try {
210 if (isUserLocked(userId)) {
211 //TODO(b/186151459) clear the uninstalled package data when user is unlocked.
212 return;
213 }
214 if (ImplInstanceManager.getAppSearchDir(userId).exists()) {
215 // Only clear the package's data if AppSearch exists for this user.
216 AppSearchImpl impl = mImplInstanceManager.getOrCreateAppSearchImpl(mContext,
217 userId);
218 //TODO(b/145759910) clear visibility setting for package.
219 impl.clearPackageData(packageName);
220 }
221 } catch (Throwable t) {
222 Log.e(TAG, "Unable to remove data for package: " + packageName, t);
Terry Wang12dc6c02021-03-31 19:26:16 -0700223 }
Terry Wangfebbead2019-10-17 17:05:18 -0700224 }
225
Cassie Wang9ba9ae12021-02-01 16:39:37 -0800226 @Override
Pinyao Tingd5c2ed92021-03-18 14:51:54 -0700227 public void onUserUnlocking(@NonNull TargetUser user) {
Cassie Wang15c86972021-02-09 13:43:25 -0800228 synchronized (mUnlockedUserIdsLocked) {
229 mUnlockedUserIdsLocked.add(user.getUserIdentifier());
230 }
Cassie Wang9ba9ae12021-02-01 16:39:37 -0800231 }
232
Yang Yu0fcd51a2021-04-23 11:25:44 -0700233 private void verifyUserUnlocked(int callingUserId) {
Terry Wange201dc02021-04-16 01:03:20 -0700234 if (isUserLocked(callingUserId)) {
235 throw new IllegalStateException("User " + callingUserId + " is locked or not running.");
236 }
237 }
238
239 private boolean isUserLocked(int callingUserId) {
Yang Yu0fcd51a2021-04-23 11:25:44 -0700240 synchronized (mUnlockedUserIdsLocked) {
241 // First, check the local copy.
242 if (mUnlockedUserIdsLocked.contains(callingUserId)) {
Terry Wange201dc02021-04-16 01:03:20 -0700243 return false;
Yang Yu0fcd51a2021-04-23 11:25:44 -0700244 }
245 // If the local copy says the user is locked, check with UM for the actual state,
246 // since the user might just have been unlocked.
Terry Wange201dc02021-04-16 01:03:20 -0700247 return !mUserManager.isUserUnlockingOrUnlocked(UserHandle.of(callingUserId));
Yang Yu0fcd51a2021-04-23 11:25:44 -0700248 }
249 }
250
Terry Wangfebbead2019-10-17 17:05:18 -0700251 private class Stub extends IAppSearchManager.Stub {
Alexander Dorokhinefd07eba2020-01-13 20:22:20 -0800252 @Override
Alexander Dorokhine969f4462020-03-05 15:54:19 -0800253 public void setSchema(
Cassie Wang0c62d992021-01-15 14:39:30 -0800254 @NonNull String packageName,
Terry Wang6413aee2020-10-07 03:04:58 -0700255 @NonNull String databaseName,
Alexander Dorokhine92ce3532020-10-06 01:39:36 -0700256 @NonNull List<Bundle> schemaBundles,
Alexander Dorokhine315cca62021-03-04 12:34:41 -0800257 @NonNull List<String> schemasNotDisplayedBySystem,
Alexander Dorokhineab789062021-01-11 21:00:00 -0800258 @NonNull Map<String, List<Bundle>> schemasPackageAccessibleBundles,
Alexander Dorokhine969f4462020-03-05 15:54:19 -0800259 boolean forceOverride,
Alexander Dorokhine9795b512021-03-23 22:06:59 -0700260 int schemaVersion,
Terry Wangc10610d2021-03-21 13:21:24 -0700261 @UserIdInt int userId,
Terry Wangdbd1dca2020-11-03 17:03:56 -0800262 @NonNull IAppSearchResultCallback callback) {
Alexander Dorokhine5258ad22021-04-15 10:59:55 -0700263 Objects.requireNonNull(packageName);
264 Objects.requireNonNull(databaseName);
265 Objects.requireNonNull(schemaBundles);
266 Objects.requireNonNull(callback);
Terry Wangf2093072020-11-30 04:47:19 -0800267 int callingUid = Binder.getCallingUid();
268 int callingUserId = handleIncomingUser(userId, callingUid);
Terry Wange04ceab2021-03-29 19:25:12 -0700269 EXECUTOR.execute(() -> {
270 try {
271 verifyUserUnlocked(callingUserId);
272 verifyCallingPackage(callingUid, packageName);
273 List<AppSearchSchema> schemas = new ArrayList<>(schemaBundles.size());
274 for (int i = 0; i < schemaBundles.size(); i++) {
275 schemas.add(new AppSearchSchema(schemaBundles.get(i)));
Alexander Dorokhineab789062021-01-11 21:00:00 -0800276 }
Terry Wange04ceab2021-03-29 19:25:12 -0700277 Map<String, List<PackageIdentifier>> schemasPackageAccessible =
278 new ArrayMap<>(schemasPackageAccessibleBundles.size());
279 for (Map.Entry<String, List<Bundle>> entry :
280 schemasPackageAccessibleBundles.entrySet()) {
281 List<PackageIdentifier> packageIdentifiers =
282 new ArrayList<>(entry.getValue().size());
283 for (int i = 0; i < entry.getValue().size(); i++) {
284 packageIdentifiers.add(
285 new PackageIdentifier(entry.getValue().get(i)));
286 }
287 schemasPackageAccessible.put(entry.getKey(), packageIdentifiers);
288 }
289 AppSearchImpl impl = mImplInstanceManager.getAppSearchImpl(callingUserId);
290 SetSchemaResponse setSchemaResponse = impl.setSchema(
291 packageName,
292 databaseName,
293 schemas,
294 schemasNotDisplayedBySystem,
295 schemasPackageAccessible,
296 forceOverride,
297 schemaVersion);
298 invokeCallbackOnResult(callback,
299 AppSearchResult.newSuccessfulResult(setSchemaResponse.getBundle()));
300 } catch (Throwable t) {
301 invokeCallbackOnError(callback, t);
Alexander Dorokhineab789062021-01-11 21:00:00 -0800302 }
Terry Wange04ceab2021-03-29 19:25:12 -0700303 });
Alexander Dorokhine179c8b82020-01-11 00:17:48 -0800304 }
305
306 @Override
Terry Wang83a24932020-12-09 21:00:18 -0800307 public void getSchema(
Cassie Wang0c62d992021-01-15 14:39:30 -0800308 @NonNull String packageName,
Terry Wang83a24932020-12-09 21:00:18 -0800309 @NonNull String databaseName,
Terry Wangf2093072020-11-30 04:47:19 -0800310 @UserIdInt int userId,
Terry Wang83a24932020-12-09 21:00:18 -0800311 @NonNull IAppSearchResultCallback callback) {
Alexander Dorokhine5258ad22021-04-15 10:59:55 -0700312 Objects.requireNonNull(packageName);
313 Objects.requireNonNull(databaseName);
314 Objects.requireNonNull(callback);
Cassie Wangb0d60122021-03-30 12:38:46 -0700315 int callingUid = Binder.getCallingUid();
Terry Wangf2093072020-11-30 04:47:19 -0800316 int callingUserId = handleIncomingUser(userId, callingUid);
Terry Wange04ceab2021-03-29 19:25:12 -0700317 EXECUTOR.execute(() -> {
318 try {
319 verifyUserUnlocked(callingUserId);
320 verifyCallingPackage(callingUid, packageName);
321 AppSearchImpl impl =
322 mImplInstanceManager.getAppSearchImpl(callingUserId);
323 GetSchemaResponse response = impl.getSchema(packageName, databaseName);
324 invokeCallbackOnResult(
325 callback,
326 AppSearchResult.newSuccessfulResult(response.getBundle()));
327 } catch (Throwable t) {
328 invokeCallbackOnError(callback, t);
329 }
330 });
Alexander Dorokhine9795b512021-03-23 22:06:59 -0700331 }
332
333 @Override
334 public void getNamespaces(
335 @NonNull String packageName,
336 @NonNull String databaseName,
337 @UserIdInt int userId,
338 @NonNull IAppSearchResultCallback callback) {
Alexander Dorokhine5258ad22021-04-15 10:59:55 -0700339 Objects.requireNonNull(packageName);
340 Objects.requireNonNull(databaseName);
341 Objects.requireNonNull(callback);
Cassie Wangb0d60122021-03-30 12:38:46 -0700342 int callingUid = Binder.getCallingUid();
Alexander Dorokhine9795b512021-03-23 22:06:59 -0700343 int callingUserId = handleIncomingUser(userId, callingUid);
Terry Wange04ceab2021-03-29 19:25:12 -0700344 EXECUTOR.execute(() -> {
345 try {
346 verifyUserUnlocked(callingUserId);
347 verifyCallingPackage(callingUid, packageName);
348 AppSearchImpl impl =
349 mImplInstanceManager.getAppSearchImpl(callingUserId);
350 List<String> namespaces = impl.getNamespaces(packageName, databaseName);
351 invokeCallbackOnResult(callback,
352 AppSearchResult.newSuccessfulResult(namespaces));
353 } catch (Throwable t) {
354 invokeCallbackOnError(callback, t);
355 }
356 });
Terry Wang83a24932020-12-09 21:00:18 -0800357 }
358
359 @Override
Alexander Dorokhine18465842020-01-21 01:08:57 -0800360 public void putDocuments(
Cassie Wang0c62d992021-01-15 14:39:30 -0800361 @NonNull String packageName,
Terry Wang6413aee2020-10-07 03:04:58 -0700362 @NonNull String databaseName,
Alexander Dorokhinec66d67c2020-10-08 13:44:04 -0700363 @NonNull List<Bundle> documentBundles,
Terry Wangf2093072020-11-30 04:47:19 -0800364 @UserIdInt int userId,
Xiaoyu Jinf8cc2012021-03-12 11:00:54 -0800365 @ElapsedRealtimeLong long binderCallStartTimeMillis,
Terry Wangdbd1dca2020-11-03 17:03:56 -0800366 @NonNull IAppSearchBatchResultCallback callback) {
Alexander Dorokhine5258ad22021-04-15 10:59:55 -0700367 Objects.requireNonNull(packageName);
368 Objects.requireNonNull(databaseName);
369 Objects.requireNonNull(documentBundles);
370 Objects.requireNonNull(callback);
Terry Wangf2093072020-11-30 04:47:19 -0800371 int callingUid = Binder.getCallingUid();
372 int callingUserId = handleIncomingUser(userId, callingUid);
Terry Wange04ceab2021-03-29 19:25:12 -0700373 EXECUTOR.execute(() -> {
Xiaoyu Jinf8cc2012021-03-12 11:00:54 -0800374 long totalLatencyStartTimeMillis = SystemClock.elapsedRealtime();
375 @AppSearchResult.ResultCode int statusCode = AppSearchResult.RESULT_OK;
376 PlatformLogger logger = null;
377 int operationSuccessCount = 0;
378 int operationFailureCount = 0;
Terry Wange04ceab2021-03-29 19:25:12 -0700379 try {
380 verifyUserUnlocked(callingUserId);
381 verifyCallingPackage(callingUid, packageName);
382 AppSearchBatchResult.Builder<String, Void> resultBuilder =
383 new AppSearchBatchResult.Builder<>();
384 AppSearchImpl impl =
385 mImplInstanceManager.getAppSearchImpl(callingUserId);
Xiaoyu Jinf8cc2012021-03-12 11:00:54 -0800386 logger = mLoggerInstanceManager.getPlatformLogger(callingUserId);
Terry Wange04ceab2021-03-29 19:25:12 -0700387 for (int i = 0; i < documentBundles.size(); i++) {
388 GenericDocument document = new GenericDocument(documentBundles.get(i));
389 try {
Xiaoyu Jinf8cc2012021-03-12 11:00:54 -0800390 impl.putDocument(packageName, databaseName, document, logger);
Alexander Dorokhine17f79372021-04-21 11:23:09 -0700391 resultBuilder.setSuccess(document.getId(), /*result=*/ null);
Xiaoyu Jinf8cc2012021-03-12 11:00:54 -0800392 ++operationSuccessCount;
Terry Wange04ceab2021-03-29 19:25:12 -0700393 } catch (Throwable t) {
Alexander Dorokhine17f79372021-04-21 11:23:09 -0700394 resultBuilder.setResult(document.getId(),
Terry Wange04ceab2021-03-29 19:25:12 -0700395 throwableToFailedResult(t));
Xiaoyu Jinf8cc2012021-03-12 11:00:54 -0800396 AppSearchResult<Void> result = throwableToFailedResult(t);
Alexander Dorokhine17f79372021-04-21 11:23:09 -0700397 resultBuilder.setResult(document.getId(), result);
Xiaoyu Jinf8cc2012021-03-12 11:00:54 -0800398 // for failures, we would just log the one for last failure
399 statusCode = result.getResultCode();
400 ++operationFailureCount;
Terry Wange04ceab2021-03-29 19:25:12 -0700401 }
Alexander Dorokhine18465842020-01-21 01:08:57 -0800402 }
Alexander Dorokhinec77f4442021-04-14 09:26:06 -0700403 // Now that the batch has been written. Persist the newly written data.
404 impl.persistToDisk(PersistType.Code.LITE);
Terry Wange04ceab2021-03-29 19:25:12 -0700405 invokeCallbackOnResult(callback, resultBuilder.build());
406 } catch (Throwable t) {
407 invokeCallbackOnError(callback, t);
Xiaoyu Jinf8cc2012021-03-12 11:00:54 -0800408 } finally {
409 if (logger != null) {
410 CallStats.Builder cBuilder = new CallStats.Builder(packageName,
411 databaseName)
412 .setCallType(CallStats.CALL_TYPE_PUT_DOCUMENTS)
413 // TODO(b/173532925) check the existing binder call latency chart
414 // is good enough for us:
415 // http://dashboards/view/_72c98f9a_91d9_41d4_ab9a_bc14f79742b4
416 .setEstimatedBinderLatencyMillis(
417 2 * (int) (totalLatencyStartTimeMillis
418 - binderCallStartTimeMillis))
419 .setNumOperationsSucceeded(operationSuccessCount)
420 .setNumOperationsFailed(operationFailureCount);
421 cBuilder.getGeneralStatsBuilder()
422 .setStatusCode(statusCode)
423 .setTotalLatencyMillis(
424 (int) (SystemClock.elapsedRealtime()
425 - totalLatencyStartTimeMillis));
426 logger.logStats(cBuilder.build());
427 }
Alexander Dorokhine18465842020-01-21 01:08:57 -0800428 }
Terry Wange04ceab2021-03-29 19:25:12 -0700429 });
Alexander Dorokhinefd07eba2020-01-13 20:22:20 -0800430 }
Alexander Dorokhine969f4462020-03-05 15:54:19 -0800431
Alexander Dorokhine69a8d9f2020-03-06 10:43:16 -0800432 @Override
Terry Wangf2093072020-11-30 04:47:19 -0800433 public void getDocuments(
Cassie Wang0c62d992021-01-15 14:39:30 -0800434 @NonNull String packageName,
Terry Wangf2093072020-11-30 04:47:19 -0800435 @NonNull String databaseName,
436 @NonNull String namespace,
Alexander Dorokhine17f79372021-04-21 11:23:09 -0700437 @NonNull List<String> ids,
Alexander Dorokhine87cdd152021-01-20 15:41:25 -0800438 @NonNull Map<String, List<String>> typePropertyPaths,
Terry Wangf2093072020-11-30 04:47:19 -0800439 @UserIdInt int userId,
Terry Wangdbd1dca2020-11-03 17:03:56 -0800440 @NonNull IAppSearchBatchResultCallback callback) {
Alexander Dorokhine5258ad22021-04-15 10:59:55 -0700441 Objects.requireNonNull(packageName);
442 Objects.requireNonNull(databaseName);
443 Objects.requireNonNull(namespace);
Alexander Dorokhine17f79372021-04-21 11:23:09 -0700444 Objects.requireNonNull(ids);
Alexander Dorokhine5258ad22021-04-15 10:59:55 -0700445 Objects.requireNonNull(callback);
Terry Wangf2093072020-11-30 04:47:19 -0800446 int callingUid = Binder.getCallingUid();
447 int callingUserId = handleIncomingUser(userId, callingUid);
Terry Wange04ceab2021-03-29 19:25:12 -0700448 EXECUTOR.execute(() -> {
449 try {
450 verifyUserUnlocked(callingUserId);
451 verifyCallingPackage(callingUid, packageName);
452 AppSearchBatchResult.Builder<String, Bundle> resultBuilder =
453 new AppSearchBatchResult.Builder<>();
454 AppSearchImpl impl =
455 mImplInstanceManager.getAppSearchImpl(callingUserId);
Alexander Dorokhine17f79372021-04-21 11:23:09 -0700456 for (int i = 0; i < ids.size(); i++) {
457 String id = ids.get(i);
Terry Wange04ceab2021-03-29 19:25:12 -0700458 try {
459 GenericDocument document =
460 impl.getDocument(
461 packageName,
462 databaseName,
463 namespace,
Alexander Dorokhine17f79372021-04-21 11:23:09 -0700464 id,
Terry Wange04ceab2021-03-29 19:25:12 -0700465 typePropertyPaths);
Alexander Dorokhine17f79372021-04-21 11:23:09 -0700466 resultBuilder.setSuccess(id, document.getBundle());
Terry Wange04ceab2021-03-29 19:25:12 -0700467 } catch (Throwable t) {
Alexander Dorokhine17f79372021-04-21 11:23:09 -0700468 resultBuilder.setResult(id, throwableToFailedResult(t));
Terry Wange04ceab2021-03-29 19:25:12 -0700469 }
Alexander Dorokhinea95f44f2020-03-06 13:53:14 -0800470 }
Terry Wange04ceab2021-03-29 19:25:12 -0700471 invokeCallbackOnResult(callback, resultBuilder.build());
472 } catch (Throwable t) {
473 invokeCallbackOnError(callback, t);
Alexander Dorokhine69a8d9f2020-03-06 10:43:16 -0800474 }
Terry Wange04ceab2021-03-29 19:25:12 -0700475 });
Alexander Dorokhine69a8d9f2020-03-06 10:43:16 -0800476 }
477
sidchhabraa7c8f8a2020-01-16 18:38:17 -0800478 @Override
Alexander Dorokhinee708e182020-03-06 15:30:34 -0800479 public void query(
Cassie Wang0c62d992021-01-15 14:39:30 -0800480 @NonNull String packageName,
Terry Wang6413aee2020-10-07 03:04:58 -0700481 @NonNull String databaseName,
Alexander Dorokhinec9fc9602020-10-06 01:39:50 -0700482 @NonNull String queryExpression,
483 @NonNull Bundle searchSpecBundle,
Terry Wangf2093072020-11-30 04:47:19 -0800484 @UserIdInt int userId,
Alexander Dorokhined48f2362020-10-20 17:40:49 -0700485 @NonNull IAppSearchResultCallback callback) {
Alexander Dorokhine5258ad22021-04-15 10:59:55 -0700486 Objects.requireNonNull(packageName);
487 Objects.requireNonNull(databaseName);
488 Objects.requireNonNull(queryExpression);
489 Objects.requireNonNull(searchSpecBundle);
490 Objects.requireNonNull(callback);
Terry Wangf2093072020-11-30 04:47:19 -0800491 int callingUid = Binder.getCallingUid();
492 int callingUserId = handleIncomingUser(userId, callingUid);
Terry Wange04ceab2021-03-29 19:25:12 -0700493 EXECUTOR.execute(() -> {
494 try {
495 verifyUserUnlocked(callingUserId);
496 verifyCallingPackage(callingUid, packageName);
497 AppSearchImpl impl =
498 mImplInstanceManager.getAppSearchImpl(callingUserId);
499 SearchResultPage searchResultPage =
500 impl.query(
501 packageName,
502 databaseName,
503 queryExpression,
Alexander Dorokhine7cbc4712021-04-27 14:47:39 -0700504 new SearchSpec(searchSpecBundle),
505 /*logger=*/ null);
Terry Wange04ceab2021-03-29 19:25:12 -0700506 invokeCallbackOnResult(
507 callback,
508 AppSearchResult.newSuccessfulResult(searchResultPage.getBundle()));
509 } catch (Throwable t) {
510 invokeCallbackOnError(callback, t);
511 }
512 });
Alexander Dorokhined48f2362020-10-20 17:40:49 -0700513 }
514
Terry Wangf2093072020-11-30 04:47:19 -0800515 @Override
Terry Wangbfbfcac2020-11-06 15:46:44 -0800516 public void globalQuery(
Cassie Wang0c62d992021-01-15 14:39:30 -0800517 @NonNull String packageName,
Terry Wangbfbfcac2020-11-06 15:46:44 -0800518 @NonNull String queryExpression,
519 @NonNull Bundle searchSpecBundle,
Terry Wangf2093072020-11-30 04:47:19 -0800520 @UserIdInt int userId,
Terry Wangbfbfcac2020-11-06 15:46:44 -0800521 @NonNull IAppSearchResultCallback callback) {
Alexander Dorokhine5258ad22021-04-15 10:59:55 -0700522 Objects.requireNonNull(packageName);
523 Objects.requireNonNull(queryExpression);
524 Objects.requireNonNull(searchSpecBundle);
525 Objects.requireNonNull(callback);
Terry Wangf2093072020-11-30 04:47:19 -0800526 int callingUid = Binder.getCallingUid();
527 int callingUserId = handleIncomingUser(userId, callingUid);
Terry Wange04ceab2021-03-29 19:25:12 -0700528 EXECUTOR.execute(() -> {
529 try {
530 verifyUserUnlocked(callingUserId);
531 verifyCallingPackage(callingUid, packageName);
532 AppSearchImpl impl =
533 mImplInstanceManager.getAppSearchImpl(callingUserId);
534 SearchResultPage searchResultPage =
535 impl.globalQuery(
536 queryExpression,
537 new SearchSpec(searchSpecBundle),
538 packageName,
Alexander Dorokhine7cbc4712021-04-27 14:47:39 -0700539 callingUid,
540 /*logger=*/ null);
Terry Wange04ceab2021-03-29 19:25:12 -0700541 invokeCallbackOnResult(
542 callback,
543 AppSearchResult.newSuccessfulResult(searchResultPage.getBundle()));
544 } catch (Throwable t) {
545 invokeCallbackOnError(callback, t);
546 }
547 });
Terry Wangbfbfcac2020-11-06 15:46:44 -0800548 }
549
Alexander Dorokhined48f2362020-10-20 17:40:49 -0700550 @Override
Cassie Wang0c62d992021-01-15 14:39:30 -0800551 public void getNextPage(
552 long nextPageToken,
553 @UserIdInt int userId,
Alexander Dorokhined48f2362020-10-20 17:40:49 -0700554 @NonNull IAppSearchResultCallback callback) {
Alexander Dorokhine5258ad22021-04-15 10:59:55 -0700555 Objects.requireNonNull(callback);
Terry Wangf2093072020-11-30 04:47:19 -0800556 int callingUid = Binder.getCallingUid();
557 int callingUserId = handleIncomingUser(userId, callingUid);
Alexander Dorokhined48f2362020-10-20 17:40:49 -0700558 // TODO(b/162450968) check nextPageToken is being advanced by the same uid as originally
559 // opened it
Terry Wange04ceab2021-03-29 19:25:12 -0700560 EXECUTOR.execute(() -> {
561 try {
562 verifyUserUnlocked(callingUserId);
563 AppSearchImpl impl =
564 mImplInstanceManager.getAppSearchImpl(callingUserId);
565 SearchResultPage searchResultPage = impl.getNextPage(nextPageToken);
566 invokeCallbackOnResult(
567 callback,
568 AppSearchResult.newSuccessfulResult(searchResultPage.getBundle()));
569 } catch (Throwable t) {
570 invokeCallbackOnError(callback, t);
571 }
572 });
Alexander Dorokhined48f2362020-10-20 17:40:49 -0700573 }
574
575 @Override
Terry Wangf2093072020-11-30 04:47:19 -0800576 public void invalidateNextPageToken(long nextPageToken, @UserIdInt int userId) {
577 int callingUid = Binder.getCallingUid();
578 int callingUserId = handleIncomingUser(userId, callingUid);
Terry Wange04ceab2021-03-29 19:25:12 -0700579 EXECUTOR.execute(() -> {
580 try {
581 verifyUserUnlocked(callingUserId);
582 AppSearchImpl impl =
583 mImplInstanceManager.getAppSearchImpl(callingUserId);
584 impl.invalidateNextPageToken(nextPageToken);
585 } catch (Throwable t) {
586 Log.e(TAG, "Unable to invalidate the query page token", t);
587 }
588 });
sidchhabraa7c8f8a2020-01-16 18:38:17 -0800589 }
Alexander Dorokhine969f4462020-03-05 15:54:19 -0800590
Alexander Dorokhinef6c66ae2020-03-09 14:47:25 -0700591 @Override
Terry Wang623e3b02021-02-02 20:27:33 -0800592 public void writeQueryResultsToFile(
593 @NonNull String packageName,
594 @NonNull String databaseName,
595 @NonNull ParcelFileDescriptor fileDescriptor,
596 @NonNull String queryExpression,
597 @NonNull Bundle searchSpecBundle,
598 @UserIdInt int userId,
599 @NonNull IAppSearchResultCallback callback) {
600 int callingUid = Binder.getCallingUid();
601 int callingUserId = handleIncomingUser(userId, callingUid);
Terry Wange04ceab2021-03-29 19:25:12 -0700602 EXECUTOR.execute(() -> {
603 try {
604 verifyCallingPackage(callingUid, packageName);
605 AppSearchImpl impl =
606 mImplInstanceManager.getAppSearchImpl(callingUserId);
607 // we don't need to append the file. The file is always brand new.
608 try (DataOutputStream outputStream = new DataOutputStream(
609 new FileOutputStream(fileDescriptor.getFileDescriptor()))) {
610 SearchResultPage searchResultPage = impl.query(
611 packageName,
612 databaseName,
613 queryExpression,
Alexander Dorokhine7cbc4712021-04-27 14:47:39 -0700614 new SearchSpec(searchSpecBundle),
615 /*logger=*/ null);
Terry Wange04ceab2021-03-29 19:25:12 -0700616 while (!searchResultPage.getResults().isEmpty()) {
617 for (int i = 0; i < searchResultPage.getResults().size(); i++) {
618 AppSearchMigrationHelper.writeBundleToOutputStream(
619 outputStream, searchResultPage.getResults().get(i)
620 .getGenericDocument().getBundle());
621 }
622 searchResultPage = impl.getNextPage(
623 searchResultPage.getNextPageToken());
Terry Wang623e3b02021-02-02 20:27:33 -0800624 }
Terry Wang623e3b02021-02-02 20:27:33 -0800625 }
Terry Wange04ceab2021-03-29 19:25:12 -0700626 invokeCallbackOnResult(callback, AppSearchResult.newSuccessfulResult(null));
627 } catch (Throwable t) {
628 invokeCallbackOnError(callback, t);
Terry Wang623e3b02021-02-02 20:27:33 -0800629 }
Terry Wange04ceab2021-03-29 19:25:12 -0700630 });
Terry Wang623e3b02021-02-02 20:27:33 -0800631 }
632
633 @Override
634 public void putDocumentsFromFile(
635 @NonNull String packageName,
636 @NonNull String databaseName,
637 @NonNull ParcelFileDescriptor fileDescriptor,
638 @UserIdInt int userId,
639 @NonNull IAppSearchResultCallback callback) {
640 int callingUid = Binder.getCallingUid();
641 int callingUserId = handleIncomingUser(userId, callingUid);
Terry Wange04ceab2021-03-29 19:25:12 -0700642 EXECUTOR.execute(() -> {
643 try {
644 verifyCallingPackage(callingUid, packageName);
645 AppSearchImpl impl =
646 mImplInstanceManager.getAppSearchImpl(callingUserId);
Terry Wang623e3b02021-02-02 20:27:33 -0800647
Terry Wange04ceab2021-03-29 19:25:12 -0700648 GenericDocument document;
649 ArrayList<Bundle> migrationFailureBundles = new ArrayList<>();
650 try (DataInputStream inputStream = new DataInputStream(
651 new FileInputStream(fileDescriptor.getFileDescriptor()))) {
652 while (true) {
653 try {
654 document = AppSearchMigrationHelper
655 .readDocumentFromInputStream(inputStream);
656 } catch (EOFException e) {
657 // nothing wrong, we just finish the reading.
658 break;
659 }
660 try {
661 impl.putDocument(packageName, databaseName, document,
662 /*logger=*/ null);
663 } catch (Throwable t) {
Alexander Dorokhine17f79372021-04-21 11:23:09 -0700664 migrationFailureBundles.add(new SetSchemaResponse.MigrationFailure(
665 document.getNamespace(),
666 document.getId(),
667 document.getSchemaType(),
668 AppSearchResult.throwableToFailedResult(t))
669 .getBundle());
Terry Wange04ceab2021-03-29 19:25:12 -0700670 }
Terry Wang623e3b02021-02-02 20:27:33 -0800671 }
672 }
Alexander Dorokhinec77f4442021-04-14 09:26:06 -0700673 impl.persistToDisk(PersistType.Code.FULL);
Terry Wange04ceab2021-03-29 19:25:12 -0700674 invokeCallbackOnResult(callback,
675 AppSearchResult.newSuccessfulResult(migrationFailureBundles));
676 } catch (Throwable t) {
677 invokeCallbackOnError(callback, t);
Terry Wang623e3b02021-02-02 20:27:33 -0800678 }
Terry Wange04ceab2021-03-29 19:25:12 -0700679 });
Terry Wang623e3b02021-02-02 20:27:33 -0800680 }
681
682 @Override
Alexander Dorokhined18f8842021-01-20 15:26:13 -0800683 public void reportUsage(
684 @NonNull String packageName,
685 @NonNull String databaseName,
686 @NonNull String namespace,
Alexander Dorokhine17f79372021-04-21 11:23:09 -0700687 @NonNull String documentId,
Alexander Dorokhined18f8842021-01-20 15:26:13 -0800688 long usageTimeMillis,
Alexander Dorokhine9795b512021-03-23 22:06:59 -0700689 boolean systemUsage,
Alexander Dorokhined18f8842021-01-20 15:26:13 -0800690 @UserIdInt int userId,
691 @NonNull IAppSearchResultCallback callback) {
692 Objects.requireNonNull(databaseName);
693 Objects.requireNonNull(namespace);
Alexander Dorokhine17f79372021-04-21 11:23:09 -0700694 Objects.requireNonNull(documentId);
Alexander Dorokhined18f8842021-01-20 15:26:13 -0800695 Objects.requireNonNull(callback);
696 int callingUid = Binder.getCallingUid();
697 int callingUserId = handleIncomingUser(userId, callingUid);
Terry Wange04ceab2021-03-29 19:25:12 -0700698 EXECUTOR.execute(() -> {
699 try {
700 verifyUserUnlocked(callingUserId);
Alexander Dorokhine9795b512021-03-23 22:06:59 -0700701
Terry Wange04ceab2021-03-29 19:25:12 -0700702 if (systemUsage) {
703 // TODO(b/183031844): Validate that the call comes from the system
704 }
705
706 AppSearchImpl impl =
707 mImplInstanceManager.getAppSearchImpl(callingUserId);
708 impl.reportUsage(
Alexander Dorokhine17f79372021-04-21 11:23:09 -0700709 packageName, databaseName, namespace, documentId,
Terry Wange04ceab2021-03-29 19:25:12 -0700710 usageTimeMillis, systemUsage);
711 invokeCallbackOnResult(
712 callback, AppSearchResult.newSuccessfulResult(/*result=*/ null));
713 } catch (Throwable t) {
714 invokeCallbackOnError(callback, t);
Alexander Dorokhine9795b512021-03-23 22:06:59 -0700715 }
Terry Wange04ceab2021-03-29 19:25:12 -0700716 });
Alexander Dorokhined18f8842021-01-20 15:26:13 -0800717 }
718
719 @Override
Alexander Dorokhine17f79372021-04-21 11:23:09 -0700720 public void removeByDocumentId(
Cassie Wang0c62d992021-01-15 14:39:30 -0800721 @NonNull String packageName,
Terry Wangf2093072020-11-30 04:47:19 -0800722 @NonNull String databaseName,
723 @NonNull String namespace,
Alexander Dorokhine17f79372021-04-21 11:23:09 -0700724 @NonNull List<String> ids,
Terry Wangf2093072020-11-30 04:47:19 -0800725 @UserIdInt int userId,
Terry Wangdbd1dca2020-11-03 17:03:56 -0800726 @NonNull IAppSearchBatchResultCallback callback) {
Alexander Dorokhine5258ad22021-04-15 10:59:55 -0700727 Objects.requireNonNull(packageName);
728 Objects.requireNonNull(databaseName);
Alexander Dorokhine17f79372021-04-21 11:23:09 -0700729 Objects.requireNonNull(ids);
Alexander Dorokhine5258ad22021-04-15 10:59:55 -0700730 Objects.requireNonNull(callback);
Terry Wangf2093072020-11-30 04:47:19 -0800731 int callingUid = Binder.getCallingUid();
732 int callingUserId = handleIncomingUser(userId, callingUid);
Terry Wange04ceab2021-03-29 19:25:12 -0700733 EXECUTOR.execute(() -> {
734 try {
735 verifyUserUnlocked(callingUserId);
736 verifyCallingPackage(callingUid, packageName);
737 AppSearchBatchResult.Builder<String, Void> resultBuilder =
738 new AppSearchBatchResult.Builder<>();
739 AppSearchImpl impl =
740 mImplInstanceManager.getAppSearchImpl(callingUserId);
Alexander Dorokhine17f79372021-04-21 11:23:09 -0700741 for (int i = 0; i < ids.size(); i++) {
742 String id = ids.get(i);
Terry Wange04ceab2021-03-29 19:25:12 -0700743 try {
Alexander Dorokhine17f79372021-04-21 11:23:09 -0700744 impl.remove(packageName, databaseName, namespace, id);
745 resultBuilder.setSuccess(id, /*result= */ null);
Terry Wange04ceab2021-03-29 19:25:12 -0700746 } catch (Throwable t) {
Alexander Dorokhine17f79372021-04-21 11:23:09 -0700747 resultBuilder.setResult(id, throwableToFailedResult(t));
Terry Wange04ceab2021-03-29 19:25:12 -0700748 }
Alexander Dorokhineff82fba2020-03-09 16:35:24 -0700749 }
Alexander Dorokhinec77f4442021-04-14 09:26:06 -0700750 // Now that the batch has been written. Persist the newly written data.
751 impl.persistToDisk(PersistType.Code.LITE);
Terry Wange04ceab2021-03-29 19:25:12 -0700752 invokeCallbackOnResult(callback, resultBuilder.build());
753 } catch (Throwable t) {
754 invokeCallbackOnError(callback, t);
Alexander Dorokhineff82fba2020-03-09 16:35:24 -0700755 }
Terry Wange04ceab2021-03-29 19:25:12 -0700756 });
Alexander Dorokhineff82fba2020-03-09 16:35:24 -0700757 }
758
759 @Override
Terry Wang26b9e5c2020-10-23 02:05:01 -0700760 public void removeByQuery(
Cassie Wang0c62d992021-01-15 14:39:30 -0800761 @NonNull String packageName,
Terry Wang26b9e5c2020-10-23 02:05:01 -0700762 @NonNull String databaseName,
763 @NonNull String queryExpression,
764 @NonNull Bundle searchSpecBundle,
Terry Wangf2093072020-11-30 04:47:19 -0800765 @UserIdInt int userId,
Alexander Dorokhine178366b2020-10-20 17:40:49 -0700766 @NonNull IAppSearchResultCallback callback) {
Alexander Dorokhine5258ad22021-04-15 10:59:55 -0700767 Objects.requireNonNull(packageName);
768 Objects.requireNonNull(databaseName);
769 Objects.requireNonNull(queryExpression);
770 Objects.requireNonNull(searchSpecBundle);
771 Objects.requireNonNull(callback);
Terry Wangf2093072020-11-30 04:47:19 -0800772 int callingUid = Binder.getCallingUid();
773 int callingUserId = handleIncomingUser(userId, callingUid);
Terry Wange04ceab2021-03-29 19:25:12 -0700774 EXECUTOR.execute(() -> {
775 try {
776 verifyUserUnlocked(callingUserId);
777 verifyCallingPackage(callingUid, packageName);
778 AppSearchImpl impl =
779 mImplInstanceManager.getAppSearchImpl(callingUserId);
780 impl.removeByQuery(
781 packageName,
782 databaseName,
783 queryExpression,
784 new SearchSpec(searchSpecBundle));
Alexander Dorokhinec77f4442021-04-14 09:26:06 -0700785 // Now that the batch has been written. Persist the newly written data.
786 impl.persistToDisk(PersistType.Code.LITE);
Terry Wange04ceab2021-03-29 19:25:12 -0700787 invokeCallbackOnResult(callback, AppSearchResult.newSuccessfulResult(null));
788 } catch (Throwable t) {
789 invokeCallbackOnError(callback, t);
790 }
791 });
Alexander Dorokhinef6c66ae2020-03-09 14:47:25 -0700792 }
793
Terry Wangdbd1dca2020-11-03 17:03:56 -0800794 @Override
Cassie Wang8f0df492021-03-24 09:23:18 -0700795 public void getStorageInfo(
796 @NonNull String packageName,
797 @NonNull String databaseName,
798 @UserIdInt int userId,
799 @NonNull IAppSearchResultCallback callback) {
Alexander Dorokhine5258ad22021-04-15 10:59:55 -0700800 Objects.requireNonNull(packageName);
801 Objects.requireNonNull(databaseName);
802 Objects.requireNonNull(callback);
Cassie Wang8f0df492021-03-24 09:23:18 -0700803 int callingUid = Binder.getCallingUid();
804 int callingUserId = handleIncomingUser(userId, callingUid);
Terry Wange04ceab2021-03-29 19:25:12 -0700805 EXECUTOR.execute(() -> {
806 try {
807 verifyUserUnlocked(callingUserId);
808 verifyCallingPackage(callingUid, packageName);
809 AppSearchImpl impl =
810 mImplInstanceManager.getAppSearchImpl(callingUserId);
811 StorageInfo storageInfo = impl.getStorageInfoForDatabase(packageName,
812 databaseName);
813 Bundle storageInfoBundle = storageInfo.getBundle();
814 invokeCallbackOnResult(
815 callback, AppSearchResult.newSuccessfulResult(storageInfoBundle));
816 } catch (Throwable t) {
817 invokeCallbackOnError(callback, t);
818 }
819 });
Cassie Wang8f0df492021-03-24 09:23:18 -0700820 }
821
822 @Override
Terry Wang2da17852020-12-16 19:59:08 -0800823 public void persistToDisk(@UserIdInt int userId) {
Cassie Wangb0d60122021-03-30 12:38:46 -0700824 int callingUid = Binder.getCallingUid();
Terry Wang2da17852020-12-16 19:59:08 -0800825 int callingUserId = handleIncomingUser(userId, callingUid);
Terry Wange04ceab2021-03-29 19:25:12 -0700826 EXECUTOR.execute(() -> {
827 try {
828 verifyUserUnlocked(callingUserId);
829 AppSearchImpl impl =
830 mImplInstanceManager.getAppSearchImpl(callingUserId);
Alexander Dorokhinec77f4442021-04-14 09:26:06 -0700831 impl.persistToDisk(PersistType.Code.FULL);
Terry Wange04ceab2021-03-29 19:25:12 -0700832 } catch (Throwable t) {
833 Log.e(TAG, "Unable to persist the data to disk", t);
834 }
835 });
Terry Wang2da17852020-12-16 19:59:08 -0800836 }
837
838 @Override
Terry Wangf2093072020-11-30 04:47:19 -0800839 public void initialize(@UserIdInt int userId, @NonNull IAppSearchResultCallback callback) {
Alexander Dorokhine5258ad22021-04-15 10:59:55 -0700840 Objects.requireNonNull(callback);
Terry Wangf2093072020-11-30 04:47:19 -0800841 int callingUid = Binder.getCallingUid();
842 int callingUserId = handleIncomingUser(userId, callingUid);
Terry Wange04ceab2021-03-29 19:25:12 -0700843 EXECUTOR.execute(() -> {
844 try {
845 verifyUserUnlocked(callingUserId);
846 mImplInstanceManager.getOrCreateAppSearchImpl(mContext, callingUserId);
Xiaoyu Jinf8cc2012021-03-12 11:00:54 -0800847 mLoggerInstanceManager.getOrCreatePlatformLogger(getContext(), callingUserId);
Terry Wange04ceab2021-03-29 19:25:12 -0700848 invokeCallbackOnResult(callback, AppSearchResult.newSuccessfulResult(null));
849 } catch (Throwable t) {
850 invokeCallbackOnError(callback, t);
851 }
852 });
Terry Wangdbd1dca2020-11-03 17:03:56 -0800853 }
854
Cassie Wang0c62d992021-01-15 14:39:30 -0800855 private void verifyCallingPackage(int callingUid, @NonNull String callingPackage) {
Alexander Dorokhine5258ad22021-04-15 10:59:55 -0700856 Objects.requireNonNull(callingPackage);
Cassie Wang0c62d992021-01-15 14:39:30 -0800857 if (mPackageManagerInternal.getPackageUid(
Yang Yu0fcd51a2021-04-23 11:25:44 -0700858 callingPackage, /*flags=*/ 0, UserHandle.getUserId(callingUid))
Cassie Wang0c62d992021-01-15 14:39:30 -0800859 != callingUid) {
860 throw new SecurityException(
861 "Specified calling package ["
862 + callingPackage
863 + "] does not match the calling uid "
864 + callingUid);
Alexander Dorokhineebd37742020-09-22 15:02:26 -0700865 }
Alexander Dorokhineebd37742020-09-22 15:02:26 -0700866 }
867
Alexander Dorokhine8c5ba912020-12-14 22:58:12 -0800868 /** Invokes the {@link IAppSearchResultCallback} with the result. */
Cassie Wang0c62d992021-01-15 14:39:30 -0800869 private void invokeCallbackOnResult(
870 IAppSearchResultCallback callback, AppSearchResult<?> result) {
Terry Wangdbd1dca2020-11-03 17:03:56 -0800871 try {
872 callback.onResult(result);
873 } catch (RemoteException e) {
Terry Wang2da17852020-12-16 19:59:08 -0800874 Log.e(TAG, "Unable to send result to the callback", e);
Alexander Dorokhine969f4462020-03-05 15:54:19 -0800875 }
Terry Wangdbd1dca2020-11-03 17:03:56 -0800876 }
Alexander Dorokhine969f4462020-03-05 15:54:19 -0800877
Alexander Dorokhine8c5ba912020-12-14 22:58:12 -0800878 /** Invokes the {@link IAppSearchBatchResultCallback} with the result. */
Cassie Wang0c62d992021-01-15 14:39:30 -0800879 private void invokeCallbackOnResult(
880 IAppSearchBatchResultCallback callback, AppSearchBatchResult<?, ?> result) {
Terry Wangdbd1dca2020-11-03 17:03:56 -0800881 try {
882 callback.onResult(result);
883 } catch (RemoteException e) {
Terry Wang2da17852020-12-16 19:59:08 -0800884 Log.e(TAG, "Unable to send result to the callback", e);
Alexander Dorokhine969f4462020-03-05 15:54:19 -0800885 }
Terry Wangdbd1dca2020-11-03 17:03:56 -0800886 }
887
888 /**
Alexander Dorokhine8c5ba912020-12-14 22:58:12 -0800889 * Invokes the {@link IAppSearchResultCallback} with an throwable.
Terry Wangdbd1dca2020-11-03 17:03:56 -0800890 *
Alexander Dorokhine8c5ba912020-12-14 22:58:12 -0800891 * <p>The throwable is convert to a {@link AppSearchResult};
Terry Wangdbd1dca2020-11-03 17:03:56 -0800892 */
893 private void invokeCallbackOnError(IAppSearchResultCallback callback, Throwable throwable) {
894 try {
895 callback.onResult(throwableToFailedResult(throwable));
896 } catch (RemoteException e) {
Terry Wang2da17852020-12-16 19:59:08 -0800897 Log.e(TAG, "Unable to send result to the callback", e);
Terry Wangdbd1dca2020-11-03 17:03:56 -0800898 }
899 }
900
901 /**
Alexander Dorokhine8c5ba912020-12-14 22:58:12 -0800902 * Invokes the {@link IAppSearchBatchResultCallback} with an unexpected internal throwable.
Terry Wangdbd1dca2020-11-03 17:03:56 -0800903 *
Alexander Dorokhineb5d34b12021-04-15 00:32:15 -0700904 * <p>The throwable is converted to {@link AppSearchResult}.
Terry Wangdbd1dca2020-11-03 17:03:56 -0800905 */
Cassie Wang0c62d992021-01-15 14:39:30 -0800906 private void invokeCallbackOnError(
Alexander Dorokhineb5d34b12021-04-15 00:32:15 -0700907 @NonNull IAppSearchBatchResultCallback callback, @NonNull Throwable throwable) {
Terry Wangdbd1dca2020-11-03 17:03:56 -0800908 try {
Alexander Dorokhineb5d34b12021-04-15 00:32:15 -0700909 callback.onSystemError(throwableToFailedResult(throwable));
Terry Wangdbd1dca2020-11-03 17:03:56 -0800910 } catch (RemoteException e) {
Terry Wang2da17852020-12-16 19:59:08 -0800911 Log.e(TAG, "Unable to send error to the callback", e);
Terry Wangdbd1dca2020-11-03 17:03:56 -0800912 }
Alexander Dorokhine969f4462020-03-05 15:54:19 -0800913 }
Terry Wangfebbead2019-10-17 17:05:18 -0700914 }
Terry Wangf2093072020-11-30 04:47:19 -0800915
Cassie Wang0c62d992021-01-15 14:39:30 -0800916 // TODO(b/173553485) verifying that the caller has permission to access target user's data
917 // TODO(b/173553485) Handle ACTION_USER_REMOVED broadcast
918 // TODO(b/173553485) Implement SystemService.onUserStopping()
Terry Wangf2093072020-11-30 04:47:19 -0800919 private static int handleIncomingUser(@UserIdInt int userId, int callingUid) {
920 int callingPid = Binder.getCallingPid();
Cassie Wang0c62d992021-01-15 14:39:30 -0800921 return ActivityManager.handleIncomingUser(
922 callingPid,
923 callingUid,
924 userId,
925 /*allowAll=*/ false,
926 /*requireFull=*/ false,
927 /*name=*/ null,
928 /*callerPackage=*/ null);
Terry Wangf2093072020-11-30 04:47:19 -0800929 }
Yang Yu0fcd51a2021-04-23 11:25:44 -0700930
931 // TODO(b/179160886): Cache the previous storage stats.
932 private class AppSearchStorageStatsAugmenter implements StorageStatsAugmenter {
933 @Override
934 public void augmentStatsForPackage(
935 @NonNull PackageStats stats,
936 @NonNull String packageName,
937 @UserIdInt int userId,
938 boolean callerHasStatsPermission) {
939 Objects.requireNonNull(stats);
940 Objects.requireNonNull(packageName);
941 try {
942 verifyUserUnlocked(userId);
943 AppSearchImpl impl = mImplInstanceManager.getOrCreateAppSearchImpl(mContext,
944 userId);
945 stats.dataSize += impl.getStorageInfoForPackage(packageName).getSizeBytes();
946 } catch (Throwable t) {
947 Log.e(
948 TAG,
949 "Unable to augment storage stats for userId "
950 + userId
951 + " packageName "
952 + packageName,
953 t);
954 }
955 }
956
957 @Override
958 public void augmentStatsForUid(
959 @NonNull PackageStats stats, int uid, boolean callerHasStatsPermission) {
960 Objects.requireNonNull(stats);
961 int userId = UserHandle.getUserId(uid);
962 try {
963 verifyUserUnlocked(userId);
964 String[] packagesForUid = mPackageManager.getPackagesForUid(uid);
965 if (packagesForUid == null) {
966 return;
967 }
968 AppSearchImpl impl = mImplInstanceManager.getOrCreateAppSearchImpl(mContext,
969 userId);
970 for (String packageName : packagesForUid) {
971 stats.dataSize += impl.getStorageInfoForPackage(packageName).getSizeBytes();
972 }
973 } catch (Throwable t) {
974 Log.e(TAG, "Unable to augment storage stats for uid " + uid, t);
975 }
976 }
977 }
Terry Wangfebbead2019-10-17 17:05:18 -0700978}