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 com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_COPY_ACCOUNT_TASK_MS;
20 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_CREATE_PROFILE_TASK_MS;
21 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_DOWNLOAD_PACKAGE_TASK_MS;
22 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_ENCRYPT_DEVICE_ACTIVITY_TIME_MS;
23 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_INSTALL_PACKAGE_TASK_MS;
24 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_PREPROVISIONING_ACTIVITY_TIME_MS;
25 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_PROVISIONING_ACTIVITY_TIME_MS;
26 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_START_PROFILE_TASK_MS;
27 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_TERMS_ACTIVITY_TIME_MS;
28 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_TOTAL_TASK_TIME_MS;
29 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_WEB_ACTIVITY_TIME_MS;
30 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.VIEW_UNKNOWN;
31 import static com.android.managedprovisioning.common.Globals.ACTION_RESUME_PROVISIONING;
32 
33 import android.content.Context;
34 import android.content.Intent;
35 import android.os.SystemClock;
36 import android.stats.devicepolicy.DevicePolicyEnums;
37 
38 import androidx.annotation.NonNull;
39 import androidx.annotation.Nullable;
40 
41 import com.android.internal.annotations.VisibleForTesting;
42 import com.android.managedprovisioning.analytics.TimeLogger.TimeCategory;
43 import com.android.managedprovisioning.common.ManagedProvisioningSharedPreferences;
44 import com.android.managedprovisioning.task.AbstractProvisioningTask;
45 
46 import java.util.ArrayList;
47 import java.util.List;
48 import java.util.Set;
49 import java.util.function.LongSupplier;
50 
51 /**
52  * Class containing various auxiliary methods used by provisioning analytics tracker.
53  */
54 public class AnalyticsUtils {
55 
56     final static int CATEGORY_VIEW_UNKNOWN = -1;
57 
AnalyticsUtils()58     public AnalyticsUtils() {}
59 
60     private static final String PROVISIONING_EXTRA_PREFIX = "android.app.extra.PROVISIONING_";
61 
62     /**
63      * Returns package name of the installer package, null if package is not present on the device
64      * and empty string if installer package is not present on the device.
65      *
66      * @param context Context used to get package manager
67      * @param packageName Package name of the installed package
68      */
69     @Nullable
getInstallerPackageName(Context context, String packageName)70     public static String getInstallerPackageName(Context context, String packageName) {
71         try {
72             return context.getPackageManager().getInstallerPackageName(packageName);
73         } catch (IllegalArgumentException e) {
74             return null;
75         }
76     }
77 
78     /**
79      * Returns elapsed real time.
80      */
elapsedRealTime()81     public Long elapsedRealTime() {
82         return SystemClock.elapsedRealtime();
83     }
84 
85     /**
86      * Returns list of all valid provisioning extras sent by the dpc.
87      *
88      * @param intent Intent that started provisioning
89      */
90     @NonNull
getAllProvisioningExtras(Intent intent)91     public static List<String> getAllProvisioningExtras(Intent intent) {
92         if (intent == null || ACTION_RESUME_PROVISIONING.equals(intent.getAction())) {
93             // Provisioning extras should have already been logged for resume case.
94             return new ArrayList<String>();
95         } else {
96             return getExtrasFromBundle(intent);
97         }
98     }
99 
100     /**
101      * Returns unique string for all provisioning task errors.
102      *
103      * @param task Provisioning task which threw error
104      * @param errorCode Unique code from class indicating the error
105      */
106     @Nullable
getErrorString(AbstractProvisioningTask task, int errorCode)107     public static String getErrorString(AbstractProvisioningTask task, int errorCode) {
108         if (task == null) {
109             return null;
110         }
111         // We do not have definite codes for all provisioning errors yet. We just pass the task's
112         // class name and the internal task's error code to generate a unique error code.
113         return task.getClass().getSimpleName() + ":" + errorCode;
114     }
115 
116     @NonNull
getExtrasFromBundle(Intent intent)117     private static List<String> getExtrasFromBundle(Intent intent) {
118         List<String> provisioningExtras = new ArrayList<String>();
119         if (intent != null && intent.getExtras() != null) {
120             final Set<String> keys = intent.getExtras().keySet();
121             for (String key : keys) {
122                 if (isValidProvisioningExtra(key)) {
123                     provisioningExtras.add(key);
124                 }
125             }
126         }
127         return provisioningExtras;
128     }
129 
130     /**
131      * Returns if a string is a valid provisioning extra.
132      */
isValidProvisioningExtra(String provisioningExtra)133     private static boolean isValidProvisioningExtra(String provisioningExtra) {
134         // Currently it verifies using the prefix. We should further change this to verify using the
135         // actual DPM extras.
136         return provisioningExtra != null && provisioningExtra.startsWith(PROVISIONING_EXTRA_PREFIX);
137     }
138 
139     /**
140      * Converts from {@link MetricsEvent} constants to {@link DevicePolicyEnums} constants.
141      * <p>If such a {@link MetricsEvent} does not exist, the metric is assumed
142      * to belong to {@link DevicePolicyEnums}.
143      */
getDevicePolicyEventForCategory(@imeCategory int metricsEvent)144     static int getDevicePolicyEventForCategory(@TimeCategory int metricsEvent) {
145         switch (metricsEvent) {
146             case PROVISIONING_COPY_ACCOUNT_TASK_MS:
147                 return DevicePolicyEnums.PROVISIONING_COPY_ACCOUNT_TASK_MS;
148             case PROVISIONING_CREATE_PROFILE_TASK_MS:
149                 return DevicePolicyEnums.PROVISIONING_CREATE_PROFILE_TASK_MS;
150             case PROVISIONING_DOWNLOAD_PACKAGE_TASK_MS:
151                 return DevicePolicyEnums.PROVISIONING_DOWNLOAD_PACKAGE_TASK_MS;
152             case PROVISIONING_ENCRYPT_DEVICE_ACTIVITY_TIME_MS:
153                 return DevicePolicyEnums.PROVISIONING_ENCRYPT_DEVICE_ACTIVITY_TIME_MS;
154             case PROVISIONING_INSTALL_PACKAGE_TASK_MS:
155                 return DevicePolicyEnums.PROVISIONING_INSTALL_PACKAGE_TASK_MS;
156             case PROVISIONING_PREPROVISIONING_ACTIVITY_TIME_MS:
157                 return DevicePolicyEnums.PROVISIONING_PREPROVISIONING_ACTIVITY_TIME_MS;
158             case PROVISIONING_PROVISIONING_ACTIVITY_TIME_MS:
159                 return DevicePolicyEnums.PROVISIONING_PROVISIONING_ACTIVITY_TIME_MS;
160             case PROVISIONING_START_PROFILE_TASK_MS:
161                 return DevicePolicyEnums.PROVISIONING_START_PROFILE_TASK_MS;
162             case PROVISIONING_WEB_ACTIVITY_TIME_MS:
163                 return DevicePolicyEnums.PROVISIONING_WEB_ACTIVITY_TIME_MS;
164             case PROVISIONING_TERMS_ACTIVITY_TIME_MS:
165                 return DevicePolicyEnums.PROVISIONING_TERMS_ACTIVITY_TIME_MS;
166             case PROVISIONING_TOTAL_TASK_TIME_MS:
167                 return DevicePolicyEnums.PROVISIONING_TOTAL_TASK_TIME_MS;
168             case VIEW_UNKNOWN:
169                 return -1;
170             default:
171                 return metricsEvent;
172         }
173     }
174 
175     /**
176      * Returns the time passed since provisioning started, in milliseconds.
177      * Returns <code>-1</code> if the provisioning start time was not specified via
178      * {@link ManagedProvisioningSharedPreferences#writeProvisioningStartedTimestamp(long)}.
179      */
getProvisioningTime(ManagedProvisioningSharedPreferences sharedPreferences)180     static long getProvisioningTime(ManagedProvisioningSharedPreferences sharedPreferences) {
181         return getProvisioningTime(sharedPreferences, SystemClock::elapsedRealtime);
182     }
183 
184     @VisibleForTesting
getProvisioningTime(ManagedProvisioningSharedPreferences sharedPreferences, LongSupplier getTimeFunction)185     static long getProvisioningTime(ManagedProvisioningSharedPreferences sharedPreferences,
186             LongSupplier getTimeFunction) {
187         if (sharedPreferences.getProvisioningStartedTimestamp() == 0) {
188             return -1;
189         }
190         return getTimeFunction.getAsLong() - sharedPreferences.getProvisioningStartedTimestamp();
191     }
192 }
193