1 /* 2 * Copyright 2022 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 17 package android.app.appsearch.stats; 18 19 import android.annotation.IntDef; 20 import android.annotation.NonNull; 21 import android.app.appsearch.AppSearchResult; 22 import android.app.appsearch.SetSchemaRequest; 23 import android.app.appsearch.annotation.CanIgnoreReturnValue; 24 import android.app.appsearch.util.BundleUtil; 25 import android.os.Bundle; 26 27 import java.lang.annotation.Retention; 28 import java.lang.annotation.RetentionPolicy; 29 import java.util.Objects; 30 31 /** 32 * Class holds detailed stats for Schema migration. 33 * 34 * @hide 35 */ 36 public final class SchemaMigrationStats { 37 38 // Indicate the how a SetSchema call relative to SchemaMigration case. 39 @IntDef( 40 value = { 41 NO_MIGRATION, 42 FIRST_CALL_GET_INCOMPATIBLE, 43 SECOND_CALL_APPLY_NEW_SCHEMA, 44 }) 45 @Retention(RetentionPolicy.SOURCE) 46 public @interface SchemaMigrationCallType {} 47 48 /** This SetSchema call is not relative to a SchemaMigration case. */ 49 public static final int NO_MIGRATION = 0; 50 /** This is the first SetSchema call in Migration cases to get all incompatible changes. */ 51 public static final int FIRST_CALL_GET_INCOMPATIBLE = 1; 52 /** This is the second SetSchema call in Migration cases to apply new schema changes */ 53 public static final int SECOND_CALL_APPLY_NEW_SCHEMA = 2; 54 55 private static final String PACKAGE_NAME_FIELD = "packageName"; 56 private static final String DATABASE_FIELD = "database"; 57 private static final String STATUS_CODE_FIELD = "StatusCode"; 58 private static final String EXECUTOR_ACQUISITION_MILLIS_FIELD = 59 "ExecutorAcquisitionLatencyMillis"; 60 private static final String TOTAL_LATENCY_MILLIS_FIELD = "totalLatencyMillis"; 61 private static final String GET_SCHEMA_LATENCY_MILLIS_FIELD = "getSchemaLatencyMillis"; 62 private static final String QUERY_AND_TRANSFORM_LATENCY_MILLIS_FIELD = 63 "queryAndTransformLatencyMillis"; 64 private static final String FIRST_SET_SCHEMA_LATENCY_MILLIS_FIELD = 65 "firstSetSchemaLatencyMillis"; 66 private static final String IS_FIRST_SET_SCHEMA_SUCCESS_FIELD = "isFirstSetSchemaSuccess"; 67 private static final String SECOND_SET_SCHEMA_LATENCY_MILLIS_FIELD = 68 "secondSetSchemaLatencyMillis"; 69 private static final String SAVE_DOCUMENT_LATENCY_MILLIS_FIELD = "saveDocumentLatencyMillis"; 70 private static final String TOTAL_NEED_MIGRATED_DOCUMENT_COUNT_FIELD = 71 "totalNeedMigratedDocumentCount"; 72 private static final String MIGRATION_FAILURE_COUNT_FIELD = "migrationFailureCount"; 73 private static final String TOTAL_SUCCESS_MIGRATED_DOCUMENT_COUNT_FIELD = 74 "totalSuccessMigratedDocumentCount"; 75 76 /** 77 * Contains all {@link SchemaMigrationStats} information in a packaged format. 78 * 79 * <p>Keys are the {@code *_FIELD} constants in this class. 80 */ 81 @NonNull final Bundle mBundle; 82 83 /** Build a {@link SchemaMigrationStats} from the given bundle. */ SchemaMigrationStats(@onNull Bundle bundle)84 public SchemaMigrationStats(@NonNull Bundle bundle) { 85 mBundle = Objects.requireNonNull(bundle); 86 } 87 88 /** 89 * Returns the {@link Bundle} populated by this builder. 90 * 91 * @hide 92 */ 93 @NonNull getBundle()94 public Bundle getBundle() { 95 return mBundle; 96 } 97 98 /** Returns calling package name. */ 99 @NonNull getPackageName()100 public String getPackageName() { 101 return mBundle.getString(PACKAGE_NAME_FIELD); 102 } 103 104 /** Returns calling database name. */ 105 @NonNull getDatabase()106 public String getDatabase() { 107 return mBundle.getString(DATABASE_FIELD); 108 } 109 110 /** Returns status of the schema migration action. */ 111 @AppSearchResult.ResultCode getStatusCode()112 public int getStatusCode() { 113 return mBundle.getInt(STATUS_CODE_FIELD); 114 } 115 116 /** Gets the latency for waiting the executor. */ getExecutorAcquisitionLatencyMillis()117 public int getExecutorAcquisitionLatencyMillis() { 118 return mBundle.getInt(EXECUTOR_ACQUISITION_MILLIS_FIELD); 119 } 120 121 /** Gets total latency for the schema migration action in milliseconds. */ getTotalLatencyMillis()122 public int getTotalLatencyMillis() { 123 return mBundle.getInt(TOTAL_LATENCY_MILLIS_FIELD); 124 } 125 126 /** Returns GetSchema latency in milliseconds. */ getGetSchemaLatencyMillis()127 public int getGetSchemaLatencyMillis() { 128 return mBundle.getInt(GET_SCHEMA_LATENCY_MILLIS_FIELD); 129 } 130 131 /** 132 * Returns latency of querying all documents that need to be migrated to new version and 133 * transforming documents to new version in milliseconds. 134 */ getQueryAndTransformLatencyMillis()135 public int getQueryAndTransformLatencyMillis() { 136 return mBundle.getInt(QUERY_AND_TRANSFORM_LATENCY_MILLIS_FIELD); 137 } 138 139 /** 140 * Returns latency of first SetSchema action in milliseconds. 141 * 142 * <p>If all schema fields are backward compatible, the schema will be successful set to Icing. 143 * Otherwise, we will retrieve incompatible types here. 144 * 145 * <p>Please see {@link SetSchemaRequest} for what is "incompatible". 146 */ getFirstSetSchemaLatencyMillis()147 public int getFirstSetSchemaLatencyMillis() { 148 return mBundle.getInt(FIRST_SET_SCHEMA_LATENCY_MILLIS_FIELD); 149 } 150 151 /** Returns whether the first SetSchema action success. */ isFirstSetSchemaSuccess()152 public boolean isFirstSetSchemaSuccess() { 153 return mBundle.getBoolean(IS_FIRST_SET_SCHEMA_SUCCESS_FIELD); 154 } 155 156 /** 157 * Returns latency of second SetSchema action in milliseconds. 158 * 159 * <p>If all schema fields are backward compatible, the schema will be successful set to Icing 160 * in the first setSchema action and this value will be 0. Otherwise, schema types will be set 161 * to Icing by this action. 162 */ getSecondSetSchemaLatencyMillis()163 public int getSecondSetSchemaLatencyMillis() { 164 return mBundle.getInt(SECOND_SET_SCHEMA_LATENCY_MILLIS_FIELD); 165 } 166 167 /** Returns latency of putting migrated document to Icing lib in milliseconds. */ getSaveDocumentLatencyMillis()168 public int getSaveDocumentLatencyMillis() { 169 return mBundle.getInt(SAVE_DOCUMENT_LATENCY_MILLIS_FIELD); 170 } 171 172 /** Returns number of document that need to be migrated to another version. */ getTotalNeedMigratedDocumentCount()173 public int getTotalNeedMigratedDocumentCount() { 174 return mBundle.getInt(TOTAL_NEED_MIGRATED_DOCUMENT_COUNT_FIELD); 175 } 176 177 /** Returns number of {@link android.app.appsearch.SetSchemaResponse.MigrationFailure}. */ getMigrationFailureCount()178 public int getMigrationFailureCount() { 179 return mBundle.getInt(MIGRATION_FAILURE_COUNT_FIELD); 180 } 181 182 /** Returns number of successfully migrated and saved in Icing. */ getTotalSuccessMigratedDocumentCount()183 public int getTotalSuccessMigratedDocumentCount() { 184 return mBundle.getInt(TOTAL_SUCCESS_MIGRATED_DOCUMENT_COUNT_FIELD); 185 } 186 187 /** Builder for {@link SchemaMigrationStats}. */ 188 public static class Builder { 189 190 private final Bundle mBundle; 191 192 /** Creates a {@link SchemaMigrationStats.Builder}. */ Builder(@onNull String packageName, @NonNull String database)193 public Builder(@NonNull String packageName, @NonNull String database) { 194 mBundle = new Bundle(); 195 mBundle.putString(PACKAGE_NAME_FIELD, packageName); 196 mBundle.putString(DATABASE_FIELD, database); 197 } 198 199 /** 200 * Creates a {@link SchemaMigrationStats.Builder} from a given {@link SchemaMigrationStats}. 201 * 202 * <p>The returned builder is a deep copy whose data is separate from this 203 * SchemaMigrationStats. 204 */ Builder(@onNull SchemaMigrationStats stats)205 public Builder(@NonNull SchemaMigrationStats stats) { 206 mBundle = BundleUtil.deepCopy(stats.mBundle); 207 } 208 209 /** 210 * Creates a new {@link SchemaMigrationStats.Builder} from the given Bundle 211 * 212 * <p>The bundle is NOT copied. 213 */ Builder(@onNull Bundle bundle)214 public Builder(@NonNull Bundle bundle) { 215 mBundle = Objects.requireNonNull(bundle); 216 } 217 218 /** Sets status code for the schema migration action. */ 219 @CanIgnoreReturnValue 220 @NonNull setStatusCode(@ppSearchResult.ResultCode int statusCode)221 public Builder setStatusCode(@AppSearchResult.ResultCode int statusCode) { 222 mBundle.putInt(STATUS_CODE_FIELD, statusCode); 223 return this; 224 } 225 226 /** Sets the latency for waiting the executor. */ 227 @CanIgnoreReturnValue 228 @NonNull setExecutorAcquisitionLatencyMillis(int executorAcquisitionLatencyMillis)229 public Builder setExecutorAcquisitionLatencyMillis(int executorAcquisitionLatencyMillis) { 230 mBundle.putInt(EXECUTOR_ACQUISITION_MILLIS_FIELD, executorAcquisitionLatencyMillis); 231 return this; 232 } 233 234 /** Sets total latency for the schema migration action in milliseconds. */ 235 @CanIgnoreReturnValue 236 @NonNull setTotalLatencyMillis(int totalLatencyMillis)237 public Builder setTotalLatencyMillis(int totalLatencyMillis) { 238 mBundle.putInt(TOTAL_LATENCY_MILLIS_FIELD, totalLatencyMillis); 239 return this; 240 } 241 242 /** Sets latency for the GetSchema action in milliseconds. */ 243 @CanIgnoreReturnValue 244 @NonNull setGetSchemaLatencyMillis(int getSchemaLatencyMillis)245 public Builder setGetSchemaLatencyMillis(int getSchemaLatencyMillis) { 246 mBundle.putInt(GET_SCHEMA_LATENCY_MILLIS_FIELD, getSchemaLatencyMillis); 247 return this; 248 } 249 250 /** 251 * Sets latency for querying all documents that need to be migrated to new version and 252 * transforming documents to new version in milliseconds. 253 */ 254 @CanIgnoreReturnValue 255 @NonNull setQueryAndTransformLatencyMillis(int queryAndTransformLatencyMillis)256 public Builder setQueryAndTransformLatencyMillis(int queryAndTransformLatencyMillis) { 257 mBundle.putInt( 258 QUERY_AND_TRANSFORM_LATENCY_MILLIS_FIELD, queryAndTransformLatencyMillis); 259 return this; 260 } 261 262 /** Sets latency of first SetSchema action in milliseconds. */ 263 @CanIgnoreReturnValue 264 @NonNull setFirstSetSchemaLatencyMillis(int firstSetSchemaLatencyMillis)265 public Builder setFirstSetSchemaLatencyMillis(int firstSetSchemaLatencyMillis) { 266 mBundle.putInt(FIRST_SET_SCHEMA_LATENCY_MILLIS_FIELD, firstSetSchemaLatencyMillis); 267 return this; 268 } 269 270 /** Returns status of the first SetSchema action. */ 271 @CanIgnoreReturnValue 272 @NonNull setIsFirstSetSchemaSuccess(boolean isFirstSetSchemaSuccess)273 public Builder setIsFirstSetSchemaSuccess(boolean isFirstSetSchemaSuccess) { 274 mBundle.putBoolean(IS_FIRST_SET_SCHEMA_SUCCESS_FIELD, isFirstSetSchemaSuccess); 275 return this; 276 } 277 278 /** Sets latency of second SetSchema action in milliseconds. */ 279 @CanIgnoreReturnValue 280 @NonNull setSecondSetSchemaLatencyMillis(int secondSetSchemaLatencyMillis)281 public Builder setSecondSetSchemaLatencyMillis(int secondSetSchemaLatencyMillis) { 282 mBundle.putInt(SECOND_SET_SCHEMA_LATENCY_MILLIS_FIELD, secondSetSchemaLatencyMillis); 283 return this; 284 } 285 286 /** Sets latency for putting migrated document to Icing lib in milliseconds. */ 287 @CanIgnoreReturnValue 288 @NonNull setSaveDocumentLatencyMillis(int saveDocumentLatencyMillis)289 public Builder setSaveDocumentLatencyMillis(int saveDocumentLatencyMillis) { 290 mBundle.putInt(SAVE_DOCUMENT_LATENCY_MILLIS_FIELD, saveDocumentLatencyMillis); 291 return this; 292 } 293 294 /** Sets number of document that need to be migrated to another version. */ 295 @CanIgnoreReturnValue 296 @NonNull setTotalNeedMigratedDocumentCount(int migratedDocumentCount)297 public Builder setTotalNeedMigratedDocumentCount(int migratedDocumentCount) { 298 mBundle.putInt(TOTAL_NEED_MIGRATED_DOCUMENT_COUNT_FIELD, migratedDocumentCount); 299 return this; 300 } 301 302 /** Sets total document count of successfully migrated and saved in Icing. */ 303 @CanIgnoreReturnValue 304 @NonNull setTotalSuccessMigratedDocumentCount(int totalSuccessMigratedDocumentCount)305 public Builder setTotalSuccessMigratedDocumentCount(int totalSuccessMigratedDocumentCount) { 306 mBundle.putInt( 307 TOTAL_SUCCESS_MIGRATED_DOCUMENT_COUNT_FIELD, totalSuccessMigratedDocumentCount); 308 return this; 309 } 310 311 /** Sets number of {@link android.app.appsearch.SetSchemaResponse.MigrationFailure}. */ 312 @CanIgnoreReturnValue 313 @NonNull setMigrationFailureCount(int migrationFailureCount)314 public Builder setMigrationFailureCount(int migrationFailureCount) { 315 mBundle.putInt(MIGRATION_FAILURE_COUNT_FIELD, migrationFailureCount); 316 return this; 317 } 318 319 /** 320 * Builds a new {@link SchemaMigrationStats} from the {@link SchemaMigrationStats.Builder}. 321 */ 322 @NonNull build()323 public SchemaMigrationStats build() { 324 return new SchemaMigrationStats(mBundle); 325 } 326 } 327 } 328