summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/current.txt3
-rw-r--r--api/system-current.txt1
-rw-r--r--api/test-current.txt1
-rw-r--r--core/java/android/provider/Settings.java11
-rw-r--r--core/java/android/service/autofill/FieldClassification.java18
-rw-r--r--core/java/android/service/autofill/UserData.java155
-rw-r--r--core/tests/coretests/src/android/provider/SettingsBackupTest.java1
-rw-r--r--proto/src/metrics_constants.proto28
-rw-r--r--services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java2
-rw-r--r--services/autofill/java/com/android/server/autofill/Session.java57
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerDebugConfig.java2
-rw-r--r--services/core/java/com/android/server/power/batterysaver/BatterySavingStats.java51
-rw-r--r--services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySavingStatsTest.java47
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);
}
}