/* * Copyright 2016, The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.managedprovisioning.analytics; import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE; import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE; import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_TRIGGER; import static android.app.admin.DevicePolicyManager.PROVISIONING_TRIGGER_QR_CODE; import static android.app.admin.DevicePolicyManager.PROVISIONING_TRIGGER_UNSPECIFIED; import static android.nfc.NfcAdapter.ACTION_NDEF_DISCOVERED; import static android.stats.devicepolicy.DevicePolicyEnums.PROVISIONING_DPC_SETUP_COMPLETED; import static android.stats.devicepolicy.DevicePolicyEnums.PROVISIONING_DPC_SETUP_STARTED; import static android.stats.devicepolicy.DevicePolicyEnums.PROVISIONING_MANAGED_PROFILE_ON_FULLY_MANAGED_DEVICE; import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_ACTION; import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_CANCELLED; import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_DPC_INSTALLED_BY_PACKAGE; import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_DPC_PACKAGE_NAME; import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_ENTRY_POINT_NFC; import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_ENTRY_POINT_QR_CODE; import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_ENTRY_POINT_TRUSTED_SOURCE; import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_ERROR; import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_EXTRA; import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_SESSION_COMPLETED; import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_SESSION_STARTED; import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_TERMS_COUNT; import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_TERMS_READ; import android.annotation.IntDef; import android.app.admin.DevicePolicyEventLogger; import android.app.admin.DevicePolicyManager; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.stats.devicepolicy.DevicePolicyEnums; import com.android.managedprovisioning.common.ManagedProvisioningSharedPreferences; import com.android.managedprovisioning.model.ProvisioningParams; import com.android.managedprovisioning.task.AbstractProvisioningTask; import java.util.List; /** * Utility class to log metrics. */ public class ProvisioningAnalyticsTracker { private final MetricsLoggerWrapper mMetricsLoggerWrapper = new MetricsLoggerWrapper(); // Only add to the end of the list. Do not change or rearrange these values, that will break // historical data. Do not use negative numbers or zero, logger only handles positive // integers. public static final int CANCELLED_BEFORE_PROVISIONING = 1; public static final int CANCELLED_DURING_PROVISIONING = 2; public static final int CANCELLED_DURING_PROVISIONING_PREPARE = 3; private final ManagedProvisioningSharedPreferences mSharedPreferences; @IntDef({ CANCELLED_BEFORE_PROVISIONING, CANCELLED_DURING_PROVISIONING, CANCELLED_DURING_PROVISIONING_PREPARE}) public @interface CancelState {} private static final int PROVISIONING_FLOW_TYPE_ADMIN_INTEGRATED = 1; private static final int PROVISIONING_FLOW_TYPE_LEGACY = 2; private static final int DPC_SETUP_ACTION_UNKNOWN = 1; private static final int DPC_SETUP_ACTION_PROVISIONING_SUCCESSFUL = 2; private static final int DPC_SETUP_ACTION_ADMIN_POLICY_COMPLIANCE = 3; private final MetricsWriter mMetricsWriter; public ProvisioningAnalyticsTracker(MetricsWriter metricsWriter, ManagedProvisioningSharedPreferences prefs) { // Disables instantiation. Use getInstance() instead. mMetricsWriter = metricsWriter; mSharedPreferences = prefs; } /** * Logs some metrics when the provisioning starts. * * @param context Context passed to MetricsLogger * @param params Provisioning params */ public void logProvisioningStarted(Context context, ProvisioningParams params) { logDpcPackageInformation(context, params.inferDeviceAdminPackageName()); logNetworkType(context); } /** * Logs some metrics when the preprovisioning starts. * * @param context Context passed to MetricsLogger * @param intent Intent that started provisioning */ public void logPreProvisioningStarted(Context context, Intent intent) { logProvisioningExtras(context, intent); maybeLogEntryPoint(context, intent); } /** * Logs when provisioning is cancelled. * * @param context Context passed to MetricsLogger * @param cancelState State when provisioning was cancelled */ public void logProvisioningCancelled(Context context, @CancelState int cancelState) { mMetricsLoggerWrapper.logAction(context, PROVISIONING_CANCELLED, cancelState); mMetricsWriter.write(DevicePolicyEventLogger .createEvent(DevicePolicyEnums.PROVISIONING_CANCELLED) .setInt(cancelState) .setTimePeriod(AnalyticsUtils.getProvisioningTime(mSharedPreferences))); } /** * Logs error during provisioning tasks. * * @param context Context passed to MetricsLogger * @param task Provisioning task which threw error * @param errorCode Code indicating the type of error that happened. */ public void logProvisioningError(Context context, AbstractProvisioningTask task, int errorCode) { mMetricsLoggerWrapper.logAction(context, PROVISIONING_ERROR, AnalyticsUtils.getErrorString(task, errorCode)); mMetricsWriter.write(DevicePolicyEventLogger .createEvent(DevicePolicyEnums.PROVISIONING_ERROR) .setStrings(AnalyticsUtils.getErrorString(task, errorCode)) .setTimePeriod(AnalyticsUtils.getProvisioningTime(mSharedPreferences))); } /** * Logs error code, when provisioning is not allowed. * * @param context Context passed to MetricsLogger * @param provisioningErrorCode Code indicating why provisioning is not allowed. */ public void logProvisioningNotAllowed(Context context, int provisioningErrorCode) { mMetricsLoggerWrapper.logAction(context, PROVISIONING_ERROR, provisioningErrorCode); mMetricsWriter.write(DevicePolicyEventLogger .createEvent(DevicePolicyEnums.PROVISIONING_ERROR) .setStrings(String.valueOf(provisioningErrorCode)) .setTimePeriod(AnalyticsUtils.getProvisioningTime(mSharedPreferences))); } /** * logs when a provisioning session has started. * * @param context Context passed to MetricsLogger */ public void logProvisioningSessionStarted(Context context) { mMetricsLoggerWrapper.logAction(context, PROVISIONING_SESSION_STARTED); mMetricsWriter.write(DevicePolicyEventLogger .createEvent(DevicePolicyEnums.PROVISIONING_SESSION_STARTED) .setTimePeriod(AnalyticsUtils.getProvisioningTime(mSharedPreferences))); } /** * logs when a provisioning session has completed. * * @param context Context passed to MetricsLogger */ public void logProvisioningSessionCompleted(Context context) { mMetricsLoggerWrapper.logAction(context, PROVISIONING_SESSION_COMPLETED); mMetricsWriter.write(DevicePolicyEventLogger .createEvent(DevicePolicyEnums.PROVISIONING_SESSION_COMPLETED) .setTimePeriod(AnalyticsUtils.getProvisioningTime(mSharedPreferences))); } /** * logs number of terms displayed on the terms screen. * * @param context Context passed to MetricsLogger * @param count Number of terms displayed */ public void logNumberOfTermsDisplayed(Context context, int count) { mMetricsLoggerWrapper.logAction(context, PROVISIONING_TERMS_COUNT, count); mMetricsWriter.write(DevicePolicyEventLogger .createEvent(DevicePolicyEnums.PROVISIONING_TERMS_COUNT) .setInt(count) .setTimePeriod(AnalyticsUtils.getProvisioningTime(mSharedPreferences))); } /** * logs number of terms read on the terms screen. * * @param context Context passed to MetricsLogger * @param count Number of terms read */ public void logNumberOfTermsRead(Context context, int count) { mMetricsLoggerWrapper.logAction(context, PROVISIONING_TERMS_READ, count); mMetricsWriter.write(DevicePolicyEventLogger .createEvent(DevicePolicyEnums.PROVISIONING_TERMS_READ) .setInt(count) .setTimePeriod(AnalyticsUtils.getProvisioningTime(mSharedPreferences))); } /** * Logs when the provisioning preparation has started. *
The preparation includes network setup, downloading, verifying and installing the * admin app. */ public void logProvisioningPrepareStarted() { mMetricsWriter.write(DevicePolicyEventLogger .createEvent(DevicePolicyEnums.PROVISIONING_PREPARE_STARTED) .setTimePeriod(AnalyticsUtils.getProvisioningTime(mSharedPreferences))); } /** * Logs when the provisioning preparation has completed. *
The preparation includes network setup, downloading, verifying and installing the * admin app. */ public void logProvisioningPrepareCompleted() { mMetricsWriter.write(DevicePolicyEventLogger .createEvent(DevicePolicyEnums.PROVISIONING_PREPARE_COMPLETED) .setTimePeriod(AnalyticsUtils.getProvisioningTime(mSharedPreferences))); } public void logTimeLoggerEvent(int devicePolicyEvent, int time) { mMetricsWriter.write(DevicePolicyEventLogger .createEvent(devicePolicyEvent) .setInt(time) .setTimePeriod(AnalyticsUtils.getProvisioningTime(mSharedPreferences))); } /** * Logs the provisioning action. * @param context Context passed to MetricsLogger * @param provisioningAction Action that triggered provisioning */ public void logProvisioningAction(Context context, String provisioningAction) { mMetricsLoggerWrapper.logAction(context, PROVISIONING_ACTION, provisioningAction); mMetricsWriter.write(DevicePolicyEventLogger .createEvent(DevicePolicyEnums.PROVISIONING_ACTION) .setStrings(provisioningAction) .setTimePeriod(AnalyticsUtils.getProvisioningTime(mSharedPreferences))); maybeLogManagedProfileOnFullyManagedDevice(context, provisioningAction); } /** * Logs organization owned managed profile provisioning. */ public void logOrganizationOwnedManagedProfileProvisioning() { mMetricsWriter.write(DevicePolicyEventLogger .createEvent(DevicePolicyEnums.PROVISIONING_ORGANIZATION_OWNED_MANAGED_PROFILE) .setTimePeriod(AnalyticsUtils.getProvisioningTime(mSharedPreferences))); } /** * Logs when the DPC is started, for the purpose of enterprise setup. Note that in the admin- * integrated flow, this is when {@link DevicePolicyManager#ACTION_ADMIN_POLICY_COMPLIANCE} is * sent to the DPC, not {@link DevicePolicyManager#ACTION_GET_PROVISIONING_MODE}. * @param context Context passed to MetricsLogger * @param intentAction Action that was sent to the DPC */ public void logDpcSetupStarted(Context context, String intentAction) { mMetricsLoggerWrapper.logAction(context, PROVISIONING_DPC_SETUP_STARTED); int intentActionCode; switch(intentAction) { case DevicePolicyManager.ACTION_PROVISIONING_SUCCESSFUL: intentActionCode = DPC_SETUP_ACTION_PROVISIONING_SUCCESSFUL; break; case DevicePolicyManager.ACTION_ADMIN_POLICY_COMPLIANCE: intentActionCode = DPC_SETUP_ACTION_ADMIN_POLICY_COMPLIANCE; break; default: intentActionCode = DPC_SETUP_ACTION_UNKNOWN; break; } mMetricsWriter.write(DevicePolicyEventLogger .createEvent(PROVISIONING_DPC_SETUP_STARTED) .setInt(intentActionCode) .setTimePeriod(AnalyticsUtils.getProvisioningTime(mSharedPreferences))); } /** * Logs when the DPC finishes with enterprise setup. Note that this is only logged when setup * happens inside Setup Wizard; if it happens after Setup Wizard, we never find out when the * DPC finishes. * @param context Context passed to MetricsLogger * @param resultCode The result code that is returned by the DPC */ public void logDpcSetupCompleted(Context context, int resultCode) { mMetricsLoggerWrapper.logAction(context, PROVISIONING_DPC_SETUP_COMPLETED); mMetricsWriter.write(DevicePolicyEventLogger .createEvent(PROVISIONING_DPC_SETUP_COMPLETED) .setInt(resultCode) .setTimePeriod(AnalyticsUtils.getProvisioningTime(mSharedPreferences))); } /** * Logs the type of provisioning flow if this is organization owned provisioning. *
It would be either admin integrated flow or legacy.
*
* @param params Used to extract whether this is the admin integrated flow
*/
public void logProvisioningFlowType(ProvisioningParams params) {
mMetricsWriter.write(DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.PROVISIONING_FLOW_TYPE)
.setInt(params.flowType == ProvisioningParams.FLOW_TYPE_ADMIN_INTEGRATED
? PROVISIONING_FLOW_TYPE_ADMIN_INTEGRATED
: PROVISIONING_FLOW_TYPE_LEGACY)
.setTimePeriod(AnalyticsUtils.getProvisioningTime(mSharedPreferences)));
}
/**
* Logs whether an {@link android.app.Activity} is in landscape mode, along with its name.
*/
public void logIsLandscape(boolean isLandscape, String activityName) {
mMetricsWriter.write(DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.PROVISIONING_IS_LANDSCAPE)
.setBoolean(isLandscape)
.setStrings(activityName)
.setTimePeriod(AnalyticsUtils.getProvisioningTime(mSharedPreferences)));
}
/**
* Logs whether the app is in night mode.
*/
public void logIsNightMode(boolean isNightMode) {
mMetricsWriter.write(DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.PROVISIONING_IS_NIGHT_MODE)
.setBoolean(isNightMode)
.setTimePeriod(AnalyticsUtils.getProvisioningTime(mSharedPreferences)));
}
/**
* Logs all the provisioning extras passed by the dpc.
*
* @param context Context passed to MetricsLogger
* @param intent Intent that started provisioning
*/
private void logProvisioningExtras(Context context, Intent intent) {
final List