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