Update Framework from Jetpack.
Changes included: #efb600e:Add Closeable to AppSearchSession, allow it persist data to disk. Bug: 162450968 Test: presubmit Change-Id: Ib00cf83e41f0e3e2f79b4c46d9a50407e72bd9bb
This commit is contained in:
@@ -23,6 +23,9 @@ import android.os.Bundle;
|
||||
import android.os.ParcelableException;
|
||||
import android.os.RemoteException;
|
||||
import android.util.ArraySet;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.util.Preconditions;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -39,10 +42,13 @@ import java.util.function.Consumer;
|
||||
* This class is thread safe.
|
||||
*/
|
||||
public final class AppSearchSession {
|
||||
private static final String TAG = "AppSearchSession";
|
||||
private final String mDatabaseName;
|
||||
@UserIdInt
|
||||
private final int mUserId;
|
||||
private final IAppSearchManager mService;
|
||||
private boolean mIsMutated = false;
|
||||
private boolean mIsClosed = false;
|
||||
|
||||
static void createSearchSession(
|
||||
@NonNull AppSearchManager.SearchContext searchContext,
|
||||
@@ -150,6 +156,7 @@ public final class AppSearchSession {
|
||||
Objects.requireNonNull(request);
|
||||
Objects.requireNonNull(executor);
|
||||
Objects.requireNonNull(callback);
|
||||
Preconditions.checkState(!mIsClosed, "AppSearchSession has already been closed");
|
||||
List<Bundle> schemaBundles = new ArrayList<>(request.getSchemas().size());
|
||||
for (AppSearchSchema schema : request.getSchemas()) {
|
||||
schemaBundles.add(schema.getBundle());
|
||||
@@ -166,6 +173,7 @@ public final class AppSearchSession {
|
||||
executor.execute(() -> callback.accept(result));
|
||||
}
|
||||
});
|
||||
mIsMutated = true;
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
@@ -182,6 +190,7 @@ public final class AppSearchSession {
|
||||
@NonNull Consumer<AppSearchResult<Set<AppSearchSchema>>> callback) {
|
||||
Objects.requireNonNull(executor);
|
||||
Objects.requireNonNull(callback);
|
||||
Preconditions.checkState(!mIsClosed, "AppSearchSession has already been closed");
|
||||
try {
|
||||
mService.getSchema(
|
||||
mDatabaseName,
|
||||
@@ -232,6 +241,7 @@ public final class AppSearchSession {
|
||||
Objects.requireNonNull(request);
|
||||
Objects.requireNonNull(executor);
|
||||
Objects.requireNonNull(callback);
|
||||
Preconditions.checkState(!mIsClosed, "AppSearchSession has already been closed");
|
||||
List<GenericDocument> documents = request.getDocuments();
|
||||
List<Bundle> documentBundles = new ArrayList<>(documents.size());
|
||||
for (int i = 0; i < documents.size(); i++) {
|
||||
@@ -248,6 +258,7 @@ public final class AppSearchSession {
|
||||
executor.execute(() -> callback.onSystemError(exception.getCause()));
|
||||
}
|
||||
});
|
||||
mIsMutated = true;
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
@@ -275,6 +286,7 @@ public final class AppSearchSession {
|
||||
Objects.requireNonNull(request);
|
||||
Objects.requireNonNull(executor);
|
||||
Objects.requireNonNull(callback);
|
||||
Preconditions.checkState(!mIsClosed, "AppSearchSession has already been closed");
|
||||
try {
|
||||
mService.getDocuments(mDatabaseName, request.getNamespace(),
|
||||
new ArrayList<>(request.getUris()), mUserId,
|
||||
@@ -379,6 +391,7 @@ public final class AppSearchSession {
|
||||
Objects.requireNonNull(queryExpression);
|
||||
Objects.requireNonNull(searchSpec);
|
||||
Objects.requireNonNull(executor);
|
||||
Preconditions.checkState(!mIsClosed, "AppSearchSession has already been closed");
|
||||
return new SearchResults(mService, mDatabaseName, queryExpression, searchSpec, mUserId,
|
||||
executor);
|
||||
}
|
||||
@@ -404,6 +417,7 @@ public final class AppSearchSession {
|
||||
Objects.requireNonNull(request);
|
||||
Objects.requireNonNull(executor);
|
||||
Objects.requireNonNull(callback);
|
||||
Preconditions.checkState(!mIsClosed, "AppSearchSession has already been closed");
|
||||
try {
|
||||
mService.removeByUri(mDatabaseName, request.getNamespace(),
|
||||
new ArrayList<>(request.getUris()), mUserId,
|
||||
@@ -416,6 +430,7 @@ public final class AppSearchSession {
|
||||
executor.execute(() -> callback.onSystemError(exception.getCause()));
|
||||
}
|
||||
});
|
||||
mIsMutated = true;
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
@@ -448,6 +463,7 @@ public final class AppSearchSession {
|
||||
Objects.requireNonNull(searchSpec);
|
||||
Objects.requireNonNull(executor);
|
||||
Objects.requireNonNull(callback);
|
||||
Preconditions.checkState(!mIsClosed, "AppSearchSession has already been closed");
|
||||
try {
|
||||
mService.removeByQuery(mDatabaseName, queryExpression, searchSpec.getBundle(), mUserId,
|
||||
new IAppSearchResultCallback.Stub() {
|
||||
@@ -455,8 +471,26 @@ public final class AppSearchSession {
|
||||
executor.execute(() -> callback.accept(result));
|
||||
}
|
||||
});
|
||||
mIsMutated = true;
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the SearchSessionImpl to persists all update/delete requests to the disk.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
// TODO(b/175637134) when unhide it, implement Closeable and remove this method.
|
||||
public void close() {
|
||||
if (mIsMutated && !mIsClosed) {
|
||||
try {
|
||||
mService.persistToDisk(mUserId);
|
||||
mIsClosed = true;
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Unable to close the AppSearchSession", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,6 +192,13 @@ interface IAppSearchManager {
|
||||
in int userId,
|
||||
in IAppSearchResultCallback callback);
|
||||
|
||||
/**
|
||||
* Persists all update/delete requests to the disk.
|
||||
*
|
||||
* @param userId Id of the calling user
|
||||
*/
|
||||
void persistToDisk(in int userId);
|
||||
|
||||
/**
|
||||
* Creates and initializes AppSearchImpl for the calling app.
|
||||
*
|
||||
|
||||
@@ -24,6 +24,8 @@ import android.os.Bundle;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.util.Preconditions;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
@@ -62,6 +64,8 @@ public class SearchResults implements Closeable {
|
||||
|
||||
private boolean mIsFirstLoad = true;
|
||||
|
||||
private boolean mIsClosed = false;
|
||||
|
||||
SearchResults(
|
||||
@NonNull IAppSearchManager service,
|
||||
@Nullable String databaseName,
|
||||
@@ -88,6 +92,7 @@ public class SearchResults implements Closeable {
|
||||
* @param callback Callback to receive the pending result of performing this operation.
|
||||
*/
|
||||
public void getNextPage(@NonNull Consumer<AppSearchResult<List<SearchResult>>> callback) {
|
||||
Preconditions.checkState(!mIsClosed, "SearchResults has already been closed");
|
||||
try {
|
||||
if (mIsFirstLoad) {
|
||||
mIsFirstLoad = false;
|
||||
@@ -111,10 +116,13 @@ public class SearchResults implements Closeable {
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
try {
|
||||
mService.invalidateNextPageToken(mNextPageToken, mUserId);
|
||||
} catch (RemoteException e) {
|
||||
Log.d(TAG, "Unable to close the SearchResults", e);
|
||||
if (!mIsClosed) {
|
||||
try {
|
||||
mService.invalidateNextPageToken(mNextPageToken, mUserId);
|
||||
mIsClosed = true;
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Unable to close the SearchResults", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -279,7 +279,7 @@ public class AppSearchManagerService extends SystemService {
|
||||
AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId);
|
||||
impl.invalidateNextPageToken(nextPageToken);
|
||||
} catch (Throwable t) {
|
||||
Log.d(TAG, "Unable to invalidate the query page token", t);
|
||||
Log.e(TAG, "Unable to invalidate the query page token", t);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(callingIdentity);
|
||||
}
|
||||
@@ -347,6 +347,21 @@ public class AppSearchManagerService extends SystemService {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void persistToDisk(@UserIdInt int userId) {
|
||||
int callingUid = Binder.getCallingUidOrThrow();
|
||||
int callingUserId = handleIncomingUser(userId, callingUid);
|
||||
final long callingIdentity = Binder.clearCallingIdentity();
|
||||
try {
|
||||
AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId);
|
||||
impl.persistToDisk();
|
||||
} catch (Throwable t) {
|
||||
Log.e(TAG, "Unable to persist the data to disk", t);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(callingIdentity);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize(@UserIdInt int userId, @NonNull IAppSearchResultCallback callback) {
|
||||
Preconditions.checkNotNull(callback);
|
||||
@@ -388,7 +403,7 @@ public class AppSearchManagerService extends SystemService {
|
||||
try {
|
||||
callback.onResult(result);
|
||||
} catch (RemoteException e) {
|
||||
Log.d(TAG, "Unable to send result to the callback", e);
|
||||
Log.e(TAG, "Unable to send result to the callback", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -398,7 +413,7 @@ public class AppSearchManagerService extends SystemService {
|
||||
try {
|
||||
callback.onResult(result);
|
||||
} catch (RemoteException e) {
|
||||
Log.d(TAG, "Unable to send result to the callback", e);
|
||||
Log.e(TAG, "Unable to send result to the callback", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -411,7 +426,7 @@ public class AppSearchManagerService extends SystemService {
|
||||
try {
|
||||
callback.onResult(throwableToFailedResult(throwable));
|
||||
} catch (RemoteException e) {
|
||||
Log.d(TAG, "Unable to send result to the callback", e);
|
||||
Log.e(TAG, "Unable to send result to the callback", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -425,7 +440,7 @@ public class AppSearchManagerService extends SystemService {
|
||||
try {
|
||||
callback.onSystemError(new ParcelableException(throwable));
|
||||
} catch (RemoteException e) {
|
||||
Log.d(TAG, "Unable to send error to the callback", e);
|
||||
Log.e(TAG, "Unable to send error to the callback", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@ import com.google.android.icing.proto.GetSchemaResultProto;
|
||||
import com.google.android.icing.proto.IcingSearchEngineOptions;
|
||||
import com.google.android.icing.proto.InitializeResultProto;
|
||||
import com.google.android.icing.proto.OptimizeResultProto;
|
||||
import com.google.android.icing.proto.PersistToDiskResultProto;
|
||||
import com.google.android.icing.proto.PropertyConfigProto;
|
||||
import com.google.android.icing.proto.PropertyProto;
|
||||
import com.google.android.icing.proto.PutResultProto;
|
||||
@@ -630,6 +631,24 @@ public final class AppSearchImpl {
|
||||
deleteResultProto.getStatus(), StatusProto.Code.OK, StatusProto.Code.NOT_FOUND);
|
||||
}
|
||||
|
||||
/**
|
||||
* Persists all update/delete requests to the disk.
|
||||
*
|
||||
* <p>If the app crashes after a call to PersistToDisk(), Icing would be able to fully recover
|
||||
* all data written up to this point without a costly recovery process.
|
||||
*
|
||||
* <p>If the app crashes before a call to PersistToDisk(), Icing would trigger a costly recovery
|
||||
* process in next initialization. After that, Icing would still be able to recover all written
|
||||
* data.
|
||||
*
|
||||
* @throws AppSearchException
|
||||
*/
|
||||
public void persistToDisk() throws AppSearchException {
|
||||
PersistToDiskResultProto persistToDiskResultProto =
|
||||
mIcingSearchEngineLocked.persistToDisk();
|
||||
checkSuccess(persistToDiskResultProto.getStatus());
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears documents and schema across all packages and databaseNames.
|
||||
*
|
||||
|
||||
@@ -1 +1 @@
|
||||
Idd770a064edfeb6dc648571fc6706c087b8e605a
|
||||
I596ad1269b4d3a4f26db67f5d970aeaa3bf94a9d
|
||||
|
||||
@@ -58,10 +58,17 @@ public class AppSearchSessionShimImpl implements AppSearchSessionShim {
|
||||
@NonNull
|
||||
public static ListenableFuture<AppSearchSessionShim> createSearchSession(
|
||||
@NonNull AppSearchManager.SearchContext searchContext) {
|
||||
return createSearchSession(searchContext, Executors.newCachedThreadPool());
|
||||
}
|
||||
|
||||
/** Creates the SearchSession with given ExecutorService. */
|
||||
@NonNull
|
||||
public static ListenableFuture<AppSearchSessionShim> createSearchSession(
|
||||
@NonNull AppSearchManager.SearchContext searchContext,
|
||||
@NonNull ExecutorService executor) {
|
||||
Context context = ApplicationProvider.getApplicationContext();
|
||||
AppSearchManager appSearchManager = context.getSystemService(AppSearchManager.class);
|
||||
SettableFuture<AppSearchResult<AppSearchSession>> future = SettableFuture.create();
|
||||
ExecutorService executor = Executors.newCachedThreadPool();
|
||||
appSearchManager.createSearchSession(searchContext, executor, future::set);
|
||||
return Futures.transform(
|
||||
future,
|
||||
@@ -138,6 +145,11 @@ public class AppSearchSessionShimImpl implements AppSearchSessionShim {
|
||||
return Futures.transformAsync(future, this::transformResult, mExecutor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
mAppSearchSession.close();
|
||||
}
|
||||
|
||||
private <T> ListenableFuture<T> transformResult(
|
||||
@NonNull AppSearchResult<T> result) throws AppSearchException {
|
||||
if (!result.isSuccess()) {
|
||||
|
||||
@@ -208,4 +208,13 @@ public interface AppSearchSessionShim {
|
||||
@NonNull
|
||||
ListenableFuture<Void> removeByQuery(
|
||||
@NonNull String queryExpression, @NonNull SearchSpec searchSpec);
|
||||
|
||||
/**
|
||||
* Closes the SearchSessionImpl to persists all update/delete requests to the disk.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
|
||||
// TODO(b/175637134) when unhide it, extends Closeable and remove this method.
|
||||
void close();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user