1 /* 2 * Copyright 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.server.appsearch.external.localstorage.stats; 17 18 import android.annotation.IntDef; 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.app.appsearch.AppSearchResult; 22 import android.app.appsearch.SearchSpec; 23 24 import com.android.internal.util.Preconditions; 25 26 import java.lang.annotation.Retention; 27 import java.lang.annotation.RetentionPolicy; 28 import java.util.Objects; 29 30 /** 31 * Class holds detailed stats for {@link android.app.appsearch.AppSearchSession#search(String, 32 * SearchSpec)} 33 * 34 * @hide 35 */ 36 public final class SearchStats { 37 @IntDef( 38 value = { 39 // Searches apps' own documents. 40 VISIBILITY_SCOPE_LOCAL, 41 // Searches the global documents. Including platform surfaceable and 3p-access. 42 VISIBILITY_SCOPE_GLOBAL, 43 // TODO(b/173532925) Add THIRD_PARTY_ACCESS once we can distinguish platform 44 // surfaceable from 3p access(right both of them are categorized as 45 // VISIBILITY_SCOPE_GLOBAL) 46 }) 47 @Retention(RetentionPolicy.SOURCE) 48 public @interface VisibilityScope {} 49 50 // Searches apps' own documents. 51 public static final int VISIBILITY_SCOPE_LOCAL = 1; 52 // Searches the global documents. Including platform surfaceable and 3p-access. 53 public static final int VISIBILITY_SCOPE_GLOBAL = 2; 54 55 // TODO(b/173532925): Add a field searchType to indicate where the search is used(normal 56 // query vs in removeByQuery vs during migration) 57 58 @NonNull private final String mPackageName; 59 @Nullable private final String mDatabase; 60 /** 61 * The status code returned by {@link AppSearchResult#getResultCode()} for the call or internal 62 * state. 63 */ 64 @AppSearchResult.ResultCode private final int mStatusCode; 65 66 private final int mTotalLatencyMillis; 67 /** Time used to rewrite the search spec. */ 68 private final int mRewriteSearchSpecLatencyMillis; 69 /** Time used to rewrite the search results. */ 70 private final int mRewriteSearchResultLatencyMillis; 71 /** Defines the scope the query is searching over */ 72 @VisibilityScope private final int mVisibilityScope; 73 /** Overall time used for the native function call. */ 74 private final int mNativeLatencyMillis; 75 /** Number of terms in the query string. */ 76 private final int mNativeNumTerms; 77 /** Length of the query string. */ 78 private final int mNativeQueryLength; 79 /** Number of namespaces filtered. */ 80 private final int mNativeNumNamespacesFiltered; 81 /** Number of schema types filtered. */ 82 private final int mNativeNumSchemaTypesFiltered; 83 /** The requested number of results in one page. */ 84 private final int mNativeRequestedPageSize; 85 /** The actual number of results returned in the current page. */ 86 private final int mNativeNumResultsReturnedCurrentPage; 87 /** 88 * Whether the function call is querying the first page. If it's not, Icing will fetch the 89 * results from cache so that some steps may be skipped. 90 */ 91 private final boolean mNativeIsFirstPage; 92 /** 93 * Time used to parse the query, including 2 parts: tokenizing and transforming tokens into an 94 * iterator tree. 95 */ 96 private final int mNativeParseQueryLatencyMillis; 97 /** Strategy of scoring and ranking. */ 98 @SearchSpec.RankingStrategy private final int mNativeRankingStrategy; 99 /** Number of documents scored. */ 100 private final int mNativeNumDocumentsScored; 101 /** Time used to score the raw results. */ 102 private final int mNativeScoringLatencyMillis; 103 /** Time used to rank the scored results. */ 104 private final int mNativeRankingLatencyMillis; 105 /** 106 * Time used to fetch the document protos. Note that it includes the time to snippet if {@link 107 * SearchStats#mNativeNumResultsWithSnippets} is greater than 0. 108 */ 109 private final int mNativeDocumentRetrievingLatencyMillis; 110 /** How many snippets are calculated. */ 111 private final int mNativeNumResultsWithSnippets; 112 SearchStats(@onNull Builder builder)113 SearchStats(@NonNull Builder builder) { 114 Objects.requireNonNull(builder); 115 mPackageName = builder.mPackageName; 116 mDatabase = builder.mDatabase; 117 mStatusCode = builder.mStatusCode; 118 mTotalLatencyMillis = builder.mTotalLatencyMillis; 119 mRewriteSearchSpecLatencyMillis = builder.mRewriteSearchSpecLatencyMillis; 120 mRewriteSearchResultLatencyMillis = builder.mRewriteSearchResultLatencyMillis; 121 mVisibilityScope = builder.mVisibilityScope; 122 mNativeLatencyMillis = builder.mNativeLatencyMillis; 123 mNativeNumTerms = builder.mNativeNumTerms; 124 mNativeQueryLength = builder.mNativeQueryLength; 125 mNativeNumNamespacesFiltered = builder.mNativeNumNamespacesFiltered; 126 mNativeNumSchemaTypesFiltered = builder.mNativeNumSchemaTypesFiltered; 127 mNativeRequestedPageSize = builder.mNativeRequestedPageSize; 128 mNativeNumResultsReturnedCurrentPage = builder.mNativeNumResultsReturnedCurrentPage; 129 mNativeIsFirstPage = builder.mNativeIsFirstPage; 130 mNativeParseQueryLatencyMillis = builder.mNativeParseQueryLatencyMillis; 131 mNativeRankingStrategy = builder.mNativeRankingStrategy; 132 mNativeNumDocumentsScored = builder.mNativeNumDocumentsScored; 133 mNativeScoringLatencyMillis = builder.mNativeScoringLatencyMillis; 134 mNativeRankingLatencyMillis = builder.mNativeRankingLatencyMillis; 135 mNativeNumResultsWithSnippets = builder.mNativeNumResultsWithSnippets; 136 mNativeDocumentRetrievingLatencyMillis = builder.mNativeDocumentRetrievingLatencyMillis; 137 } 138 139 /** Returns the package name of the session. */ 140 @NonNull getPackageName()141 public String getPackageName() { 142 return mPackageName; 143 } 144 145 /** 146 * Returns the database name of the session. 147 * 148 * @return database name used by the session. {@code null} if and only if it is a global 149 * search(visibilityScope is {@link SearchStats#VISIBILITY_SCOPE_GLOBAL}). 150 */ 151 @Nullable getDatabase()152 public String getDatabase() { 153 return mDatabase; 154 } 155 156 /** Returns status of the search. */ 157 @AppSearchResult.ResultCode getStatusCode()158 public int getStatusCode() { 159 return mStatusCode; 160 } 161 162 /** Returns the total latency of the search. */ getTotalLatencyMillis()163 public int getTotalLatencyMillis() { 164 return mTotalLatencyMillis; 165 } 166 167 /** Returns how much time spent on rewriting the {@link SearchSpec}. */ getRewriteSearchSpecLatencyMillis()168 public int getRewriteSearchSpecLatencyMillis() { 169 return mRewriteSearchSpecLatencyMillis; 170 } 171 172 /** Returns how much time spent on rewriting the {@link android.app.appsearch.SearchResult}. */ getRewriteSearchResultLatencyMillis()173 public int getRewriteSearchResultLatencyMillis() { 174 return mRewriteSearchResultLatencyMillis; 175 } 176 177 /** Returns the visibility scope of the search. */ 178 @VisibilityScope getVisibilityScope()179 public int getVisibilityScope() { 180 return mVisibilityScope; 181 } 182 183 /** Returns how much time spent on the native calls. */ getNativeLatencyMillis()184 public int getNativeLatencyMillis() { 185 return mNativeLatencyMillis; 186 } 187 188 /** Returns number of terms in the search string. */ getTermCount()189 public int getTermCount() { 190 return mNativeNumTerms; 191 } 192 193 /** Returns the length of the search string. */ getQueryLength()194 public int getQueryLength() { 195 return mNativeQueryLength; 196 } 197 198 /** Returns number of namespaces filtered. */ getFilteredNamespaceCount()199 public int getFilteredNamespaceCount() { 200 return mNativeNumNamespacesFiltered; 201 } 202 203 /** Returns number of schema types filtered. */ getFilteredSchemaTypeCount()204 public int getFilteredSchemaTypeCount() { 205 return mNativeNumSchemaTypesFiltered; 206 } 207 208 /** Returns the requested number of results in one page. */ getRequestedPageSize()209 public int getRequestedPageSize() { 210 return mNativeRequestedPageSize; 211 } 212 213 /** Returns the actual number of results returned in the current page. */ getCurrentPageReturnedResultCount()214 public int getCurrentPageReturnedResultCount() { 215 return mNativeNumResultsReturnedCurrentPage; 216 } 217 218 // TODO(b/185184738) Make it an integer to show how many pages having been returned. 219 /** Returns whether the function call is querying the first page. */ isFirstPage()220 public boolean isFirstPage() { 221 return mNativeIsFirstPage; 222 } 223 224 /** 225 * Returns time used to parse the query, including 2 parts: tokenizing and transforming tokens 226 * into an iterator tree. 227 */ getParseQueryLatencyMillis()228 public int getParseQueryLatencyMillis() { 229 return mNativeParseQueryLatencyMillis; 230 } 231 232 /** Returns strategy of scoring and ranking. */ 233 @SearchSpec.RankingStrategy getRankingStrategy()234 public int getRankingStrategy() { 235 return mNativeRankingStrategy; 236 } 237 238 /** Returns number of documents scored. */ getScoredDocumentCount()239 public int getScoredDocumentCount() { 240 return mNativeNumDocumentsScored; 241 } 242 243 /** Returns time used to score the raw results. */ getScoringLatencyMillis()244 public int getScoringLatencyMillis() { 245 return mNativeScoringLatencyMillis; 246 } 247 248 /** Returns time used to rank the scored results. */ getRankingLatencyMillis()249 public int getRankingLatencyMillis() { 250 return mNativeRankingLatencyMillis; 251 } 252 253 /** 254 * Returns time used to fetch the document protos. Note that it includes the time to snippet if 255 * {@link SearchStats#mNativeNumResultsWithSnippets} is not zero. 256 */ getDocumentRetrievingLatencyMillis()257 public int getDocumentRetrievingLatencyMillis() { 258 return mNativeDocumentRetrievingLatencyMillis; 259 } 260 261 /** Returns the number of the results in the page returned were snippeted. */ getResultWithSnippetsCount()262 public int getResultWithSnippetsCount() { 263 return mNativeNumResultsWithSnippets; 264 } 265 266 /** Builder for {@link SearchStats} */ 267 public static class Builder { 268 @NonNull final String mPackageName; 269 @Nullable String mDatabase; 270 @AppSearchResult.ResultCode int mStatusCode; 271 int mTotalLatencyMillis; 272 int mRewriteSearchSpecLatencyMillis; 273 int mRewriteSearchResultLatencyMillis; 274 int mVisibilityScope; 275 int mNativeLatencyMillis; 276 int mNativeNumTerms; 277 int mNativeQueryLength; 278 int mNativeNumNamespacesFiltered; 279 int mNativeNumSchemaTypesFiltered; 280 int mNativeRequestedPageSize; 281 int mNativeNumResultsReturnedCurrentPage; 282 boolean mNativeIsFirstPage; 283 int mNativeParseQueryLatencyMillis; 284 int mNativeRankingStrategy; 285 int mNativeNumDocumentsScored; 286 int mNativeScoringLatencyMillis; 287 int mNativeRankingLatencyMillis; 288 int mNativeNumResultsWithSnippets; 289 int mNativeDocumentRetrievingLatencyMillis; 290 291 /** 292 * Constructor 293 * 294 * @param visibilityScope scope for the corresponding search. 295 * @param packageName name of the calling package. 296 */ Builder(@isibilityScope int visibilityScope, @NonNull String packageName)297 public Builder(@VisibilityScope int visibilityScope, @NonNull String packageName) { 298 mVisibilityScope = visibilityScope; 299 mPackageName = Objects.requireNonNull(packageName); 300 } 301 302 /** Sets the database used by the session. */ 303 @NonNull setDatabase(@onNull String database)304 public Builder setDatabase(@NonNull String database) { 305 mDatabase = Objects.requireNonNull(database); 306 return this; 307 } 308 309 /** Sets the status of the search. */ 310 @NonNull setStatusCode(@ppSearchResult.ResultCode int statusCode)311 public Builder setStatusCode(@AppSearchResult.ResultCode int statusCode) { 312 mStatusCode = statusCode; 313 return this; 314 } 315 316 /** Sets total latency for the search. */ 317 @NonNull setTotalLatencyMillis(int totalLatencyMillis)318 public Builder setTotalLatencyMillis(int totalLatencyMillis) { 319 mTotalLatencyMillis = totalLatencyMillis; 320 return this; 321 } 322 323 /** Sets time used to rewrite the search spec. */ 324 @NonNull setRewriteSearchSpecLatencyMillis(int rewriteSearchSpecLatencyMillis)325 public Builder setRewriteSearchSpecLatencyMillis(int rewriteSearchSpecLatencyMillis) { 326 mRewriteSearchSpecLatencyMillis = rewriteSearchSpecLatencyMillis; 327 return this; 328 } 329 330 /** Sets time used to rewrite the search results. */ 331 @NonNull setRewriteSearchResultLatencyMillis(int rewriteSearchResultLatencyMillis)332 public Builder setRewriteSearchResultLatencyMillis(int rewriteSearchResultLatencyMillis) { 333 mRewriteSearchResultLatencyMillis = rewriteSearchResultLatencyMillis; 334 return this; 335 } 336 337 /** Sets overall time used for the native function calls. */ 338 @NonNull setNativeLatencyMillis(int nativeLatencyMillis)339 public Builder setNativeLatencyMillis(int nativeLatencyMillis) { 340 mNativeLatencyMillis = nativeLatencyMillis; 341 return this; 342 } 343 344 /** Sets number of terms in the search string. */ 345 @NonNull setTermCount(int termCount)346 public Builder setTermCount(int termCount) { 347 mNativeNumTerms = termCount; 348 return this; 349 } 350 351 /** Sets length of the search string. */ 352 @NonNull setQueryLength(int queryLength)353 public Builder setQueryLength(int queryLength) { 354 mNativeQueryLength = queryLength; 355 return this; 356 } 357 358 /** Sets number of namespaces filtered. */ 359 @NonNull setFilteredNamespaceCount(int filteredNamespaceCount)360 public Builder setFilteredNamespaceCount(int filteredNamespaceCount) { 361 mNativeNumNamespacesFiltered = filteredNamespaceCount; 362 return this; 363 } 364 365 /** Sets number of schema types filtered. */ 366 @NonNull setFilteredSchemaTypeCount(int filteredSchemaTypeCount)367 public Builder setFilteredSchemaTypeCount(int filteredSchemaTypeCount) { 368 mNativeNumSchemaTypesFiltered = filteredSchemaTypeCount; 369 return this; 370 } 371 372 /** Sets the requested number of results in one page. */ 373 @NonNull setRequestedPageSize(int requestedPageSize)374 public Builder setRequestedPageSize(int requestedPageSize) { 375 mNativeRequestedPageSize = requestedPageSize; 376 return this; 377 } 378 379 /** Sets the actual number of results returned in the current page. */ 380 @NonNull setCurrentPageReturnedResultCount(int currentPageReturnedResultCount)381 public Builder setCurrentPageReturnedResultCount(int currentPageReturnedResultCount) { 382 mNativeNumResultsReturnedCurrentPage = currentPageReturnedResultCount; 383 return this; 384 } 385 386 /** 387 * Sets whether the function call is querying the first page. If it's not, Icing will fetch 388 * the results from cache so that some steps may be skipped. 389 */ 390 @NonNull setIsFirstPage(boolean nativeIsFirstPage)391 public Builder setIsFirstPage(boolean nativeIsFirstPage) { 392 mNativeIsFirstPage = nativeIsFirstPage; 393 return this; 394 } 395 396 /** 397 * Sets time used to parse the query, including 2 parts: tokenizing and transforming tokens 398 * into an iterator tree. 399 */ 400 @NonNull setParseQueryLatencyMillis(int parseQueryLatencyMillis)401 public Builder setParseQueryLatencyMillis(int parseQueryLatencyMillis) { 402 mNativeParseQueryLatencyMillis = parseQueryLatencyMillis; 403 return this; 404 } 405 406 /** Sets strategy of scoring and ranking. */ 407 @NonNull setRankingStrategy(@earchSpec.RankingStrategy int rankingStrategy)408 public Builder setRankingStrategy(@SearchSpec.RankingStrategy int rankingStrategy) { 409 mNativeRankingStrategy = rankingStrategy; 410 return this; 411 } 412 413 /** Sets number of documents scored. */ 414 @NonNull setScoredDocumentCount(int scoredDocumentCount)415 public Builder setScoredDocumentCount(int scoredDocumentCount) { 416 mNativeNumDocumentsScored = scoredDocumentCount; 417 return this; 418 } 419 420 /** Sets time used to score the raw results. */ 421 @NonNull setScoringLatencyMillis(int scoringLatencyMillis)422 public Builder setScoringLatencyMillis(int scoringLatencyMillis) { 423 mNativeScoringLatencyMillis = scoringLatencyMillis; 424 return this; 425 } 426 427 /** Sets time used to rank the scored results. */ 428 @NonNull setRankingLatencyMillis(int rankingLatencyMillis)429 public Builder setRankingLatencyMillis(int rankingLatencyMillis) { 430 mNativeRankingLatencyMillis = rankingLatencyMillis; 431 return this; 432 } 433 434 /** Sets time used to fetch the document protos. */ 435 @NonNull setDocumentRetrievingLatencyMillis(int documentRetrievingLatencyMillis)436 public Builder setDocumentRetrievingLatencyMillis(int documentRetrievingLatencyMillis) { 437 mNativeDocumentRetrievingLatencyMillis = documentRetrievingLatencyMillis; 438 return this; 439 } 440 441 /** Sets how many snippets are calculated. */ 442 @NonNull setResultWithSnippetsCount(int resultWithSnippetsCount)443 public Builder setResultWithSnippetsCount(int resultWithSnippetsCount) { 444 mNativeNumResultsWithSnippets = resultWithSnippetsCount; 445 return this; 446 } 447 448 /** 449 * Constructs a new {@link SearchStats} from the contents of this {@link 450 * SearchStats.Builder}. 451 */ 452 @NonNull build()453 public SearchStats build() { 454 if (mDatabase == null) { 455 Preconditions.checkState( 456 mVisibilityScope != SearchStats.VISIBILITY_SCOPE_LOCAL, 457 "database can not be null if visibilityScope is local."); 458 } 459 460 return new SearchStats(/* builder= */ this); 461 } 462 } 463 } 464