From 43fe0b1b5ec8a1890902ef30e98e2c2523bfb5f9 Mon Sep 17 00:00:00 2001 From: Alexander Dorokhine Date: Fri, 19 Feb 2021 11:43:43 -0800 Subject: [PATCH] Update framework from jetpack. Changes included: * bdc86ce: Remove parameters from javadocs for methods that differ in framework. * c8e1f21: Add logger interface for AppSearch * 1de2a5a: Remove parameters from javadocs for methods that differ in framework. Bug: 173532925 Test: Presubmit Change-Id: Ia27d60be83b6ac3a6ad53ceb9bda58d5bd91bcb7 --- .../app/appsearch/GenericDocument.java | 6 +- .../app/appsearch/PutDocumentsRequest.java | 24 +- .../localstorage/AppSearchLogger.java | 43 ++++ .../AppSearchMigrationHelperImpl.java | 2 +- .../localstorage/stats/CallStats.java | 200 ++++++++++++++++ .../localstorage/stats/GeneralStats.java | 122 ++++++++++ .../localstorage/stats/PutDocumentStats.java | 219 ++++++++++++++++++ apex/appsearch/synced_jetpack_changeid.txt | 2 +- .../external/AppSearchSessionShim.java | 30 +-- .../external/GlobalSearchSessionShim.java | 6 +- .../testing/external/SearchResultsShim.java | 22 +- .../stats/AppSearchStatsTest.java | 124 ++++++++++ 12 files changed, 765 insertions(+), 35 deletions(-) create mode 100644 apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLogger.java create mode 100644 apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/CallStats.java create mode 100644 apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/GeneralStats.java create mode 100644 apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/PutDocumentStats.java create mode 100644 services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/stats/AppSearchStatsTest.java diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/GenericDocument.java b/apex/appsearch/framework/java/external/android/app/appsearch/GenericDocument.java index 138eb23148aff..72bb9f3d07c80 100644 --- a/apex/appsearch/framework/java/external/android/app/appsearch/GenericDocument.java +++ b/apex/appsearch/framework/java/external/android/app/appsearch/GenericDocument.java @@ -583,9 +583,9 @@ public class GenericDocument { * @param schemaType the {@link AppSearchSchema} type of the {@link GenericDocument}. The * provided {@code schemaType} must be defined using {@link AppSearchSession#setSchema} * prior to inserting a document of this {@code schemaType} into the AppSearch index - * using {@link AppSearchSession#put}. Otherwise, the document will - * be rejected by {@link AppSearchSession#put} with result code - * {@link AppSearchResult#RESULT_NOT_FOUND}. + * using {@link AppSearchSession#put}. Otherwise, the document will be rejected by + * {@link AppSearchSession#put} with result code {@link + * AppSearchResult#RESULT_NOT_FOUND}. */ @SuppressWarnings("unchecked") public Builder(@NonNull String uri, @NonNull String schemaType) { diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/PutDocumentsRequest.java b/apex/appsearch/framework/java/external/android/app/appsearch/PutDocumentsRequest.java index 05b2128809628..57700f89403e6 100644 --- a/apex/appsearch/framework/java/external/android/app/appsearch/PutDocumentsRequest.java +++ b/apex/appsearch/framework/java/external/android/app/appsearch/PutDocumentsRequest.java @@ -28,9 +28,11 @@ import java.util.Collections; import java.util.List; /** - * Encapsulates a request to index a document into an {@link AppSearchSession} database. + * Encapsulates a request to index documents into an {@link AppSearchSession} database. * *

@see AppSearchSession#putDocuments + * + * @see AppSearchSession#put */ public final class PutDocumentsRequest { private final List mDocuments; @@ -39,7 +41,7 @@ public final class PutDocumentsRequest { mDocuments = documents; } - /** Returns the documents that are part of this request. */ + /** Returns a list of {@link GenericDocument} objects that are part of this request. */ @NonNull public List getGenericDocuments() { return Collections.unmodifiableList(mDocuments); @@ -54,14 +56,22 @@ public final class PutDocumentsRequest { private final List mDocuments = new ArrayList<>(); private boolean mBuilt = false; - /** Adds one or more {@link GenericDocument} objects to the request. */ + /** + * Adds one or more {@link GenericDocument} objects to the request. + * + * @throws IllegalStateException if the builder has already been used. + */ @NonNull public Builder addGenericDocuments(@NonNull GenericDocument... documents) { Preconditions.checkNotNull(documents); return addGenericDocuments(Arrays.asList(documents)); } - /** Adds a collection of {@link GenericDocument} objects to the request. */ + /** + * Adds a collection of {@link GenericDocument} objects to the request. + * + * @throws IllegalStateException if the builder has already been used. + */ @NonNull public Builder addGenericDocuments( @NonNull Collection documents) { @@ -71,7 +81,11 @@ public final class PutDocumentsRequest { return this; } - /** Creates a new {@link PutDocumentsRequest} object. */ + /** + * Creates a new {@link PutDocumentsRequest} object. + * + * @throws IllegalStateException if the builder has already been used. + */ @NonNull public PutDocumentsRequest build() { Preconditions.checkState(!mBuilt, "Builder has already been used"); 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 new file mode 100644 index 0000000000000..0f23d926648b2 --- /dev/null +++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLogger.java @@ -0,0 +1,43 @@ +/* + * Copyright 2020 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; + +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.PutDocumentStats; + +/** + * An interface for implementing client-defined logging AppSearch operations stats. + * + *

Any implementation needs to provide general information on how to log all the stats types. + * (e.g. {@link CallStats}) + * + *

All implementations of this interface must be thread safe. + * + * @hide + */ +public interface AppSearchLogger { + /** Logs {@link CallStats} */ + void logStats(@NonNull CallStats stats) throws AppSearchException; + + /** Logs {@link PutDocumentStats} */ + void logStats(@NonNull PutDocumentStats 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/AppSearchMigrationHelperImpl.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchMigrationHelperImpl.java index a501e99db1efe..a7f1cc4c793fa 100644 --- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchMigrationHelperImpl.java +++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchMigrationHelperImpl.java @@ -76,7 +76,7 @@ class AppSearchMigrationHelperImpl implements AppSearchMigrationHelper { int currentVersion = mCurrentVersionMap.get(schemaType); int finalVersion = mFinalVersionMap.get(schemaType); try (FileOutputStream outputStream = new FileOutputStream(mFile)) { - // TODO(b/177266929) change the output stream so that we can use it in platform + // TODO(b/151178558) change the output stream so that we can use it in platform CodedOutputStream codedOutputStream = CodedOutputStream.newInstance(outputStream); SearchResultPage searchResultPage = mAppSearchImpl.query( diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/CallStats.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/CallStats.java new file mode 100644 index 0000000000000..81a5067c9fa19 --- /dev/null +++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/CallStats.java @@ -0,0 +1,200 @@ +/* + * 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 com.android.internal.util.Preconditions; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * A class for setting basic information to log for all function calls. + * + *

This class can set which stats to log for both batch and non-batch {@link + * android.app.appsearch.AppSearchSession} calls. + * + *

Some function calls like {@link android.app.appsearch.AppSearchSession#setSchema} have their + * own detailed stats class {@link placeholder}. However, {@link CallStats} can still be used along + * with the detailed stats class for easy aggregation/analysis with other function calls. + * + * @hide + */ +public class CallStats { + @IntDef( + value = { + CALL_TYPE_UNKNOWN, + CALL_TYPE_INITIALIZE, + CALL_TYPE_SET_SCHEMA, + CALL_TYPE_PUT_DOCUMENTS, + CALL_TYPE_GET_DOCUMENTS, + CALL_TYPE_REMOVE_DOCUMENTS, + CALL_TYPE_PUT_DOCUMENT, + CALL_TYPE_GET_DOCUMENT, + CALL_TYPE_REMOVE_DOCUMENT, + CALL_TYPE_QUERY, + CALL_TYPE_OPTIMIZE, + CALL_TYPE_FLUSH, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface CallType {} + + public static final int CALL_TYPE_UNKNOWN = 0; + public static final int CALL_TYPE_INITIALIZE = 1; + public static final int CALL_TYPE_SET_SCHEMA = 2; + public static final int CALL_TYPE_PUT_DOCUMENTS = 3; + public static final int CALL_TYPE_GET_DOCUMENTS = 4; + public static final int CALL_TYPE_REMOVE_DOCUMENTS = 5; + public static final int CALL_TYPE_PUT_DOCUMENT = 6; + public static final int CALL_TYPE_GET_DOCUMENT = 7; + public static final int CALL_TYPE_REMOVE_DOCUMENT = 8; + public static final int CALL_TYPE_QUERY = 9; + public static final int CALL_TYPE_OPTIMIZE = 10; + public static final int CALL_TYPE_FLUSH = 11; + + @NonNull private final GeneralStats mGeneralStats; + @CallType private final int mCallType; + private final int mEstimatedBinderLatencyMillis; + private final int mNumOperationsSucceeded; + private final int mNumOperationsFailed; + + CallStats(@NonNull Builder builder) { + Preconditions.checkNotNull(builder); + mGeneralStats = Preconditions.checkNotNull(builder.mGeneralStats); + mCallType = builder.mCallType; + mEstimatedBinderLatencyMillis = builder.mEstimatedBinderLatencyMillis; + mNumOperationsSucceeded = builder.mNumOperationsSucceeded; + mNumOperationsFailed = builder.mNumOperationsFailed; + } + + /** Returns general information for the call. */ + @NonNull + public GeneralStats getGeneralStats() { + return mGeneralStats; + } + + /** Returns type of the call. */ + @CallType + public int getCallType() { + return mCallType; + } + + /** Returns estimated binder latency, in milliseconds */ + public int getEstimatedBinderLatencyMillis() { + return mEstimatedBinderLatencyMillis; + } + + /** + * Returns number of operations succeeded. + * + *

For example, for {@link android.app.appsearch.AppSearchSession#put}, it is the total + * number of individual successful put operations. In this case, how many documents are + * successfully indexed. + * + *

For non-batch calls such as {@link android.app.appsearch.AppSearchSession#setSchema}, the + * sum of {@link CallStats#getNumOperationsSucceeded()} and {@link + * CallStats#getNumOperationsFailed()} is always 1 since there is only one operation. + */ + public int getNumOperationsSucceeded() { + return mNumOperationsSucceeded; + } + + /** + * Returns number of operations failed. + * + *

For example, for {@link android.app.appsearch.AppSearchSession#put}, it is the total + * number of individual failed put operations. In this case, how many documents are failed to be + * indexed. + * + *

For non-batch calls such as {@link android.app.appsearch.AppSearchSession#setSchema}, the + * sum of {@link CallStats#getNumOperationsSucceeded()} and {@link + * CallStats#getNumOperationsFailed()} is always 1 since there is only one operation. + */ + public int getNumOperationsFailed() { + return mNumOperationsFailed; + } + + /** Builder for {@link CallStats}. */ + public static class Builder { + @NonNull final GeneralStats mGeneralStats; + @CallType int mCallType; + int mEstimatedBinderLatencyMillis; + int mNumOperationsSucceeded; + int mNumOperationsFailed; + + /** Builder takes {@link GeneralStats} to hold general stats. */ + public Builder(@NonNull GeneralStats generalStats) { + mGeneralStats = Preconditions.checkNotNull(generalStats); + } + + /** Sets type of the call. */ + @NonNull + public Builder setCallType(@CallType int callType) { + mCallType = callType; + return this; + } + + /** Sets estimated binder latency, in milliseconds. */ + @NonNull + public Builder setEstimatedBinderLatencyMillis(int estimatedBinderLatencyMillis) { + mEstimatedBinderLatencyMillis = estimatedBinderLatencyMillis; + return this; + } + + /** + * Sets number of operations succeeded. + * + *

For example, for {@link android.app.appsearch.AppSearchSession#put}, it is the total + * number of individual successful put operations. In this case, how many documents are + * successfully indexed. + * + *

For non-batch calls such as {@link android.app.appsearch.AppSearchSession#setSchema}, + * the sum of {@link CallStats#getNumOperationsSucceeded()} and {@link + * CallStats#getNumOperationsFailed()} is always 1 since there is only one operation. + */ + @NonNull + public Builder setNumOperationsSucceeded(int numOperationsSucceeded) { + mNumOperationsSucceeded = numOperationsSucceeded; + return this; + } + + /** + * Sets number of operations failed. + * + *

For example, for {@link android.app.appsearch.AppSearchSession#put}, it is the total + * number of individual failed put operations. In this case, how many documents are failed + * to be indexed. + * + *

For non-batch calls such as {@link android.app.appsearch.AppSearchSession#setSchema}, + * the sum of {@link CallStats#getNumOperationsSucceeded()} and {@link + * CallStats#getNumOperationsFailed()} is always 1 since there is only one operation. + */ + @NonNull + public Builder setNumOperationsFailed(int numOperationsFailed) { + mNumOperationsFailed = numOperationsFailed; + return this; + } + + /** Creates {@link CallStats} object from {@link Builder} instance. */ + @NonNull + public CallStats build() { + return new CallStats(/* builder= */ this); + } + } +} diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/GeneralStats.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/GeneralStats.java new file mode 100644 index 0000000000000..d2a45d5304f95 --- /dev/null +++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/GeneralStats.java @@ -0,0 +1,122 @@ +/* + * 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.NonNull; +import android.app.appsearch.AppSearchResult; + +import com.android.internal.util.Preconditions; + +/** + * A class for holding general logging information. + * + *

This class cannot be logged by {@link + * com.android.server.appsearch.external.localstorage.AppSearchLogger} directly. It is used for + * defining general logging information that is shared across different stats classes. + * + * @see PutDocumentStats + * @see CallStats + * @hide + */ +public final class GeneralStats { + /** Package name of the application. */ + @NonNull private final String mPackageName; + + /** Database name within AppSearch. */ + @NonNull 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; + + GeneralStats(@NonNull Builder builder) { + Preconditions.checkNotNull(builder); + mPackageName = Preconditions.checkNotNull(builder.mPackageName); + mDatabase = Preconditions.checkNotNull(builder.mDatabase); + mStatusCode = builder.mStatusCode; + mTotalLatencyMillis = builder.mTotalLatencyMillis; + } + + /** Returns package name. */ + @NonNull + public String getPackageName() { + return mPackageName; + } + + /** Returns database name. */ + @NonNull + public String getDatabase() { + return mDatabase; + } + + /** Returns result code from {@link AppSearchResult#getResultCode()} */ + @AppSearchResult.ResultCode + public int getStatusCode() { + return mStatusCode; + } + + /** Returns total latency, in milliseconds. */ + public int getTotalLatencyMillis() { + return mTotalLatencyMillis; + } + + /** Builder for {@link GeneralStats}. */ + public static class Builder { + @NonNull final String mPackageName; + @NonNull final String mDatabase; + @AppSearchResult.ResultCode int mStatusCode; + int mTotalLatencyMillis; + + /** + * Constructor + * + * @param packageName name of the package logging stats + * @param dataBase name of the database logging stats + */ + public Builder(@NonNull String packageName, @NonNull String dataBase) { + mPackageName = Preconditions.checkNotNull(packageName); + mDatabase = Preconditions.checkNotNull(dataBase); + } + + /** Sets status code returned from {@link AppSearchResult#getResultCode()} */ + @NonNull + public Builder setStatusCode(@AppSearchResult.ResultCode int statusCode) { + mStatusCode = statusCode; + return this; + } + + /** Sets total latency, in milliseconds. */ + @NonNull + public Builder setTotalLatencyMillis(int totalLatencyMillis) { + mTotalLatencyMillis = totalLatencyMillis; + return this; + } + + /** + * Creates a new {@link GeneralStats} object from the contents of this {@link Builder} + * instance. + */ + @NonNull + public GeneralStats build() { + return new GeneralStats(/* builder= */ this); + } + } +} diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/PutDocumentStats.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/PutDocumentStats.java new file mode 100644 index 0000000000000..b1b643b668598 --- /dev/null +++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/PutDocumentStats.java @@ -0,0 +1,219 @@ +/* + * 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.NonNull; + +import com.android.internal.util.Preconditions; + +/** + * A class for holding detailed stats to log for each individual document put by a {@link + * android.app.appsearch.AppSearchSession#put} call. + * + * @hide + */ +public final class PutDocumentStats { + /** {@link GeneralStats} holds the general stats. */ + @NonNull private final GeneralStats mGeneralStats; + + /** Time used to generate a document proto from a Bundle. */ + private final int mGenerateDocumentProtoLatencyMillis; + + /** Time used to rewrite types and namespaces in the document. */ + private final int mRewriteDocumentTypesLatencyMillis; + + /** Overall time used for the native function call. */ + private final int mNativeLatencyMillis; + + /** Time used to store the document. */ + private final int mNativeDocumentStoreLatencyMillis; + + /** Time used to index the document. It doesn't include the time to merge indices. */ + private final int mNativeIndexLatencyMillis; + + /** Time used to merge the indices. */ + private final int mNativeIndexMergeLatencyMillis; + + /** Document size in bytes. */ + private final int mNativeDocumentSizeBytes; + + /** Number of tokens added to the index. */ + private final int mNativeNumTokensIndexed; + + /** Number of tokens clipped for exceeding the max number. */ + private final int mNativeNumTokensClipped; + + PutDocumentStats(@NonNull Builder builder) { + Preconditions.checkNotNull(builder); + mGeneralStats = Preconditions.checkNotNull(builder.mGeneralStats); + mGenerateDocumentProtoLatencyMillis = builder.mGenerateDocumentProtoLatencyMillis; + mRewriteDocumentTypesLatencyMillis = builder.mRewriteDocumentTypesLatencyMillis; + mNativeLatencyMillis = builder.mNativeLatencyMillis; + mNativeDocumentStoreLatencyMillis = builder.mNativeDocumentStoreLatencyMillis; + mNativeIndexLatencyMillis = builder.mNativeIndexLatencyMillis; + mNativeIndexMergeLatencyMillis = builder.mNativeIndexMergeLatencyMillis; + mNativeDocumentSizeBytes = builder.mNativeDocumentSizeBytes; + mNativeNumTokensIndexed = builder.mNativeNumTokensIndexed; + mNativeNumTokensClipped = builder.mNativeNumTokensClipped; + } + + /** Returns the {@link GeneralStats} object attached to this instance. */ + @NonNull + public GeneralStats getGeneralStats() { + return mGeneralStats; + } + + /** Returns time spent on generating document proto, in milliseconds. */ + public int getGenerateDocumentProtoLatencyMillis() { + return mGenerateDocumentProtoLatencyMillis; + } + + /** Returns time spent on rewriting types and namespaces in document, in milliseconds. */ + public int getRewriteDocumentTypesLatencyMillis() { + return mRewriteDocumentTypesLatencyMillis; + } + + /** Returns time spent in native, in milliseconds. */ + public int getNativeLatencyMillis() { + return mNativeLatencyMillis; + } + + /** Returns time spent on document store, in milliseconds. */ + public int getNativeDocumentStoreLatencyMillis() { + return mNativeDocumentStoreLatencyMillis; + } + + /** Returns time spent on indexing, in milliseconds. */ + public int getNativeIndexLatencyMillis() { + return mNativeIndexLatencyMillis; + } + + /** Returns time spent on merging indices, in milliseconds. */ + public int getNativeIndexMergeLatencyMillis() { + return mNativeIndexMergeLatencyMillis; + } + + /** Returns document size, in bytes. */ + public int getNativeDocumentSizeBytes() { + return mNativeDocumentSizeBytes; + } + + /** Returns number of tokens indexed. */ + public int getNativeNumTokensIndexed() { + return mNativeNumTokensIndexed; + } + + /** Returns number of tokens clipped for exceeding the max number. */ + public int getNativeNumTokensClipped() { + return mNativeNumTokensClipped; + } + + /** Builder for {@link PutDocumentStats}. */ + public static class Builder { + @NonNull final GeneralStats mGeneralStats; + int mGenerateDocumentProtoLatencyMillis; + int mRewriteDocumentTypesLatencyMillis; + int mNativeLatencyMillis; + int mNativeDocumentStoreLatencyMillis; + int mNativeIndexLatencyMillis; + int mNativeIndexMergeLatencyMillis; + int mNativeDocumentSizeBytes; + int mNativeNumTokensIndexed; + int mNativeNumTokensClipped; + + /** Builder takes {@link GeneralStats} to hold general stats. */ + public Builder(@NonNull GeneralStats generalStats) { + mGeneralStats = Preconditions.checkNotNull(generalStats); + } + + /** Sets how much time we spend for generating document proto, in milliseconds. */ + @NonNull + public Builder setGenerateDocumentProtoLatencyMillis( + int generateDocumentProtoLatencyMillis) { + mGenerateDocumentProtoLatencyMillis = generateDocumentProtoLatencyMillis; + return this; + } + + /** + * Sets how much time we spend for rewriting types and namespaces in document, in + * milliseconds. + */ + @NonNull + public Builder setRewriteDocumentTypesLatencyMillis(int rewriteDocumentTypesLatencyMillis) { + mRewriteDocumentTypesLatencyMillis = rewriteDocumentTypesLatencyMillis; + return this; + } + + /** Sets the native latency, in milliseconds. */ + @NonNull + public Builder setNativeLatencyMillis(int nativeLatencyMillis) { + mNativeLatencyMillis = nativeLatencyMillis; + return this; + } + + /** Sets how much time we spend on document store, in milliseconds. */ + @NonNull + public Builder setNativeDocumentStoreLatencyMillis(int nativeDocumentStoreLatencyMillis) { + mNativeDocumentStoreLatencyMillis = nativeDocumentStoreLatencyMillis; + return this; + } + + /** Sets the native index latency, in milliseconds. */ + @NonNull + public Builder setNativeIndexLatencyMillis(int nativeIndexLatencyMillis) { + mNativeIndexLatencyMillis = nativeIndexLatencyMillis; + return this; + } + + /** Sets how much time we spend on merging indices, in milliseconds. */ + @NonNull + public Builder setNativeIndexMergeLatencyMillis(int nativeIndexMergeLatencyMillis) { + mNativeIndexMergeLatencyMillis = nativeIndexMergeLatencyMillis; + return this; + } + + /** Sets document size, in bytes. */ + @NonNull + public Builder setNativeDocumentSizeBytes(int nativeDocumentSizeBytes) { + mNativeDocumentSizeBytes = nativeDocumentSizeBytes; + return this; + } + + /** Sets number of tokens indexed in native. */ + @NonNull + public Builder setNativeNumTokensIndexed(int nativeNumTokensIndexed) { + mNativeNumTokensIndexed = nativeNumTokensIndexed; + return this; + } + + /** Sets number of tokens clipped for exceeding the max number. */ + @NonNull + public Builder setNativeNumTokensClipped(int nativeNumTokensClipped) { + mNativeNumTokensClipped = nativeNumTokensClipped; + return this; + } + + /** + * Creates a new {@link PutDocumentStats} object from the contents of this {@link Builder} + * instance. + */ + @NonNull + public PutDocumentStats build() { + return new PutDocumentStats(/* builder= */ this); + } + } +} diff --git a/apex/appsearch/synced_jetpack_changeid.txt b/apex/appsearch/synced_jetpack_changeid.txt index d076db3b8f826..fc0299ef88af9 100644 --- a/apex/appsearch/synced_jetpack_changeid.txt +++ b/apex/appsearch/synced_jetpack_changeid.txt @@ -1 +1 @@ -Ia9a8daef1a6d7d9432f7808d440abd64f4797701 +I895f5fb3bcb4be0642c6193000e57d80aafe2166 diff --git a/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchSessionShim.java b/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchSessionShim.java index ea21e19b2bea2..34c7ccbd4df13 100644 --- a/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchSessionShim.java +++ b/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchSessionShim.java @@ -90,11 +90,11 @@ public interface AppSearchSessionShim extends Closeable { *

It is a no-op to set the same schema as has been previously set; this is handled * efficiently. * - *

By default, documents are visible on platform surfaces. To opt out, call - * {@link SetSchemaRequest.Builder#setSchemaTypeVisibilityForSystemUi} with {@code visible} as - * false. Any visibility settings apply only to the schemas that are included in the - * {@code request}. Visibility settings for a schema type do not persist across - * {@link #setSchema} calls. + *

By default, documents are visible on platform surfaces. To opt out, call {@code + * SetSchemaRequest.Builder#setPlatformSurfaceable} with {@code surfaceable} as false. Any + * visibility settings apply only to the schemas that are included in the {@code request}. + * Visibility settings for a schema type do not apply or persist across {@link + * SetSchemaRequest}s. * *

Migration: make non-backwards-compatible changes will delete all stored documents in old * schema. You can save your documents by setting {@link @@ -118,6 +118,8 @@ public interface AppSearchSessionShim extends Closeable { * @see android.app.appsearch.AppSearchSchema.Migrator * @see android.app.appsearch.AppSearchMigrationHelper.Transformer */ + // TODO(b/169883602): Change @code references to @link when setPlatformSurfaceable APIs are + // exposed. @NonNull ListenableFuture setSchema(@NonNull SetSchemaRequest request); @@ -132,15 +134,17 @@ public interface AppSearchSessionShim extends Closeable { ListenableFuture> getSchema(); /** - * Indexes documents into AppSearch. + * Indexes documents into the {@link AppSearchSessionShim} database. * - *

Each {@link GenericDocument}'s {@code schemaType} field must be set to the name of a - * schema type previously registered via the {@link #setSchema} method. + *

Each {@link GenericDocument} object must have a {@code schemaType} field set to an {@link + * AppSearchSchema} type that has been previously registered by calling the {@link #setSchema} + * method. * - * @param request {@link PutDocumentsRequest} containing documents to be indexed - * @return The pending result of performing this operation. The keys of the returned {@link - * AppSearchBatchResult} are the URIs of the input documents. The values are {@code null} if - * they were successfully indexed, or a failed {@link AppSearchResult} otherwise. + * @param request containing documents to be indexed. + * @return a {@link ListenableFuture} which resolves to an {@link AppSearchBatchResult}. The + * keys of the returned {@link AppSearchBatchResult} are the URIs of the input documents. + * The values are either {@code null} if the corresponding document was successfully + * indexed, or a failed {@link AppSearchResult} otherwise. */ @NonNull ListenableFuture> put(@NonNull PutDocumentsRequest request); @@ -213,7 +217,7 @@ public interface AppSearchSessionShim extends Closeable { * adding projection, can be set by calling the corresponding {@link SearchSpec.Builder} setter. * *

This method is lightweight. The heavy work will be done in {@link - * SearchResultsShim#getNextPage()}. + * SearchResultsShim#getNextPage}. * * @param queryExpression query string to search. * @param searchSpec spec for setting document filters, adding projection, setting term match diff --git a/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/GlobalSearchSessionShim.java b/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/GlobalSearchSessionShim.java index 31c934f8bb270..d912c08e7d5f8 100644 --- a/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/GlobalSearchSessionShim.java +++ b/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/GlobalSearchSessionShim.java @@ -37,11 +37,11 @@ public interface GlobalSearchSessionShim extends Closeable { * SetSchemaRequest.Builder#setSchemaTypeVisibilityForSystemUi}, or {@link * SetSchemaRequest.Builder#setDocumentClassVisibilityForSystemUi} when building a schema. * - *

See {@link AppSearchSessionShim#search(String, SearchSpec)} for a detailed explanation on - * forming a query string. + *

See {@link AppSearchSessionShim#search} for a detailed explanation on forming a query + * string. * *

This method is lightweight. The heavy work will be done in {@link - * SearchResultsShim#getNextPage()}. + * SearchResultsShim#getNextPage}. * * @param queryExpression query string to search. * @param searchSpec spec for setting document filters, adding projection, setting term match diff --git a/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/SearchResultsShim.java b/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/SearchResultsShim.java index 328c65ca27278..38f61f83d24e0 100644 --- a/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/SearchResultsShim.java +++ b/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/SearchResultsShim.java @@ -24,25 +24,29 @@ import java.io.Closeable; import java.util.List; /** - * SearchResultsShim are a returned object from a query API. + * Encapsulates results of a search operation. * - *

Each {@link SearchResult} contains a document and may contain other fields like snippets based - * on request. + *

Each {@link AppSearchSessionShim#search} operation returns a list of {@link SearchResult} + * objects, referred to as a "page", limited by the size configured by {@link + * SearchSpec.Builder#setResultCountPerPage}. * - *

Should close this object after finish fetching results. + *

To fetch a page of results, call {@link #getNextPage()}. + * + *

All instances of {@link SearchResultsShim} must call {@link SearchResultsShim#close()} after + * the results are fetched. * *

This class is not thread safe. */ public interface SearchResultsShim extends Closeable { /** - * Gets a whole page of {@link SearchResult}s. + * Retrieves the next page of {@link SearchResult} objects. * - *

Re-call this method to get next page of {@link SearchResult}, until it returns an empty - * list. + *

The page size is configured by {@link SearchSpec.Builder#setResultCountPerPage}. * - *

The page size is set by {@link SearchSpec.Builder#setResultCountPerPage}. + *

Continue calling this method to access results until it returns an empty list, signifying + * there are no more results. * - * @return The pending result of performing this operation. + * @return a {@link ListenableFuture} which resolves to a list of {@link SearchResult} objects. */ @NonNull ListenableFuture> getNextPage(); 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 new file mode 100644 index 0000000000000..4308885faaadd --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/stats/AppSearchStatsTest.java @@ -0,0 +1,124 @@ +/* + * 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 static com.google.common.truth.Truth.assertThat; + +import org.junit.Test; + +public class AppSearchStatsTest { + static final String TEST_PACKAGE_NAME = "com.google.test"; + static final String TEST_DATA_BASE = "testDataBase"; + static final int TEST_STATUS_CODE = 2; + static final int TEST_TOTAL_LATENCY_MILLIS = 20; + + @Test + public void testAppSearchStats_GeneralStats() { + final GeneralStats gStats = + new GeneralStats.Builder(TEST_PACKAGE_NAME, TEST_DATA_BASE) + .setStatusCode(TEST_STATUS_CODE) + .setTotalLatencyMillis(TEST_TOTAL_LATENCY_MILLIS) + .build(); + + assertThat(gStats.getPackageName()).isEqualTo(TEST_PACKAGE_NAME); + assertThat(gStats.getDatabase()).isEqualTo(TEST_DATA_BASE); + assertThat(gStats.getStatusCode()).isEqualTo(TEST_STATUS_CODE); + assertThat(gStats.getTotalLatencyMillis()).isEqualTo(TEST_TOTAL_LATENCY_MILLIS); + } + + @Test + public void testAppSearchStats_CallStats() { + final int estimatedBinderLatencyMillis = 1; + final int numOperationsSucceeded = 2; + final int numOperationsFailed = 3; + + final GeneralStats gStats = + new GeneralStats.Builder(TEST_PACKAGE_NAME, TEST_DATA_BASE) + .setStatusCode(TEST_STATUS_CODE) + .setTotalLatencyMillis(TEST_TOTAL_LATENCY_MILLIS) + .build(); + final @CallStats.CallType int callType = CallStats.CALL_TYPE_PUT_DOCUMENTS; + final CallStats cStats = + new CallStats.Builder(gStats) + .setCallType(callType) + .setEstimatedBinderLatencyMillis(estimatedBinderLatencyMillis) + .setNumOperationsSucceeded(numOperationsSucceeded) + .setNumOperationsFailed(numOperationsFailed) + .build(); + + assertThat(cStats.getGeneralStats().getPackageName()).isEqualTo(TEST_PACKAGE_NAME); + assertThat(cStats.getGeneralStats().getDatabase()).isEqualTo(TEST_DATA_BASE); + assertThat(cStats.getGeneralStats().getStatusCode()).isEqualTo(TEST_STATUS_CODE); + assertThat(cStats.getGeneralStats().getTotalLatencyMillis()) + .isEqualTo(TEST_TOTAL_LATENCY_MILLIS); + assertThat(cStats.getEstimatedBinderLatencyMillis()) + .isEqualTo(estimatedBinderLatencyMillis); + assertThat(cStats.getCallType()).isEqualTo(callType); + assertThat(cStats.getNumOperationsSucceeded()).isEqualTo(numOperationsSucceeded); + assertThat(cStats.getNumOperationsFailed()).isEqualTo(numOperationsFailed); + } + + @Test + public void testAppSearchStats_PutDocumentStats() { + final int generateDocumentProtoLatencyMillis = 1; + final int rewriteDocumentTypesLatencyMillis = 2; + final int nativeLatencyMillis = 3; + final int nativeDocumentStoreLatencyMillis = 4; + final int nativeIndexLatencyMillis = 5; + final int nativeIndexMergeLatencyMillis = 6; + final int nativeDocumentSize = 7; + final int nativeNumTokensIndexed = 8; + final int nativeNumTokensClipped = 9; + + final GeneralStats gStats = + new GeneralStats.Builder(TEST_PACKAGE_NAME, TEST_DATA_BASE) + .setStatusCode(TEST_STATUS_CODE) + .setTotalLatencyMillis(TEST_TOTAL_LATENCY_MILLIS) + .build(); + final PutDocumentStats pStats = + new PutDocumentStats.Builder(gStats) + .setGenerateDocumentProtoLatencyMillis(generateDocumentProtoLatencyMillis) + .setRewriteDocumentTypesLatencyMillis(rewriteDocumentTypesLatencyMillis) + .setNativeLatencyMillis(nativeLatencyMillis) + .setNativeDocumentStoreLatencyMillis(nativeDocumentStoreLatencyMillis) + .setNativeIndexLatencyMillis(nativeIndexLatencyMillis) + .setNativeIndexMergeLatencyMillis(nativeIndexMergeLatencyMillis) + .setNativeDocumentSizeBytes(nativeDocumentSize) + .setNativeNumTokensIndexed(nativeNumTokensIndexed) + .setNativeNumTokensClipped(nativeNumTokensClipped) + .build(); + + assertThat(pStats.getGeneralStats().getPackageName()).isEqualTo(TEST_PACKAGE_NAME); + assertThat(pStats.getGeneralStats().getDatabase()).isEqualTo(TEST_DATA_BASE); + assertThat(pStats.getGeneralStats().getStatusCode()).isEqualTo(TEST_STATUS_CODE); + assertThat(pStats.getGeneralStats().getTotalLatencyMillis()) + .isEqualTo(TEST_TOTAL_LATENCY_MILLIS); + assertThat(pStats.getGenerateDocumentProtoLatencyMillis()) + .isEqualTo(generateDocumentProtoLatencyMillis); + assertThat(pStats.getRewriteDocumentTypesLatencyMillis()) + .isEqualTo(rewriteDocumentTypesLatencyMillis); + assertThat(pStats.getNativeLatencyMillis()).isEqualTo(nativeLatencyMillis); + assertThat(pStats.getNativeDocumentStoreLatencyMillis()) + .isEqualTo(nativeDocumentStoreLatencyMillis); + assertThat(pStats.getNativeIndexLatencyMillis()).isEqualTo(nativeIndexLatencyMillis); + assertThat(pStats.getNativeIndexMergeLatencyMillis()) + .isEqualTo(nativeIndexMergeLatencyMillis); + assertThat(pStats.getNativeDocumentSizeBytes()).isEqualTo(nativeDocumentSize); + assertThat(pStats.getNativeNumTokensIndexed()).isEqualTo(nativeNumTokensIndexed); + assertThat(pStats.getNativeNumTokensClipped()).isEqualTo(nativeNumTokensClipped); + } +}