blob: 777f9fe00bcad0aa58cda0f98b76a851bc550d49 [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;
Alexander Dorokhineab789062021-01-11 21:00:00 -080032import android.app.appsearch.PackageIdentifier;
Terry Wang26b9e5c2020-10-23 02:05:01 -070033import android.app.appsearch.SearchResultPage;
Alexander Dorokhinec9fc9602020-10-06 01:39:50 -070034import android.app.appsearch.SearchSpec;
Terry Wang623e3b02021-02-02 20:27:33 -080035import android.app.appsearch.SetSchemaResponse;
Cassie Wang8f0df492021-03-24 09:23:18 -070036import android.app.appsearch.StorageInfo;
Alexander Dorokhined5e8eda2021-05-04 13:24:47 -070037import android.app.appsearch.aidl.AppSearchBatchResultParcel;
38import android.app.appsearch.aidl.AppSearchResultParcel;
39import android.app.appsearch.aidl.IAppSearchBatchResultCallback;
40import android.app.appsearch.aidl.IAppSearchManager;
41import android.app.appsearch.aidl.IAppSearchResultCallback;
Terry Wang12dc6c02021-03-31 19:26:16 -070042import android.content.BroadcastReceiver;
Terry Wangfebbead2019-10-17 17:05:18 -070043import android.content.Context;
Terry Wang12dc6c02021-03-31 19:26:16 -070044import android.content.Intent;
45import android.content.IntentFilter;
Alexander Dorokhinea5d0d322021-05-10 15:59:31 -070046import android.content.pm.PackageInfo;
Yang Yu0fcd51a2021-04-23 11:25:44 -070047import android.content.pm.PackageManager;
Cassie Wang0c62d992021-01-15 14:39:30 -080048import android.content.pm.PackageManagerInternal;
Yang Yu0fcd51a2021-04-23 11:25:44 -070049import android.content.pm.PackageStats;
Alexander Dorokhine270d4f12020-01-15 17:24:35 -080050import android.os.Binder;
Alexander Dorokhine92ce3532020-10-06 01:39:36 -070051import android.os.Bundle;
Terry Wang623e3b02021-02-02 20:27:33 -080052import android.os.ParcelFileDescriptor;
Terry Wangdbd1dca2020-11-03 17:03:56 -080053import android.os.RemoteException;
Xiaoyu Jinf8cc2012021-03-12 11:00:54 -080054import android.os.SystemClock;
Cassie Wang0c62d992021-01-15 14:39:30 -080055import android.os.UserHandle;
Pinyao Tingd5c2ed92021-03-18 14:51:54 -070056import android.os.UserManager;
Alexander Dorokhineab789062021-01-11 21:00:00 -080057import android.util.ArrayMap;
Cassie Wang9ba9ae12021-02-01 16:39:37 -080058import android.util.ArraySet;
Terry Wangdbd1dca2020-11-03 17:03:56 -080059import android.util.Log;
Terry Wangfebbead2019-10-17 17:05:18 -070060
Cassie Wang15c86972021-02-09 13:43:25 -080061import com.android.internal.annotations.GuardedBy;
Alexander Dorokhinea5d0d322021-05-10 15:59:31 -070062import com.android.server.LocalManagerRegistry;
Cassie Wang0c62d992021-01-15 14:39:30 -080063import com.android.server.LocalServices;
Terry Wangfebbead2019-10-17 17:05:18 -070064import com.android.server.SystemService;
Alexander Dorokhinef660d8f2020-10-29 22:37:00 -070065import com.android.server.appsearch.external.localstorage.AppSearchImpl;
Xiaoyu Jinf8cc2012021-03-12 11:00:54 -080066import com.android.server.appsearch.external.localstorage.stats.CallStats;
67import com.android.server.appsearch.stats.LoggerInstanceManager;
68import com.android.server.appsearch.stats.PlatformLogger;
Alexander Dorokhinea5d0d322021-05-10 15:59:31 -070069import com.android.server.usage.StorageStatsManagerLocal;
70import com.android.server.usage.StorageStatsManagerLocal.StorageStatsAugmenter;
Alexander Dorokhinefd07eba2020-01-13 20:22:20 -080071
Alexander Dorokhinec77f4442021-04-14 09:26:06 -070072import com.google.android.icing.proto.PersistType;
73
Terry Wang623e3b02021-02-02 20:27:33 -080074import java.io.DataInputStream;
75import java.io.DataOutputStream;
76import java.io.EOFException;
77import java.io.FileInputStream;
78import java.io.FileOutputStream;
Alexander Dorokhine6a99f942020-12-04 02:57:22 -080079import java.util.ArrayList;
Alexander Dorokhine18465842020-01-21 01:08:57 -080080import java.util.List;
Alexander Dorokhineab789062021-01-11 21:00:00 -080081import java.util.Map;
Alexander Dorokhined18f8842021-01-20 15:26:13 -080082import java.util.Objects;
Cassie Wang9ba9ae12021-02-01 16:39:37 -080083import java.util.Set;
Terry Wange04ceab2021-03-29 19:25:12 -070084import java.util.concurrent.Executor;
Terry Wangd2186e52021-04-14 13:19:45 -070085import java.util.concurrent.LinkedBlockingQueue;
Terry Wange04ceab2021-03-29 19:25:12 -070086import java.util.concurrent.ThreadPoolExecutor;
87import java.util.concurrent.TimeUnit;
Alexander Dorokhine18465842020-01-21 01:08:57 -080088
Cassie Wang0c62d992021-01-15 14:39:30 -080089/** TODO(b/142567528): add comments when implement this class */
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;
Cassie Wang0c62d992021-01-15 14:39:30 -080094 private PackageManagerInternal mPackageManagerInternal;
Cassie Wang21c2d6a2021-01-20 23:59:55 -080095 private ImplInstanceManager mImplInstanceManager;
Pinyao Tingd5c2ed92021-03-18 14:51:54 -070096 private UserManager mUserManager;
Xiaoyu Jinf8cc2012021-03-12 11:00:54 -080097 private LoggerInstanceManager mLoggerInstanceManager;
Terry Wangfebbead2019-10-17 17:05:18 -070098
Terry Wange04ceab2021-03-29 19:25:12 -070099 // Never call shutdownNow(). It will cancel the futures it's returned. And since
100 // Executor#execute won't return anything, we will hang forever waiting for the execution.
101 // AppSearch multi-thread execution is guarded by Read & Write Lock in AppSearchImpl, all
102 // mutate requests will need to gain write lock and query requests need to gain read lock.
103 private static final Executor EXECUTOR = new ThreadPoolExecutor(/*corePoolSize=*/1,
104 Runtime.getRuntime().availableProcessors(), /*keepAliveTime*/ 60L, TimeUnit.SECONDS,
Terry Wangd2186e52021-04-14 13:19:45 -0700105 new LinkedBlockingQueue<>());
Terry Wange04ceab2021-03-29 19:25:12 -0700106
Cassie Wang15c86972021-02-09 13:43:25 -0800107 // Cache of unlocked user ids so we don't have to query UserManager service each time. The
108 // "locked" suffix refers to the fact that access to the field should be locked; unrelated to
109 // the unlocked status of user ids.
110 @GuardedBy("mUnlockedUserIdsLocked")
111 private final Set<Integer> mUnlockedUserIdsLocked = new ArraySet<>();
Cassie Wang9ba9ae12021-02-01 16:39:37 -0800112
Terry Wangfebbead2019-10-17 17:05:18 -0700113 public AppSearchManagerService(Context context) {
114 super(context);
Terry Wang12dc6c02021-03-31 19:26:16 -0700115 mContext = context;
Terry Wangfebbead2019-10-17 17:05:18 -0700116 }
117
118 @Override
119 public void onStart() {
120 publishBinderService(Context.APP_SEARCH_SERVICE, new Stub());
Yang Yu0fcd51a2021-04-23 11:25:44 -0700121 mPackageManager = getContext().getPackageManager();
Cassie Wang0c62d992021-01-15 14:39:30 -0800122 mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
Terry Wang12dc6c02021-03-31 19:26:16 -0700123 mImplInstanceManager = ImplInstanceManager.getInstance(mContext);
124 mUserManager = mContext.getSystemService(UserManager.class);
Xiaoyu Jinf8cc2012021-03-12 11:00:54 -0800125 mLoggerInstanceManager = LoggerInstanceManager.getInstance();
Terry Wang12dc6c02021-03-31 19:26:16 -0700126 registerReceivers();
Alexander Dorokhinea5d0d322021-05-10 15:59:31 -0700127 LocalManagerRegistry.getManager(StorageStatsManagerLocal.class)
Yang Yu0fcd51a2021-04-23 11:25:44 -0700128 .registerStorageStatsAugmenter(new AppSearchStorageStatsAugmenter(), TAG);
Terry Wang12dc6c02021-03-31 19:26:16 -0700129 }
130
131 private void registerReceivers() {
132 mContext.registerReceiverAsUser(new UserActionReceiver(), UserHandle.ALL,
133 new IntentFilter(Intent.ACTION_USER_REMOVED), /*broadcastPermission=*/ null,
134 /*scheduler=*/ null);
Terry Wange201dc02021-04-16 01:03:20 -0700135
136 //TODO(b/145759910) Add a direct callback when user clears the data instead of relying on
137 // broadcasts
138 IntentFilter packageChangedFilter = new IntentFilter();
139 packageChangedFilter.addAction(Intent.ACTION_PACKAGE_FULLY_REMOVED);
140 packageChangedFilter.addAction(Intent.ACTION_PACKAGE_DATA_CLEARED);
141 packageChangedFilter.addDataScheme("package");
142 packageChangedFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
143 mContext.registerReceiverAsUser(new PackageChangedReceiver(), UserHandle.ALL,
144 packageChangedFilter, /*broadcastPermission=*/ null,
145 /*scheduler=*/ null);
Terry Wang12dc6c02021-03-31 19:26:16 -0700146 }
147
148 private class UserActionReceiver extends BroadcastReceiver {
149 @Override
150 public void onReceive(@NonNull Context context, @NonNull Intent intent) {
151 switch (intent.getAction()) {
152 case Intent.ACTION_USER_REMOVED:
Terry Wange201dc02021-04-16 01:03:20 -0700153 int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
Terry Wang12dc6c02021-03-31 19:26:16 -0700154 if (userId == USER_NULL) {
Terry Wange201dc02021-04-16 01:03:20 -0700155 Log.e(TAG, "userId is missing in the intent: " + intent);
Terry Wang12dc6c02021-03-31 19:26:16 -0700156 return;
157 }
158 handleUserRemoved(userId);
159 break;
160 default:
Terry Wange201dc02021-04-16 01:03:20 -0700161 Log.e(TAG, "Received unknown intent: " + intent);
Terry Wang12dc6c02021-03-31 19:26:16 -0700162 }
163 }
164 }
165
166 /**
167 * Handles user removed action.
168 *
169 * <p>Only need to clear the AppSearchImpl instance. The data of AppSearch is saved in the
170 * "credential encrypted" system directory of each user. That directory will be auto-deleted
171 * when a user is removed.
172 *
173 * @param userId The multi-user userId of the user that need to be removed.
174 *
175 * @see android.os.Environment#getDataSystemCeDirectory
176 */
177 private void handleUserRemoved(@UserIdInt int userId) {
178 try {
179 mImplInstanceManager.removeAppSearchImplForUser(userId);
Xiaoyu Jinf8cc2012021-03-12 11:00:54 -0800180 mLoggerInstanceManager.removePlatformLoggerForUser(userId);
Terry Wange201dc02021-04-16 01:03:20 -0700181 Log.i(TAG, "Removed AppSearchImpl instance for user: " + userId);
Terry Wang12dc6c02021-03-31 19:26:16 -0700182 } catch (Throwable t) {
Terry Wange201dc02021-04-16 01:03:20 -0700183 Log.e(TAG, "Unable to remove data for user: " + userId, t);
184 }
185 }
186
187 private class PackageChangedReceiver extends BroadcastReceiver {
188 @Override
189 public void onReceive(@NonNull Context context, @NonNull Intent intent) {
190 switch (intent.getAction()) {
191 case Intent.ACTION_PACKAGE_FULLY_REMOVED:
192 case Intent.ACTION_PACKAGE_DATA_CLEARED:
193 String packageName = intent.getData().getSchemeSpecificPart();
194 if (packageName == null) {
195 Log.e(TAG, "Package name is missing in the intent: " + intent);
196 return;
197 }
198 int uid = intent.getIntExtra(Intent.EXTRA_UID, INVALID_UID);
199 if (uid == INVALID_UID) {
200 Log.e(TAG, "uid is missing in the intent: " + intent);
201 return;
202 }
203 handlePackageRemoved(packageName, uid);
204 break;
205 default:
206 Log.e(TAG, "Received unknown intent: " + intent);
207 }
208 }
209 }
210
211 private void handlePackageRemoved(String packageName, int uid) {
212 int userId = UserHandle.getUserId(uid);
213 try {
214 if (isUserLocked(userId)) {
215 //TODO(b/186151459) clear the uninstalled package data when user is unlocked.
216 return;
217 }
218 if (ImplInstanceManager.getAppSearchDir(userId).exists()) {
219 // Only clear the package's data if AppSearch exists for this user.
220 AppSearchImpl impl = mImplInstanceManager.getOrCreateAppSearchImpl(mContext,
221 userId);
222 //TODO(b/145759910) clear visibility setting for package.
223 impl.clearPackageData(packageName);
224 }
225 } catch (Throwable t) {
226 Log.e(TAG, "Unable to remove data for package: " + packageName, t);
Terry Wang12dc6c02021-03-31 19:26:16 -0700227 }
Terry Wangfebbead2019-10-17 17:05:18 -0700228 }
229
Cassie Wang9ba9ae12021-02-01 16:39:37 -0800230 @Override
Pinyao Tingd5c2ed92021-03-18 14:51:54 -0700231 public void onUserUnlocking(@NonNull TargetUser user) {
Cassie Wang15c86972021-02-09 13:43:25 -0800232 synchronized (mUnlockedUserIdsLocked) {
233 mUnlockedUserIdsLocked.add(user.getUserIdentifier());
234 }
Cassie Wang9ba9ae12021-02-01 16:39:37 -0800235 }
236
Terry Wangde9f3382021-04-28 19:45:07 -0700237 @Override
238 public void onUserStopping(@NonNull TargetUser user) {
239 synchronized (mUnlockedUserIdsLocked) {
240 mUnlockedUserIdsLocked.remove(user.getUserIdentifier());
241 try {
242 mImplInstanceManager.closeAndRemoveAppSearchImplForUser(user.getUserIdentifier());
243 } catch (Throwable t) {
244 Log.e(TAG, "Error handling user stopping.", t);
245 }
246 }
247 }
248
Yang Yu0fcd51a2021-04-23 11:25:44 -0700249 private void verifyUserUnlocked(int callingUserId) {
Terry Wange201dc02021-04-16 01:03:20 -0700250 if (isUserLocked(callingUserId)) {
251 throw new IllegalStateException("User " + callingUserId + " is locked or not running.");
252 }
253 }
254
255 private boolean isUserLocked(int callingUserId) {
Yang Yu0fcd51a2021-04-23 11:25:44 -0700256 synchronized (mUnlockedUserIdsLocked) {
257 // First, check the local copy.
258 if (mUnlockedUserIdsLocked.contains(callingUserId)) {
Terry Wange201dc02021-04-16 01:03:20 -0700259 return false;
Yang Yu0fcd51a2021-04-23 11:25:44 -0700260 }
261 // If the local copy says the user is locked, check with UM for the actual state,
262 // since the user might just have been unlocked.
Terry Wange201dc02021-04-16 01:03:20 -0700263 return !mUserManager.isUserUnlockingOrUnlocked(UserHandle.of(callingUserId));
Yang Yu0fcd51a2021-04-23 11:25:44 -0700264 }
265 }
266
Terry Wangfebbead2019-10-17 17:05:18 -0700267 private class Stub extends IAppSearchManager.Stub {
Alexander Dorokhinefd07eba2020-01-13 20:22:20 -0800268 @Override
Alexander Dorokhine969f4462020-03-05 15:54:19 -0800269 public void setSchema(
Cassie Wang0c62d992021-01-15 14:39:30 -0800270 @NonNull String packageName,
Terry Wang6413aee2020-10-07 03:04:58 -0700271 @NonNull String databaseName,
Alexander Dorokhine92ce3532020-10-06 01:39:36 -0700272 @NonNull List<Bundle> schemaBundles,
Alexander Dorokhine315cca62021-03-04 12:34:41 -0800273 @NonNull List<String> schemasNotDisplayedBySystem,
Alexander Dorokhineab789062021-01-11 21:00:00 -0800274 @NonNull Map<String, List<Bundle>> schemasPackageAccessibleBundles,
Alexander Dorokhine969f4462020-03-05 15:54:19 -0800275 boolean forceOverride,
Alexander Dorokhine9795b512021-03-23 22:06:59 -0700276 int schemaVersion,
Terry Wangc10610d2021-03-21 13:21:24 -0700277 @UserIdInt int userId,
Terry Wangdbd1dca2020-11-03 17:03:56 -0800278 @NonNull IAppSearchResultCallback callback) {
Alexander Dorokhine5258ad22021-04-15 10:59:55 -0700279 Objects.requireNonNull(packageName);
280 Objects.requireNonNull(databaseName);
281 Objects.requireNonNull(schemaBundles);
282 Objects.requireNonNull(callback);
Terry Wangf2093072020-11-30 04:47:19 -0800283 int callingUid = Binder.getCallingUid();
284 int callingUserId = handleIncomingUser(userId, callingUid);
Terry Wange04ceab2021-03-29 19:25:12 -0700285 EXECUTOR.execute(() -> {
286 try {
287 verifyUserUnlocked(callingUserId);
288 verifyCallingPackage(callingUid, packageName);
289 List<AppSearchSchema> schemas = new ArrayList<>(schemaBundles.size());
290 for (int i = 0; i < schemaBundles.size(); i++) {
291 schemas.add(new AppSearchSchema(schemaBundles.get(i)));
Alexander Dorokhineab789062021-01-11 21:00:00 -0800292 }
Terry Wange04ceab2021-03-29 19:25:12 -0700293 Map<String, List<PackageIdentifier>> schemasPackageAccessible =
294 new ArrayMap<>(schemasPackageAccessibleBundles.size());
295 for (Map.Entry<String, List<Bundle>> entry :
296 schemasPackageAccessibleBundles.entrySet()) {
297 List<PackageIdentifier> packageIdentifiers =
298 new ArrayList<>(entry.getValue().size());
299 for (int i = 0; i < entry.getValue().size(); i++) {
300 packageIdentifiers.add(
301 new PackageIdentifier(entry.getValue().get(i)));
302 }
303 schemasPackageAccessible.put(entry.getKey(), packageIdentifiers);
304 }
305 AppSearchImpl impl = mImplInstanceManager.getAppSearchImpl(callingUserId);
306 SetSchemaResponse setSchemaResponse = impl.setSchema(
307 packageName,
308 databaseName,
309 schemas,
310 schemasNotDisplayedBySystem,
311 schemasPackageAccessible,
312 forceOverride,
313 schemaVersion);
314 invokeCallbackOnResult(callback,
315 AppSearchResult.newSuccessfulResult(setSchemaResponse.getBundle()));
316 } catch (Throwable t) {
317 invokeCallbackOnError(callback, t);
Alexander Dorokhineab789062021-01-11 21:00:00 -0800318 }
Terry Wange04ceab2021-03-29 19:25:12 -0700319 });
Alexander Dorokhine179c8b82020-01-11 00:17:48 -0800320 }
321
322 @Override
Terry Wang83a24932020-12-09 21:00:18 -0800323 public void getSchema(
Cassie Wang0c62d992021-01-15 14:39:30 -0800324 @NonNull String packageName,
Terry Wang83a24932020-12-09 21:00:18 -0800325 @NonNull String databaseName,
Terry Wangf2093072020-11-30 04:47:19 -0800326 @UserIdInt int userId,
Terry Wang83a24932020-12-09 21:00:18 -0800327 @NonNull IAppSearchResultCallback callback) {
Alexander Dorokhine5258ad22021-04-15 10:59:55 -0700328 Objects.requireNonNull(packageName);
329 Objects.requireNonNull(databaseName);
330 Objects.requireNonNull(callback);
Cassie Wangb0d60122021-03-30 12:38:46 -0700331 int callingUid = Binder.getCallingUid();
Terry Wangf2093072020-11-30 04:47:19 -0800332 int callingUserId = handleIncomingUser(userId, callingUid);
Terry Wange04ceab2021-03-29 19:25:12 -0700333 EXECUTOR.execute(() -> {
334 try {
335 verifyUserUnlocked(callingUserId);
336 verifyCallingPackage(callingUid, packageName);
337 AppSearchImpl impl =
338 mImplInstanceManager.getAppSearchImpl(callingUserId);
339 GetSchemaResponse response = impl.getSchema(packageName, databaseName);
340 invokeCallbackOnResult(
341 callback,
342 AppSearchResult.newSuccessfulResult(response.getBundle()));
343 } catch (Throwable t) {
344 invokeCallbackOnError(callback, t);
345 }
346 });
Alexander Dorokhine9795b512021-03-23 22:06:59 -0700347 }
348
349 @Override
350 public void getNamespaces(
351 @NonNull String packageName,
352 @NonNull String databaseName,
353 @UserIdInt int userId,
354 @NonNull IAppSearchResultCallback callback) {
Alexander Dorokhine5258ad22021-04-15 10:59:55 -0700355 Objects.requireNonNull(packageName);
356 Objects.requireNonNull(databaseName);
357 Objects.requireNonNull(callback);
Cassie Wangb0d60122021-03-30 12:38:46 -0700358 int callingUid = Binder.getCallingUid();
Alexander Dorokhine9795b512021-03-23 22:06:59 -0700359 int callingUserId = handleIncomingUser(userId, callingUid);
Terry Wange04ceab2021-03-29 19:25:12 -0700360 EXECUTOR.execute(() -> {
361 try {
362 verifyUserUnlocked(callingUserId);
363 verifyCallingPackage(callingUid, packageName);
364 AppSearchImpl impl =
365 mImplInstanceManager.getAppSearchImpl(callingUserId);
366 List<String> namespaces = impl.getNamespaces(packageName, databaseName);
367 invokeCallbackOnResult(callback,
368 AppSearchResult.newSuccessfulResult(namespaces));
369 } catch (Throwable t) {
370 invokeCallbackOnError(callback, t);
371 }
372 });
Terry Wang83a24932020-12-09 21:00:18 -0800373 }
374
375 @Override
Alexander Dorokhine18465842020-01-21 01:08:57 -0800376 public void putDocuments(
Cassie Wang0c62d992021-01-15 14:39:30 -0800377 @NonNull String packageName,
Terry Wang6413aee2020-10-07 03:04:58 -0700378 @NonNull String databaseName,
Alexander Dorokhinec66d67c2020-10-08 13:44:04 -0700379 @NonNull List<Bundle> documentBundles,
Terry Wangf2093072020-11-30 04:47:19 -0800380 @UserIdInt int userId,
Xiaoyu Jinf8cc2012021-03-12 11:00:54 -0800381 @ElapsedRealtimeLong long binderCallStartTimeMillis,
Terry Wangdbd1dca2020-11-03 17:03:56 -0800382 @NonNull IAppSearchBatchResultCallback callback) {
Alexander Dorokhine5258ad22021-04-15 10:59:55 -0700383 Objects.requireNonNull(packageName);
384 Objects.requireNonNull(databaseName);
385 Objects.requireNonNull(documentBundles);
386 Objects.requireNonNull(callback);
Terry Wangf2093072020-11-30 04:47:19 -0800387 int callingUid = Binder.getCallingUid();
388 int callingUserId = handleIncomingUser(userId, callingUid);
Terry Wange04ceab2021-03-29 19:25:12 -0700389 EXECUTOR.execute(() -> {
Xiaoyu Jinf8cc2012021-03-12 11:00:54 -0800390 long totalLatencyStartTimeMillis = SystemClock.elapsedRealtime();
391 @AppSearchResult.ResultCode int statusCode = AppSearchResult.RESULT_OK;
392 PlatformLogger logger = null;
393 int operationSuccessCount = 0;
394 int operationFailureCount = 0;
Terry Wange04ceab2021-03-29 19:25:12 -0700395 try {
396 verifyUserUnlocked(callingUserId);
397 verifyCallingPackage(callingUid, packageName);
398 AppSearchBatchResult.Builder<String, Void> resultBuilder =
399 new AppSearchBatchResult.Builder<>();
400 AppSearchImpl impl =
401 mImplInstanceManager.getAppSearchImpl(callingUserId);
Xiaoyu Jinf8cc2012021-03-12 11:00:54 -0800402 logger = mLoggerInstanceManager.getPlatformLogger(callingUserId);
Terry Wange04ceab2021-03-29 19:25:12 -0700403 for (int i = 0; i < documentBundles.size(); i++) {
404 GenericDocument document = new GenericDocument(documentBundles.get(i));
405 try {
Xiaoyu Jinf8cc2012021-03-12 11:00:54 -0800406 impl.putDocument(packageName, databaseName, document, logger);
Alexander Dorokhine17f79372021-04-21 11:23:09 -0700407 resultBuilder.setSuccess(document.getId(), /*result=*/ null);
Xiaoyu Jinf8cc2012021-03-12 11:00:54 -0800408 ++operationSuccessCount;
Terry Wange04ceab2021-03-29 19:25:12 -0700409 } catch (Throwable t) {
Alexander Dorokhine17f79372021-04-21 11:23:09 -0700410 resultBuilder.setResult(document.getId(),
Terry Wange04ceab2021-03-29 19:25:12 -0700411 throwableToFailedResult(t));
Xiaoyu Jinf8cc2012021-03-12 11:00:54 -0800412 AppSearchResult<Void> result = throwableToFailedResult(t);
Alexander Dorokhine17f79372021-04-21 11:23:09 -0700413 resultBuilder.setResult(document.getId(), result);
Xiaoyu Jinf8cc2012021-03-12 11:00:54 -0800414 // for failures, we would just log the one for last failure
415 statusCode = result.getResultCode();
416 ++operationFailureCount;
Terry Wange04ceab2021-03-29 19:25:12 -0700417 }
Alexander Dorokhine18465842020-01-21 01:08:57 -0800418 }
Alexander Dorokhinec77f4442021-04-14 09:26:06 -0700419 // Now that the batch has been written. Persist the newly written data.
420 impl.persistToDisk(PersistType.Code.LITE);
Terry Wange04ceab2021-03-29 19:25:12 -0700421 invokeCallbackOnResult(callback, resultBuilder.build());
422 } catch (Throwable t) {
423 invokeCallbackOnError(callback, t);
Xiaoyu Jinf8cc2012021-03-12 11:00:54 -0800424 } finally {
425 if (logger != null) {
426 CallStats.Builder cBuilder = new CallStats.Builder(packageName,
427 databaseName)
428 .setCallType(CallStats.CALL_TYPE_PUT_DOCUMENTS)
429 // TODO(b/173532925) check the existing binder call latency chart
430 // is good enough for us:
431 // http://dashboards/view/_72c98f9a_91d9_41d4_ab9a_bc14f79742b4
432 .setEstimatedBinderLatencyMillis(
433 2 * (int) (totalLatencyStartTimeMillis
434 - binderCallStartTimeMillis))
435 .setNumOperationsSucceeded(operationSuccessCount)
436 .setNumOperationsFailed(operationFailureCount);
437 cBuilder.getGeneralStatsBuilder()
438 .setStatusCode(statusCode)
439 .setTotalLatencyMillis(
440 (int) (SystemClock.elapsedRealtime()
441 - totalLatencyStartTimeMillis));
442 logger.logStats(cBuilder.build());
443 }
Alexander Dorokhine18465842020-01-21 01:08:57 -0800444 }
Terry Wange04ceab2021-03-29 19:25:12 -0700445 });
Alexander Dorokhinefd07eba2020-01-13 20:22:20 -0800446 }
Alexander Dorokhine969f4462020-03-05 15:54:19 -0800447
Alexander Dorokhine69a8d9f2020-03-06 10:43:16 -0800448 @Override
Terry Wangf2093072020-11-30 04:47:19 -0800449 public void getDocuments(
Cassie Wang0c62d992021-01-15 14:39:30 -0800450 @NonNull String packageName,
Terry Wangf2093072020-11-30 04:47:19 -0800451 @NonNull String databaseName,
452 @NonNull String namespace,
Alexander Dorokhine17f79372021-04-21 11:23:09 -0700453 @NonNull List<String> ids,
Alexander Dorokhine87cdd152021-01-20 15:41:25 -0800454 @NonNull Map<String, List<String>> typePropertyPaths,
Terry Wangf2093072020-11-30 04:47:19 -0800455 @UserIdInt int userId,
Terry Wangdbd1dca2020-11-03 17:03:56 -0800456 @NonNull IAppSearchBatchResultCallback callback) {
Alexander Dorokhine5258ad22021-04-15 10:59:55 -0700457 Objects.requireNonNull(packageName);
458 Objects.requireNonNull(databaseName);
459 Objects.requireNonNull(namespace);
Alexander Dorokhine17f79372021-04-21 11:23:09 -0700460 Objects.requireNonNull(ids);
Alexander Dorokhine5258ad22021-04-15 10:59:55 -0700461 Objects.requireNonNull(callback);
Terry Wangf2093072020-11-30 04:47:19 -0800462 int callingUid = Binder.getCallingUid();
463 int callingUserId = handleIncomingUser(userId, callingUid);
Terry Wange04ceab2021-03-29 19:25:12 -0700464 EXECUTOR.execute(() -> {
465 try {
466 verifyUserUnlocked(callingUserId);
467 verifyCallingPackage(callingUid, packageName);
468 AppSearchBatchResult.Builder<String, Bundle> resultBuilder =
469 new AppSearchBatchResult.Builder<>();
470 AppSearchImpl impl =
471 mImplInstanceManager.getAppSearchImpl(callingUserId);
Alexander Dorokhine17f79372021-04-21 11:23:09 -0700472 for (int i = 0; i < ids.size(); i++) {
473 String id = ids.get(i);
Terry Wange04ceab2021-03-29 19:25:12 -0700474 try {
475 GenericDocument document =
476 impl.getDocument(
477 packageName,
478 databaseName,
479 namespace,
Alexander Dorokhine17f79372021-04-21 11:23:09 -0700480 id,
Terry Wange04ceab2021-03-29 19:25:12 -0700481 typePropertyPaths);
Alexander Dorokhine17f79372021-04-21 11:23:09 -0700482 resultBuilder.setSuccess(id, document.getBundle());
Terry Wange04ceab2021-03-29 19:25:12 -0700483 } catch (Throwable t) {
Alexander Dorokhine17f79372021-04-21 11:23:09 -0700484 resultBuilder.setResult(id, throwableToFailedResult(t));
Terry Wange04ceab2021-03-29 19:25:12 -0700485 }
Alexander Dorokhinea95f44f2020-03-06 13:53:14 -0800486 }
Terry Wange04ceab2021-03-29 19:25:12 -0700487 invokeCallbackOnResult(callback, resultBuilder.build());
488 } catch (Throwable t) {
489 invokeCallbackOnError(callback, t);
Alexander Dorokhine69a8d9f2020-03-06 10:43:16 -0800490 }
Terry Wange04ceab2021-03-29 19:25:12 -0700491 });
Alexander Dorokhine69a8d9f2020-03-06 10:43:16 -0800492 }
493
sidchhabraa7c8f8a2020-01-16 18:38:17 -0800494 @Override
Alexander Dorokhinee708e182020-03-06 15:30:34 -0800495 public void query(
Cassie Wang0c62d992021-01-15 14:39:30 -0800496 @NonNull String packageName,
Terry Wang6413aee2020-10-07 03:04:58 -0700497 @NonNull String databaseName,
Alexander Dorokhinec9fc9602020-10-06 01:39:50 -0700498 @NonNull String queryExpression,
499 @NonNull Bundle searchSpecBundle,
Terry Wangf2093072020-11-30 04:47:19 -0800500 @UserIdInt int userId,
Alexander Dorokhined48f2362020-10-20 17:40:49 -0700501 @NonNull IAppSearchResultCallback callback) {
Alexander Dorokhine5258ad22021-04-15 10:59:55 -0700502 Objects.requireNonNull(packageName);
503 Objects.requireNonNull(databaseName);
504 Objects.requireNonNull(queryExpression);
505 Objects.requireNonNull(searchSpecBundle);
506 Objects.requireNonNull(callback);
Terry Wangf2093072020-11-30 04:47:19 -0800507 int callingUid = Binder.getCallingUid();
508 int callingUserId = handleIncomingUser(userId, callingUid);
Terry Wange04ceab2021-03-29 19:25:12 -0700509 EXECUTOR.execute(() -> {
510 try {
511 verifyUserUnlocked(callingUserId);
512 verifyCallingPackage(callingUid, packageName);
513 AppSearchImpl impl =
514 mImplInstanceManager.getAppSearchImpl(callingUserId);
515 SearchResultPage searchResultPage =
516 impl.query(
517 packageName,
518 databaseName,
519 queryExpression,
Alexander Dorokhine7cbc4712021-04-27 14:47:39 -0700520 new SearchSpec(searchSpecBundle),
521 /*logger=*/ null);
Terry Wange04ceab2021-03-29 19:25:12 -0700522 invokeCallbackOnResult(
523 callback,
524 AppSearchResult.newSuccessfulResult(searchResultPage.getBundle()));
525 } catch (Throwable t) {
526 invokeCallbackOnError(callback, t);
527 }
528 });
Alexander Dorokhined48f2362020-10-20 17:40:49 -0700529 }
530
Terry Wangf2093072020-11-30 04:47:19 -0800531 @Override
Terry Wangbfbfcac2020-11-06 15:46:44 -0800532 public void globalQuery(
Cassie Wang0c62d992021-01-15 14:39:30 -0800533 @NonNull String packageName,
Terry Wangbfbfcac2020-11-06 15:46:44 -0800534 @NonNull String queryExpression,
535 @NonNull Bundle searchSpecBundle,
Terry Wangf2093072020-11-30 04:47:19 -0800536 @UserIdInt int userId,
Terry Wangbfbfcac2020-11-06 15:46:44 -0800537 @NonNull IAppSearchResultCallback callback) {
Alexander Dorokhine5258ad22021-04-15 10:59:55 -0700538 Objects.requireNonNull(packageName);
539 Objects.requireNonNull(queryExpression);
540 Objects.requireNonNull(searchSpecBundle);
541 Objects.requireNonNull(callback);
Terry Wangf2093072020-11-30 04:47:19 -0800542 int callingUid = Binder.getCallingUid();
543 int callingUserId = handleIncomingUser(userId, callingUid);
Terry Wange04ceab2021-03-29 19:25:12 -0700544 EXECUTOR.execute(() -> {
545 try {
546 verifyUserUnlocked(callingUserId);
547 verifyCallingPackage(callingUid, packageName);
548 AppSearchImpl impl =
549 mImplInstanceManager.getAppSearchImpl(callingUserId);
550 SearchResultPage searchResultPage =
551 impl.globalQuery(
552 queryExpression,
553 new SearchSpec(searchSpecBundle),
554 packageName,
Alexander Dorokhine7cbc4712021-04-27 14:47:39 -0700555 callingUid,
556 /*logger=*/ null);
Terry Wange04ceab2021-03-29 19:25:12 -0700557 invokeCallbackOnResult(
558 callback,
559 AppSearchResult.newSuccessfulResult(searchResultPage.getBundle()));
560 } catch (Throwable t) {
561 invokeCallbackOnError(callback, t);
562 }
563 });
Terry Wangbfbfcac2020-11-06 15:46:44 -0800564 }
565
Alexander Dorokhined48f2362020-10-20 17:40:49 -0700566 @Override
Cassie Wang0c62d992021-01-15 14:39:30 -0800567 public void getNextPage(
568 long nextPageToken,
569 @UserIdInt int userId,
Alexander Dorokhined48f2362020-10-20 17:40:49 -0700570 @NonNull IAppSearchResultCallback callback) {
Alexander Dorokhine5258ad22021-04-15 10:59:55 -0700571 Objects.requireNonNull(callback);
Terry Wangf2093072020-11-30 04:47:19 -0800572 int callingUid = Binder.getCallingUid();
573 int callingUserId = handleIncomingUser(userId, callingUid);
Alexander Dorokhined48f2362020-10-20 17:40:49 -0700574 // TODO(b/162450968) check nextPageToken is being advanced by the same uid as originally
575 // opened it
Terry Wange04ceab2021-03-29 19:25:12 -0700576 EXECUTOR.execute(() -> {
577 try {
578 verifyUserUnlocked(callingUserId);
579 AppSearchImpl impl =
580 mImplInstanceManager.getAppSearchImpl(callingUserId);
581 SearchResultPage searchResultPage = impl.getNextPage(nextPageToken);
582 invokeCallbackOnResult(
583 callback,
584 AppSearchResult.newSuccessfulResult(searchResultPage.getBundle()));
585 } catch (Throwable t) {
586 invokeCallbackOnError(callback, t);
587 }
588 });
Alexander Dorokhined48f2362020-10-20 17:40:49 -0700589 }
590
591 @Override
Terry Wangf2093072020-11-30 04:47:19 -0800592 public void invalidateNextPageToken(long nextPageToken, @UserIdInt int userId) {
593 int callingUid = Binder.getCallingUid();
594 int callingUserId = handleIncomingUser(userId, callingUid);
Terry Wange04ceab2021-03-29 19:25:12 -0700595 EXECUTOR.execute(() -> {
596 try {
597 verifyUserUnlocked(callingUserId);
598 AppSearchImpl impl =
599 mImplInstanceManager.getAppSearchImpl(callingUserId);
600 impl.invalidateNextPageToken(nextPageToken);
601 } catch (Throwable t) {
602 Log.e(TAG, "Unable to invalidate the query page token", t);
603 }
604 });
sidchhabraa7c8f8a2020-01-16 18:38:17 -0800605 }
Alexander Dorokhine969f4462020-03-05 15:54:19 -0800606
Alexander Dorokhinef6c66ae2020-03-09 14:47:25 -0700607 @Override
Terry Wang623e3b02021-02-02 20:27:33 -0800608 public void writeQueryResultsToFile(
609 @NonNull String packageName,
610 @NonNull String databaseName,
611 @NonNull ParcelFileDescriptor fileDescriptor,
612 @NonNull String queryExpression,
613 @NonNull Bundle searchSpecBundle,
614 @UserIdInt int userId,
615 @NonNull IAppSearchResultCallback callback) {
616 int callingUid = Binder.getCallingUid();
617 int callingUserId = handleIncomingUser(userId, callingUid);
Terry Wange04ceab2021-03-29 19:25:12 -0700618 EXECUTOR.execute(() -> {
619 try {
620 verifyCallingPackage(callingUid, packageName);
621 AppSearchImpl impl =
622 mImplInstanceManager.getAppSearchImpl(callingUserId);
623 // we don't need to append the file. The file is always brand new.
624 try (DataOutputStream outputStream = new DataOutputStream(
625 new FileOutputStream(fileDescriptor.getFileDescriptor()))) {
626 SearchResultPage searchResultPage = impl.query(
627 packageName,
628 databaseName,
629 queryExpression,
Alexander Dorokhine7cbc4712021-04-27 14:47:39 -0700630 new SearchSpec(searchSpecBundle),
631 /*logger=*/ null);
Terry Wange04ceab2021-03-29 19:25:12 -0700632 while (!searchResultPage.getResults().isEmpty()) {
633 for (int i = 0; i < searchResultPage.getResults().size(); i++) {
634 AppSearchMigrationHelper.writeBundleToOutputStream(
635 outputStream, searchResultPage.getResults().get(i)
636 .getGenericDocument().getBundle());
637 }
638 searchResultPage = impl.getNextPage(
639 searchResultPage.getNextPageToken());
Terry Wang623e3b02021-02-02 20:27:33 -0800640 }
Terry Wang623e3b02021-02-02 20:27:33 -0800641 }
Terry Wange04ceab2021-03-29 19:25:12 -0700642 invokeCallbackOnResult(callback, AppSearchResult.newSuccessfulResult(null));
643 } catch (Throwable t) {
644 invokeCallbackOnError(callback, t);
Terry Wang623e3b02021-02-02 20:27:33 -0800645 }
Terry Wange04ceab2021-03-29 19:25:12 -0700646 });
Terry Wang623e3b02021-02-02 20:27:33 -0800647 }
648
649 @Override
650 public void putDocumentsFromFile(
651 @NonNull String packageName,
652 @NonNull String databaseName,
653 @NonNull ParcelFileDescriptor fileDescriptor,
654 @UserIdInt int userId,
655 @NonNull IAppSearchResultCallback callback) {
656 int callingUid = Binder.getCallingUid();
657 int callingUserId = handleIncomingUser(userId, callingUid);
Terry Wange04ceab2021-03-29 19:25:12 -0700658 EXECUTOR.execute(() -> {
659 try {
660 verifyCallingPackage(callingUid, packageName);
661 AppSearchImpl impl =
662 mImplInstanceManager.getAppSearchImpl(callingUserId);
Terry Wang623e3b02021-02-02 20:27:33 -0800663
Terry Wange04ceab2021-03-29 19:25:12 -0700664 GenericDocument document;
665 ArrayList<Bundle> migrationFailureBundles = new ArrayList<>();
666 try (DataInputStream inputStream = new DataInputStream(
667 new FileInputStream(fileDescriptor.getFileDescriptor()))) {
668 while (true) {
669 try {
670 document = AppSearchMigrationHelper
671 .readDocumentFromInputStream(inputStream);
672 } catch (EOFException e) {
673 // nothing wrong, we just finish the reading.
674 break;
675 }
676 try {
677 impl.putDocument(packageName, databaseName, document,
678 /*logger=*/ null);
679 } catch (Throwable t) {
Alexander Dorokhine17f79372021-04-21 11:23:09 -0700680 migrationFailureBundles.add(new SetSchemaResponse.MigrationFailure(
681 document.getNamespace(),
682 document.getId(),
683 document.getSchemaType(),
684 AppSearchResult.throwableToFailedResult(t))
685 .getBundle());
Terry Wange04ceab2021-03-29 19:25:12 -0700686 }
Terry Wang623e3b02021-02-02 20:27:33 -0800687 }
688 }
Alexander Dorokhinec77f4442021-04-14 09:26:06 -0700689 impl.persistToDisk(PersistType.Code.FULL);
Terry Wange04ceab2021-03-29 19:25:12 -0700690 invokeCallbackOnResult(callback,
691 AppSearchResult.newSuccessfulResult(migrationFailureBundles));
692 } catch (Throwable t) {
693 invokeCallbackOnError(callback, t);
Terry Wang623e3b02021-02-02 20:27:33 -0800694 }
Terry Wange04ceab2021-03-29 19:25:12 -0700695 });
Terry Wang623e3b02021-02-02 20:27:33 -0800696 }
697
698 @Override
Alexander Dorokhined18f8842021-01-20 15:26:13 -0800699 public void reportUsage(
700 @NonNull String packageName,
701 @NonNull String databaseName,
702 @NonNull String namespace,
Alexander Dorokhine17f79372021-04-21 11:23:09 -0700703 @NonNull String documentId,
Alexander Dorokhined18f8842021-01-20 15:26:13 -0800704 long usageTimeMillis,
Alexander Dorokhine9795b512021-03-23 22:06:59 -0700705 boolean systemUsage,
Alexander Dorokhined18f8842021-01-20 15:26:13 -0800706 @UserIdInt int userId,
707 @NonNull IAppSearchResultCallback callback) {
708 Objects.requireNonNull(databaseName);
709 Objects.requireNonNull(namespace);
Alexander Dorokhine17f79372021-04-21 11:23:09 -0700710 Objects.requireNonNull(documentId);
Alexander Dorokhined18f8842021-01-20 15:26:13 -0800711 Objects.requireNonNull(callback);
712 int callingUid = Binder.getCallingUid();
713 int callingUserId = handleIncomingUser(userId, callingUid);
Terry Wange04ceab2021-03-29 19:25:12 -0700714 EXECUTOR.execute(() -> {
715 try {
716 verifyUserUnlocked(callingUserId);
Alexander Dorokhine9795b512021-03-23 22:06:59 -0700717
Terry Wange04ceab2021-03-29 19:25:12 -0700718 if (systemUsage) {
719 // TODO(b/183031844): Validate that the call comes from the system
720 }
721
722 AppSearchImpl impl =
723 mImplInstanceManager.getAppSearchImpl(callingUserId);
724 impl.reportUsage(
Alexander Dorokhine17f79372021-04-21 11:23:09 -0700725 packageName, databaseName, namespace, documentId,
Terry Wange04ceab2021-03-29 19:25:12 -0700726 usageTimeMillis, systemUsage);
727 invokeCallbackOnResult(
728 callback, AppSearchResult.newSuccessfulResult(/*result=*/ null));
729 } catch (Throwable t) {
730 invokeCallbackOnError(callback, t);
Alexander Dorokhine9795b512021-03-23 22:06:59 -0700731 }
Terry Wange04ceab2021-03-29 19:25:12 -0700732 });
Alexander Dorokhined18f8842021-01-20 15:26:13 -0800733 }
734
735 @Override
Alexander Dorokhine17f79372021-04-21 11:23:09 -0700736 public void removeByDocumentId(
Cassie Wang0c62d992021-01-15 14:39:30 -0800737 @NonNull String packageName,
Terry Wangf2093072020-11-30 04:47:19 -0800738 @NonNull String databaseName,
739 @NonNull String namespace,
Alexander Dorokhine17f79372021-04-21 11:23:09 -0700740 @NonNull List<String> ids,
Terry Wangf2093072020-11-30 04:47:19 -0800741 @UserIdInt int userId,
Terry Wangdbd1dca2020-11-03 17:03:56 -0800742 @NonNull IAppSearchBatchResultCallback callback) {
Alexander Dorokhine5258ad22021-04-15 10:59:55 -0700743 Objects.requireNonNull(packageName);
744 Objects.requireNonNull(databaseName);
Alexander Dorokhine17f79372021-04-21 11:23:09 -0700745 Objects.requireNonNull(ids);
Alexander Dorokhine5258ad22021-04-15 10:59:55 -0700746 Objects.requireNonNull(callback);
Terry Wangf2093072020-11-30 04:47:19 -0800747 int callingUid = Binder.getCallingUid();
748 int callingUserId = handleIncomingUser(userId, callingUid);
Terry Wange04ceab2021-03-29 19:25:12 -0700749 EXECUTOR.execute(() -> {
750 try {
751 verifyUserUnlocked(callingUserId);
752 verifyCallingPackage(callingUid, packageName);
753 AppSearchBatchResult.Builder<String, Void> resultBuilder =
754 new AppSearchBatchResult.Builder<>();
755 AppSearchImpl impl =
756 mImplInstanceManager.getAppSearchImpl(callingUserId);
Alexander Dorokhine17f79372021-04-21 11:23:09 -0700757 for (int i = 0; i < ids.size(); i++) {
758 String id = ids.get(i);
Terry Wange04ceab2021-03-29 19:25:12 -0700759 try {
Alexander Dorokhine17f79372021-04-21 11:23:09 -0700760 impl.remove(packageName, databaseName, namespace, id);
761 resultBuilder.setSuccess(id, /*result= */ null);
Terry Wange04ceab2021-03-29 19:25:12 -0700762 } catch (Throwable t) {
Alexander Dorokhine17f79372021-04-21 11:23:09 -0700763 resultBuilder.setResult(id, throwableToFailedResult(t));
Terry Wange04ceab2021-03-29 19:25:12 -0700764 }
Alexander Dorokhineff82fba2020-03-09 16:35:24 -0700765 }
Alexander Dorokhinec77f4442021-04-14 09:26:06 -0700766 // Now that the batch has been written. Persist the newly written data.
767 impl.persistToDisk(PersistType.Code.LITE);
Terry Wange04ceab2021-03-29 19:25:12 -0700768 invokeCallbackOnResult(callback, resultBuilder.build());
769 } catch (Throwable t) {
770 invokeCallbackOnError(callback, t);
Alexander Dorokhineff82fba2020-03-09 16:35:24 -0700771 }
Terry Wange04ceab2021-03-29 19:25:12 -0700772 });
Alexander Dorokhineff82fba2020-03-09 16:35:24 -0700773 }
774
775 @Override
Terry Wang26b9e5c2020-10-23 02:05:01 -0700776 public void removeByQuery(
Cassie Wang0c62d992021-01-15 14:39:30 -0800777 @NonNull String packageName,
Terry Wang26b9e5c2020-10-23 02:05:01 -0700778 @NonNull String databaseName,
779 @NonNull String queryExpression,
780 @NonNull Bundle searchSpecBundle,
Terry Wangf2093072020-11-30 04:47:19 -0800781 @UserIdInt int userId,
Alexander Dorokhine178366b2020-10-20 17:40:49 -0700782 @NonNull IAppSearchResultCallback callback) {
Alexander Dorokhine5258ad22021-04-15 10:59:55 -0700783 Objects.requireNonNull(packageName);
784 Objects.requireNonNull(databaseName);
785 Objects.requireNonNull(queryExpression);
786 Objects.requireNonNull(searchSpecBundle);
787 Objects.requireNonNull(callback);
Terry Wangf2093072020-11-30 04:47:19 -0800788 int callingUid = Binder.getCallingUid();
789 int callingUserId = handleIncomingUser(userId, callingUid);
Terry Wange04ceab2021-03-29 19:25:12 -0700790 EXECUTOR.execute(() -> {
791 try {
792 verifyUserUnlocked(callingUserId);
793 verifyCallingPackage(callingUid, packageName);
794 AppSearchImpl impl =
795 mImplInstanceManager.getAppSearchImpl(callingUserId);
796 impl.removeByQuery(
797 packageName,
798 databaseName,
799 queryExpression,
800 new SearchSpec(searchSpecBundle));
Alexander Dorokhinec77f4442021-04-14 09:26:06 -0700801 // Now that the batch has been written. Persist the newly written data.
802 impl.persistToDisk(PersistType.Code.LITE);
Terry Wange04ceab2021-03-29 19:25:12 -0700803 invokeCallbackOnResult(callback, AppSearchResult.newSuccessfulResult(null));
804 } catch (Throwable t) {
805 invokeCallbackOnError(callback, t);
806 }
807 });
Alexander Dorokhinef6c66ae2020-03-09 14:47:25 -0700808 }
809
Terry Wangdbd1dca2020-11-03 17:03:56 -0800810 @Override
Cassie Wang8f0df492021-03-24 09:23:18 -0700811 public void getStorageInfo(
812 @NonNull String packageName,
813 @NonNull String databaseName,
814 @UserIdInt int userId,
815 @NonNull IAppSearchResultCallback callback) {
Alexander Dorokhine5258ad22021-04-15 10:59:55 -0700816 Objects.requireNonNull(packageName);
817 Objects.requireNonNull(databaseName);
818 Objects.requireNonNull(callback);
Cassie Wang8f0df492021-03-24 09:23:18 -0700819 int callingUid = Binder.getCallingUid();
820 int callingUserId = handleIncomingUser(userId, callingUid);
Terry Wange04ceab2021-03-29 19:25:12 -0700821 EXECUTOR.execute(() -> {
822 try {
823 verifyUserUnlocked(callingUserId);
824 verifyCallingPackage(callingUid, packageName);
825 AppSearchImpl impl =
826 mImplInstanceManager.getAppSearchImpl(callingUserId);
827 StorageInfo storageInfo = impl.getStorageInfoForDatabase(packageName,
828 databaseName);
829 Bundle storageInfoBundle = storageInfo.getBundle();
830 invokeCallbackOnResult(
831 callback, AppSearchResult.newSuccessfulResult(storageInfoBundle));
832 } catch (Throwable t) {
833 invokeCallbackOnError(callback, t);
834 }
835 });
Cassie Wang8f0df492021-03-24 09:23:18 -0700836 }
837
838 @Override
Terry Wang2da17852020-12-16 19:59:08 -0800839 public void persistToDisk(@UserIdInt int userId) {
Cassie Wangb0d60122021-03-30 12:38:46 -0700840 int callingUid = Binder.getCallingUid();
Terry Wang2da17852020-12-16 19:59:08 -0800841 int callingUserId = handleIncomingUser(userId, callingUid);
Terry Wange04ceab2021-03-29 19:25:12 -0700842 EXECUTOR.execute(() -> {
843 try {
844 verifyUserUnlocked(callingUserId);
845 AppSearchImpl impl =
846 mImplInstanceManager.getAppSearchImpl(callingUserId);
Alexander Dorokhinec77f4442021-04-14 09:26:06 -0700847 impl.persistToDisk(PersistType.Code.FULL);
Terry Wange04ceab2021-03-29 19:25:12 -0700848 } catch (Throwable t) {
849 Log.e(TAG, "Unable to persist the data to disk", t);
850 }
851 });
Terry Wang2da17852020-12-16 19:59:08 -0800852 }
853
854 @Override
Terry Wangf2093072020-11-30 04:47:19 -0800855 public void initialize(@UserIdInt int userId, @NonNull IAppSearchResultCallback callback) {
Alexander Dorokhine5258ad22021-04-15 10:59:55 -0700856 Objects.requireNonNull(callback);
Terry Wangf2093072020-11-30 04:47:19 -0800857 int callingUid = Binder.getCallingUid();
858 int callingUserId = handleIncomingUser(userId, callingUid);
Terry Wange04ceab2021-03-29 19:25:12 -0700859 EXECUTOR.execute(() -> {
860 try {
861 verifyUserUnlocked(callingUserId);
862 mImplInstanceManager.getOrCreateAppSearchImpl(mContext, callingUserId);
Xiaoyu Jinf8cc2012021-03-12 11:00:54 -0800863 mLoggerInstanceManager.getOrCreatePlatformLogger(getContext(), callingUserId);
Terry Wange04ceab2021-03-29 19:25:12 -0700864 invokeCallbackOnResult(callback, AppSearchResult.newSuccessfulResult(null));
865 } catch (Throwable t) {
866 invokeCallbackOnError(callback, t);
867 }
868 });
Terry Wangdbd1dca2020-11-03 17:03:56 -0800869 }
870
Cassie Wang0c62d992021-01-15 14:39:30 -0800871 private void verifyCallingPackage(int callingUid, @NonNull String callingPackage) {
Alexander Dorokhine5258ad22021-04-15 10:59:55 -0700872 Objects.requireNonNull(callingPackage);
Cassie Wang0c62d992021-01-15 14:39:30 -0800873 if (mPackageManagerInternal.getPackageUid(
Yang Yu0fcd51a2021-04-23 11:25:44 -0700874 callingPackage, /*flags=*/ 0, UserHandle.getUserId(callingUid))
Cassie Wang0c62d992021-01-15 14:39:30 -0800875 != callingUid) {
876 throw new SecurityException(
877 "Specified calling package ["
878 + callingPackage
879 + "] does not match the calling uid "
880 + callingUid);
Alexander Dorokhineebd37742020-09-22 15:02:26 -0700881 }
Alexander Dorokhineebd37742020-09-22 15:02:26 -0700882 }
883
Alexander Dorokhine8c5ba912020-12-14 22:58:12 -0800884 /** Invokes the {@link IAppSearchResultCallback} with the result. */
Cassie Wang0c62d992021-01-15 14:39:30 -0800885 private void invokeCallbackOnResult(
886 IAppSearchResultCallback callback, AppSearchResult<?> result) {
Terry Wangdbd1dca2020-11-03 17:03:56 -0800887 try {
Alexander Dorokhined5e8eda2021-05-04 13:24:47 -0700888 callback.onResult(new AppSearchResultParcel<>(result));
Terry Wangdbd1dca2020-11-03 17:03:56 -0800889 } catch (RemoteException e) {
Terry Wang2da17852020-12-16 19:59:08 -0800890 Log.e(TAG, "Unable to send result to the callback", e);
Alexander Dorokhine969f4462020-03-05 15:54:19 -0800891 }
Terry Wangdbd1dca2020-11-03 17:03:56 -0800892 }
Alexander Dorokhine969f4462020-03-05 15:54:19 -0800893
Alexander Dorokhine8c5ba912020-12-14 22:58:12 -0800894 /** Invokes the {@link IAppSearchBatchResultCallback} with the result. */
Cassie Wang0c62d992021-01-15 14:39:30 -0800895 private void invokeCallbackOnResult(
Alexander Dorokhined5e8eda2021-05-04 13:24:47 -0700896 IAppSearchBatchResultCallback callback, AppSearchBatchResult<String, ?> result) {
Terry Wangdbd1dca2020-11-03 17:03:56 -0800897 try {
Alexander Dorokhined5e8eda2021-05-04 13:24:47 -0700898 callback.onResult(new AppSearchBatchResultParcel<>(result));
Terry Wangdbd1dca2020-11-03 17:03:56 -0800899 } catch (RemoteException e) {
Terry Wang2da17852020-12-16 19:59:08 -0800900 Log.e(TAG, "Unable to send result to the callback", e);
Alexander Dorokhine969f4462020-03-05 15:54:19 -0800901 }
Terry Wangdbd1dca2020-11-03 17:03:56 -0800902 }
903
904 /**
Alexander Dorokhine8c5ba912020-12-14 22:58:12 -0800905 * Invokes the {@link IAppSearchResultCallback} with an throwable.
Terry Wangdbd1dca2020-11-03 17:03:56 -0800906 *
Alexander Dorokhine8c5ba912020-12-14 22:58:12 -0800907 * <p>The throwable is convert to a {@link AppSearchResult};
Terry Wangdbd1dca2020-11-03 17:03:56 -0800908 */
909 private void invokeCallbackOnError(IAppSearchResultCallback callback, Throwable throwable) {
Alexander Dorokhined5e8eda2021-05-04 13:24:47 -0700910 AppSearchResult<?> result = throwableToFailedResult(throwable);
Terry Wangdbd1dca2020-11-03 17:03:56 -0800911 try {
Alexander Dorokhined5e8eda2021-05-04 13:24:47 -0700912 callback.onResult(new AppSearchResultParcel<>(result));
Terry Wangdbd1dca2020-11-03 17:03:56 -0800913 } catch (RemoteException e) {
Terry Wang2da17852020-12-16 19:59:08 -0800914 Log.e(TAG, "Unable to send result to the callback", e);
Terry Wangdbd1dca2020-11-03 17:03:56 -0800915 }
916 }
917
918 /**
Alexander Dorokhine8c5ba912020-12-14 22:58:12 -0800919 * Invokes the {@link IAppSearchBatchResultCallback} with an unexpected internal throwable.
Terry Wangdbd1dca2020-11-03 17:03:56 -0800920 *
Alexander Dorokhineb5d34b12021-04-15 00:32:15 -0700921 * <p>The throwable is converted to {@link AppSearchResult}.
Terry Wangdbd1dca2020-11-03 17:03:56 -0800922 */
Cassie Wang0c62d992021-01-15 14:39:30 -0800923 private void invokeCallbackOnError(
Alexander Dorokhineb5d34b12021-04-15 00:32:15 -0700924 @NonNull IAppSearchBatchResultCallback callback, @NonNull Throwable throwable) {
Alexander Dorokhined5e8eda2021-05-04 13:24:47 -0700925 AppSearchResult<?> result = throwableToFailedResult(throwable);
Terry Wangdbd1dca2020-11-03 17:03:56 -0800926 try {
Alexander Dorokhined5e8eda2021-05-04 13:24:47 -0700927 callback.onSystemError(new AppSearchResultParcel<>(result));
Terry Wangdbd1dca2020-11-03 17:03:56 -0800928 } catch (RemoteException e) {
Terry Wang2da17852020-12-16 19:59:08 -0800929 Log.e(TAG, "Unable to send error to the callback", e);
Terry Wangdbd1dca2020-11-03 17:03:56 -0800930 }
Alexander Dorokhine969f4462020-03-05 15:54:19 -0800931 }
Terry Wangfebbead2019-10-17 17:05:18 -0700932 }
Terry Wangf2093072020-11-30 04:47:19 -0800933
Cassie Wang0c62d992021-01-15 14:39:30 -0800934 // TODO(b/173553485) verifying that the caller has permission to access target user's data
935 // TODO(b/173553485) Handle ACTION_USER_REMOVED broadcast
936 // TODO(b/173553485) Implement SystemService.onUserStopping()
Terry Wangf2093072020-11-30 04:47:19 -0800937 private static int handleIncomingUser(@UserIdInt int userId, int callingUid) {
938 int callingPid = Binder.getCallingPid();
Cassie Wang0c62d992021-01-15 14:39:30 -0800939 return ActivityManager.handleIncomingUser(
940 callingPid,
941 callingUid,
942 userId,
943 /*allowAll=*/ false,
944 /*requireFull=*/ false,
945 /*name=*/ null,
946 /*callerPackage=*/ null);
Terry Wangf2093072020-11-30 04:47:19 -0800947 }
Yang Yu0fcd51a2021-04-23 11:25:44 -0700948
949 // TODO(b/179160886): Cache the previous storage stats.
950 private class AppSearchStorageStatsAugmenter implements StorageStatsAugmenter {
951 @Override
Alexander Dorokhinea5d0d322021-05-10 15:59:31 -0700952 public void augmentStatsForPackageForUser(
Yang Yu0fcd51a2021-04-23 11:25:44 -0700953 @NonNull PackageStats stats,
954 @NonNull String packageName,
Alexander Dorokhinea5d0d322021-05-10 15:59:31 -0700955 @NonNull UserHandle userHandle,
956 boolean canCallerAccessAllStats) {
Yang Yu0fcd51a2021-04-23 11:25:44 -0700957 Objects.requireNonNull(stats);
958 Objects.requireNonNull(packageName);
Alexander Dorokhinea5d0d322021-05-10 15:59:31 -0700959 Objects.requireNonNull(userHandle);
960 int userId = userHandle.getIdentifier();
Yang Yu0fcd51a2021-04-23 11:25:44 -0700961 try {
962 verifyUserUnlocked(userId);
963 AppSearchImpl impl = mImplInstanceManager.getOrCreateAppSearchImpl(mContext,
964 userId);
965 stats.dataSize += impl.getStorageInfoForPackage(packageName).getSizeBytes();
966 } catch (Throwable t) {
967 Log.e(
968 TAG,
969 "Unable to augment storage stats for userId "
970 + userId
971 + " packageName "
972 + packageName,
973 t);
974 }
975 }
976
977 @Override
978 public void augmentStatsForUid(
Alexander Dorokhinea5d0d322021-05-10 15:59:31 -0700979 @NonNull PackageStats stats, int uid, boolean canCallerAccessAllStats) {
Yang Yu0fcd51a2021-04-23 11:25:44 -0700980 Objects.requireNonNull(stats);
981 int userId = UserHandle.getUserId(uid);
982 try {
983 verifyUserUnlocked(userId);
984 String[] packagesForUid = mPackageManager.getPackagesForUid(uid);
985 if (packagesForUid == null) {
986 return;
987 }
988 AppSearchImpl impl = mImplInstanceManager.getOrCreateAppSearchImpl(mContext,
989 userId);
Alexander Dorokhinea5d0d322021-05-10 15:59:31 -0700990 for (int i = 0; i < packagesForUid.length; i++) {
991 stats.dataSize +=
992 impl.getStorageInfoForPackage(packagesForUid[i]).getSizeBytes();
Yang Yu0fcd51a2021-04-23 11:25:44 -0700993 }
994 } catch (Throwable t) {
995 Log.e(TAG, "Unable to augment storage stats for uid " + uid, t);
996 }
997 }
Alexander Dorokhinea5d0d322021-05-10 15:59:31 -0700998
999 @Override
1000 public void augmentStatsForUser(
1001 @NonNull PackageStats stats, @NonNull UserHandle userHandle) {
1002 // TODO(b/179160886): this implementation could incur many jni calls and a lot of
1003 // in-memory processing from getStorageInfoForPackage. Instead, we can just compute the
1004 // size of the icing dir (or use the overall StorageInfo without interpolating it).
1005 Objects.requireNonNull(stats);
1006 Objects.requireNonNull(userHandle);
1007 int userId = userHandle.getIdentifier();
1008 try {
1009 verifyUserUnlocked(userId);
1010 List<PackageInfo> packagesForUser =
1011 mPackageManager.getInstalledPackagesAsUser(/*flags=*/0, userId);
1012 if (packagesForUser == null) {
1013 return;
1014 }
1015 AppSearchImpl impl =
1016 mImplInstanceManager.getOrCreateAppSearchImpl(mContext, userId);
1017 for (int i = 0; i < packagesForUser.size(); i++) {
1018 String packageName = packagesForUser.get(i).packageName;
1019 stats.dataSize += impl.getStorageInfoForPackage(packageName).getSizeBytes();
1020 }
1021 } catch (Throwable t) {
1022 Log.e(TAG, "Unable to augment storage stats for user " + userId, t);
1023 }
1024 }
Yang Yu0fcd51a2021-04-23 11:25:44 -07001025 }
Terry Wangfebbead2019-10-17 17:05:18 -07001026}