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