1 /*
2  * Copyright (C) 2018 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.admin;
18 
19 import android.annotation.Nullable;
20 import android.content.ComponentName;
21 import android.stats.devicepolicy.nano.StringList;
22 import android.util.StatsLog;
23 
24 import com.android.framework.protobuf.nano.MessageNano;
25 import com.android.internal.util.Preconditions;
26 
27 import java.util.Arrays;
28 
29 /**
30  * A wrapper for logging managed device events using {@link StatsLog}.
31  * <p/>
32  * This class allows chaining - each of its methods returns a reference to the current instance.
33  * <p/>
34  * Example usage:
35  * <code><pre>
36  * import android.stats.devicepolicy.DevicePolicyEnums;
37  *
38  * DevicePolicyEventLogger
39  *     .createEvent(DevicePolicyEnums.USER_RESTRICTION_CHANGED)
40  *     .setAdmin(who)
41  *     .setString(key)
42  *     .setBoolean(enabledFromThisOwner)
43  *     .write();
44  * </pre></code>
45  *
46  * @see StatsLog
47  * @hide
48  */
49 public class DevicePolicyEventLogger {
50     private final int mEventId;
51     private int mIntValue;
52     private boolean mBooleanValue;
53     private long mTimePeriodMs;
54     private String[] mStringArrayValue;
55     private String mAdminPackageName;
56 
DevicePolicyEventLogger(int eventId)57     private DevicePolicyEventLogger(int eventId) {
58         mEventId = eventId;
59     }
60 
61     /**
62      * Creates a new {@link DevicePolicyEventLogger} instance for the specified
63      * <code>eventId</code>.
64      *
65      * @param eventId one of {@link android.stats.devicepolicy.DevicePolicyEnums} as defined in
66      * <code>core/proto/android/stats/devicepolicy/device_policy_enums.proto</code>
67      */
createEvent(int eventId)68     public static DevicePolicyEventLogger createEvent(int eventId) {
69         return new DevicePolicyEventLogger(eventId);
70     }
71 
72     /**
73      * Returns the event id.
74      */
getEventId()75     public int getEventId() {
76         return mEventId;
77     }
78 
79     /**
80      * Sets a generic <code>int</code> value.
81      */
setInt(int value)82     public DevicePolicyEventLogger setInt(int value) {
83         mIntValue = value;
84         return this;
85     }
86 
87     /**
88      * Returns the generic <code>int</code> value.
89      */
getInt()90     public int getInt() {
91         return mIntValue;
92     }
93 
94     /**
95      * Sets a generic <code>boolean</code> value.
96      */
setBoolean(boolean value)97     public DevicePolicyEventLogger setBoolean(boolean value) {
98         mBooleanValue = value;
99         return this;
100     }
101 
102     /**
103      * Returns the generic <code>boolean</code> value.
104      */
getBoolean()105     public boolean getBoolean() {
106         return mBooleanValue;
107     }
108 
109     /**
110      * Sets a time period in milliseconds.
111      */
setTimePeriod(long timePeriodMillis)112     public DevicePolicyEventLogger setTimePeriod(long timePeriodMillis) {
113         mTimePeriodMs = timePeriodMillis;
114         return this;
115     }
116 
117     /**
118      * Returns the time period in milliseconds.
119      */
getTimePeriod()120     public long getTimePeriod() {
121         return mTimePeriodMs;
122     }
123 
124     /**
125      * Sets generic <code>String</code> values.
126      */
setStrings(String... values)127     public DevicePolicyEventLogger setStrings(String... values) {
128         mStringArrayValue = values;
129         return this;
130     }
131 
132     /**
133      * Sets generic <code>String</code> values.
134      * <p/>
135      * {@link #write()} logs the concatenation of <code>value</code> and <code>values</code>,
136      * in that order.
137      */
setStrings(String value, String[] values)138     public DevicePolicyEventLogger setStrings(String value, String[] values) {
139         Preconditions.checkNotNull(values, "values parameter cannot be null");
140         mStringArrayValue = new String[values.length + 1];
141         mStringArrayValue[0] = value;
142         System.arraycopy(values, 0, mStringArrayValue, 1, values.length);
143         return this;
144     }
145 
146     /**
147      * Sets generic <code>String</code> values.
148      * <p/>
149      * {@link #write()} logs the concatenation of <code>value1</code>, <code>value2</code>
150      * and <code>values</code>, in that order.
151      */
setStrings(String value1, String value2, String[] values)152     public DevicePolicyEventLogger setStrings(String value1, String value2, String[] values) {
153         Preconditions.checkNotNull(values, "values parameter cannot be null");
154         mStringArrayValue = new String[values.length + 2];
155         mStringArrayValue[0] = value1;
156         mStringArrayValue[1] = value2;
157         System.arraycopy(values, 0, mStringArrayValue, 2, values.length);
158         return this;
159     }
160 
161     /**
162      * Returns a copy of the generic <code>String[]</code> value.
163      */
getStringArray()164     public String[] getStringArray() {
165         if (mStringArrayValue == null) {
166             return null;
167         }
168         return Arrays.copyOf(mStringArrayValue, mStringArrayValue.length);
169     }
170 
171     /**
172      * Sets the package name of the admin application.
173      */
setAdmin(@ullable String packageName)174     public DevicePolicyEventLogger setAdmin(@Nullable String packageName) {
175         mAdminPackageName = packageName;
176         return this;
177     }
178 
179     /**
180      * Sets the package name of the admin application from the {@link ComponentName}.
181      */
setAdmin(@ullable ComponentName componentName)182     public DevicePolicyEventLogger setAdmin(@Nullable ComponentName componentName) {
183         mAdminPackageName = (componentName != null ? componentName.getPackageName() : null);
184         return this;
185     }
186 
187     /**
188      * Returns the package name of the admin application.
189      */
getAdminPackageName()190     public String getAdminPackageName() {
191         return mAdminPackageName;
192     }
193 
194     /**
195      * Writes the metric to {@link StatsLog}.
196      */
write()197     public void write() {
198         byte[] bytes = stringArrayValueToBytes(mStringArrayValue);
199         StatsLog.write(StatsLog.DEVICE_POLICY_EVENT, mEventId, mAdminPackageName, mIntValue,
200                 mBooleanValue, mTimePeriodMs, bytes);
201     }
202 
203     /**
204      * Converts the <code>String[] array</code> to <code>byte[]</code>.
205      * <p/>
206      * We can't log <code>String[]</code> using {@link StatsLog}. The convention is to assign
207      * the array to a proto object and convert it to <code>byte[]</code>.
208      */
stringArrayValueToBytes(String[] array)209     private static byte[] stringArrayValueToBytes(String[] array) {
210         if (array == null) {
211             return null;
212         }
213         StringList stringList = new StringList();
214         stringList.stringValue = array;
215         return MessageNano.toByteArray(stringList);
216     }
217 }
218