1 /* 2 * Copyright (C) 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.task; 18 19 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_COPY_ACCOUNT_TASK_MS; 20 import static com.android.managedprovisioning.analytics.ProvisioningAnalyticsTracker.COPY_ACCOUNT_EXCEPTION; 21 import static com.android.managedprovisioning.analytics.ProvisioningAnalyticsTracker.COPY_ACCOUNT_FAILED; 22 import static com.android.managedprovisioning.analytics.ProvisioningAnalyticsTracker.COPY_ACCOUNT_SUCCEEDED; 23 import static com.android.managedprovisioning.analytics.ProvisioningAnalyticsTracker.COPY_ACCOUNT_TIMED_OUT; 24 25 import android.accounts.Account; 26 import android.accounts.AccountManager; 27 import android.accounts.AuthenticatorException; 28 import android.accounts.OperationCanceledException; 29 import android.content.Context; 30 import android.os.UserHandle; 31 32 import com.android.internal.annotations.VisibleForTesting; 33 import com.android.managedprovisioning.analytics.MetricsWriter; 34 import com.android.managedprovisioning.analytics.MetricsWriterFactory; 35 import com.android.managedprovisioning.analytics.ProvisioningAnalyticsTracker; 36 import com.android.managedprovisioning.common.ManagedProvisioningSharedPreferences; 37 import com.android.managedprovisioning.common.ProvisionLogger; 38 import com.android.managedprovisioning.R; 39 import com.android.managedprovisioning.common.SettingsFacade; 40 import com.android.managedprovisioning.model.ProvisioningParams; 41 42 import java.io.IOException; 43 import java.util.concurrent.TimeUnit; 44 45 /** 46 * This task copies the account in {@link ProvisioningParams#accountToMigrate} from an existing 47 * user to the user that is being provisioned. 48 * 49 * <p>If the account migration fails or times out, we still return success as we consider account 50 * migration not to be a critical operation.</p> 51 */ 52 public class CopyAccountToUserTask extends AbstractProvisioningTask { 53 private static final int ACCOUNT_COPY_TIMEOUT_SECONDS = 60 * 3; // 3 minutes 54 55 private final int mSourceUserId; 56 private final ProvisioningAnalyticsTracker mProvisioningAnalyticsTracker; 57 CopyAccountToUserTask( int sourceUserId, Context context, ProvisioningParams provisioningParams, Callback callback)58 public CopyAccountToUserTask( 59 int sourceUserId, 60 Context context, 61 ProvisioningParams provisioningParams, 62 Callback callback) { 63 this(sourceUserId, context, provisioningParams, callback, 64 new ProvisioningAnalyticsTracker( 65 MetricsWriterFactory.getMetricsWriter(context, new SettingsFacade()), 66 new ManagedProvisioningSharedPreferences(context))); 67 } 68 69 @VisibleForTesting CopyAccountToUserTask( int sourceUserId, Context context, ProvisioningParams provisioningParams, Callback callback, ProvisioningAnalyticsTracker provisioningAnalyticsTracker)70 CopyAccountToUserTask( 71 int sourceUserId, 72 Context context, 73 ProvisioningParams provisioningParams, 74 Callback callback, 75 ProvisioningAnalyticsTracker provisioningAnalyticsTracker) { 76 super(context, provisioningParams, callback, provisioningAnalyticsTracker); 77 mSourceUserId = sourceUserId; 78 mProvisioningAnalyticsTracker = provisioningAnalyticsTracker; 79 } 80 81 @Override run(int userId)82 public void run(int userId) { 83 startTaskTimer(); 84 85 final boolean copySucceeded = maybeCopyAccount(userId); 86 // Do not log time if account migration did not succeed, as that isn't useful. 87 if (copySucceeded) { 88 stopTaskTimer(); 89 } 90 // account migration is not considered a critical operation, so succeed anyway 91 success(); 92 } 93 94 @Override getStatusMsgId()95 public int getStatusMsgId() { 96 return R.string.progress_finishing_touches; 97 } 98 99 @Override getMetricsCategory()100 protected int getMetricsCategory() { 101 return PROVISIONING_COPY_ACCOUNT_TASK_MS; 102 } 103 104 @VisibleForTesting maybeCopyAccount(int targetUserId)105 boolean maybeCopyAccount(int targetUserId) { 106 Account accountToMigrate = mProvisioningParams.accountToMigrate; 107 UserHandle sourceUser = UserHandle.of(mSourceUserId); 108 UserHandle targetUser = UserHandle.of(targetUserId); 109 110 if (accountToMigrate == null) { 111 ProvisionLogger.logd("No account to migrate."); 112 return false; 113 } 114 if (sourceUser.equals(targetUser)) { 115 ProvisionLogger.loge("sourceUser and targetUser are the same, won't migrate account."); 116 return false; 117 } 118 ProvisionLogger.logd("Attempting to copy account from " + sourceUser + " to " + targetUser); 119 try { 120 AccountManager accountManager = (AccountManager) 121 mContext.getSystemService(Context.ACCOUNT_SERVICE); 122 boolean copySucceeded = accountManager.copyAccountToUser( 123 accountToMigrate, 124 sourceUser, 125 targetUser, 126 /* callback= */ null, /* handler= */ null) 127 .getResult(ACCOUNT_COPY_TIMEOUT_SECONDS, TimeUnit.SECONDS); 128 if (copySucceeded) { 129 ProvisionLogger.logi("Copied account to " + targetUser); 130 mProvisioningAnalyticsTracker.logCopyAccountStatus(mContext, 131 COPY_ACCOUNT_SUCCEEDED); 132 return true; 133 } else { 134 mProvisioningAnalyticsTracker.logCopyAccountStatus(mContext, COPY_ACCOUNT_FAILED); 135 ProvisionLogger.loge("Could not copy account to " + targetUser); 136 } 137 } catch (OperationCanceledException e) { 138 mProvisioningAnalyticsTracker.logCopyAccountStatus(mContext, COPY_ACCOUNT_TIMED_OUT); 139 ProvisionLogger.loge("Exception copying account to " + targetUser, e); 140 } catch (AuthenticatorException | IOException e) { 141 mProvisioningAnalyticsTracker.logCopyAccountStatus(mContext, COPY_ACCOUNT_EXCEPTION); 142 ProvisionLogger.loge("Exception copying account to " + targetUser, e); 143 } 144 return false; 145 } 146 } 147