• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2016, 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 com.android.managedprovisioning.analytics;
18 
19 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE;
20 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE;
21 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_TRIGGER;
22 import static android.app.admin.DevicePolicyManager.PROVISIONING_TRIGGER_QR_CODE;
23 import static android.app.admin.DevicePolicyManager.PROVISIONING_TRIGGER_UNSPECIFIED;
24 import static android.nfc.NfcAdapter.ACTION_NDEF_DISCOVERED;
25 import static android.stats.devicepolicy.DevicePolicyEnums.PROVISIONING_DPC_SETUP_COMPLETED;
26 import static android.stats.devicepolicy.DevicePolicyEnums.PROVISIONING_DPC_SETUP_STARTED;
27 import static android.stats.devicepolicy.DevicePolicyEnums.PROVISIONING_MANAGED_PROFILE_ON_FULLY_MANAGED_DEVICE;
28 
29 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_ACTION;
30 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_CANCELLED;
31 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_DPC_INSTALLED_BY_PACKAGE;
32 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_DPC_PACKAGE_NAME;
33 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_ENTRY_POINT_NFC;
34 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_ENTRY_POINT_QR_CODE;
35 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_ENTRY_POINT_TRUSTED_SOURCE;
36 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_ERROR;
37 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_EXTRA;
38 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_SESSION_COMPLETED;
39 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_SESSION_STARTED;
40 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_TERMS_COUNT;
41 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_TERMS_READ;
42 
43 import android.annotation.IntDef;
44 import android.app.admin.DevicePolicyEventLogger;
45 import android.app.admin.DevicePolicyManager;
46 import android.content.ComponentName;
47 import android.content.Context;
48 import android.content.Intent;
49 import android.stats.devicepolicy.DevicePolicyEnums;
50 
51 import com.android.managedprovisioning.common.ManagedProvisioningSharedPreferences;
52 import com.android.managedprovisioning.model.ProvisioningParams;
53 import com.android.managedprovisioning.task.AbstractProvisioningTask;
54 
55 import java.util.List;
56 
57 /**
58  * Utility class to log metrics.
59  */
60 public class ProvisioningAnalyticsTracker {
61 
62     private final MetricsLoggerWrapper mMetricsLoggerWrapper = new MetricsLoggerWrapper();
63 
64     // Only add to the end of the list. Do not change or rearrange these values, that will break
65     // historical data. Do not use negative numbers or zero, logger only handles positive
66     // integers.
67     public static final int CANCELLED_BEFORE_PROVISIONING = 1;
68     public static final int CANCELLED_DURING_PROVISIONING = 2;
69     public static final int CANCELLED_DURING_PROVISIONING_PREPARE = 3;
70     private final ManagedProvisioningSharedPreferences mSharedPreferences;
71 
72     @IntDef({
73         CANCELLED_BEFORE_PROVISIONING,
74         CANCELLED_DURING_PROVISIONING,
75         CANCELLED_DURING_PROVISIONING_PREPARE})
76     public @interface CancelState {}
77 
78     private static final int PROVISIONING_FLOW_TYPE_ADMIN_INTEGRATED = 1;
79     private static final int PROVISIONING_FLOW_TYPE_LEGACY = 2;
80 
81     private static final int DPC_SETUP_ACTION_UNKNOWN = 1;
82     private static final int DPC_SETUP_ACTION_PROVISIONING_SUCCESSFUL = 2;
83     private static final int DPC_SETUP_ACTION_ADMIN_POLICY_COMPLIANCE = 3;
84 
85     private final MetricsWriter mMetricsWriter;
86 
ProvisioningAnalyticsTracker(MetricsWriter metricsWriter, ManagedProvisioningSharedPreferences prefs)87     public ProvisioningAnalyticsTracker(MetricsWriter metricsWriter,
88             ManagedProvisioningSharedPreferences prefs) {
89         // Disables instantiation. Use getInstance() instead.
90         mMetricsWriter = metricsWriter;
91         mSharedPreferences = prefs;
92     }
93 
94     /**
95      * Logs some metrics when the provisioning starts.
96      *
97      * @param context Context passed to MetricsLogger
98      * @param params Provisioning params
99      */
logProvisioningStarted(Context context, ProvisioningParams params)100     public void logProvisioningStarted(Context context, ProvisioningParams params) {
101         logDpcPackageInformation(context, params.inferDeviceAdminPackageName());
102         logNetworkType(context);
103     }
104 
105     /**
106      * Logs some metrics when the preprovisioning starts.
107      *
108      * @param context Context passed to MetricsLogger
109      * @param intent Intent that started provisioning
110      */
logPreProvisioningStarted(Context context, Intent intent)111     public void logPreProvisioningStarted(Context context, Intent intent) {
112         logProvisioningExtras(context, intent);
113         maybeLogEntryPoint(context, intent);
114     }
115 
116     /**
117      * Logs when provisioning is cancelled.
118      *
119      * @param context Context passed to MetricsLogger
120      * @param cancelState State when provisioning was cancelled
121      */
logProvisioningCancelled(Context context, @CancelState int cancelState)122     public void logProvisioningCancelled(Context context, @CancelState int cancelState) {
123         mMetricsLoggerWrapper.logAction(context, PROVISIONING_CANCELLED, cancelState);
124         mMetricsWriter.write(DevicePolicyEventLogger
125                 .createEvent(DevicePolicyEnums.PROVISIONING_CANCELLED)
126                 .setInt(cancelState)
127                 .setTimePeriod(AnalyticsUtils.getProvisioningTime(mSharedPreferences)));
128     }
129 
130     /**
131      * Logs error during provisioning tasks.
132      *
133      * @param context Context passed to MetricsLogger
134      * @param task Provisioning task which threw error
135      * @param errorCode Code indicating the type of error that happened.
136      */
logProvisioningError(Context context, AbstractProvisioningTask task, int errorCode)137     public void logProvisioningError(Context context, AbstractProvisioningTask task,
138             int errorCode) {
139         mMetricsLoggerWrapper.logAction(context, PROVISIONING_ERROR,
140                 AnalyticsUtils.getErrorString(task, errorCode));
141         mMetricsWriter.write(DevicePolicyEventLogger
142                 .createEvent(DevicePolicyEnums.PROVISIONING_ERROR)
143                 .setStrings(AnalyticsUtils.getErrorString(task, errorCode))
144                 .setTimePeriod(AnalyticsUtils.getProvisioningTime(mSharedPreferences)));
145     }
146 
147     /**
148      * Logs error code, when provisioning is not allowed.
149      *
150      * @param context Context passed to MetricsLogger
151      * @param provisioningErrorCode Code indicating why provisioning is not allowed.
152      */
logProvisioningNotAllowed(Context context, int provisioningErrorCode)153     public void logProvisioningNotAllowed(Context context, int provisioningErrorCode) {
154         mMetricsLoggerWrapper.logAction(context, PROVISIONING_ERROR, provisioningErrorCode);
155         mMetricsWriter.write(DevicePolicyEventLogger
156                 .createEvent(DevicePolicyEnums.PROVISIONING_ERROR)
157                 .setStrings(String.valueOf(provisioningErrorCode))
158                 .setTimePeriod(AnalyticsUtils.getProvisioningTime(mSharedPreferences)));
159     }
160 
161     /**
162      * logs when a provisioning session has started.
163      *
164      * @param context Context passed to MetricsLogger
165      */
logProvisioningSessionStarted(Context context)166     public void logProvisioningSessionStarted(Context context) {
167         mMetricsLoggerWrapper.logAction(context, PROVISIONING_SESSION_STARTED);
168         mMetricsWriter.write(DevicePolicyEventLogger
169                 .createEvent(DevicePolicyEnums.PROVISIONING_SESSION_STARTED)
170                 .setTimePeriod(AnalyticsUtils.getProvisioningTime(mSharedPreferences)));
171     }
172 
173     /**
174      * logs when a provisioning session has completed.
175      *
176      * @param context Context passed to MetricsLogger
177      */
logProvisioningSessionCompleted(Context context)178     public void logProvisioningSessionCompleted(Context context) {
179         mMetricsLoggerWrapper.logAction(context, PROVISIONING_SESSION_COMPLETED);
180         mMetricsWriter.write(DevicePolicyEventLogger
181                 .createEvent(DevicePolicyEnums.PROVISIONING_SESSION_COMPLETED)
182                 .setTimePeriod(AnalyticsUtils.getProvisioningTime(mSharedPreferences)));
183     }
184 
185     /**
186      * logs number of terms displayed on the terms screen.
187      *
188      * @param context Context passed to MetricsLogger
189      * @param count Number of terms displayed
190      */
logNumberOfTermsDisplayed(Context context, int count)191     public void logNumberOfTermsDisplayed(Context context, int count) {
192         mMetricsLoggerWrapper.logAction(context, PROVISIONING_TERMS_COUNT, count);
193         mMetricsWriter.write(DevicePolicyEventLogger
194                 .createEvent(DevicePolicyEnums.PROVISIONING_TERMS_COUNT)
195                 .setInt(count)
196                 .setTimePeriod(AnalyticsUtils.getProvisioningTime(mSharedPreferences)));
197     }
198 
199     /**
200      * logs number of terms read on the terms screen.
201      *
202      * @param context Context passed to MetricsLogger
203      * @param count Number of terms read
204      */
logNumberOfTermsRead(Context context, int count)205     public void logNumberOfTermsRead(Context context, int count) {
206         mMetricsLoggerWrapper.logAction(context, PROVISIONING_TERMS_READ, count);
207         mMetricsWriter.write(DevicePolicyEventLogger
208                 .createEvent(DevicePolicyEnums.PROVISIONING_TERMS_READ)
209                 .setInt(count)
210                 .setTimePeriod(AnalyticsUtils.getProvisioningTime(mSharedPreferences)));
211     }
212 
213     /**
214      * Logs when the provisioning preparation has started.
215      * <p>The preparation includes network setup, downloading, verifying and installing the
216      * admin app.
217      */
logProvisioningPrepareStarted()218     public void logProvisioningPrepareStarted() {
219         mMetricsWriter.write(DevicePolicyEventLogger
220                 .createEvent(DevicePolicyEnums.PROVISIONING_PREPARE_STARTED)
221                 .setTimePeriod(AnalyticsUtils.getProvisioningTime(mSharedPreferences)));
222     }
223 
224     /**
225      * Logs when the provisioning preparation has completed.
226      * <p>The preparation includes network setup, downloading, verifying and installing the
227      * admin app.
228      */
logProvisioningPrepareCompleted()229     public void logProvisioningPrepareCompleted() {
230         mMetricsWriter.write(DevicePolicyEventLogger
231                 .createEvent(DevicePolicyEnums.PROVISIONING_PREPARE_COMPLETED)
232                 .setTimePeriod(AnalyticsUtils.getProvisioningTime(mSharedPreferences)));
233     }
234 
logTimeLoggerEvent(int devicePolicyEvent, int time)235     public void logTimeLoggerEvent(int devicePolicyEvent, int time) {
236         mMetricsWriter.write(DevicePolicyEventLogger
237                 .createEvent(devicePolicyEvent)
238                 .setInt(time)
239                 .setTimePeriod(AnalyticsUtils.getProvisioningTime(mSharedPreferences)));
240     }
241 
242     /**
243      * Logs the provisioning action.
244      *  @param context Context passed to MetricsLogger
245      * @param provisioningAction Action that triggered provisioning
246      */
logProvisioningAction(Context context, String provisioningAction)247     public void logProvisioningAction(Context context, String provisioningAction) {
248         mMetricsLoggerWrapper.logAction(context, PROVISIONING_ACTION, provisioningAction);
249         mMetricsWriter.write(DevicePolicyEventLogger
250                 .createEvent(DevicePolicyEnums.PROVISIONING_ACTION)
251                 .setStrings(provisioningAction)
252                 .setTimePeriod(AnalyticsUtils.getProvisioningTime(mSharedPreferences)));
253         maybeLogManagedProfileOnFullyManagedDevice(context, provisioningAction);
254     }
255 
256     /**
257      * Logs organization owned managed profile provisioning.
258      */
logOrganizationOwnedManagedProfileProvisioning()259     public void logOrganizationOwnedManagedProfileProvisioning() {
260         mMetricsWriter.write(DevicePolicyEventLogger
261                 .createEvent(DevicePolicyEnums.PROVISIONING_ORGANIZATION_OWNED_MANAGED_PROFILE)
262                 .setTimePeriod(AnalyticsUtils.getProvisioningTime(mSharedPreferences)));
263     }
264 
265     /**
266      * Logs when the DPC is started, for the purpose of enterprise setup.  Note that in the admin-
267      * integrated flow, this is when {@link DevicePolicyManager#ACTION_ADMIN_POLICY_COMPLIANCE} is
268      * sent to the DPC, not {@link DevicePolicyManager#ACTION_GET_PROVISIONING_MODE}.
269      *  @param context Context passed to MetricsLogger
270      * @param intentAction Action that was sent to the DPC
271      */
logDpcSetupStarted(Context context, String intentAction)272     public void logDpcSetupStarted(Context context, String intentAction) {
273         mMetricsLoggerWrapper.logAction(context, PROVISIONING_DPC_SETUP_STARTED);
274 
275         int intentActionCode;
276         switch(intentAction) {
277             case DevicePolicyManager.ACTION_PROVISIONING_SUCCESSFUL:
278                 intentActionCode = DPC_SETUP_ACTION_PROVISIONING_SUCCESSFUL;
279                 break;
280             case DevicePolicyManager.ACTION_ADMIN_POLICY_COMPLIANCE:
281                 intentActionCode = DPC_SETUP_ACTION_ADMIN_POLICY_COMPLIANCE;
282                 break;
283             default:
284                 intentActionCode = DPC_SETUP_ACTION_UNKNOWN;
285                 break;
286         }
287 
288         mMetricsWriter.write(DevicePolicyEventLogger
289                 .createEvent(PROVISIONING_DPC_SETUP_STARTED)
290                 .setInt(intentActionCode)
291                 .setTimePeriod(AnalyticsUtils.getProvisioningTime(mSharedPreferences)));
292     }
293 
294     /**
295      * Logs when the DPC finishes with enterprise setup.  Note that this is only logged when setup
296      * happens inside Setup Wizard; if it happens after Setup Wizard, we never find out when the
297      * DPC finishes.
298      *  @param context Context passed to MetricsLogger
299      * @param resultCode The result code that is returned by the DPC
300      */
logDpcSetupCompleted(Context context, int resultCode)301     public void logDpcSetupCompleted(Context context, int resultCode) {
302         mMetricsLoggerWrapper.logAction(context, PROVISIONING_DPC_SETUP_COMPLETED);
303         mMetricsWriter.write(DevicePolicyEventLogger
304                 .createEvent(PROVISIONING_DPC_SETUP_COMPLETED)
305                 .setInt(resultCode)
306                 .setTimePeriod(AnalyticsUtils.getProvisioningTime(mSharedPreferences)));
307     }
308 
309     /**
310      * Logs the type of provisioning flow if this is organization owned provisioning.
311      * <p>It would be either admin integrated flow or legacy.
312      *
313      * @param params Used to extract whether this is the admin integrated flow
314      */
logProvisioningFlowType(ProvisioningParams params)315     public void logProvisioningFlowType(ProvisioningParams params) {
316         mMetricsWriter.write(DevicePolicyEventLogger
317                 .createEvent(DevicePolicyEnums.PROVISIONING_FLOW_TYPE)
318                 .setInt(params.flowType == ProvisioningParams.FLOW_TYPE_ADMIN_INTEGRATED
319                         ? PROVISIONING_FLOW_TYPE_ADMIN_INTEGRATED
320                         : PROVISIONING_FLOW_TYPE_LEGACY)
321                 .setTimePeriod(AnalyticsUtils.getProvisioningTime(mSharedPreferences)));
322     }
323 
324     /**
325      * Logs whether an {@link android.app.Activity} is in landscape mode, along with its name.
326      */
logIsLandscape(boolean isLandscape, String activityName)327     public void logIsLandscape(boolean isLandscape, String activityName) {
328         mMetricsWriter.write(DevicePolicyEventLogger
329                 .createEvent(DevicePolicyEnums.PROVISIONING_IS_LANDSCAPE)
330                 .setBoolean(isLandscape)
331                 .setStrings(activityName)
332                 .setTimePeriod(AnalyticsUtils.getProvisioningTime(mSharedPreferences)));
333     }
334 
335     /**
336      * Logs whether the app is in night mode.
337      */
logIsNightMode(boolean isNightMode)338     public void logIsNightMode(boolean isNightMode) {
339         mMetricsWriter.write(DevicePolicyEventLogger
340                 .createEvent(DevicePolicyEnums.PROVISIONING_IS_NIGHT_MODE)
341                 .setBoolean(isNightMode)
342                 .setTimePeriod(AnalyticsUtils.getProvisioningTime(mSharedPreferences)));
343     }
344 
345     /**
346      * Logs all the provisioning extras passed by the dpc.
347      *
348      * @param context Context passed to MetricsLogger
349      * @param intent Intent that started provisioning
350      */
logProvisioningExtras(Context context, Intent intent)351     private void logProvisioningExtras(Context context, Intent intent) {
352         final List<String> provisioningExtras = AnalyticsUtils.getAllProvisioningExtras(intent);
353         for (String extra : provisioningExtras) {
354             mMetricsLoggerWrapper.logAction(context, PROVISIONING_EXTRA, extra);
355         }
356         mMetricsWriter.write(DevicePolicyEventLogger
357                 .createEvent(DevicePolicyEnums.PROVISIONING_EXTRAS)
358                 .setStrings(provisioningExtras.toArray(new String[0]))
359                 .setTimePeriod(AnalyticsUtils.getProvisioningTime(mSharedPreferences)));
360     }
361 
362     /**
363      * Logs some entry points to provisioning.
364      *
365      * @param context Context passed to MetricsLogger
366      * @param intent Intent that started provisioning
367      */
maybeLogEntryPoint(Context context, Intent intent)368     private void maybeLogEntryPoint(Context context, Intent intent) {
369         if (intent == null || intent.getAction() == null) {
370             return;
371         }
372         switch (intent.getAction()) {
373             case ACTION_NDEF_DISCOVERED:
374                 mMetricsLoggerWrapper.logAction(context, PROVISIONING_ENTRY_POINT_NFC);
375                 mMetricsWriter.write(DevicePolicyEventLogger
376                         .createEvent(DevicePolicyEnums.PROVISIONING_ENTRY_POINT_NFC)
377                         .setTimePeriod(AnalyticsUtils.getProvisioningTime(mSharedPreferences)));
378                 break;
379             case ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE:
380                 logProvisionedFromTrustedSource(context, intent);
381                 break;
382         }
383     }
384 
logProvisionedFromTrustedSource(Context context, Intent intent)385     private void logProvisionedFromTrustedSource(Context context, Intent intent) {
386         mMetricsLoggerWrapper.logAction(context, PROVISIONING_ENTRY_POINT_TRUSTED_SOURCE);
387         final int provisioningTrigger = intent.getIntExtra(EXTRA_PROVISIONING_TRIGGER,
388                 PROVISIONING_TRIGGER_UNSPECIFIED);
389         if (provisioningTrigger == PROVISIONING_TRIGGER_QR_CODE) {
390             mMetricsLoggerWrapper.logAction(context, PROVISIONING_ENTRY_POINT_QR_CODE);
391         }
392         mMetricsWriter.write(DevicePolicyEventLogger
393                 .createEvent(DevicePolicyEnums.PROVISIONING_ENTRY_POINT_TRUSTED_SOURCE)
394                 .setInt(provisioningTrigger)
395                 .setTimePeriod(AnalyticsUtils.getProvisioningTime(mSharedPreferences)));
396     }
397 
398     /**
399      * Logs package information of the dpc.
400      *
401      * @param context Context passed to MetricsLogger
402      * @param dpcPackageName Package name of the dpc
403      */
logDpcPackageInformation(Context context, String dpcPackageName)404     private void logDpcPackageInformation(Context context, String dpcPackageName) {
405         // Logs package name of the dpc.
406         mMetricsLoggerWrapper.logAction(context, PROVISIONING_DPC_PACKAGE_NAME, dpcPackageName);
407         mMetricsWriter.write(DevicePolicyEventLogger
408                 .createEvent(DevicePolicyEnums.PROVISIONING_DPC_PACKAGE_NAME)
409                 .setStrings(dpcPackageName)
410                 .setTimePeriod(AnalyticsUtils.getProvisioningTime(mSharedPreferences)));
411 
412         // Logs package name of the package which installed dpc.
413         final String dpcInstallerPackage =
414                 AnalyticsUtils.getInstallerPackageName(context, dpcPackageName);
415         mMetricsLoggerWrapper.logAction(context, PROVISIONING_DPC_INSTALLED_BY_PACKAGE,
416                 dpcInstallerPackage);
417         mMetricsWriter.write(DevicePolicyEventLogger
418                 .createEvent(DevicePolicyEnums.PROVISIONING_DPC_INSTALLED_BY_PACKAGE)
419                 .setStrings(dpcInstallerPackage)
420                 .setTimePeriod(AnalyticsUtils.getProvisioningTime(mSharedPreferences)));
421     }
422 
423     /**
424      * Logs the network type to which the device is connected.
425      *
426      * @param context Context passed to MetricsLogger
427      */
logNetworkType(Context context)428     private void logNetworkType(Context context) {
429         NetworkTypeLogger networkTypeLogger = new NetworkTypeLogger(context);
430         networkTypeLogger.log();
431     }
432 
maybeLogManagedProfileOnFullyManagedDevice(Context context, String provisioningAction)433     private void maybeLogManagedProfileOnFullyManagedDevice(Context context,
434             String provisioningAction) {
435         final DevicePolicyManager dpm =
436                 (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
437         final ComponentName currentDeviceOwner = dpm.getDeviceOwnerComponentOnAnyUser();
438         if (currentDeviceOwner != null
439                 && ACTION_PROVISION_MANAGED_PROFILE.equals(provisioningAction)) {
440             mMetricsWriter.write(DevicePolicyEventLogger
441                     .createEvent(PROVISIONING_MANAGED_PROFILE_ON_FULLY_MANAGED_DEVICE)
442                     .setTimePeriod(AnalyticsUtils.getProvisioningTime(mSharedPreferences)));
443         }
444     }
445 }
446