blob: dba27d94ed33e7db91874b305e93e2bf42e09985 [file] [log] [blame]
/*
* 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.common.SettingsFacade;
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 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.
* <p>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.
* <p>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.
* <p>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
*/
public void logProvisioningExtras(Context context, Intent intent) {
final List<String> provisioningExtras = AnalyticsUtils.getAllProvisioningExtras(intent);
for (String extra : provisioningExtras) {
mMetricsLoggerWrapper.logAction(context, PROVISIONING_EXTRA, extra);
}
mMetricsWriter.write(DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.PROVISIONING_EXTRAS)
.setStrings(provisioningExtras.toArray(new String[0]))
.setTimePeriod(AnalyticsUtils.getProvisioningTime(mSharedPreferences)));
}
/**
* Logs some entry points to provisioning.
*
* @param context Context passed to MetricsLogger
* @param intent Intent that started provisioning
*/
public void logEntryPoint(Context context, Intent intent) {
if (intent == null || intent.getAction() == null) {
return;
}
switch (intent.getAction()) {
case ACTION_NDEF_DISCOVERED:
mMetricsLoggerWrapper.logAction(context, PROVISIONING_ENTRY_POINT_NFC);
mMetricsWriter.write(DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.PROVISIONING_ENTRY_POINT_NFC)
.setTimePeriod(AnalyticsUtils.getProvisioningTime(mSharedPreferences)));
break;
case ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE:
logProvisionedFromTrustedSource(context, intent);
break;
}
}
private void logProvisionedFromTrustedSource(Context context, Intent intent) {
mMetricsLoggerWrapper.logAction(context, PROVISIONING_ENTRY_POINT_TRUSTED_SOURCE);
final int provisioningTrigger = intent.getIntExtra(EXTRA_PROVISIONING_TRIGGER,
PROVISIONING_TRIGGER_UNSPECIFIED);
if (provisioningTrigger == PROVISIONING_TRIGGER_QR_CODE) {
mMetricsLoggerWrapper.logAction(context, PROVISIONING_ENTRY_POINT_QR_CODE);
}
mMetricsWriter.write(DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.PROVISIONING_ENTRY_POINT_TRUSTED_SOURCE)
.setInt(provisioningTrigger)
.setTimePeriod(AnalyticsUtils.getProvisioningTime(mSharedPreferences))
.setBoolean(isDuringSetupWizard(context)));
}
private boolean isDuringSetupWizard(Context context) {
SettingsFacade settingsFacade = new SettingsFacade();
return settingsFacade.isDuringSetupWizard(context);
}
/**
* Logs package information of the dpc.
*
* @param context Context passed to MetricsLogger
* @param dpcPackageName Package name of the dpc
*/
private void logDpcPackageInformation(Context context, String dpcPackageName) {
// Logs package name of the dpc.
mMetricsLoggerWrapper.logAction(context, PROVISIONING_DPC_PACKAGE_NAME, dpcPackageName);
mMetricsWriter.write(DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.PROVISIONING_DPC_PACKAGE_NAME)
.setStrings(dpcPackageName)
.setTimePeriod(AnalyticsUtils.getProvisioningTime(mSharedPreferences)));
// Logs package name of the package which installed dpc.
final String dpcInstallerPackage =
AnalyticsUtils.getInstallerPackageName(context, dpcPackageName);
mMetricsLoggerWrapper.logAction(context, PROVISIONING_DPC_INSTALLED_BY_PACKAGE,
dpcInstallerPackage);
mMetricsWriter.write(DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.PROVISIONING_DPC_INSTALLED_BY_PACKAGE)
.setStrings(dpcInstallerPackage)
.setTimePeriod(AnalyticsUtils.getProvisioningTime(mSharedPreferences)));
}
/**
* Logs the network type to which the device is connected.
*
* @param context Context passed to MetricsLogger
*/
private void logNetworkType(Context context) {
NetworkTypeLogger networkTypeLogger = new NetworkTypeLogger(context);
networkTypeLogger.log();
}
private void maybeLogManagedProfileOnFullyManagedDevice(Context context,
String provisioningAction) {
final DevicePolicyManager dpm =
(DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
final ComponentName currentDeviceOwner = dpm.getDeviceOwnerComponentOnAnyUser();
if (currentDeviceOwner != null
&& ACTION_PROVISION_MANAGED_PROFILE.equals(provisioningAction)) {
mMetricsWriter.write(DevicePolicyEventLogger
.createEvent(PROVISIONING_MANAGED_PROFILE_ON_FULLY_MANAGED_DEVICE)
.setTimePeriod(AnalyticsUtils.getProvisioningTime(mSharedPreferences)));
}
}
}