Add metric wrapper class for managed device metrics.
CTS test will be added in another CL.
Bug: 119906490
Test: None
Change-Id: I06e382ee68904d2315c58043a488c55f1484f7d1
diff --git a/Android.bp b/Android.bp
index 7e038ce8..c5ec161 100644
--- a/Android.bp
+++ b/Android.bp
@@ -725,6 +725,7 @@
"android.hardware.radio-V1.3-java",
"android.hardware.usb.gadget-V1.0-java",
"netd_aidl_interface-java",
+ "devicepolicyprotosnano",
],
// Loaded with System.loadLibrary by android.view.textclassifier
diff --git a/core/java/android/app/admin/DevicePolicyEventLogger.java b/core/java/android/app/admin/DevicePolicyEventLogger.java
new file mode 100644
index 0000000..f39a5f4
--- /dev/null
+++ b/core/java/android/app/admin/DevicePolicyEventLogger.java
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.admin;
+
+import android.stats.devicepolicy.nano.StringList;
+import android.util.StatsLog;
+
+import com.android.framework.protobuf.nano.MessageNano;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.Preconditions;
+
+/**
+ * A wrapper for logging managed device events using {@link StatsLog}.
+ * <p/>
+ * This class allows chaining - each of its methods returns a reference to the current instance.
+ * <p/>
+ * Example usage:
+ * <code><pre>
+ * import android.stats.devicepolicy.DevicePolicyEnums;
+ *
+ * DevicePolicyEventLogger
+ * .createEvent(DevicePolicyEnums.USER_RESTRICTION_CHANGED)
+ * .setAdminPackageName(who)
+ * .setString(key)
+ * .setBoolean(enabledFromThisOwner)
+ * .write();
+ * </pre></code>
+ *
+ * @see StatsLog
+ * @hide
+ */
+public final class DevicePolicyEventLogger {
+ private final int mEventId;
+ private int mIntValue;
+ private boolean mBooleanValue;
+ private long mTimePeriodMs;
+ private String[] mStringArrayValue;
+ private String mAdminPackageName;
+
+ private DevicePolicyEventLogger(int eventId) {
+ mEventId = eventId;
+ }
+
+ /**
+ * Creates a new {@link DevicePolicyEventLogger} instance for the specified
+ * <code>eventId</code>.
+ *
+ * @param eventId one of {@link android.stats.devicepolicy.DevicePolicyEnums} as defined in
+ * <code>core/proto/android/stats/devicepolicy/device_policy_enums.proto</code>
+ */
+ public static DevicePolicyEventLogger createEvent(int eventId) {
+ return new DevicePolicyEventLogger(eventId);
+ }
+
+ /**
+ * Returns the event id.
+ */
+ @VisibleForTesting
+ public int getEventId() {
+ return mEventId;
+ }
+
+ /**
+ * Sets a generic <code>int</code> value.
+ */
+ public DevicePolicyEventLogger setInt(int value) {
+ mIntValue = value;
+ return this;
+ }
+
+ /**
+ * Returns the generic <code>int</code> value.
+ */
+ @VisibleForTesting
+ public int getInt() {
+ return mIntValue;
+ }
+
+ /**
+ * Sets a generic <code>boolean</code> value.
+ */
+ public DevicePolicyEventLogger setBoolean(boolean value) {
+ mBooleanValue = value;
+ return this;
+ }
+
+ /**
+ * Returns the generic <code>boolean</code> value.
+ */
+ @VisibleForTesting
+ public boolean getBoolean() {
+ return mBooleanValue;
+ }
+
+ /**
+ * Sets a time period in milliseconds.
+ */
+ public DevicePolicyEventLogger setTimePeriod(long timePeriodMillis) {
+ mTimePeriodMs = timePeriodMillis;
+ return this;
+ }
+
+ /**
+ * Returns the time period in milliseconds.
+ */
+ @VisibleForTesting
+ public long getTimePeriod() {
+ return mTimePeriodMs;
+ }
+
+ /**
+ * Sets generic <code>String</code> values.
+ */
+ public DevicePolicyEventLogger setStrings(String... values) {
+ mStringArrayValue = values;
+ return this;
+ }
+
+ /**
+ * Sets generic <code>String</code> values.
+ * <p/>
+ * {@link #write()} logs the concatenation of <code>value</code> and <code>values</code>,
+ * in that order.
+ */
+ public DevicePolicyEventLogger setStrings(String value, String[] values) {
+ Preconditions.checkNotNull(values, "values parameter cannot be null");
+ mStringArrayValue = new String[values.length + 1];
+ mStringArrayValue[0] = value;
+ System.arraycopy(values, 0, mStringArrayValue, 1, values.length);
+ return this;
+ }
+
+ /**
+ * Sets generic <code>String</code> values.
+ * <p/>
+ * {@link #write()} logs the concatenation of <code>value1</code>, <code>value2</code>
+ * and <code>values</code>, in that order.
+ */
+ public DevicePolicyEventLogger setStrings(String value1, String value2, String[] values) {
+ Preconditions.checkNotNull(values, "values parameter cannot be null");
+ mStringArrayValue = new String[values.length + 2];
+ mStringArrayValue[0] = value1;
+ mStringArrayValue[1] = value2;
+ System.arraycopy(values, 0, mStringArrayValue, 2, values.length);
+ return this;
+ }
+
+ /**
+ * Returns the generic <code>String[]</code> value.
+ */
+ @VisibleForTesting
+ public String[] getStringArray() {
+ return mStringArrayValue;
+ }
+
+ /**
+ * Sets the package name of the admin application.
+ */
+ public DevicePolicyEventLogger setAdminPackageName(String packageName) {
+ mAdminPackageName = packageName;
+ return this;
+ }
+
+ /**
+ * Returns the package name of the admin application.
+ */
+ @VisibleForTesting
+ public String getAdminPackageName() {
+ return mAdminPackageName;
+ }
+
+ /**
+ * Writes the metric to {@link StatsLog}.
+ */
+ public void write() {
+ byte[] bytes = stringArrayValueToBytes(mStringArrayValue);
+ StatsLog.write(StatsLog.DEVICE_POLICY_EVENT, mEventId, mAdminPackageName, mIntValue,
+ mBooleanValue, mTimePeriodMs, bytes);
+ }
+
+ /**
+ * Converts the <code>String[] array</code> to <code>byte[]</code>.
+ * <p/>
+ * We can't log <code>String[]</code> using {@link StatsLog}. The convention is to assign
+ * the array to a proto object and convert it to <code>byte[]</code>.
+ */
+ private static byte[] stringArrayValueToBytes(String[] array) {
+ if (array == null) {
+ return null;
+ }
+ StringList stringList = new StringList();
+ stringList.stringValue = array;
+ return MessageNano.toByteArray(stringList);
+ }
+}