• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 The Android Open Source Project
3  *
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  */
16 package com.android.server.appsearch.appsindexer;
17 
18 import android.annotation.NonNull;
19 import android.annotation.Nullable;
20 import android.annotation.WorkerThread;
21 import android.app.appsearch.AppSearchBatchResult;
22 import android.app.appsearch.AppSearchResult;
23 import android.app.appsearch.BatchResultCallback;
24 import android.app.appsearch.exceptions.AppSearchException;
25 
26 import java.util.Objects;
27 import java.util.concurrent.CompletableFuture;
28 import java.util.concurrent.ExecutionException;
29 import java.util.concurrent.Executor;
30 import java.util.function.Consumer;
31 
32 /** Contains common methods for converting async methods to sync. */
33 public class SyncAppSearchBase {
34     protected final Object mSessionLock = new Object();
35     protected final Executor mExecutor;
36 
SyncAppSearchBase(@onNull Executor executor)37     public SyncAppSearchBase(@NonNull Executor executor) {
38         mExecutor = Objects.requireNonNull(executor);
39     }
40 
41     @WorkerThread
executeAppSearchResultOperation( Consumer<Consumer<AppSearchResult<T>>> operation)42     protected <T> T executeAppSearchResultOperation(
43             Consumer<Consumer<AppSearchResult<T>>> operation) throws AppSearchException {
44         final CompletableFuture<AppSearchResult<T>> futureResult = new CompletableFuture<>();
45 
46         // Without this catch + completeExceptionally, this crashes the device if the operation
47         // throws an error.
48         mExecutor.execute(
49                 () -> {
50                     try {
51                         operation.accept(futureResult::complete);
52                     } catch (Exception e) {
53                         futureResult.completeExceptionally(e);
54                     }
55                 });
56 
57         try {
58             // TODO(b/275592563): Change to get timeout value from config
59             AppSearchResult<T> result = futureResult.get();
60 
61             if (!result.isSuccess()) {
62                 throw new AppSearchException(result.getResultCode(), result.getErrorMessage());
63             }
64 
65             return result.getResultValue();
66         } catch (InterruptedException e) {
67             Thread.currentThread().interrupt();
68             throw new AppSearchException(
69                     AppSearchResult.RESULT_INTERNAL_ERROR, "Operation was interrupted.", e);
70         } catch (ExecutionException e) {
71             throw new AppSearchException(
72                     AppSearchResult.RESULT_UNKNOWN_ERROR,
73                     "Error executing operation.",
74                     e.getCause());
75         }
76     }
77 
78     @WorkerThread
executeAppSearchBatchResultOperation( Consumer<BatchResultCallback<T, V>> operation)79     protected <T, V> AppSearchBatchResult<T, V> executeAppSearchBatchResultOperation(
80             Consumer<BatchResultCallback<T, V>> operation) throws AppSearchException {
81         final CompletableFuture<AppSearchBatchResult<T, V>> futureResult =
82                 new CompletableFuture<>();
83 
84         mExecutor.execute(
85                 () -> {
86                     try {
87                         operation.accept(
88                                 new BatchResultCallback<>() {
89                                     @Override
90                                     public void onResult(
91                                             @NonNull AppSearchBatchResult<T, V> value) {
92                                         futureResult.complete(value);
93                                     }
94 
95                                     @Override
96                                     public void onSystemError(@Nullable Throwable throwable) {
97                                         futureResult.completeExceptionally(throwable);
98                                     }
99                                 });
100                     } catch (Exception e) {
101                         futureResult.completeExceptionally(e);
102                     }
103                 });
104 
105         try {
106             // TODO(b/275592563): Change to get timeout value from config
107             return futureResult.get();
108         } catch (InterruptedException e) {
109             Thread.currentThread().interrupt();
110             throw new AppSearchException(
111                     AppSearchResult.RESULT_INTERNAL_ERROR, "Operation was interrupted.", e);
112         } catch (ExecutionException e) {
113             throw new AppSearchException(
114                     AppSearchResult.RESULT_UNKNOWN_ERROR,
115                     "Error executing operation.",
116                     e.getCause());
117         }
118     }
119 }
120