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_START_PROFILE_TASK_MS; 20 import static com.android.internal.util.Preconditions.checkNotNull; 21 22 import android.app.ActivityManager; 23 import android.app.IActivityManager; 24 import android.content.BroadcastReceiver; 25 import android.content.Context; 26 import android.content.Intent; 27 import android.content.IntentFilter; 28 import android.os.RemoteException; 29 import android.os.UserHandle; 30 31 import com.android.internal.annotations.VisibleForTesting; 32 import com.android.managedprovisioning.common.ProvisionLogger; 33 import com.android.managedprovisioning.R; 34 import com.android.managedprovisioning.model.ProvisioningParams; 35 36 import java.util.concurrent.Semaphore; 37 import java.util.concurrent.TimeUnit; 38 39 /** 40 * This task starts the managed profile and waits for it to be unlocked. 41 */ 42 public class StartManagedProfileTask extends AbstractProvisioningTask { 43 // Maximum time we will wait for ACTION_USER_UNLOCK until we give up 44 private static final int USER_UNLOCKED_TIMEOUT_SECONDS = 120; // 2 minutes 45 @VisibleForTesting 46 static final IntentFilter UNLOCK_FILTER = new IntentFilter(Intent.ACTION_USER_UNLOCKED); 47 48 private final IActivityManager mIActivityManager; 49 50 public StartManagedProfileTask(Context context, ProvisioningParams params, Callback callback) { 51 this(ActivityManager.getService(), context, params, callback); 52 } 53 54 @VisibleForTesting 55 StartManagedProfileTask( 56 IActivityManager iActivityManager, 57 Context context, 58 ProvisioningParams params, 59 Callback callback) { 60 super(context, params, callback); 61 62 mIActivityManager = checkNotNull(iActivityManager); 63 } 64 65 @Override 66 public void run(int userId) { 67 startTaskTimer(); 68 UserUnlockedReceiver unlockedReceiver = new UserUnlockedReceiver(userId); 69 mContext.registerReceiverAsUser(unlockedReceiver, new UserHandle(userId), UNLOCK_FILTER, 70 null, null); 71 try { 72 if (!mIActivityManager.startUserInBackground(userId)) { 73 ProvisionLogger.loge("Unable to start user in background: " + userId); 74 error(0); 75 return; 76 } 77 78 if (!unlockedReceiver.waitForUserUnlocked()) { 79 ProvisionLogger.loge("Timeout whilst waiting for unlock of user: " + userId); 80 error(0); 81 return; 82 } 83 } catch (RemoteException e) { 84 ProvisionLogger.loge("Exception when starting user in background: " + userId, e); 85 error(0); 86 return; 87 } finally { 88 mContext.unregisterReceiver(unlockedReceiver); 89 } 90 stopTaskTimer(); 91 success(); 92 } 93 94 @Override 95 public int getStatusMsgId() { 96 return R.string.progress_finishing_touches; 97 } 98 99 @Override 100 protected int getMetricsCategory() { 101 return PROVISIONING_START_PROFILE_TASK_MS; 102 } 103 104 /** 105 * BroadcastReceiver that listens to {@link Intent#ACTION_USER_UNLOCKED} in order to provide 106 * a blocking wait until the managed profile has been started and unlocked. 107 */ 108 @VisibleForTesting 109 static class UserUnlockedReceiver extends BroadcastReceiver { 110 private final Semaphore semaphore = new Semaphore(0); 111 private final int mUserId; 112 113 UserUnlockedReceiver(int userId) { 114 mUserId = userId; 115 } 116 117 @Override 118 public void onReceive(Context context, Intent intent ) { 119 if (!Intent.ACTION_USER_UNLOCKED.equals(intent.getAction())) { 120 ProvisionLogger.logw("Unexpected intent: " + intent); 121 return; 122 } 123 if (intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL) == mUserId) { 124 ProvisionLogger.logd("Received ACTION_USER_UNLOCKED for user " + mUserId); 125 semaphore.release(); 126 } 127 } 128 129 public boolean waitForUserUnlocked() { 130 ProvisionLogger.logd("Waiting for ACTION_USER_UNLOCKED"); 131 try { 132 return semaphore.tryAcquire(USER_UNLOCKED_TIMEOUT_SECONDS, TimeUnit.SECONDS); 133 } catch (InterruptedException ie) { 134 return false; 135 } 136 } 137 } 138 } 139