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