diff options
| author | Alexander Dorokhine <adorokhine@google.com> | 2021-04-28 03:33:15 +0000 |
|---|---|---|
| committer | Android (Google) Code Review <android-gerrit@google.com> | 2021-04-28 03:33:15 +0000 |
| commit | 5d3d644cbc3da2b8e92f4b95f3dc481f1ea31ed9 (patch) | |
| tree | 50ab0ec633e79d88a3586d8bff2633cd2c47f175 | |
| parent | e19e70840804fae39039b47c368db23b92150af9 (diff) | |
| parent | 1b690b4540de43989d180d228e9994460a46a034 (diff) | |
Merge "Update framework from jetpack." into sc-dev
16 files changed, 1547 insertions, 59 deletions
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaResponse.java b/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaResponse.java index 8a162d49e151..b7bd3878d4fa 100644 --- a/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaResponse.java +++ b/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaResponse.java @@ -96,8 +96,13 @@ public class SetSchemaResponse { } /** - * Returns a {@link Set} of schema type that were deleted by the {@link - * AppSearchSession#setSchema} call. + * Returns a {@link Set} of deleted schema types. + * + * <p>A "deleted" type is a schema type that was previously a part of the database schema but + * was not present in the {@link SetSchemaRequest} object provided in the + * {@link AppSearchSession#setSchema) call. + * + * <p>Documents for a deleted type are removed from the database. */ @NonNull public Set<String> getDeletedTypes() { @@ -113,6 +118,15 @@ public class SetSchemaResponse { /** * Returns a {@link Set} of schema type that were migrated by the {@link * AppSearchSession#setSchema} call. + * + * <p>A "migrated" type is a schema type that has triggered a {@link Migrator} instance to + * migrate documents of the schema type to another schema type, or to another version of the + * schema type. + * + * <p>If a document fails to be migrated, a {@link MigrationFailure} will be generated for that + * document. + * + * @see Migrator */ @NonNull public Set<String> getMigratedTypes() { @@ -132,6 +146,7 @@ public class SetSchemaResponse { * <p>If a {@link Migrator} is provided for this type and the migration is success triggered. * The type will also appear in {@link #getMigratedTypes()}. * + * @see SetSchemaRequest * @see AppSearchSession#setSchema * @see SetSchemaRequest.Builder#setForceOverride */ diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/exceptions/AppSearchException.java b/apex/appsearch/framework/java/external/android/app/appsearch/exceptions/AppSearchException.java index ca4ea2bfd3bb..62593ae8fc29 100644 --- a/apex/appsearch/framework/java/external/android/app/appsearch/exceptions/AppSearchException.java +++ b/apex/appsearch/framework/java/external/android/app/appsearch/exceptions/AppSearchException.java @@ -42,6 +42,8 @@ public class AppSearchException extends Exception { * Initializes an {@link AppSearchException} with a result code and message. * * @param resultCode One of the constants documented in {@link AppSearchResult#getResultCode}. + * @param message The detail message (which is saved for later retrieval by the {@link + * #getMessage()} method). */ public AppSearchException( @AppSearchResult.ResultCode int resultCode, @Nullable String message) { @@ -52,6 +54,11 @@ public class AppSearchException extends Exception { * Initializes an {@link AppSearchException} with a result code, message and cause. * * @param resultCode One of the constants documented in {@link AppSearchResult#getResultCode}. + * @param message The detail message (which is saved for later retrieval by the {@link + * #getMessage()} method). + * @param cause The cause (which is saved for later retrieval by the {@link #getCause()} + * method). (A null value is permitted, and indicates that the cause is nonexistent or + * unknown.) */ public AppSearchException( @AppSearchResult.ResultCode int resultCode, diff --git a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java index 3f6e8a5a7906..a4188a2733b8 100644 --- a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java +++ b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java @@ -501,7 +501,8 @@ public class AppSearchManagerService extends SystemService { packageName, databaseName, queryExpression, - new SearchSpec(searchSpecBundle)); + new SearchSpec(searchSpecBundle), + /*logger=*/ null); invokeCallbackOnResult( callback, AppSearchResult.newSuccessfulResult(searchResultPage.getBundle())); @@ -535,7 +536,8 @@ public class AppSearchManagerService extends SystemService { queryExpression, new SearchSpec(searchSpecBundle), packageName, - callingUid); + callingUid, + /*logger=*/ null); invokeCallbackOnResult( callback, AppSearchResult.newSuccessfulResult(searchResultPage.getBundle())); @@ -609,7 +611,8 @@ public class AppSearchManagerService extends SystemService { packageName, databaseName, queryExpression, - new SearchSpec(searchSpecBundle)); + new SearchSpec(searchSpecBundle), + /*logger=*/ null); while (!searchResultPage.getResults().isEmpty()) { for (int i = 0; i < searchResultPage.getResults().size(); i++) { AppSearchMigrationHelper.writeBundleToOutputStream( diff --git a/apex/appsearch/service/java/com/android/server/appsearch/ImplInstanceManager.java b/apex/appsearch/service/java/com/android/server/appsearch/ImplInstanceManager.java index 45023f966ad2..94ee830f8e74 100644 --- a/apex/appsearch/service/java/com/android/server/appsearch/ImplInstanceManager.java +++ b/apex/appsearch/service/java/com/android/server/appsearch/ImplInstanceManager.java @@ -149,7 +149,8 @@ public final class ImplInstanceManager { private AppSearchImpl createImpl(@NonNull Context context, @UserIdInt int userId) throws AppSearchException { File appSearchDir = getAppSearchDir(userId); - return AppSearchImpl.create(appSearchDir, context, userId, mGlobalQuerierPackage); + return AppSearchImpl.create( + appSearchDir, context, userId, mGlobalQuerierPackage, /*logger=*/ null); } /** diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java index 98fcb1370d8b..e5e20e733264 100644 --- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java +++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java @@ -54,7 +54,9 @@ import com.android.server.appsearch.external.localstorage.converter.SearchResult import com.android.server.appsearch.external.localstorage.converter.SearchSpecToProtoConverter; import com.android.server.appsearch.external.localstorage.converter.SetSchemaResponseToProtoConverter; import com.android.server.appsearch.external.localstorage.converter.TypePropertyPathToProtoConverter; +import com.android.server.appsearch.external.localstorage.stats.InitializeStats; import com.android.server.appsearch.external.localstorage.stats.PutDocumentStats; +import com.android.server.appsearch.external.localstorage.stats.SearchStats; import com.google.android.icing.IcingSearchEngine; import com.google.android.icing.proto.DeleteByQueryResultProto; @@ -178,28 +180,63 @@ public final class AppSearchImpl implements Closeable { /** * Creates and initializes an instance of {@link AppSearchImpl} which writes data to the given * folder. + * + * <p>Clients can pass a {@link AppSearchLogger} here through their AppSearchSession, but it + * can't be saved inside {@link AppSearchImpl}, because the impl will be shared by all the + * sessions for the same package in JetPack. + * + * <p>Instead, logger instance needs to be passed to each individual method, like create, query + * and putDocument. + * + * @param logger collects stats for initialization if provided. */ @NonNull public static AppSearchImpl create( @NonNull File icingDir, @NonNull Context context, int userId, - @NonNull String globalQuerierPackage) + @NonNull String globalQuerierPackage, + @Nullable AppSearchLogger logger) throws AppSearchException { Objects.requireNonNull(icingDir); Objects.requireNonNull(context); Objects.requireNonNull(globalQuerierPackage); + + long totalLatencyStartMillis = SystemClock.elapsedRealtime(); + InitializeStats.Builder initStatsBuilder = null; + if (logger != null) { + initStatsBuilder = new InitializeStats.Builder(); + } + AppSearchImpl appSearchImpl = - new AppSearchImpl(icingDir, context, userId, globalQuerierPackage); + new AppSearchImpl( + icingDir, context, userId, globalQuerierPackage, initStatsBuilder); + + long prepareVisibilityStoreLatencyStartMillis = SystemClock.elapsedRealtime(); appSearchImpl.initializeVisibilityStore(); + long prepareVisibilityStoreLatencyEndMillis = SystemClock.elapsedRealtime(); + + if (logger != null && initStatsBuilder != null) { + initStatsBuilder + .setTotalLatencyMillis( + (int) (SystemClock.elapsedRealtime() - totalLatencyStartMillis)) + .setPrepareVisibilityStoreLatencyMillis( + (int) + (prepareVisibilityStoreLatencyEndMillis + - prepareVisibilityStoreLatencyStartMillis)); + logger.logStats(initStatsBuilder.build()); + } + return appSearchImpl; } + /** @param initStatsBuilder collects stats for initialization if provided. */ private AppSearchImpl( @NonNull File icingDir, @NonNull Context context, int userId, - @NonNull String globalQuerierPackage) + @NonNull String globalQuerierPackage, + @Nullable InitializeStats.Builder initStatsBuilder) throws AppSearchException { mReadWriteLock.writeLock().lock(); @@ -211,13 +248,24 @@ public final class AppSearchImpl implements Closeable { .setBaseDir(icingDir.getAbsolutePath()) .build(); mIcingSearchEngineLocked = new IcingSearchEngine(options); - mVisibilityStoreLocked = new VisibilityStore(this, context, userId, globalQuerierPackage); - InitializeResultProto initializeResultProto = mIcingSearchEngineLocked.initialize(); + + if (initStatsBuilder != null) { + initStatsBuilder + .setStatusCode( + statusProtoToAppSearchException(initializeResultProto.getStatus()) + .getResultCode()) + // TODO(b/173532925) how to get DeSyncs value + .setHasDeSync(false); + AppSearchLoggerHelper.copyNativeStats( + initializeResultProto.getInitializeStats(), initStatsBuilder); + } + + long prepareSchemaAndNamespacesLatencyStartMillis = SystemClock.elapsedRealtime(); SchemaProto schemaProto; - GetAllNamespacesResultProto getAllNamespacesResultProto; + GetAllNamespacesResultProto getAllNamespacesResultProto = null; try { checkSuccess(initializeResultProto.getStatus()); schemaProto = getSchemaProtoLocked(); @@ -225,6 +273,17 @@ public final class AppSearchImpl implements Closeable { checkSuccess(getAllNamespacesResultProto.getStatus()); } catch (AppSearchException e) { Log.w(TAG, "Error initializing, resetting IcingSearchEngine.", e); + if (initStatsBuilder != null && getAllNamespacesResultProto != null) { + initStatsBuilder + .setStatusCode( + statusProtoToAppSearchException( + getAllNamespacesResultProto.getStatus()) + .getResultCode()) + .setPrepareSchemaAndNamespacesLatencyMillis( + (int) + (SystemClock.elapsedRealtime() + - prepareSchemaAndNamespacesLatencyStartMillis)); + } // Some error. Reset and see if it fixes it. resetLocked(); return; @@ -240,6 +299,14 @@ public final class AppSearchImpl implements Closeable { for (String prefixedNamespace : getAllNamespacesResultProto.getNamespacesList()) { addToMap(mNamespaceMapLocked, getPrefix(prefixedNamespace), prefixedNamespace); } + + // logging prepare_schema_and_namespaces latency + if (initStatsBuilder != null) { + initStatsBuilder.setPrepareSchemaAndNamespacesLatencyMillis( + (int) + (SystemClock.elapsedRealtime() + - prepareSchemaAndNamespacesLatencyStartMillis)); + } } finally { mReadWriteLock.writeLock().unlock(); } @@ -539,7 +606,7 @@ public final class AppSearchImpl implements Closeable { addToMap(mNamespaceMapLocked, prefix, documentBuilder.getNamespace()); // Logging stats - if (logger != null) { + if (logger != null && pStatsBuilder != null) { pStatsBuilder .getGeneralStatsBuilder() .setStatusCode( @@ -562,7 +629,7 @@ public final class AppSearchImpl implements Closeable { } finally { mReadWriteLock.writeLock().unlock(); - if (logger != null) { + if (logger != null && pStatsBuilder != null) { long totalEndTimeMillis = SystemClock.elapsedRealtime(); pStatsBuilder .getGeneralStatsBuilder() @@ -644,6 +711,7 @@ public final class AppSearchImpl implements Closeable { * @param databaseName The databaseName this query for. * @param queryExpression Query String to search. * @param searchSpec Spec for setting filters, raw query etc. + * @param logger logger to collect query stats * @return The results of performing this search. It may contain an empty list of results if no * documents matched the query. * @throws AppSearchException on IcingSearchEngine error. @@ -653,8 +721,17 @@ public final class AppSearchImpl implements Closeable { @NonNull String packageName, @NonNull String databaseName, @NonNull String queryExpression, - @NonNull SearchSpec searchSpec) + @NonNull SearchSpec searchSpec, + @Nullable AppSearchLogger logger) throws AppSearchException { + long totalLatencyStartMillis = SystemClock.elapsedRealtime(); + SearchStats.Builder sStatsBuilder = null; + if (logger != null) { + sStatsBuilder = + new SearchStats.Builder(SearchStats.VISIBILITY_SCOPE_LOCAL, packageName) + .setDatabase(databaseName); + } + mReadWriteLock.readLock().lock(); try { throwIfClosedLocked(); @@ -673,9 +750,15 @@ public final class AppSearchImpl implements Closeable { Collections.singleton(createPrefix(packageName, databaseName)), allowedPrefixedSchemas, queryExpression, - searchSpec); + searchSpec, + sStatsBuilder); } finally { mReadWriteLock.readLock().unlock(); + if (logger != null && sStatsBuilder != null) { + sStatsBuilder.setTotalLatencyMillis( + (int) (SystemClock.elapsedRealtime() - totalLatencyStartMillis)); + logger.logStats(sStatsBuilder.build()); + } } } @@ -689,6 +772,7 @@ public final class AppSearchImpl implements Closeable { * @param searchSpec Spec for setting filters, raw query etc. * @param callerPackageName Package name of the caller, should belong to the {@code callerUid}. * @param callerUid UID of the client making the globalQuery call. + * @param logger logger to collect globalQuery stats * @return The results of performing this search. It may contain an empty list of results if no * documents matched the query. * @throws AppSearchException on IcingSearchEngine error. @@ -698,8 +782,16 @@ public final class AppSearchImpl implements Closeable { @NonNull String queryExpression, @NonNull SearchSpec searchSpec, @NonNull String callerPackageName, - int callerUid) + int callerUid, + @Nullable AppSearchLogger logger) throws AppSearchException { + long totalLatencyStartMillis = SystemClock.elapsedRealtime(); + SearchStats.Builder sStatsBuilder = null; + if (logger != null) { + sStatsBuilder = + new SearchStats.Builder(SearchStats.VISIBILITY_SCOPE_GLOBAL, callerPackageName); + } + mReadWriteLock.readLock().lock(); try { throwIfClosedLocked(); @@ -754,9 +846,19 @@ public final class AppSearchImpl implements Closeable { } return doQueryLocked( - prefixFilters, allowedPrefixedSchemas, queryExpression, searchSpec); + prefixFilters, + allowedPrefixedSchemas, + queryExpression, + searchSpec, + sStatsBuilder); } finally { mReadWriteLock.readLock().unlock(); + + if (logger != null && sStatsBuilder != null) { + sStatsBuilder.setTotalLatencyMillis( + (int) (SystemClock.elapsedRealtime() - totalLatencyStartMillis)); + logger.logStats(sStatsBuilder.build()); + } } } @@ -794,8 +896,11 @@ public final class AppSearchImpl implements Closeable { @NonNull Set<String> prefixes, @NonNull Set<String> allowedPrefixedSchemas, @NonNull String queryExpression, - @NonNull SearchSpec searchSpec) + @NonNull SearchSpec searchSpec, + @Nullable SearchStats.Builder sStatsBuilder) throws AppSearchException { + long rewriteSearchSpecLatencyStartMillis = SystemClock.elapsedRealtime(); + SearchSpecProto.Builder searchSpecBuilder = SearchSpecToProtoConverter.toSearchSpecProto(searchSpec).toBuilder() .setQuery(queryExpression); @@ -804,9 +909,17 @@ public final class AppSearchImpl implements Closeable { // sending request to Icing. if (!rewriteSearchSpecForPrefixesLocked( searchSpecBuilder, prefixes, allowedPrefixedSchemas)) { + if (sStatsBuilder != null) { + sStatsBuilder.setRewriteSearchSpecLatencyMillis( + (int) + (SystemClock.elapsedRealtime() + - rewriteSearchSpecLatencyStartMillis)); + } return new SearchResultPage(Bundle.EMPTY); } + // rewriteSearchSpec, rewriteResultSpec and convertScoringSpec are all counted in + // rewriteSearchSpecLatencyMillis ResultSpecProto.Builder resultSpecBuilder = SearchSpecToProtoConverter.toResultSpecProto(searchSpec).toBuilder(); @@ -822,15 +935,38 @@ public final class AppSearchImpl implements Closeable { addPerNamespaceResultGroupingsLocked( resultSpecBuilder, prefixes, searchSpec.getResultGroupingLimit()); } - rewriteResultSpecForPrefixesLocked(resultSpecBuilder, prefixes, allowedPrefixedSchemas); + rewriteResultSpecForPrefixesLocked(resultSpecBuilder, prefixes, allowedPrefixedSchemas); ScoringSpecProto scoringSpec = SearchSpecToProtoConverter.toScoringSpecProto(searchSpec); + + long rewriteSearchSpecLatencyEndMillis = SystemClock.elapsedRealtime(); + SearchResultProto searchResultProto = mIcingSearchEngineLocked.search( searchSpecBuilder.build(), scoringSpec, resultSpecBuilder.build()); + + if (sStatsBuilder != null) { + sStatsBuilder + .setStatusCode( + statusProtoToAppSearchException(searchResultProto.getStatus()) + .getResultCode()) + .setRewriteSearchSpecLatencyMillis( + (int) + (rewriteSearchSpecLatencyEndMillis + - rewriteSearchSpecLatencyStartMillis)); + AppSearchLoggerHelper.copyNativeStats(searchResultProto.getQueryStats(), sStatsBuilder); + } + checkSuccess(searchResultProto.getStatus()); - return rewriteSearchResultProto(searchResultProto, mSchemaMapLocked); + long rewriteSearchResultLatencyStartMillis = SystemClock.elapsedRealtime(); + SearchResultPage resultPage = rewriteSearchResultProto(searchResultProto, mSchemaMapLocked); + if (sStatsBuilder != null) { + sStatsBuilder.setRewriteSearchResultLatencyMillis( + (int) (SystemClock.elapsedRealtime() - rewriteSearchResultLatencyStartMillis)); + } + + return resultPage; } /** diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLogger.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLogger.java index 0f23d926648b..97c886922c32 100644 --- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLogger.java +++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLogger.java @@ -20,7 +20,9 @@ import android.annotation.NonNull; import android.app.appsearch.exceptions.AppSearchException; import com.android.server.appsearch.external.localstorage.stats.CallStats; +import com.android.server.appsearch.external.localstorage.stats.InitializeStats; import com.android.server.appsearch.external.localstorage.stats.PutDocumentStats; +import com.android.server.appsearch.external.localstorage.stats.SearchStats; /** * An interface for implementing client-defined logging AppSearch operations stats. @@ -39,5 +41,11 @@ public interface AppSearchLogger { /** Logs {@link PutDocumentStats} */ void logStats(@NonNull PutDocumentStats stats) throws AppSearchException; + /** Logs {@link InitializeStats} */ + void logStats(@NonNull InitializeStats stats) throws AppSearchException; + + /** Logs {@link SearchStats} */ + void logStats(@NonNull SearchStats stats) throws AppSearchException; + // TODO(b/173532925) Add remaining logStats once we add all the stats. } diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLoggerHelper.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLoggerHelper.java index cdd795207e0b..4a5ecf1bc0b9 100644 --- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLoggerHelper.java +++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLoggerHelper.java @@ -18,9 +18,13 @@ package com.android.server.appsearch.external.localstorage; import android.annotation.NonNull; +import com.android.server.appsearch.external.localstorage.stats.InitializeStats; import com.android.server.appsearch.external.localstorage.stats.PutDocumentStats; +import com.android.server.appsearch.external.localstorage.stats.SearchStats; +import com.google.android.icing.proto.InitializeStatsProto; import com.google.android.icing.proto.PutDocumentStatsProto; +import com.google.android.icing.proto.QueryStatsProto; import java.util.Objects; @@ -35,7 +39,7 @@ public final class AppSearchLoggerHelper { private AppSearchLoggerHelper() {} /** - * Copies native stats to builder. + * Copies native PutDocument stats to builder. * * @param fromNativeStats stats copied from * @param toStatsBuilder stats copied to @@ -56,4 +60,64 @@ public final class AppSearchLoggerHelper { .setNativeExceededMaxNumTokens( fromNativeStats.getTokenizationStats().getExceededMaxTokenNum()); } + + /** + * Copies native Initialize stats to builder. + * + * @param fromNativeStats stats copied from + * @param toStatsBuilder stats copied to + */ + static void copyNativeStats( + @NonNull InitializeStatsProto fromNativeStats, + @NonNull InitializeStats.Builder toStatsBuilder) { + Objects.requireNonNull(fromNativeStats); + Objects.requireNonNull(toStatsBuilder); + toStatsBuilder + .setNativeLatencyMillis(fromNativeStats.getLatencyMs()) + .setDocumentStoreRecoveryCause( + fromNativeStats.getDocumentStoreRecoveryCause().getNumber()) + .setIndexRestorationCause(fromNativeStats.getIndexRestorationCause().getNumber()) + .setSchemaStoreRecoveryCause( + fromNativeStats.getSchemaStoreRecoveryCause().getNumber()) + .setDocumentStoreRecoveryLatencyMillis( + fromNativeStats.getDocumentStoreRecoveryLatencyMs()) + .setIndexRestorationLatencyMillis(fromNativeStats.getIndexRestorationLatencyMs()) + .setSchemaStoreRecoveryLatencyMillis( + fromNativeStats.getSchemaStoreRecoveryLatencyMs()) + .setDocumentStoreDataStatus( + fromNativeStats.getDocumentStoreDataStatus().getNumber()) + .setDocumentCount(fromNativeStats.getNumDocuments()) + .setSchemaTypeCount(fromNativeStats.getNumSchemaTypes()); + } + + /* + * Copy native Query stats to buiilder. + * + * @param fromNativeStats Stats copied from. + * @param toStatsBuilder Stats copied to. + */ + static void copyNativeStats( + @NonNull QueryStatsProto fromNativeStats, @NonNull SearchStats.Builder toStatsBuilder) { + Objects.requireNonNull(fromNativeStats); + Objects.requireNonNull(toStatsBuilder); + toStatsBuilder + .setNativeLatencyMillis(fromNativeStats.getLatencyMs()) + .setTermCount(fromNativeStats.getNumTerms()) + // TODO(b/173532925) query length missing in native + // .setNativeQueryLength(0) + .setFilteredNamespaceCount(fromNativeStats.getNumNamespacesFiltered()) + .setFilteredSchemaTypeCount(fromNativeStats.getNumSchemaTypesFiltered()) + .setRequestedPageSize(fromNativeStats.getRequestedPageSize()) + .setCurrentPageReturnedResultCount( + fromNativeStats.getNumResultsReturnedCurrentPage()) + .setIsFirstPage(fromNativeStats.getIsFirstPage()) + .setParseQueryLatencyMillis(fromNativeStats.getParseQueryLatencyMs()) + .setRankingStrategy(fromNativeStats.getRankingStrategy().getNumber()) + .setScoredDocumentCount(fromNativeStats.getNumDocumentsScored()) + .setScoringLatencyMillis(fromNativeStats.getScoringLatencyMs()) + .setRankingLatencyMillis(fromNativeStats.getRankingLatencyMs()) + .setResultWithSnippetsCount(fromNativeStats.getNumResultsWithSnippets()) + .setDocumentRetrievingLatencyMillis( + fromNativeStats.getDocumentRetrievalLatencyMs()); + } } diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/InitializeStats.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/InitializeStats.java new file mode 100644 index 000000000000..5364a0caa1aa --- /dev/null +++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/InitializeStats.java @@ -0,0 +1,404 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.appsearch.external.localstorage.stats; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.app.appsearch.AppSearchResult; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Objects; + +/** + * Class holds detailed stats for initialization + * + * @hide + */ +public final class InitializeStats { + /** + * The cause of IcingSearchEngine recovering from a previous bad state during initialization. + */ + @IntDef( + value = { + // It needs to be sync with RecoveryCause in + // external/icing/proto/icing/proto/logging.proto#InitializeStatsProto + RECOVERY_CAUSE_NONE, + RECOVERY_CAUSE_DATA_LOSS, + RECOVERY_CAUSE_INCONSISTENT_WITH_GROUND_TRUTH, + RECOVERY_CAUSE_TOTAL_CHECKSUM_MISMATCH, + RECOVERY_CAUSE_IO_ERROR, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface RecoveryCause {} + + // No recovery happened. + public static final int RECOVERY_CAUSE_NONE = 0; + // Data loss in ground truth. + public static final int RECOVERY_CAUSE_DATA_LOSS = 1; + // Data in index is inconsistent with ground truth. + public static final int RECOVERY_CAUSE_INCONSISTENT_WITH_GROUND_TRUTH = 2; + // Total checksum of all the components does not match. + public static final int RECOVERY_CAUSE_TOTAL_CHECKSUM_MISMATCH = 3; + // Random I/O errors. + public static final int RECOVERY_CAUSE_IO_ERROR = 4; + + /** Status regarding how much data is lost during the initialization. */ + @IntDef( + value = { + // It needs to be sync with DocumentStoreDataStatus in + // external/icing/proto/icing/proto/logging.proto#InitializeStatsProto + + DOCUMENT_STORE_DATA_STATUS_NO_DATA_LOSS, + DOCUMENT_STORE_DATA_STATUS_PARTIAL_LOSS, + DOCUMENT_STORE_DATA_STATUS_COMPLETE_LOSS, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface DocumentStoreDataStatus {} + + // Document store is successfully initialized or fully recovered. + public static final int DOCUMENT_STORE_DATA_STATUS_NO_DATA_LOSS = 0; + // Ground truth data is partially lost. + public static final int DOCUMENT_STORE_DATA_STATUS_PARTIAL_LOSS = 1; + // Ground truth data is completely lost. + public static final int DOCUMENT_STORE_DATA_STATUS_COMPLETE_LOSS = 2; + + @AppSearchResult.ResultCode private final int mStatusCode; + private final int mTotalLatencyMillis; + /** Whether the initialize() detects deSync. */ + private final boolean mHasDeSync; + /** Time used to read and process the schema and namespaces. */ + private final int mPrepareSchemaAndNamespacesLatencyMillis; + /** Time used to read and process the visibility store. */ + private final int mPrepareVisibilityStoreLatencyMillis; + /** Overall time used for the native function call. */ + private final int mNativeLatencyMillis; + + @RecoveryCause private final int mNativeDocumentStoreRecoveryCause; + @RecoveryCause private final int mNativeIndexRestorationCause; + @RecoveryCause private final int mNativeSchemaStoreRecoveryCause; + /** Time used to recover the document store. */ + private final int mNativeDocumentStoreRecoveryLatencyMillis; + /** Time used to restore the index. */ + private final int mNativeIndexRestorationLatencyMillis; + /** Time used to recover the schema store. */ + private final int mNativeSchemaStoreRecoveryLatencyMillis; + /** Status regarding how much data is lost during the initialization. */ + private final int mNativeDocumentStoreDataStatus; + /** + * Returns number of documents currently in document store. Those may include alive, deleted, + * and expired documents. + */ + private final int mNativeNumDocuments; + /** Returns number of schema types currently in the schema store. */ + private final int mNativeNumSchemaTypes; + + /** Returns the status of the initialization. */ + @AppSearchResult.ResultCode + public int getStatusCode() { + return mStatusCode; + } + + /** Returns the total latency in milliseconds for the initialization. */ + public int getTotalLatencyMillis() { + return mTotalLatencyMillis; + } + + /** + * Returns whether the initialize() detects deSync. + * + * <p>If there is a deSync, it means AppSearch and IcingSearchEngine have an inconsistent view + * of what data should exist. + */ + public boolean hasDeSync() { + return mHasDeSync; + } + + /** Returns time used to read and process the schema and namespaces. */ + public int getPrepareSchemaAndNamespacesLatencyMillis() { + return mPrepareSchemaAndNamespacesLatencyMillis; + } + + /** Returns time used to read and process the visibility file. */ + public int getPrepareVisibilityStoreLatencyMillis() { + return mPrepareVisibilityStoreLatencyMillis; + } + + /** Returns overall time used for the native function call. */ + public int getNativeLatencyMillis() { + return mNativeLatencyMillis; + } + + /** + * Returns recovery cause for document store. + * + * <p>Possible recovery causes for document store: + * <li>{@link InitializeStats#RECOVERY_CAUSE_DATA_LOSS} + * <li>{@link InitializeStats#RECOVERY_CAUSE_TOTAL_CHECKSUM_MISMATCH} + * <li>{@link InitializeStats#RECOVERY_CAUSE_IO_ERROR} + */ + @RecoveryCause + public int getDocumentStoreRecoveryCause() { + return mNativeDocumentStoreRecoveryCause; + } + + /** + * Returns restoration cause for index store. + * + * <p>Possible causes: + * <li>{@link InitializeStats#RECOVERY_CAUSE_INCONSISTENT_WITH_GROUND_TRUTH} + * <li>{@link InitializeStats#RECOVERY_CAUSE_TOTAL_CHECKSUM_MISMATCH} + * <li>{@link InitializeStats#RECOVERY_CAUSE_IO_ERROR} + */ + @RecoveryCause + public int getIndexRestorationCause() { + return mNativeIndexRestorationCause; + } + + /** + * Returns recovery cause for schema store. + * + * <p>Possible causes: + * <li>IO_ERROR + */ + @RecoveryCause + public int getSchemaStoreRecoveryCause() { + return mNativeSchemaStoreRecoveryCause; + } + + /** Returns time used to recover the document store. */ + public int getDocumentStoreRecoveryLatencyMillis() { + return mNativeDocumentStoreRecoveryLatencyMillis; + } + + /** Returns time used to restore the index. */ + public int getIndexRestorationLatencyMillis() { + return mNativeIndexRestorationLatencyMillis; + } + + /** Returns time used to recover the schema store. */ + public int getSchemaStoreRecoveryLatencyMillis() { + return mNativeSchemaStoreRecoveryLatencyMillis; + } + + /** Returns status about how much data is lost during the initialization. */ + @DocumentStoreDataStatus + public int getDocumentStoreDataStatus() { + return mNativeDocumentStoreDataStatus; + } + + /** + * Returns number of documents currently in document store. Those may include alive, deleted, + * and expired documents. + */ + public int getDocumentCount() { + return mNativeNumDocuments; + } + + /** Returns number of schema types currently in the schema store. */ + public int getSchemaTypeCount() { + return mNativeNumSchemaTypes; + } + + InitializeStats(@NonNull Builder builder) { + Objects.requireNonNull(builder); + mStatusCode = builder.mStatusCode; + mTotalLatencyMillis = builder.mTotalLatencyMillis; + mHasDeSync = builder.mHasDeSync; + mPrepareSchemaAndNamespacesLatencyMillis = builder.mPrepareSchemaAndNamespacesLatencyMillis; + mPrepareVisibilityStoreLatencyMillis = builder.mPrepareVisibilityStoreLatencyMillis; + mNativeLatencyMillis = builder.mNativeLatencyMillis; + mNativeDocumentStoreRecoveryCause = builder.mNativeDocumentStoreRecoveryCause; + mNativeIndexRestorationCause = builder.mNativeIndexRestorationCause; + mNativeSchemaStoreRecoveryCause = builder.mNativeSchemaStoreRecoveryCause; + mNativeDocumentStoreRecoveryLatencyMillis = + builder.mNativeDocumentStoreRecoveryLatencyMillis; + mNativeIndexRestorationLatencyMillis = builder.mNativeIndexRestorationLatencyMillis; + mNativeSchemaStoreRecoveryLatencyMillis = builder.mNativeSchemaStoreRecoveryLatencyMillis; + mNativeDocumentStoreDataStatus = builder.mNativeDocumentStoreDataStatus; + mNativeNumDocuments = builder.mNativeNumDocuments; + mNativeNumSchemaTypes = builder.mNativeNumSchemaTypes; + } + + /** Builder for {@link InitializeStats}. */ + public static class Builder { + @AppSearchResult.ResultCode int mStatusCode; + int mTotalLatencyMillis; + boolean mHasDeSync; + int mPrepareSchemaAndNamespacesLatencyMillis; + int mPrepareVisibilityStoreLatencyMillis; + int mNativeLatencyMillis; + @RecoveryCause int mNativeDocumentStoreRecoveryCause; + @RecoveryCause int mNativeIndexRestorationCause; + @RecoveryCause int mNativeSchemaStoreRecoveryCause; + int mNativeDocumentStoreRecoveryLatencyMillis; + int mNativeIndexRestorationLatencyMillis; + int mNativeSchemaStoreRecoveryLatencyMillis; + @DocumentStoreDataStatus int mNativeDocumentStoreDataStatus; + int mNativeNumDocuments; + int mNativeNumSchemaTypes; + + /** Sets the status of the initialization. */ + @NonNull + public Builder setStatusCode(@AppSearchResult.ResultCode int statusCode) { + mStatusCode = statusCode; + return this; + } + + /** Sets the total latency of the initialization in milliseconds. */ + @NonNull + public Builder setTotalLatencyMillis(int totalLatencyMillis) { + mTotalLatencyMillis = totalLatencyMillis; + return this; + } + + /** + * Sets whether the initialize() detects deSync. + * + * <p>If there is a deSync, it means AppSearch and IcingSearchEngine have an inconsistent + * view of what data should exist. + */ + @NonNull + public Builder setHasDeSync(boolean hasDeSync) { + mHasDeSync = hasDeSync; + return this; + } + + /** Sets time used to read and process the schema and namespaces. */ + @NonNull + public Builder setPrepareSchemaAndNamespacesLatencyMillis( + int prepareSchemaAndNamespacesLatencyMillis) { + mPrepareSchemaAndNamespacesLatencyMillis = prepareSchemaAndNamespacesLatencyMillis; + return this; + } + + /** Sets time used to read and process the visibility file. */ + @NonNull + public Builder setPrepareVisibilityStoreLatencyMillis( + int prepareVisibilityStoreLatencyMillis) { + mPrepareVisibilityStoreLatencyMillis = prepareVisibilityStoreLatencyMillis; + return this; + } + + /** Sets overall time used for the native function call. */ + @NonNull + public Builder setNativeLatencyMillis(int nativeLatencyMillis) { + mNativeLatencyMillis = nativeLatencyMillis; + return this; + } + + /** + * Sets recovery cause for document store. + * + * <p>Possible recovery causes for document store: + * <li>{@link InitializeStats#RECOVERY_CAUSE_DATA_LOSS} + * <li>{@link InitializeStats#RECOVERY_CAUSE_TOTAL_CHECKSUM_MISMATCH} + * <li>{@link InitializeStats#RECOVERY_CAUSE_IO_ERROR} + */ + @NonNull + public Builder setDocumentStoreRecoveryCause( + @RecoveryCause int documentStoreRecoveryCause) { + mNativeDocumentStoreRecoveryCause = documentStoreRecoveryCause; + return this; + } + + /** + * Sets restoration cause for index store. + * + * <p>Possible causes: + * <li>{@link InitializeStats#DOCUMENT_STORE_DATA_STATUS_COMPLETE_LOSS} + * <li>{@link InitializeStats#RECOVERY_CAUSE_TOTAL_CHECKSUM_MISMATCH} + * <li>{@link InitializeStats#RECOVERY_CAUSE_IO_ERROR} + */ + @NonNull + public Builder setIndexRestorationCause(@RecoveryCause int indexRestorationCause) { + mNativeIndexRestorationCause = indexRestorationCause; + return this; + } + + /** + * Returns recovery cause for schema store. + * + * <p>Possible causes: + * <li>{@link InitializeStats#RECOVERY_CAUSE_IO_ERROR} + */ + @NonNull + public Builder setSchemaStoreRecoveryCause(@RecoveryCause int schemaStoreRecoveryCause) { + mNativeSchemaStoreRecoveryCause = schemaStoreRecoveryCause; + return this; + } + + /** Sets time used to recover the document store. */ + @NonNull + public Builder setDocumentStoreRecoveryLatencyMillis( + int documentStoreRecoveryLatencyMillis) { + mNativeDocumentStoreRecoveryLatencyMillis = documentStoreRecoveryLatencyMillis; + return this; + } + + /** Sets time used to restore the index. */ + @NonNull + public Builder setIndexRestorationLatencyMillis(int indexRestorationLatencyMillis) { + mNativeIndexRestorationLatencyMillis = indexRestorationLatencyMillis; + return this; + } + + /** Sets time used to recover the schema store. */ + @NonNull + public Builder setSchemaStoreRecoveryLatencyMillis(int schemaStoreRecoveryLatencyMillis) { + mNativeSchemaStoreRecoveryLatencyMillis = schemaStoreRecoveryLatencyMillis; + return this; + } + + /** + * Sets Native Document Store Data status. status is defined in + * external/icing/proto/icing/proto/logging.proto + */ + @NonNull + public Builder setDocumentStoreDataStatus( + @DocumentStoreDataStatus int documentStoreDataStatus) { + mNativeDocumentStoreDataStatus = documentStoreDataStatus; + return this; + } + + /** + * Sets number of documents currently in document store. Those may include alive, deleted, + * and expired documents. + */ + @NonNull + public Builder setDocumentCount(int numDocuments) { + mNativeNumDocuments = numDocuments; + return this; + } + + /** Sets number of schema types currently in the schema store. */ + @NonNull + public Builder setSchemaTypeCount(int numSchemaTypes) { + mNativeNumSchemaTypes = numSchemaTypes; + return this; + } + + /** + * Constructs a new {@link InitializeStats} from the contents of this {@link + * InitializeStats.Builder} + */ + @NonNull + public InitializeStats build() { + return new InitializeStats(/* builder= */ this); + } + } +} diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/SearchStats.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/SearchStats.java new file mode 100644 index 000000000000..7b22b2f23142 --- /dev/null +++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/SearchStats.java @@ -0,0 +1,460 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.server.appsearch.external.localstorage.stats; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.app.appsearch.AppSearchResult; +import android.app.appsearch.SearchSpec; + +import com.android.internal.util.Preconditions; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Objects; + +/** + * Class holds detailed stats for {@link android.app.appsearch.AppSearchSession#search(String, + * SearchSpec)} + * + * @hide + */ +public final class SearchStats { + @IntDef( + value = { + // Searches apps' own documents. + VISIBILITY_SCOPE_LOCAL, + // Searches the global documents. Including platform surfaceable and 3p-access. + VISIBILITY_SCOPE_GLOBAL, + // TODO(b/173532925) Add THIRD_PARTY_ACCESS once we can distinguish platform + // surfaceable from 3p access(right both of them are categorized as + // VISIBILITY_SCOPE_GLOBAL) + }) + @Retention(RetentionPolicy.SOURCE) + public @interface VisibilityScope {} + + // Searches apps' own documents. + public static final int VISIBILITY_SCOPE_LOCAL = 1; + // Searches the global documents. Including platform surfaceable and 3p-access. + public static final int VISIBILITY_SCOPE_GLOBAL = 2; + + @NonNull private final String mPackageName; + @Nullable private final String mDatabase; + /** + * The status code returned by {@link AppSearchResult#getResultCode()} for the call or internal + * state. + */ + @AppSearchResult.ResultCode private final int mStatusCode; + + private final int mTotalLatencyMillis; + /** Time used to rewrite the search spec. */ + private final int mRewriteSearchSpecLatencyMillis; + /** Time used to rewrite the search results. */ + private final int mRewriteSearchResultLatencyMillis; + /** Defines the scope the query is searching over */ + @VisibilityScope private final int mVisibilityScope; + /** Overall time used for the native function call. */ + private final int mNativeLatencyMillis; + /** Number of terms in the query string. */ + private final int mNativeNumTerms; + /** Length of the query string. */ + private final int mNativeQueryLength; + /** Number of namespaces filtered. */ + private final int mNativeNumNamespacesFiltered; + /** Number of schema types filtered. */ + private final int mNativeNumSchemaTypesFiltered; + /** The requested number of results in one page. */ + private final int mNativeRequestedPageSize; + /** The actual number of results returned in the current page. */ + private final int mNativeNumResultsReturnedCurrentPage; + /** + * Whether the function call is querying the first page. If it's not, Icing will fetch the + * results from cache so that some steps may be skipped. + */ + private final boolean mNativeIsFirstPage; + /** + * Time used to parse the query, including 2 parts: tokenizing and transforming tokens into an + * iterator tree. + */ + private final int mNativeParseQueryLatencyMillis; + /** Strategy of scoring and ranking. */ + @SearchSpec.RankingStrategy private final int mNativeRankingStrategy; + /** Number of documents scored. */ + private final int mNativeNumDocumentsScored; + /** Time used to score the raw results. */ + private final int mNativeScoringLatencyMillis; + /** Time used to rank the scored results. */ + private final int mNativeRankingLatencyMillis; + /** + * Time used to fetch the document protos. Note that it includes the time to snippet if {@link + * SearchStats#mNativeNumResultsWithSnippets} is greater than 0. + */ + private final int mNativeDocumentRetrievingLatencyMillis; + /** How many snippets are calculated. */ + private final int mNativeNumResultsWithSnippets; + + SearchStats(@NonNull Builder builder) { + Objects.requireNonNull(builder); + mPackageName = builder.mPackageName; + mDatabase = builder.mDatabase; + mStatusCode = builder.mStatusCode; + mTotalLatencyMillis = builder.mTotalLatencyMillis; + mRewriteSearchSpecLatencyMillis = builder.mRewriteSearchSpecLatencyMillis; + mRewriteSearchResultLatencyMillis = builder.mRewriteSearchResultLatencyMillis; + mVisibilityScope = builder.mVisibilityScope; + mNativeLatencyMillis = builder.mNativeLatencyMillis; + mNativeNumTerms = builder.mNativeNumTerms; + mNativeQueryLength = builder.mNativeQueryLength; + mNativeNumNamespacesFiltered = builder.mNativeNumNamespacesFiltered; + mNativeNumSchemaTypesFiltered = builder.mNativeNumSchemaTypesFiltered; + mNativeRequestedPageSize = builder.mNativeRequestedPageSize; + mNativeNumResultsReturnedCurrentPage = builder.mNativeNumResultsReturnedCurrentPage; + mNativeIsFirstPage = builder.mNativeIsFirstPage; + mNativeParseQueryLatencyMillis = builder.mNativeParseQueryLatencyMillis; + mNativeRankingStrategy = builder.mNativeRankingStrategy; + mNativeNumDocumentsScored = builder.mNativeNumDocumentsScored; + mNativeScoringLatencyMillis = builder.mNativeScoringLatencyMillis; + mNativeRankingLatencyMillis = builder.mNativeRankingLatencyMillis; + mNativeNumResultsWithSnippets = builder.mNativeNumResultsWithSnippets; + mNativeDocumentRetrievingLatencyMillis = builder.mNativeDocumentRetrievingLatencyMillis; + } + + /** Returns the package name of the session. */ + @NonNull + public String getPackageName() { + return mPackageName; + } + + /** + * Returns the database name of the session. + * + * @return database name used by the session. {@code null} if and only if it is a global + * search(visibilityScope is {@link SearchStats#VISIBILITY_SCOPE_GLOBAL}). + */ + @Nullable + public String getDatabase() { + return mDatabase; + } + + /** Returns status of the search. */ + @AppSearchResult.ResultCode + public int getStatusCode() { + return mStatusCode; + } + + /** Returns the total latency of the search. */ + public int getTotalLatencyMillis() { + return mTotalLatencyMillis; + } + + /** Returns how much time spent on rewriting the {@link SearchSpec}. */ + public int getRewriteSearchSpecLatencyMillis() { + return mRewriteSearchSpecLatencyMillis; + } + + /** Returns how much time spent on rewriting the {@link android.app.appsearch.SearchResult}. */ + public int getRewriteSearchResultLatencyMillis() { + return mRewriteSearchResultLatencyMillis; + } + + /** Returns the visibility scope of the search. */ + @VisibilityScope + public int getVisibilityScope() { + return mVisibilityScope; + } + + /** Returns how much time spent on the native calls. */ + public int getNativeLatencyMillis() { + return mNativeLatencyMillis; + } + + /** Returns number of terms in the search string. */ + public int getTermCount() { + return mNativeNumTerms; + } + + /** Returns the length of the search string. */ + public int getQueryLength() { + return mNativeQueryLength; + } + + /** Returns number of namespaces filtered. */ + public int getFilteredNamespaceCount() { + return mNativeNumNamespacesFiltered; + } + + /** Returns number of schema types filtered. */ + public int getFilteredSchemaTypeCount() { + return mNativeNumSchemaTypesFiltered; + } + + /** Returns the requested number of results in one page. */ + public int getRequestedPageSize() { + return mNativeRequestedPageSize; + } + + /** Returns the actual number of results returned in the current page. */ + public int getCurrentPageReturnedResultCount() { + return mNativeNumResultsReturnedCurrentPage; + } + + // TODO(b/185184738) Make it an integer to show how many pages having been returned. + /** Returns whether the function call is querying the first page. */ + public boolean isFirstPage() { + return mNativeIsFirstPage; + } + + /** + * Returns time used to parse the query, including 2 parts: tokenizing and transforming tokens + * into an iterator tree. + */ + public int getParseQueryLatencyMillis() { + return mNativeParseQueryLatencyMillis; + } + + /** Returns strategy of scoring and ranking. */ + @SearchSpec.RankingStrategy + public int getRankingStrategy() { + return mNativeRankingStrategy; + } + + /** Returns number of documents scored. */ + public int getScoredDocumentCount() { + return mNativeNumDocumentsScored; + } + + /** Returns time used to score the raw results. */ + public int getScoringLatencyMillis() { + return mNativeScoringLatencyMillis; + } + + /** Returns time used to rank the scored results. */ + public int getRankingLatencyMillis() { + return mNativeRankingLatencyMillis; + } + + /** + * Returns time used to fetch the document protos. Note that it includes the time to snippet if + * {@link SearchStats#mNativeNumResultsWithSnippets} is not zero. + */ + public int getDocumentRetrievingLatencyMillis() { + return mNativeDocumentRetrievingLatencyMillis; + } + + /** Returns the number of the results in the page returned were snippeted. */ + public int getResultWithSnippetsCount() { + return mNativeNumResultsWithSnippets; + } + + /** Builder for {@link SearchStats} */ + public static class Builder { + @NonNull final String mPackageName; + @Nullable String mDatabase; + @AppSearchResult.ResultCode int mStatusCode; + int mTotalLatencyMillis; + int mRewriteSearchSpecLatencyMillis; + int mRewriteSearchResultLatencyMillis; + int mVisibilityScope; + int mNativeLatencyMillis; + int mNativeNumTerms; + int mNativeQueryLength; + int mNativeNumNamespacesFiltered; + int mNativeNumSchemaTypesFiltered; + int mNativeRequestedPageSize; + int mNativeNumResultsReturnedCurrentPage; + boolean mNativeIsFirstPage; + int mNativeParseQueryLatencyMillis; + int mNativeRankingStrategy; + int mNativeNumDocumentsScored; + int mNativeScoringLatencyMillis; + int mNativeRankingLatencyMillis; + int mNativeNumResultsWithSnippets; + int mNativeDocumentRetrievingLatencyMillis; + + /** + * Constructor + * + * @param visibilityScope scope for the corresponding search. + * @param packageName name of the calling package. + */ + public Builder(@VisibilityScope int visibilityScope, @NonNull String packageName) { + mVisibilityScope = visibilityScope; + mPackageName = Objects.requireNonNull(packageName); + } + + /** Sets the database used by the session. */ + @NonNull + public Builder setDatabase(@NonNull String database) { + mDatabase = Objects.requireNonNull(database); + return this; + } + + /** Sets the status of the search. */ + @NonNull + public Builder setStatusCode(@AppSearchResult.ResultCode int statusCode) { + mStatusCode = statusCode; + return this; + } + + /** Sets total latency for the search. */ + @NonNull + public Builder setTotalLatencyMillis(int totalLatencyMillis) { + mTotalLatencyMillis = totalLatencyMillis; + return this; + } + + /** Sets time used to rewrite the search spec. */ + @NonNull + public Builder setRewriteSearchSpecLatencyMillis(int rewriteSearchSpecLatencyMillis) { + mRewriteSearchSpecLatencyMillis = rewriteSearchSpecLatencyMillis; + return this; + } + + /** Sets time used to rewrite the search results. */ + @NonNull + public Builder setRewriteSearchResultLatencyMillis(int rewriteSearchResultLatencyMillis) { + mRewriteSearchResultLatencyMillis = rewriteSearchResultLatencyMillis; + return this; + } + + /** Sets overall time used for the native function calls. */ + @NonNull + public Builder setNativeLatencyMillis(int nativeLatencyMillis) { + mNativeLatencyMillis = nativeLatencyMillis; + return this; + } + + /** Sets number of terms in the search string. */ + @NonNull + public Builder setTermCount(int termCount) { + mNativeNumTerms = termCount; + return this; + } + + /** Sets length of the search string. */ + @NonNull + public Builder setQueryLength(int queryLength) { + mNativeQueryLength = queryLength; + return this; + } + + /** Sets number of namespaces filtered. */ + @NonNull + public Builder setFilteredNamespaceCount(int filteredNamespaceCount) { + mNativeNumNamespacesFiltered = filteredNamespaceCount; + return this; + } + + /** Sets number of schema types filtered. */ + @NonNull + public Builder setFilteredSchemaTypeCount(int filteredSchemaTypeCount) { + mNativeNumSchemaTypesFiltered = filteredSchemaTypeCount; + return this; + } + + /** Sets the requested number of results in one page. */ + @NonNull + public Builder setRequestedPageSize(int requestedPageSize) { + mNativeRequestedPageSize = requestedPageSize; + return this; + } + + /** Sets the actual number of results returned in the current page. */ + @NonNull + public Builder setCurrentPageReturnedResultCount(int currentPageReturnedResultCount) { + mNativeNumResultsReturnedCurrentPage = currentPageReturnedResultCount; + return this; + } + + /** + * Sets whether the function call is querying the first page. If it's not, Icing will fetch + * the results from cache so that some steps may be skipped. + */ + @NonNull + public Builder setIsFirstPage(boolean nativeIsFirstPage) { + mNativeIsFirstPage = nativeIsFirstPage; + return this; + } + + /** + * Sets time used to parse the query, including 2 parts: tokenizing and transforming tokens + * into an iterator tree. + */ + @NonNull + public Builder setParseQueryLatencyMillis(int parseQueryLatencyMillis) { + mNativeParseQueryLatencyMillis = parseQueryLatencyMillis; + return this; + } + + /** Sets strategy of scoring and ranking. */ + @NonNull + public Builder setRankingStrategy(@SearchSpec.RankingStrategy int rankingStrategy) { + mNativeRankingStrategy = rankingStrategy; + return this; + } + + /** Sets number of documents scored. */ + @NonNull + public Builder setScoredDocumentCount(int scoredDocumentCount) { + mNativeNumDocumentsScored = scoredDocumentCount; + return this; + } + + /** Sets time used to score the raw results. */ + @NonNull + public Builder setScoringLatencyMillis(int scoringLatencyMillis) { + mNativeScoringLatencyMillis = scoringLatencyMillis; + return this; + } + + /** Sets time used to rank the scored results. */ + @NonNull + public Builder setRankingLatencyMillis(int rankingLatencyMillis) { + mNativeRankingLatencyMillis = rankingLatencyMillis; + return this; + } + + /** Sets time used to fetch the document protos. */ + @NonNull + public Builder setDocumentRetrievingLatencyMillis(int documentRetrievingLatencyMillis) { + mNativeDocumentRetrievingLatencyMillis = documentRetrievingLatencyMillis; + return this; + } + + /** Sets how many snippets are calculated. */ + @NonNull + public Builder setResultWithSnippetsCount(int resultWithSnippetsCount) { + mNativeNumResultsWithSnippets = resultWithSnippetsCount; + return this; + } + + /** + * Constructs a new {@link SearchStats} from the contents of this {@link + * SearchStats.Builder}. + */ + @NonNull + public SearchStats build() { + if (mDatabase == null) { + Preconditions.checkState( + mVisibilityScope != SearchStats.VISIBILITY_SCOPE_LOCAL, + "database can not be null if visibilityScope is local."); + } + + return new SearchStats(/* builder= */ this); + } + } +} diff --git a/apex/appsearch/service/java/com/android/server/appsearch/stats/PlatformLogger.java b/apex/appsearch/service/java/com/android/server/appsearch/stats/PlatformLogger.java index 731ab35bf367..88f238e91e45 100644 --- a/apex/appsearch/service/java/com/android/server/appsearch/stats/PlatformLogger.java +++ b/apex/appsearch/service/java/com/android/server/appsearch/stats/PlatformLogger.java @@ -31,7 +31,9 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.FrameworkStatsLog; import com.android.server.appsearch.external.localstorage.AppSearchLogger; import com.android.server.appsearch.external.localstorage.stats.CallStats; +import com.android.server.appsearch.external.localstorage.stats.InitializeStats; import com.android.server.appsearch.external.localstorage.stats.PutDocumentStats; +import com.android.server.appsearch.external.localstorage.stats.SearchStats; import java.io.UnsupportedEncodingException; import java.security.MessageDigest; @@ -189,6 +191,16 @@ public final class PlatformLogger implements AppSearchLogger { } } + @Override + public void logStats(@NonNull InitializeStats stats) throws AppSearchException { + // TODO(b/173532925): Implement + } + + @Override + public void logStats(@NonNull SearchStats stats) throws AppSearchException { + // TODO(b/173532925): Implement + } + /** * Removes cached UID for package. * diff --git a/apex/appsearch/synced_jetpack_changeid.txt b/apex/appsearch/synced_jetpack_changeid.txt index ce0ebe62f65b..10bba13a8e2f 100644 --- a/apex/appsearch/synced_jetpack_changeid.txt +++ b/apex/appsearch/synced_jetpack_changeid.txt @@ -1 +1 @@ -I06df2c636d26419e653c5d8c9e7d15449da6816e +I19dac52031c47099f621eced9f148931f1021f25 diff --git a/services/tests/servicestests/src/com/android/server/appsearch/AppSearchImplPlatformTest.java b/services/tests/servicestests/src/com/android/server/appsearch/AppSearchImplPlatformTest.java index b552fd5e8718..79e5865abd82 100644 --- a/services/tests/servicestests/src/com/android/server/appsearch/AppSearchImplPlatformTest.java +++ b/services/tests/servicestests/src/com/android/server/appsearch/AppSearchImplPlatformTest.java @@ -70,7 +70,8 @@ public class AppSearchImplPlatformTest { mTemporaryFolder.newFolder(), mContext, mContext.getUserId(), - mContext.getPackageName()); + mContext.getPackageName(), + /*logger=*/ null); mGlobalQuerierUid = mContext.getPackageManager().getPackageUid(mContext.getPackageName(), /*flags=*/ 0); } @@ -117,9 +118,8 @@ public class AppSearchImplPlatformTest { // No query filters specified, global query can retrieve all documents. SearchSpec searchSpec = new SearchSpec.Builder().setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY).build(); - SearchResultPage searchResultPage = - mAppSearchImpl.globalQuery( - "", searchSpec, mContext.getPackageName(), mGlobalQuerierUid); + SearchResultPage searchResultPage = mAppSearchImpl.globalQuery( + "", searchSpec, mContext.getPackageName(), mGlobalQuerierUid, /*logger=*/ null); assertThat(searchResultPage.getResults()).hasSize(2); // Document2 will be first since it got indexed later and has a "better", aka more recent @@ -174,9 +174,8 @@ public class AppSearchImplPlatformTest { .setTermMatch(SearchSpec.TERM_MATCH_PREFIX) .addFilterPackageNames("package1") .build(); - SearchResultPage searchResultPage = - mAppSearchImpl.globalQuery( - "", searchSpec, mContext.getPackageName(), mGlobalQuerierUid); + SearchResultPage searchResultPage = mAppSearchImpl.globalQuery( + "", searchSpec, mContext.getPackageName(), mGlobalQuerierUid, /*logger=*/ null); assertThat(searchResultPage.getResults()).hasSize(1); assertThat(searchResultPage.getResults().get(0).getGenericDocument()).isEqualTo(document1); @@ -186,9 +185,8 @@ public class AppSearchImplPlatformTest { .setTermMatch(SearchSpec.TERM_MATCH_PREFIX) .addFilterPackageNames("package2") .build(); - searchResultPage = - mAppSearchImpl.globalQuery( - "", searchSpec, mContext.getPackageName(), mGlobalQuerierUid); + searchResultPage = mAppSearchImpl.globalQuery( + "", searchSpec, mContext.getPackageName(), mGlobalQuerierUid, /*logger=*/ null); assertThat(searchResultPage.getResults()).hasSize(1); assertThat(searchResultPage.getResults().get(0).getGenericDocument()).isEqualTo(document2); } diff --git a/services/tests/servicestests/src/com/android/server/appsearch/VisibilityStoreTest.java b/services/tests/servicestests/src/com/android/server/appsearch/VisibilityStoreTest.java index 11ae76b94495..28955d6e727f 100644 --- a/services/tests/servicestests/src/com/android/server/appsearch/VisibilityStoreTest.java +++ b/services/tests/servicestests/src/com/android/server/appsearch/VisibilityStoreTest.java @@ -67,7 +67,8 @@ public class VisibilityStoreTest { mTemporaryFolder.newFolder(), mContext, mContext.getUserId(), - /*globalQuerierPackage=*/ mContext.getPackageName()); + /*globalQuerierPackage=*/ mContext.getPackageName(), + /*logger=*/ null); mGlobalQuerierUid = mContext.getPackageManager().getPackageUid(mContext.getPackageName(), /*flags=*/ 0); @@ -163,7 +164,8 @@ public class VisibilityStoreTest { mTemporaryFolder.newFolder(), mContext, mContext.getUserId(), - /*globalQuerierPackage=*/ mContext.getPackageName()); + /*globalQuerierPackage=*/ mContext.getPackageName(), + /*logger=*/ null); VisibilityStore visibilityStore = appSearchImpl.getVisibilityStoreLocked(); // Use some arbitrary callerUid. If we can't find the global querier's uid though, diff --git a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java index 9a7cf803763d..b36720303a55 100644 --- a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java +++ b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java @@ -82,7 +82,8 @@ public class AppSearchImplTest { mTemporaryFolder.newFolder(), context, VisibilityStore.NO_OP_USER_ID, - /*globalQuerierPackage=*/ context.getPackageName()); + /*globalQuerierPackage=*/ context.getPackageName(), + /*logger=*/ null); } // TODO(b/175430168) add test to verify reset is working properly. @@ -604,7 +605,7 @@ public class AppSearchImplTest { SearchSpec searchSpec = new SearchSpec.Builder().setTermMatch(TermMatchType.Code.PREFIX_VALUE).build(); SearchResultPage searchResultPage = - mAppSearchImpl.query("package", "EmptyDatabase", "", searchSpec); + mAppSearchImpl.query("package", "EmptyDatabase", "", searchSpec, /*logger=*/ null); assertThat(searchResultPage.getResults()).isEmpty(); } @@ -647,7 +648,7 @@ public class AppSearchImplTest { SearchSpec searchSpec = new SearchSpec.Builder().setTermMatch(TermMatchType.Code.PREFIX_VALUE).build(); SearchResultPage searchResultPage = - mAppSearchImpl.query("package2", "database2", "", searchSpec); + mAppSearchImpl.query("package2", "database2", "", searchSpec, /*logger=*/ null); assertThat(searchResultPage.getResults()).isEmpty(); // Insert package2 document @@ -655,7 +656,9 @@ public class AppSearchImplTest { mAppSearchImpl.putDocument("package2", "database2", document, /*logger=*/ null); // No query filters specified. package2 should only get its own documents back. - searchResultPage = mAppSearchImpl.query("package2", "database2", "", searchSpec); + searchResultPage = + mAppSearchImpl.query("package2", "database2", "", searchSpec, /*logger= + */ null); assertThat(searchResultPage.getResults()).hasSize(1); assertThat(searchResultPage.getResults().get(0).getGenericDocument()).isEqualTo(document); } @@ -703,7 +706,7 @@ public class AppSearchImplTest { .addFilterPackageNames("package1") .build(); SearchResultPage searchResultPage = - mAppSearchImpl.query("package2", "database2", "", searchSpec); + mAppSearchImpl.query("package2", "database2", "", searchSpec, /*logger=*/ null); assertThat(searchResultPage.getResults()).isEmpty(); // Insert package2 document @@ -716,7 +719,9 @@ public class AppSearchImplTest { .setTermMatch(TermMatchType.Code.PREFIX_VALUE) .addFilterPackageNames("package2") .build(); - searchResultPage = mAppSearchImpl.query("package2", "database2", "", searchSpec); + searchResultPage = + mAppSearchImpl.query("package2", "database2", "", searchSpec, /*logger= + */ null); assertThat(searchResultPage.getResults()).hasSize(1); assertThat(searchResultPage.getResults().get(0).getGenericDocument()).isEqualTo(document); } @@ -727,7 +732,11 @@ public class AppSearchImplTest { new SearchSpec.Builder().setTermMatch(TermMatchType.Code.PREFIX_VALUE).build(); SearchResultPage searchResultPage = mAppSearchImpl.globalQuery( - "", searchSpec, /*callerPackageName=*/ "", /*callerUid=*/ 0); + "", + searchSpec, + /*callerPackageName=*/ "", + /*callerUid=*/ 0, + /*logger=*/ null); assertThat(searchResultPage.getResults()).isEmpty(); } @@ -1033,7 +1042,12 @@ public class AppSearchImplTest { SearchSpec searchSpec = new SearchSpec.Builder().setTermMatch(TermMatchType.Code.PREFIX_VALUE).build(); SearchResultPage searchResultPage = - mAppSearchImpl.query("package", "database", /*queryExpression=*/ "", searchSpec); + mAppSearchImpl.query( + "package", + "database", + /*queryExpression=*/ "", + searchSpec, + /*logger=*/ null); assertThat(searchResultPage.getResults()).hasSize(1); assertThat(searchResultPage.getResults().get(0).getGenericDocument()).isEqualTo(document); @@ -1042,7 +1056,12 @@ public class AppSearchImplTest { // Verify the document is cleared. searchResultPage = - mAppSearchImpl.query("package2", "database2", /*queryExpression=*/ "", searchSpec); + mAppSearchImpl.query( + "package2", + "database2", + /*queryExpression=*/ "", + searchSpec, + /*logger=*/ null); assertThat(searchResultPage.getResults()).isEmpty(); // Verify the schema is cleared. @@ -1244,7 +1263,8 @@ public class AppSearchImplTest { new SearchSpec.Builder() .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY) .setRankingStrategy(SearchSpec.RANKING_STRATEGY_USAGE_COUNT) - .build()) + .build(), + /*logger=*/ null) .getResults(); assertThat(page).hasSize(2); assertThat(page.get(0).getGenericDocument().getId()).isEqualTo("id1"); @@ -1262,7 +1282,8 @@ public class AppSearchImplTest { .setRankingStrategy( SearchSpec .RANKING_STRATEGY_USAGE_LAST_USED_TIMESTAMP) - .build()) + .build(), + /*logger=*/ null) .getResults(); assertThat(page).hasSize(2); assertThat(page.get(0).getGenericDocument().getId()).isEqualTo("id2"); @@ -1279,7 +1300,8 @@ public class AppSearchImplTest { .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY) .setRankingStrategy( SearchSpec.RANKING_STRATEGY_SYSTEM_USAGE_COUNT) - .build()) + .build(), + /*logger=*/ null) .getResults(); assertThat(page).hasSize(2); assertThat(page.get(0).getGenericDocument().getId()).isEqualTo("id2"); @@ -1297,7 +1319,8 @@ public class AppSearchImplTest { .setRankingStrategy( SearchSpec .RANKING_STRATEGY_SYSTEM_USAGE_LAST_USED_TIMESTAMP) - .build()) + .build(), + /*logger=*/ null) .getResults(); assertThat(page).hasSize(2); assertThat(page.get(0).getGenericDocument().getId()).isEqualTo("id1"); @@ -1499,7 +1522,9 @@ public class AppSearchImplTest { mTemporaryFolder.newFolder(), context, VisibilityStore.NO_OP_USER_ID, - /*globalQuerierPackage=*/ ""); + /*globalQuerierPackage=*/ "", + /*logger + =*/ null); // Initial check that we could do something at first. List<AppSearchSchema> schemas = @@ -1561,7 +1586,8 @@ public class AppSearchImplTest { "query", new SearchSpec.Builder() .setTermMatch(TermMatchType.Code.PREFIX_VALUE) - .build()); + .build(), + /*logger=*/ null); }); expectThrows( @@ -1573,7 +1599,8 @@ public class AppSearchImplTest { .setTermMatch(TermMatchType.Code.PREFIX_VALUE) .build(), "package", - /*callerUid=*/ 1); + /*callerUid=*/ 1, + /*logger=*/ null); }); expectThrows( @@ -1647,7 +1674,8 @@ public class AppSearchImplTest { appsearchDir, context, VisibilityStore.NO_OP_USER_ID, - /*globalQuerierPackage=*/ ""); + /*globalQuerierPackage=*/ "", + /*logger=*/ null); List<AppSearchSchema> schemas = Collections.singletonList(new AppSearchSchema.Builder("type").build()); @@ -1677,7 +1705,8 @@ public class AppSearchImplTest { appsearchDir, context, VisibilityStore.NO_OP_USER_ID, - /*globalQuerierPackage=*/ ""); + /*globalQuerierPackage=*/ "", + /*logger=*/ null); getResult = appSearchImpl2.getDocument( "package", "database", "namespace1", "id1", Collections.emptyMap()); @@ -1694,7 +1723,8 @@ public class AppSearchImplTest { appsearchDir, context, VisibilityStore.NO_OP_USER_ID, - /*globalQuerierPackage=*/ ""); + /*globalQuerierPackage=*/ "", + /*logger=*/ null); List<AppSearchSchema> schemas = Collections.singletonList(new AppSearchSchema.Builder("type").build()); @@ -1748,7 +1778,8 @@ public class AppSearchImplTest { appsearchDir, context, VisibilityStore.NO_OP_USER_ID, - /*globalQuerierPackage=*/ ""); + /*globalQuerierPackage=*/ "", + /*logger=*/ null); expectThrows( AppSearchException.class, () -> @@ -1774,7 +1805,8 @@ public class AppSearchImplTest { appsearchDir, context, VisibilityStore.NO_OP_USER_ID, - /*globalQuerierPackage=*/ ""); + /*globalQuerierPackage=*/ "", + /*logger=*/ null); List<AppSearchSchema> schemas = Collections.singletonList(new AppSearchSchema.Builder("type").build()); @@ -1835,7 +1867,8 @@ public class AppSearchImplTest { appsearchDir, context, VisibilityStore.NO_OP_USER_ID, - /*globalQuerierPackage=*/ ""); + /*globalQuerierPackage=*/ "", + /*logger=*/ null); expectThrows( AppSearchException.class, () -> diff --git a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchLoggerTest.java b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchLoggerTest.java index 1194e76ee2b5..5989bb65bd39 100644 --- a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchLoggerTest.java +++ b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchLoggerTest.java @@ -23,13 +23,21 @@ import android.annotation.Nullable; import android.app.appsearch.AppSearchResult; import android.app.appsearch.AppSearchSchema; import android.app.appsearch.GenericDocument; +import android.app.appsearch.SearchResultPage; +import android.app.appsearch.SearchSpec; import android.content.Context; import androidx.test.core.app.ApplicationProvider; import com.android.server.appsearch.external.localstorage.stats.CallStats; +import com.android.server.appsearch.external.localstorage.stats.InitializeStats; import com.android.server.appsearch.external.localstorage.stats.PutDocumentStats; +import com.android.server.appsearch.external.localstorage.stats.SearchStats; +import com.android.server.appsearch.proto.InitializeStatsProto; import com.android.server.appsearch.proto.PutDocumentStatsProto; +import com.android.server.appsearch.proto.QueryStatsProto; +import com.android.server.appsearch.proto.ScoringSpecProto; +import com.android.server.appsearch.proto.TermMatchType; import org.junit.Before; import org.junit.Rule; @@ -54,23 +62,93 @@ public class AppSearchLoggerTest { mTemporaryFolder.newFolder(), context, VisibilityStore.NO_OP_USER_ID, - /*globalQuerierPackage=*/ context.getPackageName()); + /*globalQuerierPackage=*/ context.getPackageName(), + /*logger=*/ null); mLogger = new TestLogger(); } // Test only not thread safe. public class TestLogger implements AppSearchLogger { + @Nullable CallStats mCallStats; @Nullable PutDocumentStats mPutDocumentStats; + @Nullable InitializeStats mInitializeStats; + @Nullable SearchStats mSearchStats; @Override public void logStats(@NonNull CallStats stats) { - throw new UnsupportedOperationException(); + mCallStats = stats; } @Override public void logStats(@NonNull PutDocumentStats stats) { mPutDocumentStats = stats; } + + @Override + public void logStats(@NonNull InitializeStats stats) { + mInitializeStats = stats; + } + + @Override + public void logStats(@NonNull SearchStats stats) { + mSearchStats = stats; + } + } + + @Test + public void testAppSearchLoggerHelper_testCopyNativeStats_initialize() { + int nativeLatencyMillis = 3; + int nativeDocumentStoreRecoveryCause = InitializeStatsProto.RecoveryCause.DATA_LOSS_VALUE; + int nativeIndexRestorationCause = + InitializeStatsProto.RecoveryCause.INCONSISTENT_WITH_GROUND_TRUTH_VALUE; + int nativeSchemaStoreRecoveryCause = + InitializeStatsProto.RecoveryCause.TOTAL_CHECKSUM_MISMATCH_VALUE; + int nativeDocumentStoreRecoveryLatencyMillis = 7; + int nativeIndexRestorationLatencyMillis = 8; + int nativeSchemaStoreRecoveryLatencyMillis = 9; + int nativeDocumentStoreDataStatus = + InitializeStatsProto.DocumentStoreDataStatus.NO_DATA_LOSS_VALUE; + int nativeNumDocuments = 11; + int nativeNumSchemaTypes = 12; + InitializeStatsProto.Builder nativeInitBuilder = + InitializeStatsProto.newBuilder() + .setLatencyMs(nativeLatencyMillis) + .setDocumentStoreRecoveryCause( + InitializeStatsProto.RecoveryCause.forNumber( + nativeDocumentStoreRecoveryCause)) + .setIndexRestorationCause( + InitializeStatsProto.RecoveryCause.forNumber( + nativeIndexRestorationCause)) + .setSchemaStoreRecoveryCause( + InitializeStatsProto.RecoveryCause.forNumber( + nativeSchemaStoreRecoveryCause)) + .setDocumentStoreRecoveryLatencyMs(nativeDocumentStoreRecoveryLatencyMillis) + .setIndexRestorationLatencyMs(nativeIndexRestorationLatencyMillis) + .setSchemaStoreRecoveryLatencyMs(nativeSchemaStoreRecoveryLatencyMillis) + .setDocumentStoreDataStatus( + InitializeStatsProto.DocumentStoreDataStatus.forNumber( + nativeDocumentStoreDataStatus)) + .setNumDocuments(nativeNumDocuments) + .setNumSchemaTypes(nativeNumSchemaTypes); + InitializeStats.Builder initBuilder = new InitializeStats.Builder(); + + AppSearchLoggerHelper.copyNativeStats(nativeInitBuilder.build(), initBuilder); + + InitializeStats iStats = initBuilder.build(); + assertThat(iStats.getNativeLatencyMillis()).isEqualTo(nativeLatencyMillis); + assertThat(iStats.getDocumentStoreRecoveryCause()) + .isEqualTo(nativeDocumentStoreRecoveryCause); + assertThat(iStats.getIndexRestorationCause()).isEqualTo(nativeIndexRestorationCause); + assertThat(iStats.getSchemaStoreRecoveryCause()).isEqualTo(nativeSchemaStoreRecoveryCause); + assertThat(iStats.getDocumentStoreRecoveryLatencyMillis()) + .isEqualTo(nativeDocumentStoreRecoveryLatencyMillis); + assertThat(iStats.getIndexRestorationLatencyMillis()) + .isEqualTo(nativeIndexRestorationLatencyMillis); + assertThat(iStats.getSchemaStoreRecoveryLatencyMillis()) + .isEqualTo(nativeSchemaStoreRecoveryLatencyMillis); + assertThat(iStats.getDocumentStoreDataStatus()).isEqualTo(nativeDocumentStoreDataStatus); + assertThat(iStats.getDocumentCount()).isEqualTo(nativeNumDocuments); + assertThat(iStats.getSchemaTypeCount()).isEqualTo(nativeNumSchemaTypes); } @Test @@ -111,10 +189,97 @@ public class AppSearchLoggerTest { assertThat(pStats.getNativeExceededMaxNumTokens()).isEqualTo(nativeExceededMaxNumTokens); } + @Test + public void testAppSearchLoggerHelper_testCopyNativeStats_search() { + int nativeLatencyMillis = 4; + int nativeNumTerms = 5; + // TODO(b/185804196) query length needs to be added in the native stats. + // int nativeQueryLength = 6; + int nativeNumNamespacesFiltered = 7; + int nativeNumSchemaTypesFiltered = 8; + int nativeRequestedPageSize = 9; + int nativeNumResultsReturnedCurrentPage = 10; + boolean nativeIsFirstPage = true; + int nativeParseQueryLatencyMillis = 11; + int nativeRankingStrategy = ScoringSpecProto.RankingStrategy.Code.CREATION_TIMESTAMP_VALUE; + int nativeNumDocumentsScored = 13; + int nativeScoringLatencyMillis = 14; + int nativeRankingLatencyMillis = 15; + int nativeNumResultsWithSnippets = 16; + int nativeDocumentRetrievingLatencyMillis = 17; + QueryStatsProto nativeQueryStats = + QueryStatsProto.newBuilder() + .setLatencyMs(nativeLatencyMillis) + .setNumTerms(nativeNumTerms) + .setNumNamespacesFiltered(nativeNumNamespacesFiltered) + .setNumSchemaTypesFiltered(nativeNumSchemaTypesFiltered) + .setRequestedPageSize(nativeRequestedPageSize) + .setNumResultsReturnedCurrentPage(nativeNumResultsReturnedCurrentPage) + .setIsFirstPage(nativeIsFirstPage) + .setParseQueryLatencyMs(nativeParseQueryLatencyMillis) + .setRankingStrategy( + ScoringSpecProto.RankingStrategy.Code.forNumber( + nativeRankingStrategy)) + .setNumDocumentsScored(nativeNumDocumentsScored) + .setScoringLatencyMs(nativeScoringLatencyMillis) + .setRankingLatencyMs(nativeRankingLatencyMillis) + .setNumResultsWithSnippets(nativeNumResultsWithSnippets) + .setDocumentRetrievalLatencyMs(nativeDocumentRetrievingLatencyMillis) + .build(); + SearchStats.Builder qBuilder = + new SearchStats.Builder(SearchStats.VISIBILITY_SCOPE_LOCAL, "packageName") + .setDatabase("database"); + + AppSearchLoggerHelper.copyNativeStats(nativeQueryStats, qBuilder); + + SearchStats sStats = qBuilder.build(); + assertThat(sStats.getNativeLatencyMillis()).isEqualTo(nativeLatencyMillis); + assertThat(sStats.getTermCount()).isEqualTo(nativeNumTerms); + // assertThat(sStats.getNativeQueryLength()).isEqualTo(nativeQueryLength); + assertThat(sStats.getFilteredNamespaceCount()).isEqualTo(nativeNumNamespacesFiltered); + assertThat(sStats.getFilteredSchemaTypeCount()).isEqualTo(nativeNumSchemaTypesFiltered); + assertThat(sStats.getRequestedPageSize()).isEqualTo(nativeRequestedPageSize); + assertThat(sStats.getCurrentPageReturnedResultCount()) + .isEqualTo(nativeNumResultsReturnedCurrentPage); + assertThat(sStats.isFirstPage()).isTrue(); + assertThat(sStats.getParseQueryLatencyMillis()).isEqualTo(nativeParseQueryLatencyMillis); + assertThat(sStats.getRankingStrategy()).isEqualTo(nativeRankingStrategy); + assertThat(sStats.getScoredDocumentCount()).isEqualTo(nativeNumDocumentsScored); + assertThat(sStats.getScoringLatencyMillis()).isEqualTo(nativeScoringLatencyMillis); + assertThat(sStats.getRankingLatencyMillis()).isEqualTo(nativeRankingLatencyMillis); + assertThat(sStats.getResultWithSnippetsCount()).isEqualTo(nativeNumResultsWithSnippets); + assertThat(sStats.getDocumentRetrievingLatencyMillis()) + .isEqualTo(nativeDocumentRetrievingLatencyMillis); + } + // // Testing actual logging // @Test + public void testLoggingStats_initialize() throws Exception { + Context context = ApplicationProvider.getApplicationContext(); + + AppSearchImpl appSearchImpl = + AppSearchImpl.create( + mTemporaryFolder.newFolder(), + context, + VisibilityStore.NO_OP_USER_ID, + /*globalQuerierPackage=*/ context.getPackageName(), + mLogger); + + InitializeStats iStats = mLogger.mInitializeStats; + assertThat(iStats).isNotNull(); + assertThat(iStats.getStatusCode()).isEqualTo(AppSearchResult.RESULT_OK); + assertThat(iStats.getTotalLatencyMillis()).isGreaterThan(0); + assertThat(iStats.hasDeSync()).isFalse(); + assertThat(iStats.getNativeLatencyMillis()).isGreaterThan(0); + assertThat(iStats.getDocumentStoreDataStatus()) + .isEqualTo(InitializeStatsProto.DocumentStoreDataStatus.NO_DATA_LOSS_VALUE); + assertThat(iStats.getDocumentCount()).isEqualTo(0); + assertThat(iStats.getSchemaTypeCount()).isEqualTo(0); + } + + @Test public void testLoggingStats_putDocument() throws Exception { // Insert schema final String testPackageName = "testPackage"; @@ -141,4 +306,53 @@ public class AppSearchLoggerTest { // The rest of native stats have been tested in testCopyNativeStats assertThat(pStats.getNativeDocumentSizeBytes()).isGreaterThan(0); } + + @Test + public void testLoggingStats_search() throws Exception { + // Insert schema + final String testPackageName = "testPackage"; + final String testDatabase = "testDatabase"; + List<AppSearchSchema> schemas = + Collections.singletonList(new AppSearchSchema.Builder("type").build()); + mAppSearchImpl.setSchema( + testPackageName, + testDatabase, + schemas, + /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(), + /*schemasPackageAccessible=*/ Collections.emptyMap(), + /*forceOverride=*/ false, + /*version=*/ 0); + GenericDocument document = new GenericDocument.Builder<>("namespace", "id", "type").build(); + mAppSearchImpl.putDocument(testPackageName, testDatabase, document, mLogger); + + // No query filters specified. package2 should only get its own documents back. + SearchSpec searchSpec = + new SearchSpec.Builder().setTermMatch(TermMatchType.Code.PREFIX_VALUE).build(); + SearchResultPage searchResultPage = + mAppSearchImpl.query( + testPackageName, + testDatabase, + /*QueryExpression=*/ "", + searchSpec, + /*logger=*/ mLogger); + + assertThat(searchResultPage.getResults()).hasSize(1); + assertThat(searchResultPage.getResults().get(0).getGenericDocument()).isEqualTo(document); + + SearchStats sStats = mLogger.mSearchStats; + + assertThat(sStats).isNotNull(); + assertThat(sStats.getPackageName()).isEqualTo(testPackageName); + assertThat(sStats.getDatabase()).isEqualTo(testDatabase); + assertThat(sStats.getStatusCode()).isEqualTo(AppSearchResult.RESULT_OK); + assertThat(sStats.getTotalLatencyMillis()).isGreaterThan(0); + assertThat(sStats.getVisibilityScope()).isEqualTo(SearchStats.VISIBILITY_SCOPE_LOCAL); + assertThat(sStats.getTermCount()).isEqualTo(0); + // assertThat(sStats.getNativeQueryLength()).isEqualTo(0); + assertThat(sStats.getFilteredNamespaceCount()).isEqualTo(1); + assertThat(sStats.getFilteredSchemaTypeCount()).isEqualTo(1); + assertThat(sStats.getCurrentPageReturnedResultCount()).isEqualTo(1); + assertThat(sStats.isFirstPage()).isTrue(); + assertThat(sStats.getScoredDocumentCount()).isEqualTo(1); + } } diff --git a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/stats/AppSearchStatsTest.java b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/stats/AppSearchStatsTest.java index 8dbf249c4e96..5c7ccfc458b2 100644 --- a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/stats/AppSearchStatsTest.java +++ b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/stats/AppSearchStatsTest.java @@ -134,4 +134,135 @@ public class AppSearchStatsTest { assertThat(pStats.getNativeNumTokensIndexed()).isEqualTo(nativeNumTokensIndexed); assertThat(pStats.getNativeExceededMaxNumTokens()).isEqualTo(nativeExceededMaxNumTokens); } + + @Test + public void testAppSearchStats_InitializeStats() { + int prepareSchemaAndNamespacesLatencyMillis = 1; + int prepareVisibilityFileLatencyMillis = 2; + int nativeLatencyMillis = 3; + int nativeDocumentStoreRecoveryCause = 4; + int nativeIndexRestorationCause = 5; + int nativeSchemaStoreRecoveryCause = 6; + int nativeDocumentStoreRecoveryLatencyMillis = 7; + int nativeIndexRestorationLatencyMillis = 8; + int nativeSchemaStoreRecoveryLatencyMillis = 9; + int nativeDocumentStoreDataStatus = 10; + int nativeNumDocuments = 11; + int nativeNumSchemaTypes = 12; + + final InitializeStats.Builder iStatsBuilder = + new InitializeStats.Builder() + .setStatusCode(TEST_STATUS_CODE) + .setTotalLatencyMillis(TEST_TOTAL_LATENCY_MILLIS) + .setHasDeSync(/* hasDeSyncs= */ true) + .setPrepareSchemaAndNamespacesLatencyMillis( + prepareSchemaAndNamespacesLatencyMillis) + .setPrepareVisibilityStoreLatencyMillis(prepareVisibilityFileLatencyMillis) + .setNativeLatencyMillis(nativeLatencyMillis) + .setDocumentStoreRecoveryCause(nativeDocumentStoreRecoveryCause) + .setIndexRestorationCause(nativeIndexRestorationCause) + .setSchemaStoreRecoveryCause(nativeSchemaStoreRecoveryCause) + .setDocumentStoreRecoveryLatencyMillis( + nativeDocumentStoreRecoveryLatencyMillis) + .setIndexRestorationLatencyMillis(nativeIndexRestorationLatencyMillis) + .setSchemaStoreRecoveryLatencyMillis(nativeSchemaStoreRecoveryLatencyMillis) + .setDocumentStoreDataStatus(nativeDocumentStoreDataStatus) + .setDocumentCount(nativeNumDocuments) + .setSchemaTypeCount(nativeNumSchemaTypes); + final InitializeStats iStats = iStatsBuilder.build(); + + assertThat(iStats.getStatusCode()).isEqualTo(TEST_STATUS_CODE); + assertThat(iStats.getTotalLatencyMillis()).isEqualTo(TEST_TOTAL_LATENCY_MILLIS); + assertThat(iStats.hasDeSync()).isTrue(); + assertThat(iStats.getPrepareSchemaAndNamespacesLatencyMillis()) + .isEqualTo(prepareSchemaAndNamespacesLatencyMillis); + assertThat(iStats.getPrepareVisibilityStoreLatencyMillis()) + .isEqualTo(prepareVisibilityFileLatencyMillis); + assertThat(iStats.getNativeLatencyMillis()).isEqualTo(nativeLatencyMillis); + assertThat(iStats.getDocumentStoreRecoveryCause()) + .isEqualTo(nativeDocumentStoreRecoveryCause); + assertThat(iStats.getIndexRestorationCause()).isEqualTo(nativeIndexRestorationCause); + assertThat(iStats.getSchemaStoreRecoveryCause()).isEqualTo(nativeSchemaStoreRecoveryCause); + assertThat(iStats.getDocumentStoreRecoveryLatencyMillis()) + .isEqualTo(nativeDocumentStoreRecoveryLatencyMillis); + assertThat(iStats.getIndexRestorationLatencyMillis()) + .isEqualTo(nativeIndexRestorationLatencyMillis); + assertThat(iStats.getSchemaStoreRecoveryLatencyMillis()) + .isEqualTo(nativeSchemaStoreRecoveryLatencyMillis); + assertThat(iStats.getDocumentStoreDataStatus()).isEqualTo(nativeDocumentStoreDataStatus); + assertThat(iStats.getDocumentCount()).isEqualTo(nativeNumDocuments); + assertThat(iStats.getSchemaTypeCount()).isEqualTo(nativeNumSchemaTypes); + } + + @Test + public void testAppSearchStats_SearchStats() { + int rewriteSearchSpecLatencyMillis = 1; + int rewriteSearchResultLatencyMillis = 2; + int visibilityScope = SearchStats.VISIBILITY_SCOPE_LOCAL; + int nativeLatencyMillis = 4; + int nativeNumTerms = 5; + int nativeQueryLength = 6; + int nativeNumNamespacesFiltered = 7; + int nativeNumSchemaTypesFiltered = 8; + int nativeRequestedPageSize = 9; + int nativeNumResultsReturnedCurrentPage = 10; + boolean nativeIsFirstPage = true; + int nativeParseQueryLatencyMillis = 11; + int nativeRankingStrategy = 12; + int nativeNumDocumentsScored = 13; + int nativeScoringLatencyMillis = 14; + int nativeRankingLatencyMillis = 15; + int nativeNumResultsSnippeted = 16; + int nativeDocumentRetrievingLatencyMillis = 17; + final SearchStats.Builder sStatsBuilder = + new SearchStats.Builder(visibilityScope, TEST_PACKAGE_NAME) + .setDatabase(TEST_DATA_BASE) + .setStatusCode(TEST_STATUS_CODE) + .setTotalLatencyMillis(TEST_TOTAL_LATENCY_MILLIS) + .setRewriteSearchSpecLatencyMillis(rewriteSearchSpecLatencyMillis) + .setRewriteSearchResultLatencyMillis(rewriteSearchResultLatencyMillis) + .setNativeLatencyMillis(nativeLatencyMillis) + .setTermCount(nativeNumTerms) + .setQueryLength(nativeQueryLength) + .setFilteredNamespaceCount(nativeNumNamespacesFiltered) + .setFilteredSchemaTypeCount(nativeNumSchemaTypesFiltered) + .setRequestedPageSize(nativeRequestedPageSize) + .setCurrentPageReturnedResultCount(nativeNumResultsReturnedCurrentPage) + .setIsFirstPage(nativeIsFirstPage) + .setParseQueryLatencyMillis(nativeParseQueryLatencyMillis) + .setRankingStrategy(nativeRankingStrategy) + .setScoredDocumentCount(nativeNumDocumentsScored) + .setScoringLatencyMillis(nativeScoringLatencyMillis) + .setRankingLatencyMillis(nativeRankingLatencyMillis) + .setResultWithSnippetsCount(nativeNumResultsSnippeted) + .setDocumentRetrievingLatencyMillis(nativeDocumentRetrievingLatencyMillis); + final SearchStats sStats = sStatsBuilder.build(); + + assertThat(sStats.getPackageName()).isEqualTo(TEST_PACKAGE_NAME); + assertThat(sStats.getDatabase()).isEqualTo(TEST_DATA_BASE); + assertThat(sStats.getStatusCode()).isEqualTo(TEST_STATUS_CODE); + assertThat(sStats.getTotalLatencyMillis()).isEqualTo(TEST_TOTAL_LATENCY_MILLIS); + assertThat(sStats.getRewriteSearchSpecLatencyMillis()) + .isEqualTo(rewriteSearchSpecLatencyMillis); + assertThat(sStats.getRewriteSearchResultLatencyMillis()) + .isEqualTo(rewriteSearchResultLatencyMillis); + assertThat(sStats.getVisibilityScope()).isEqualTo(visibilityScope); + assertThat(sStats.getNativeLatencyMillis()).isEqualTo(nativeLatencyMillis); + assertThat(sStats.getTermCount()).isEqualTo(nativeNumTerms); + assertThat(sStats.getQueryLength()).isEqualTo(nativeQueryLength); + assertThat(sStats.getFilteredNamespaceCount()).isEqualTo(nativeNumNamespacesFiltered); + assertThat(sStats.getFilteredSchemaTypeCount()).isEqualTo(nativeNumSchemaTypesFiltered); + assertThat(sStats.getRequestedPageSize()).isEqualTo(nativeRequestedPageSize); + assertThat(sStats.getCurrentPageReturnedResultCount()) + .isEqualTo(nativeNumResultsReturnedCurrentPage); + assertThat(sStats.isFirstPage()).isTrue(); + assertThat(sStats.getParseQueryLatencyMillis()).isEqualTo(nativeParseQueryLatencyMillis); + assertThat(sStats.getRankingStrategy()).isEqualTo(nativeRankingStrategy); + assertThat(sStats.getScoredDocumentCount()).isEqualTo(nativeNumDocumentsScored); + assertThat(sStats.getScoringLatencyMillis()).isEqualTo(nativeScoringLatencyMillis); + assertThat(sStats.getRankingLatencyMillis()).isEqualTo(nativeRankingLatencyMillis); + assertThat(sStats.getResultWithSnippetsCount()).isEqualTo(nativeNumResultsSnippeted); + assertThat(sStats.getDocumentRetrievingLatencyMillis()) + .isEqualTo(nativeDocumentRetrievingLatencyMillis); + } } |
