diff options
13 files changed, 254 insertions, 123 deletions
diff --git a/api/current.txt b/api/current.txt index 3963f3ac0c43..d9241a676a5c 100644 --- a/api/current.txt +++ b/api/current.txt @@ -38702,7 +38702,7 @@ package android.service.autofill { } public static final class FieldClassification.Match { - method public java.lang.String getRemoteId(); + method public java.lang.String getCategoryId(); method public float getScore(); } @@ -38867,6 +38867,7 @@ package android.service.autofill { method public int describeContents(); method public java.lang.String getFieldClassificationAlgorithm(); method public java.lang.String getId(); + method public static int getMaxCategoryCount(); method public static int getMaxFieldClassificationIdsSize(); method public static int getMaxUserDataSize(); method public static int getMaxValueLength(); diff --git a/api/system-current.txt b/api/system-current.txt index 5afb455d9640..44349dc1a47e 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -4175,6 +4175,7 @@ package android.provider { method public static boolean putString(android.content.ContentResolver, java.lang.String, java.lang.String, java.lang.String, boolean); method public static void resetToDefaults(android.content.ContentResolver, java.lang.String); field public static final java.lang.String AUTOFILL_FEATURE_FIELD_CLASSIFICATION = "autofill_field_classification"; + field public static final java.lang.String AUTOFILL_USER_DATA_MAX_CATEGORY_COUNT = "autofill_user_data_max_category_count"; field public static final java.lang.String AUTOFILL_USER_DATA_MAX_FIELD_CLASSIFICATION_IDS_SIZE = "autofill_user_data_max_field_classification_size"; field public static final java.lang.String AUTOFILL_USER_DATA_MAX_USER_DATA_SIZE = "autofill_user_data_max_user_data_size"; field public static final java.lang.String AUTOFILL_USER_DATA_MAX_VALUE_LENGTH = "autofill_user_data_max_value_length"; diff --git a/api/test-current.txt b/api/test-current.txt index eda6296fb39a..9bfc105efa8f 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -541,6 +541,7 @@ package android.provider { field public static final java.lang.String ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED = "accessibility_display_magnification_enabled"; field public static final java.lang.String AUTOFILL_FEATURE_FIELD_CLASSIFICATION = "autofill_field_classification"; field public static final java.lang.String AUTOFILL_SERVICE = "autofill_service"; + field public static final java.lang.String AUTOFILL_USER_DATA_MAX_CATEGORY_COUNT = "autofill_user_data_max_category_count"; field public static final java.lang.String AUTOFILL_USER_DATA_MAX_FIELD_CLASSIFICATION_IDS_SIZE = "autofill_user_data_max_field_classification_size"; field public static final java.lang.String AUTOFILL_USER_DATA_MAX_USER_DATA_SIZE = "autofill_user_data_max_user_data_size"; field public static final java.lang.String AUTOFILL_USER_DATA_MAX_VALUE_LENGTH = "autofill_user_data_max_value_length"; diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 1feb822ffc58..630b63f4cba4 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -5385,6 +5385,17 @@ public final class Settings { "autofill_user_data_max_field_classification_size"; /** + * Defines value returned by + * {@link android.service.autofill.UserData#getMaxCategoryCount()}. + * + * @hide + */ + @SystemApi + @TestApi + public static final String AUTOFILL_USER_DATA_MAX_CATEGORY_COUNT = + "autofill_user_data_max_category_count"; + + /** * Defines value returned by {@link android.service.autofill.UserData#getMaxValueLength()}. * * @hide diff --git a/core/java/android/service/autofill/FieldClassification.java b/core/java/android/service/autofill/FieldClassification.java index cd1efd68df6f..5bf56cb9c1b5 100644 --- a/core/java/android/service/autofill/FieldClassification.java +++ b/core/java/android/service/autofill/FieldClassification.java @@ -108,21 +108,21 @@ public final class FieldClassification { */ public static final class Match { - private final String mRemoteId; + private final String mCategoryId; private final float mScore; /** @hide */ - public Match(String remoteId, float score) { - mRemoteId = Preconditions.checkNotNull(remoteId); + public Match(String categoryId, float score) { + mCategoryId = Preconditions.checkNotNull(categoryId); mScore = score; } /** - * Gets the remote id of the {@link UserData} entry. + * Gets the category id of the {@link UserData} entry. */ @NonNull - public String getRemoteId() { - return mRemoteId; + public String getCategoryId() { + return mCategoryId; } /** @@ -149,13 +149,13 @@ public final class FieldClassification { public String toString() { if (!sDebug) return super.toString(); - final StringBuilder string = new StringBuilder("Match: remoteId="); - Helper.appendRedacted(string, mRemoteId); + final StringBuilder string = new StringBuilder("Match: categoryId="); + Helper.appendRedacted(string, mCategoryId); return string.append(", score=").append(mScore).toString(); } private void writeToParcel(@NonNull Parcel parcel) { - parcel.writeString(mRemoteId); + parcel.writeString(mCategoryId); parcel.writeFloat(mScore); } diff --git a/core/java/android/service/autofill/UserData.java b/core/java/android/service/autofill/UserData.java index 6bab6aa82375..a1dd1f846515 100644 --- a/core/java/android/service/autofill/UserData.java +++ b/core/java/android/service/autofill/UserData.java @@ -15,6 +15,7 @@ */ package android.service.autofill; +import static android.provider.Settings.Secure.AUTOFILL_USER_DATA_MAX_CATEGORY_COUNT; import static android.provider.Settings.Secure.AUTOFILL_USER_DATA_MAX_FIELD_CLASSIFICATION_IDS_SIZE; import static android.provider.Settings.Secure.AUTOFILL_USER_DATA_MAX_USER_DATA_SIZE; import static android.provider.Settings.Secure.AUTOFILL_USER_DATA_MAX_VALUE_LENGTH; @@ -31,6 +32,7 @@ import android.os.Parcelable; import android.provider.Settings; import android.service.autofill.FieldClassification.Match; import android.text.TextUtils; +import android.util.ArraySet; import android.util.Log; import android.view.autofill.AutofillManager; import android.view.autofill.Helper; @@ -48,23 +50,24 @@ public final class UserData implements Parcelable { private static final String TAG = "UserData"; - private static final int DEFAULT_MAX_USER_DATA_SIZE = 10; + private static final int DEFAULT_MAX_USER_DATA_SIZE = 50; + private static final int DEFAULT_MAX_CATEGORY_COUNT = 10; private static final int DEFAULT_MAX_FIELD_CLASSIFICATION_IDS_SIZE = 10; - private static final int DEFAULT_MIN_VALUE_LENGTH = 5; + private static final int DEFAULT_MIN_VALUE_LENGTH = 3; private static final int DEFAULT_MAX_VALUE_LENGTH = 100; private final String mId; private final String mAlgorithm; private final Bundle mAlgorithmArgs; - private final String[] mRemoteIds; + private final String[] mCategoryIds; private final String[] mValues; private UserData(Builder builder) { mId = builder.mId; mAlgorithm = builder.mAlgorithm; mAlgorithmArgs = builder.mAlgorithmArgs; - mRemoteIds = new String[builder.mRemoteIds.size()]; - builder.mRemoteIds.toArray(mRemoteIds); + mCategoryIds = new String[builder.mCategoryIds.size()]; + builder.mCategoryIds.toArray(mCategoryIds); mValues = new String[builder.mValues.size()]; builder.mValues.toArray(mValues); } @@ -91,8 +94,8 @@ public final class UserData implements Parcelable { } /** @hide */ - public String[] getRemoteIds() { - return mRemoteIds; + public String[] getCategoryIds() { + return mCategoryIds; } /** @hide */ @@ -106,11 +109,11 @@ public final class UserData implements Parcelable { pw.print(prefix); pw.print("Algorithm: "); pw.print(mAlgorithm); pw.print(" Args: "); pw.println(mAlgorithmArgs); - // Cannot disclose remote ids or values because they could contain PII - pw.print(prefix); pw.print("Remote ids size: "); pw.println(mRemoteIds.length); - for (int i = 0; i < mRemoteIds.length; i++) { + // Cannot disclose field ids or values because they could contain PII + pw.print(prefix); pw.print("Field ids size: "); pw.println(mCategoryIds.length); + for (int i = 0; i < mCategoryIds.length; i++) { pw.print(prefix); pw.print(prefix); pw.print(i); pw.print(": "); - pw.println(Helper.getRedacted(mRemoteIds[i])); + pw.println(Helper.getRedacted(mCategoryIds[i])); } pw.print(prefix); pw.print("Values size: "); pw.println(mValues.length); for (int i = 0; i < mValues.length; i++) { @@ -124,6 +127,7 @@ public final class UserData implements Parcelable { pw.print(prefix); pw.print("maxUserDataSize: "); pw.println(getMaxUserDataSize()); pw.print(prefix); pw.print("maxFieldClassificationIdsSize: "); pw.println(getMaxFieldClassificationIdsSize()); + pw.print(prefix); pw.print("maxCategoryCount: "); pw.println(getMaxCategoryCount()); pw.print(prefix); pw.print("minValueLength: "); pw.println(getMinValueLength()); pw.print(prefix); pw.print("maxValueLength: "); pw.println(getMaxValueLength()); } @@ -133,44 +137,59 @@ public final class UserData implements Parcelable { */ public static final class Builder { private final String mId; - private final ArrayList<String> mRemoteIds; + private final ArrayList<String> mCategoryIds; private final ArrayList<String> mValues; private String mAlgorithm; private Bundle mAlgorithmArgs; private boolean mDestroyed; + // Non-persistent array used to limit the number of unique ids. + private final ArraySet<String> mUniqueCategoryIds; + /** * Creates a new builder for the user data used for <a href="#FieldClassification">field * classification</a>. * - * <p>The user data must contain at least one pair of {@code remoteId} -> {@code value}, and - * more pairs can be added through the {@link #add(String, String)} method. + * <p>The user data must contain at least one pair of {@code value} -> {@code categoryId}, + * and more pairs can be added through the {@link #add(String, String)} method. For example: + * + * <pre class="prettyprint"> + * new UserData.Builder("v1", "Bart Simpson", "name") + * .add("bart.simpson@example.com", "email") + * .add("el_barto@example.com", "email") + * .build(); + * </pre> * * @param id id used to identify the whole {@link UserData} object. This id is also returned * by {@link AutofillManager#getUserDataId()}, which can be used to check if the * {@link UserData} is up-to-date without fetching the whole object (through * {@link AutofillManager#getUserData()}). - * @param remoteId unique string used to identify a user data value. + * * @param value value of the user data. + * @param categoryId string used to identify the category the value is associated with. * * @throws IllegalArgumentException if any of the following occurs: * <ol> - * <li>{@code id} is empty - * <li>{@code remoteId} is empty - * <li>{@code value} is empty - * <li>the length of {@code value} is lower than {@link UserData#getMinValueLength()} - * <li>the length of {@code value} is higher than {@link UserData#getMaxValueLength()} + * <li>{@code id} is empty</li> + * <li>{@code categoryId} is empty</li> + * <li>{@code value} is empty</li> + * <li>the length of {@code value} is lower than {@link UserData#getMinValueLength()}</li> + * <li>the length of {@code value} is higher than + * {@link UserData#getMaxValueLength()}</li> * </ol> + * */ - public Builder(@NonNull String id, @NonNull String remoteId, @NonNull String value) { + // TODO(b/70407264): ignore entry instead of throwing exception when settings changed + public Builder(@NonNull String id, @NonNull String value, @NonNull String categoryId) { mId = checkNotEmpty("id", id); - checkNotEmpty("remoteId", remoteId); + checkNotEmpty("categoryId", categoryId); checkValidValue(value); - final int capacity = getMaxUserDataSize(); - mRemoteIds = new ArrayList<>(capacity); - mValues = new ArrayList<>(capacity); - mRemoteIds.add(remoteId); - mValues.add(value); + final int maxUserDataSize = getMaxUserDataSize(); + mCategoryIds = new ArrayList<>(maxUserDataSize); + mValues = new ArrayList<>(maxUserDataSize); + mUniqueCategoryIds = new ArraySet<>(getMaxCategoryCount()); + + addMapping(value, categoryId); } /** @@ -190,6 +209,7 @@ public final class UserData implements Parcelable { */ public Builder setFieldClassificationAlgorithm(@Nullable String name, @Nullable Bundle args) { + throwIfDestroyed(); mAlgorithm = name; mAlgorithmArgs = args; return this; @@ -198,37 +218,58 @@ public final class UserData implements Parcelable { /** * Adds a new value for user data. * - * @param remoteId unique string used to identify the user data. * @param value value of the user data. + * @param categoryId string used to identify the category the value is associated with. * - * @throws IllegalStateException if {@link #build()} or - * {@link #add(String, String)} with the same {@code remoteId} has already - * been called, or if the number of values add (i.e., calls made to this method plus - * constructor) is more than {@link UserData#getMaxUserDataSize()}. + * @throws IllegalStateException if: + * <ol> + * <li>{@link #build()} already called</li> + * <li>the {@code value} has already been added</li> + * <li>the number of unique {@code categoryId} values added so far is more than + * {@link UserData#getMaxCategoryCount()}</li> + * <li>the number of {@code values} added so far is is more than + * {@link UserData#getMaxUserDataSize()}</li> + * </ol> * - * @throws IllegalArgumentException if {@code remoteId} or {@code value} are empty or if the - * length of {@code value} is lower than {@link UserData#getMinValueLength()} - * or higher than {@link UserData#getMaxValueLength()}. + * @throws IllegalArgumentException if any of the following occurs: + * <ol> + * <li>{@code id} is empty</li> + * <li>{@code categoryId} is empty</li> + * <li>{@code value} is empty</li> + * <li>the length of {@code value} is lower than {@link UserData#getMinValueLength()}</li> + * <li>the length of {@code value} is higher than + * {@link UserData#getMaxValueLength()}</li> + * </ol> */ - public Builder add(@NonNull String remoteId, @NonNull String value) { + // TODO(b/70407264): ignore entry instead of throwing exception when settings changed + public Builder add(@NonNull String value, @NonNull String categoryId) { throwIfDestroyed(); - checkNotEmpty("remoteId", remoteId); + checkNotEmpty("categoryId", categoryId); checkValidValue(value); - Preconditions.checkState(!mRemoteIds.contains(remoteId), - // Don't include remoteId on message because it could contain PII - "already has entry with same remoteId"); + if (!mUniqueCategoryIds.contains(categoryId)) { + // New category - check size + Preconditions.checkState(mUniqueCategoryIds.size() < getMaxCategoryCount(), + "already added " + mUniqueCategoryIds.size() + " unique category ids"); + + } + Preconditions.checkState(!mValues.contains(value), - // Don't include remoteId on message because it could contain PII + // Don't include value on message because it could contain PII "already has entry with same value"); - Preconditions.checkState(mRemoteIds.size() < getMaxUserDataSize(), - "already added " + mRemoteIds.size() + " elements"); - mRemoteIds.add(remoteId); - mValues.add(value); + Preconditions.checkState(mValues.size() < getMaxUserDataSize(), + "already added " + mValues.size() + " elements"); + addMapping(value, categoryId); return this; } + private void addMapping(@NonNull String value, @NonNull String categoryId) { + mCategoryIds.add(categoryId); + mValues.add(value); + mUniqueCategoryIds.add(categoryId); + } + private String checkNotEmpty(@NonNull String name, @Nullable String value) { Preconditions.checkNotNull(value); Preconditions.checkArgument(!TextUtils.isEmpty(value), "%s cannot be empty", name); @@ -273,9 +314,9 @@ public final class UserData implements Parcelable { final StringBuilder builder = new StringBuilder("UserData: [id=").append(mId) .append(", algorithm=").append(mAlgorithm); - // Cannot disclose remote ids or values because they could contain PII - builder.append(", remoteIds="); - Helper.appendRedacted(builder, mRemoteIds); + // Cannot disclose category ids or values because they could contain PII + builder.append(", categoryIds="); + Helper.appendRedacted(builder, mCategoryIds); builder.append(", values="); Helper.appendRedacted(builder, mValues); return builder.append("]").toString(); @@ -293,7 +334,7 @@ public final class UserData implements Parcelable { @Override public void writeToParcel(Parcel parcel, int flags) { parcel.writeString(mId); - parcel.writeStringArray(mRemoteIds); + parcel.writeStringArray(mCategoryIds); parcel.writeStringArray(mValues); parcel.writeString(mAlgorithm); parcel.writeBundle(mAlgorithmArgs); @@ -307,12 +348,12 @@ public final class UserData implements Parcelable { // the system obeys the contract of the builder to avoid attacks // using specially crafted parcels. final String id = parcel.readString(); - final String[] remoteIds = parcel.readStringArray(); + final String[] categoryIds = parcel.readStringArray(); final String[] values = parcel.readStringArray(); - final Builder builder = new Builder(id, remoteIds[0], values[0]) + final Builder builder = new Builder(id, values[0], categoryIds[0]) .setFieldClassificationAlgorithm(parcel.readString(), parcel.readBundle()); - for (int i = 1; i < remoteIds.length; i++) { - builder.add(remoteIds[i], values[i]); + for (int i = 1; i < categoryIds.length; i++) { + builder.add(values[i], categoryIds[i]); } return builder.build(); } @@ -340,6 +381,14 @@ public final class UserData implements Parcelable { } /** + * Gets the maximum number of unique category ids that can be passed to + * the builder's constructor and {@link Builder#add(String, String)}. + */ + public static int getMaxCategoryCount() { + return getInt(AUTOFILL_USER_DATA_MAX_CATEGORY_COUNT, DEFAULT_MAX_CATEGORY_COUNT); + } + + /** * Gets the minimum length of values passed to the builder's constructor or * or {@link Builder#add(String, String)}. */ diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java index 85cf9b6c3c91..b367f29da1a0 100644 --- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java +++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java @@ -468,6 +468,7 @@ public class SettingsBackupTest { Settings.Secure.ASSIST_SCREENSHOT_ENABLED, Settings.Secure.ASSIST_STRUCTURE_ENABLED, Settings.Secure.AUTOFILL_FEATURE_FIELD_CLASSIFICATION, + Settings.Secure.AUTOFILL_USER_DATA_MAX_CATEGORY_COUNT, Settings.Secure.AUTOFILL_USER_DATA_MAX_FIELD_CLASSIFICATION_IDS_SIZE, Settings.Secure.AUTOFILL_USER_DATA_MAX_USER_DATA_SIZE, Settings.Secure.AUTOFILL_USER_DATA_MAX_VALUE_LENGTH, diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto index 7eebf5a3f94a..320c37fdc319 100644 --- a/proto/src/metrics_constants.proto +++ b/proto/src/metrics_constants.proto @@ -5229,6 +5229,34 @@ message MetricsEvent { // OS: P DIALOG_TV_NETWORK_PROXY = 1301; + // Events for battery saver turning on/off and/or the interactive state changes. + // OS: P + BATTERY_SAVER = 1302; + + // Device interactive state -- i.e. the screen ON (=1) or OFF (=1) + // OS: P + FIELD_INTERACTIVE = 1303; + + // Time spent in milliseconds in the current mode. + // OS: P + FIELD_DURATION_MILLIS = 1304; + + // Battery level in uA (0 - ~3,000,000 depending on device) when the current "mode" started. + // OS: P + FIELD_START_BATTERY_UA = 1305; + + // Battery level in uA (0 - ~3,000,000 depending on device) when this event was created. + // OS: P + FIELD_END_BATTERY_UA = 1306; + + // Battery level in % (0-100) when the current "mode" started. + // OS: P + FIELD_START_BATTERY_PERCENT = 1307; + + // Battery level in % (0-100) when this event was created. + // OS: P + FIELD_END_BATTERY_PERCENT = 1308; + // ---- End P Constants, all P constants go above this line ---- // Add new aosp constants above this line. // END OF AOSP CONSTANTS diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java index 31f293334c65..712ea36be6ca 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java +++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java @@ -870,7 +870,7 @@ final class AutofillManagerServiceImpl { } mUserData = userData; // Log it - int numberFields = mUserData == null ? 0: mUserData.getRemoteIds().length; + int numberFields = mUserData == null ? 0: mUserData.getCategoryIds().length; mMetricsLogger.write(Helper.newLogMaker(MetricsEvent.AUTOFILL_USERDATA_UPDATED, getServicePackageName(), null) .setCounterValue(numberFields)); diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java index 55c36b072c96..d0475810ee66 100644 --- a/services/autofill/java/com/android/server/autofill/Session.java +++ b/services/autofill/java/com/android/server/autofill/Session.java @@ -1174,12 +1174,12 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState @NonNull UserData userData, @NonNull Collection<ViewState> viewStates) { final String[] userValues = userData.getValues(); - final String[] remoteIds = userData.getRemoteIds(); + final String[] categoryIds = userData.getCategoryIds(); // Sanity check - if (userValues == null || remoteIds == null || userValues.length != remoteIds.length) { + if (userValues == null || categoryIds == null || userValues.length != categoryIds.length) { final int valuesLength = userValues == null ? -1 : userValues.length; - final int idsLength = remoteIds == null ? -1 : remoteIds.length; + final int idsLength = categoryIds == null ? -1 : categoryIds.length; Slog.w(TAG, "setScores(): user data mismatch: values.length = " + valuesLength + ", ids.length = " + idsLength); return; @@ -1196,12 +1196,12 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState final int viewsSize = viewStates.size(); // First, we get all scores. - final AutofillId[] fieldIds = new AutofillId[viewsSize]; + final AutofillId[] autofillIds = new AutofillId[viewsSize]; final ArrayList<AutofillValue> currentValues = new ArrayList<>(viewsSize); int k = 0; for (ViewState viewState : viewStates) { currentValues.add(viewState.getCurrentValue()); - fieldIds[k++] = viewState.id; + autofillIds[k++] = viewState.id; } // Then use the results, asynchronously @@ -1221,32 +1221,53 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState } int i = 0, j = 0; try { + // Iteract over all autofill fields first for (i = 0; i < viewsSize; i++) { - final AutofillId fieldId = fieldIds[i]; + final AutofillId autofillId = autofillIds[i]; - ArrayList<Match> matches = null; + // Search the best scores for each category (as some categories could have + // multiple user values + ArrayMap<String, Float> scoresByField = null; for (j = 0; j < userValues.length; j++) { - String remoteId = remoteIds[j]; + final String categoryId = categoryIds[j]; final float score = scores.scores[i][j]; if (score > 0) { + if (scoresByField == null) { + scoresByField = new ArrayMap<>(userValues.length); + } + final Float currentScore = scoresByField.get(categoryId); + if (currentScore != null && currentScore > score) { + if (sVerbose) { + Slog.v(TAG, "skipping score " + score + + " because it's less than " + currentScore); + } + continue; + } if (sVerbose) { Slog.v(TAG, "adding score " + score + " at index " + j + " and id " - + fieldId); - } - if (matches == null) { - matches = new ArrayList<>(userValues.length); + + autofillId); } - matches.add(new Match(remoteId, score)); + scoresByField.put(categoryId, score); } else if (sVerbose) { - Slog.v(TAG, "skipping score 0 at index " + j + " and id " + fieldId); + Slog.v(TAG, "skipping score 0 at index " + j + " and id " + autofillId); } } - if (matches != null) { - detectedFieldIds.add(fieldId); - detectedFieldClassifications.add(new FieldClassification(matches)); + if (scoresByField == null) { + if (sVerbose) Slog.v(TAG, "no score for autofillId=" + autofillId); + continue; } - } + + // Then create the matches for that autofill id + final ArrayList<Match> matches = new ArrayList<>(scoresByField.size()); + for (j = 0; j < scoresByField.size(); j++) { + final String fieldId = scoresByField.keyAt(j); + final float score = scoresByField.valueAt(j); + matches.add(new Match(fieldId, score)); + } + detectedFieldIds.add(autofillId); + detectedFieldClassifications.add(new FieldClassification(matches)); + } // for i } catch (ArrayIndexOutOfBoundsException e) { wtf(e, "Error accessing FC score at [%d, %d] (%s): %s", i, j, scores, e); return; diff --git a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java index 87e8121a474d..836791649748 100644 --- a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java +++ b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java @@ -81,7 +81,7 @@ class ActivityManagerDebugConfig { static final boolean DEBUG_FOREGROUND_SERVICE = DEBUG_ALL || false; static final boolean DEBUG_SERVICE_EXECUTING = DEBUG_ALL || false; static final boolean DEBUG_STACK = DEBUG_ALL || false; - static final boolean DEBUG_STATES = DEBUG_ALL_ACTIVITIES || false; + static final boolean DEBUG_STATES = DEBUG_ALL_ACTIVITIES || true; static final boolean DEBUG_SWITCH = DEBUG_ALL || false; static final boolean DEBUG_TASKS = DEBUG_ALL || false; static final boolean DEBUG_TRANSITION = DEBUG_ALL || false; diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySavingStats.java b/services/core/java/com/android/server/power/batterysaver/BatterySavingStats.java index 37df94fee207..5d76329eb8a1 100644 --- a/services/core/java/com/android/server/power/batterysaver/BatterySavingStats.java +++ b/services/core/java/com/android/server/power/batterysaver/BatterySavingStats.java @@ -15,6 +15,7 @@ */ package com.android.server.power.batterysaver; +import android.metrics.LogMaker; import android.os.BatteryManagerInternal; import android.os.SystemClock; import android.util.ArrayMap; @@ -23,6 +24,8 @@ import android.util.Slog; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.MetricsLogger; +import com.android.internal.logging.nano.MetricsProto; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.server.EventLogTags; import com.android.server.LocalServices; import com.android.server.power.BatterySaverPolicy; @@ -43,6 +46,9 @@ public class BatterySavingStats { private static final boolean DEBUG = BatterySaverPolicy.DEBUG; + @VisibleForTesting + static final boolean SEND_TRON_EVENTS = true; + private final Object mLock = new Object(); /** Whether battery saver is on or off. */ @@ -132,15 +138,6 @@ public class BatterySavingStats { } } - @VisibleForTesting - static final String COUNTER_POWER_PERCENT_PREFIX = "battery_saver_stats_percent_"; - - @VisibleForTesting - static final String COUNTER_POWER_MILLIAMPS_PREFIX = "battery_saver_stats_milliamps_"; - - @VisibleForTesting - static final String COUNTER_TIME_SECONDS_PREFIX = "battery_saver_stats_seconds_"; - private static BatterySavingStats sInstance; private BatteryManagerInternal mBatteryManagerInternal; @@ -427,10 +424,9 @@ public class BatterySavingStats { if (stateChanging) { if (mLastState >= 0) { final long deltaTime = now - mStartTime; - final int deltaBattery = mStartBatteryLevel - batteryLevel; - final int deltaPercent = mStartPercent - batteryPercent; - report(mLastState, deltaTime, deltaBattery, deltaPercent); + report(mLastState, deltaTime, mStartBatteryLevel, mStartPercent, + batteryLevel, batteryPercent); } mStartTime = now; mStartBatteryLevel = batteryLevel; @@ -439,23 +435,28 @@ public class BatterySavingStats { mLastState = newState; } - String getCounterSuffix(int state) { - final boolean batterySaver = + void report(int state, long deltaTimeMs, + int startBatteryLevelUa, int startBatteryLevelPercent, + int endBatteryLevelUa, int endBatteryLevelPercent) { + if (!SEND_TRON_EVENTS) { + return; + } + final boolean batterySaverOn = BatterySaverState.fromIndex(state) != BatterySaverState.OFF; final boolean interactive = InteractiveState.fromIndex(state) != InteractiveState.NON_INTERACTIVE; - if (batterySaver) { - return interactive ? "11" : "10"; - } else { - return interactive ? "01" : "00"; - } - } - void report(int state, long deltaTimeMs, int deltaBatteryUa, int deltaPercent) { - final String suffix = getCounterSuffix(state); - mMetricsLogger.count(COUNTER_POWER_MILLIAMPS_PREFIX + suffix, deltaBatteryUa / 1000); - mMetricsLogger.count(COUNTER_POWER_PERCENT_PREFIX + suffix, deltaPercent); - mMetricsLogger.count(COUNTER_TIME_SECONDS_PREFIX + suffix, (int) (deltaTimeMs / 1000)); + final LogMaker logMaker = new LogMaker(MetricsProto.MetricsEvent.BATTERY_SAVER) + .setSubtype(batterySaverOn ? 1 : 0) + .addTaggedData(MetricsEvent.FIELD_INTERACTIVE, interactive ? 1 : 0) + .addTaggedData(MetricsEvent.FIELD_DURATION_MILLIS, deltaTimeMs) + .addTaggedData(MetricsEvent.FIELD_START_BATTERY_UA, startBatteryLevelUa) + .addTaggedData(MetricsEvent.FIELD_START_BATTERY_PERCENT, + startBatteryLevelPercent) + .addTaggedData(MetricsEvent.FIELD_END_BATTERY_UA, endBatteryLevelUa) + .addTaggedData(MetricsEvent.FIELD_END_BATTERY_PERCENT, endBatteryLevelPercent); + + mMetricsLogger.write(logMaker); } } } diff --git a/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySavingStatsTest.java b/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySavingStatsTest.java index f7516b2c3694..f7112d43443b 100644 --- a/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySavingStatsTest.java +++ b/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySavingStatsTest.java @@ -15,25 +15,30 @@ */ package com.android.server.power.batterysaver; +import static com.android.server.power.batterysaver.BatterySavingStats.SEND_TRON_EVENTS; + import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import android.metrics.LogMaker; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; import com.android.internal.logging.MetricsLogger; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.server.power.batterysaver.BatterySavingStats.BatterySaverState; import com.android.server.power.batterysaver.BatterySavingStats.DozeState; import com.android.server.power.batterysaver.BatterySavingStats.InteractiveState; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; import java.io.ByteArrayOutputStream; import java.io.PrintWriter; @@ -222,8 +227,28 @@ public class BatterySavingStatsTest { target.toDebugString()); } - private void assertMetricsLog(String counter, int value) { - verify(mMetricsLogger, times(1)).count(eq(counter), eq(value)); + private void assertLog(boolean batterySaver, boolean interactive, long deltaTimeMs, + int deltaBatteryLevelUa, int deltaBatteryLevelPercent) { + if (SEND_TRON_EVENTS) { + ArgumentCaptor<LogMaker> ac = ArgumentCaptor.forClass(LogMaker.class); + verify(mMetricsLogger, times(1)).write(ac.capture()); + + LogMaker lm = ac.getValue(); + assertEquals(MetricsEvent.BATTERY_SAVER, lm.getCategory()); + assertEquals(batterySaver ? 1 : 0, + lm.getTaggedData(MetricsEvent.RESERVED_FOR_LOGBUILDER_SUBTYPE)); + assertEquals(interactive ? 1 : 0, lm.getTaggedData(MetricsEvent.FIELD_INTERACTIVE)); + assertEquals(deltaTimeMs, lm.getTaggedData(MetricsEvent.FIELD_DURATION_MILLIS)); + + assertEquals(deltaBatteryLevelUa, + (int) lm.getTaggedData(MetricsEvent.FIELD_START_BATTERY_UA) + - (int) lm.getTaggedData(MetricsEvent.FIELD_END_BATTERY_UA)); + assertEquals(deltaBatteryLevelPercent, + (int) lm.getTaggedData(MetricsEvent.FIELD_START_BATTERY_PERCENT) + - (int) lm.getTaggedData(MetricsEvent.FIELD_END_BATTERY_PERCENT)); + } else { + verify(mMetricsLogger, times(0)).write(any(LogMaker.class)); + } } @Test @@ -249,9 +274,7 @@ public class BatterySavingStatsTest { InteractiveState.NON_INTERACTIVE, DozeState.NOT_DOZING); - assertMetricsLog(BatterySavingStats.COUNTER_POWER_MILLIAMPS_PREFIX + "01", 2); - assertMetricsLog(BatterySavingStats.COUNTER_POWER_PERCENT_PREFIX + "01", 200); - assertMetricsLog(BatterySavingStats.COUNTER_TIME_SECONDS_PREFIX + "01", 60); + assertLog(false, true, 60_000, 2000, 200); target.advanceClock(1); target.drainBattery(2000); @@ -282,9 +305,7 @@ public class BatterySavingStatsTest { InteractiveState.INTERACTIVE, DozeState.NOT_DOZING); - assertMetricsLog(BatterySavingStats.COUNTER_POWER_MILLIAMPS_PREFIX + "00", 2 * 3); - assertMetricsLog(BatterySavingStats.COUNTER_POWER_PERCENT_PREFIX + "00", 200 * 3); - assertMetricsLog(BatterySavingStats.COUNTER_TIME_SECONDS_PREFIX + "00", 60 * 3); + assertLog(false, false, 60_000 * 3, 2000 * 3, 200 * 3); target.advanceClock(10); target.drainBattery(10000); @@ -292,9 +313,7 @@ public class BatterySavingStatsTest { reset(mMetricsLogger); target.startCharging(); - assertMetricsLog(BatterySavingStats.COUNTER_POWER_MILLIAMPS_PREFIX + "11", 10); - assertMetricsLog(BatterySavingStats.COUNTER_POWER_PERCENT_PREFIX + "11", 1000); - assertMetricsLog(BatterySavingStats.COUNTER_TIME_SECONDS_PREFIX + "11", 60 * 10); + assertLog(true, true, 60_000 * 10, 10000, 1000); target.advanceClock(1); target.drainBattery(2000); @@ -312,8 +331,6 @@ public class BatterySavingStatsTest { target.startCharging(); - assertMetricsLog(BatterySavingStats.COUNTER_POWER_MILLIAMPS_PREFIX + "10", 2); - assertMetricsLog(BatterySavingStats.COUNTER_POWER_PERCENT_PREFIX + "10", 200); - assertMetricsLog(BatterySavingStats.COUNTER_TIME_SECONDS_PREFIX + "10", 60); + assertLog(true, false, 60_000, 2000, 200); } } |