blob: 4e95bd0017dc33bfa2beb9954ab95fdae081280d [file] [log] [blame]
/*
* Copyright (C) 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.task;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_START_PROFILE_TASK_MS;
import static com.android.internal.util.Preconditions.checkNotNull;
import android.app.ActivityManager;
import android.app.IActivityManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.RemoteException;
import android.os.UserHandle;
import com.android.internal.annotations.VisibleForTesting;
import com.android.managedprovisioning.analytics.MetricsWriterFactory;
import com.android.managedprovisioning.analytics.ProvisioningAnalyticsTracker;
import com.android.managedprovisioning.common.ManagedProvisioningSharedPreferences;
import com.android.managedprovisioning.common.ProvisionLogger;
import com.android.managedprovisioning.R;
import com.android.managedprovisioning.common.SettingsFacade;
import com.android.managedprovisioning.model.ProvisioningParams;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
/**
* This task starts the managed profile and waits for it to be unlocked.
*/
public class StartManagedProfileTask extends AbstractProvisioningTask {
// Maximum time we will wait for ACTION_USER_UNLOCK until we give up
private static final int USER_UNLOCKED_TIMEOUT_SECONDS = 120; // 2 minutes
@VisibleForTesting
static final IntentFilter UNLOCK_FILTER = new IntentFilter(Intent.ACTION_USER_UNLOCKED);
private final IActivityManager mIActivityManager;
public StartManagedProfileTask(Context context, ProvisioningParams params, Callback callback) {
this(ActivityManager.getService(), context, params, callback,
new ProvisioningAnalyticsTracker(
MetricsWriterFactory.getMetricsWriter(context, new SettingsFacade()),
new ManagedProvisioningSharedPreferences(context)));
}
@VisibleForTesting
StartManagedProfileTask(
IActivityManager iActivityManager,
Context context,
ProvisioningParams params,
Callback callback,
ProvisioningAnalyticsTracker provisioningAnalyticsTracker) {
super(context, params, callback, provisioningAnalyticsTracker);
mIActivityManager = checkNotNull(iActivityManager);
}
@Override
public void run(int userId) {
startTaskTimer();
UserUnlockedReceiver unlockedReceiver = new UserUnlockedReceiver(userId);
mContext.registerReceiverAsUser(unlockedReceiver, new UserHandle(userId), UNLOCK_FILTER,
null, null);
try {
if (!mIActivityManager.startUserInBackground(userId)) {
ProvisionLogger.loge("Unable to start user in background: " + userId);
error(0);
return;
}
if (!unlockedReceiver.waitForUserUnlocked()) {
ProvisionLogger.loge("Timeout whilst waiting for unlock of user: " + userId);
error(0);
return;
}
} catch (RemoteException e) {
ProvisionLogger.loge("Exception when starting user in background: " + userId, e);
error(0);
return;
} finally {
mContext.unregisterReceiver(unlockedReceiver);
}
stopTaskTimer();
success();
}
@Override
public int getStatusMsgId() {
return R.string.progress_finishing_touches;
}
@Override
protected int getMetricsCategory() {
return PROVISIONING_START_PROFILE_TASK_MS;
}
/**
* BroadcastReceiver that listens to {@link Intent#ACTION_USER_UNLOCKED} in order to provide
* a blocking wait until the managed profile has been started and unlocked.
*/
@VisibleForTesting
static class UserUnlockedReceiver extends BroadcastReceiver {
private final Semaphore semaphore = new Semaphore(0);
private final int mUserId;
UserUnlockedReceiver(int userId) {
mUserId = userId;
}
@Override
public void onReceive(Context context, Intent intent ) {
if (!Intent.ACTION_USER_UNLOCKED.equals(intent.getAction())) {
ProvisionLogger.logw("Unexpected intent: " + intent);
return;
}
if (intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL) == mUserId) {
ProvisionLogger.logd("Received ACTION_USER_UNLOCKED for user " + mUserId);
semaphore.release();
}
}
public boolean waitForUserUnlocked() {
ProvisionLogger.logd("Waiting for ACTION_USER_UNLOCKED");
try {
return semaphore.tryAcquire(USER_UNLOCKED_TIMEOUT_SECONDS, TimeUnit.SECONDS);
} catch (InterruptedException ie) {
return false;
}
}
}
}