Home | History | Annotate | Download | only in managedprovisioning
      1 /*
      2  * Copyright 2014, 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;
     18 
     19 import static android.app.admin.DeviceAdminReceiver.ACTION_PROFILE_PROVISIONING_COMPLETE;
     20 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE;
     21 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE;
     22 
     23 import android.accounts.AccountManager;
     24 import android.app.Activity;
     25 import android.app.ActivityManagerNative;
     26 import android.app.IActivityManager;
     27 import android.app.Service;
     28 import android.app.admin.DevicePolicyManager;
     29 import android.content.BroadcastReceiver;
     30 import android.content.Context;
     31 import android.content.Intent;
     32 import android.content.IntentFilter;
     33 import android.content.pm.IPackageManager;
     34 import android.content.pm.PackageManager;
     35 import android.content.pm.UserInfo;
     36 import android.os.AsyncTask;
     37 import android.os.IBinder;
     38 import android.os.Process;
     39 import android.os.RemoteException;
     40 import android.os.ServiceManager;
     41 import android.os.UserHandle;
     42 import android.os.UserManager;
     43 import android.provider.Settings;
     44 import android.support.v4.content.LocalBroadcastManager;
     45 
     46 import com.android.managedprovisioning.common.Utils;
     47 import com.android.managedprovisioning.CrossProfileIntentFiltersHelper;
     48 import com.android.managedprovisioning.model.ProvisioningParams;
     49 import com.android.managedprovisioning.task.DeleteNonRequiredAppsTask;
     50 import com.android.managedprovisioning.task.DisableBluetoothSharingTask;
     51 import com.android.managedprovisioning.task.DisableInstallShortcutListenersTask;
     52 import com.android.managedprovisioning.task.ManagedProfileSettingsTask;
     53 
     54 import java.util.concurrent.Semaphore;
     55 import java.util.concurrent.TimeUnit;
     56 
     57 /**
     58  * Service that runs the profile owner provisioning.
     59  *
     60  * <p>This service is started from and sends updates to the {@link ProfileOwnerProvisioningActivity},
     61  * which contains the provisioning UI.
     62  */
     63 public class ProfileOwnerProvisioningService extends Service {
     64     // Intent actions for communication with DeviceOwnerProvisioningService.
     65     public static final String ACTION_PROVISIONING_SUCCESS =
     66             "com.android.managedprovisioning.provisioning_success";
     67     public static final String ACTION_PROVISIONING_ERROR =
     68             "com.android.managedprovisioning.error";
     69     public static final String ACTION_PROVISIONING_CANCELLED =
     70             "com.android.managedprovisioning.cancelled";
     71     public static final String EXTRA_LOG_MESSAGE_KEY = "ProvisioningErrorLogMessage";
     72 
     73     // Maximum time we will wait for ACTION_USER_UNLOCK until we give up and continue without
     74     // account migration.
     75     private static final int USER_UNLOCKED_TIMEOUT_SECONDS = 120; // 2 minutes
     76 
     77     // Status flags for the provisioning process.
     78     /** Provisioning not started. */
     79     private static final int STATUS_UNKNOWN = 0;
     80     /** Provisioning started, no errors or cancellation requested received. */
     81     private static final int STATUS_STARTED = 1;
     82     /** Provisioning in progress, but user has requested cancellation. */
     83     private static final int STATUS_CANCELLING = 2;
     84     // Final possible states for the provisioning process.
     85     /** Provisioning completed successfully. */
     86     private static final int STATUS_DONE = 3;
     87     /** Provisioning failed and cleanup complete. */
     88     private static final int STATUS_ERROR = 4;
     89     /** Provisioning cancelled and cleanup complete. */
     90     private static final int STATUS_CANCELLED = 5;
     91 
     92     private IPackageManager mIpm;
     93     private UserInfo mManagedProfileOrUserInfo;
     94     private AccountManager mAccountManager;
     95     private UserManager mUserManager;
     96     private UserUnlockedReceiver mUnlockedReceiver;
     97 
     98     private AsyncTask<Intent, Void, Void> runnerTask;
     99 
    100     // MessageId of the last error message.
    101     private String mLastErrorMessage = null;
    102 
    103     // Current status of the provisioning process.
    104     private int mProvisioningStatus = STATUS_UNKNOWN;
    105 
    106     private ProvisioningParams mParams;
    107 
    108     private final Utils mUtils = new Utils();
    109 
    110     private class RunnerTask extends AsyncTask<Intent, Void, Void> {
    111         @Override
    112         protected Void doInBackground(Intent ... intents) {
    113             // Atomically move to STATUS_STARTED at most once.
    114             synchronized (ProfileOwnerProvisioningService.this) {
    115                 if (mProvisioningStatus == STATUS_UNKNOWN) {
    116                     mProvisioningStatus = STATUS_STARTED;
    117                 } else {
    118                     // Process already started, don't start again.
    119                     return null;
    120                 }
    121             }
    122 
    123             try {
    124                 initialize(intents[0]);
    125                 startManagedProfileOrUserProvisioning();
    126             } catch (ProvisioningException e) {
    127                 // Handle internal errors.
    128                 error(e.getMessage(), e);
    129                 finish();
    130             } catch (Exception e) {
    131                 // General catch-all to ensure process cleans up in all cases.
    132                 error("Failed to initialize managed profile, aborting.", e);
    133                 finish();
    134             }
    135 
    136             return null;
    137         }
    138     }
    139 
    140     @Override
    141     public void onCreate() {
    142         super.onCreate();
    143 
    144         mIpm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
    145         mAccountManager = (AccountManager) getSystemService(Context.ACCOUNT_SERVICE);
    146         mUserManager = (UserManager) getSystemService(Context.USER_SERVICE);
    147 
    148         runnerTask = new RunnerTask();
    149     }
    150 
    151     @Override
    152     public int onStartCommand(final Intent intent, int flags, int startId) {
    153         if (ProfileOwnerProvisioningActivity.ACTION_CANCEL_PROVISIONING.equals(intent.getAction())) {
    154             ProvisionLogger.logd("Cancelling profile owner provisioning service");
    155             cancelProvisioning();
    156             return START_NOT_STICKY;
    157         }
    158 
    159         ProvisionLogger.logd("Starting profile owner provisioning service");
    160 
    161         try {
    162             runnerTask.execute(intent);
    163         } catch (IllegalStateException e) {
    164             // runnerTask is either in progress, or finished.
    165             ProvisionLogger.logd(
    166                     "ProfileOwnerProvisioningService: Provisioning already started, "
    167                     + "second provisioning intent not being processed, only reporting status.");
    168             reportStatus();
    169         }
    170         return START_NOT_STICKY;
    171     }
    172 
    173     private void reportStatus() {
    174         synchronized (this) {
    175             switch (mProvisioningStatus) {
    176                 case STATUS_DONE:
    177                     notifyActivityOfSuccess();
    178                     break;
    179                 case STATUS_CANCELLED:
    180                     notifyActivityCancelled();
    181                     break;
    182                 case STATUS_ERROR:
    183                     notifyActivityError();
    184                     break;
    185                 case STATUS_UNKNOWN:
    186                 case STATUS_STARTED:
    187                 case STATUS_CANCELLING:
    188                     // Don't notify UI of status when just-started/in-progress.
    189                     break;
    190             }
    191         }
    192     }
    193 
    194     private void cancelProvisioning() {
    195         synchronized (this) {
    196             switch (mProvisioningStatus) {
    197                 case STATUS_DONE:
    198                     // Process completed, we should honor user request to cancel
    199                     // though.
    200                     mProvisioningStatus = STATUS_CANCELLING;
    201                     cleanupUserProfile();
    202                     mProvisioningStatus = STATUS_CANCELLED;
    203                     reportStatus();
    204                     break;
    205                 case STATUS_UNKNOWN:
    206                     // Process hasn't started, move straight to cancelled state.
    207                     mProvisioningStatus = STATUS_CANCELLED;
    208                     reportStatus();
    209                     break;
    210                 case STATUS_STARTED:
    211                     // Process is mid-flow, flag up that the user has requested
    212                     // cancellation.
    213                     mProvisioningStatus = STATUS_CANCELLING;
    214                     break;
    215                 case STATUS_CANCELLING:
    216                     // Cancellation already being processed.
    217                     break;
    218                 case STATUS_CANCELLED:
    219                 case STATUS_ERROR:
    220                     // Process already completed, nothing left to cancel.
    221                     break;
    222             }
    223         }
    224     }
    225 
    226     private void initialize(Intent intent) {
    227         // Load the ProvisioningParams (from message in Intent).
    228         mParams = (ProvisioningParams) intent.getParcelableExtra(
    229                 ProvisioningParams.EXTRA_PROVISIONING_PARAMS);
    230         if (mParams.accountToMigrate != null) {
    231             ProvisionLogger.logi("Migrating account to managed profile");
    232         }
    233     }
    234 
    235     /**
    236      * This is the core method to create a managed profile or user. It goes through every
    237      * provisioning step.
    238      */
    239     private void startManagedProfileOrUserProvisioning() throws ProvisioningException {
    240 
    241         ProvisionLogger.logd("Starting managed profile or user provisioning");
    242 
    243         if(isProvisioningManagedUser()) {
    244             mManagedProfileOrUserInfo = mUserManager.getUserInfo(mUserManager.getUserHandle());
    245             if(mManagedProfileOrUserInfo == null) {
    246                 throw raiseError("Couldn't get current user information");
    247             }
    248         } else {
    249             // Work through the provisioning steps in their corresponding order
    250             createProfile(getString(R.string.default_managed_profile_name));
    251         }
    252         if (mManagedProfileOrUserInfo != null) {
    253             final DeleteNonRequiredAppsTask deleteNonRequiredAppsTask;
    254             final DisableInstallShortcutListenersTask disableInstallShortcutListenersTask;
    255             final DisableBluetoothSharingTask disableBluetoothSharingTask;
    256             final ManagedProfileSettingsTask managedProfileSettingsTask =
    257                     new ManagedProfileSettingsTask(this, mManagedProfileOrUserInfo.id);
    258 
    259             disableInstallShortcutListenersTask = new DisableInstallShortcutListenersTask(this,
    260                     mManagedProfileOrUserInfo.id);
    261             disableBluetoothSharingTask = new DisableBluetoothSharingTask(
    262                     mManagedProfileOrUserInfo.id);
    263             // TODO Add separate set of apps for MANAGED_USER, currently same as of DEVICE_OWNER.
    264             deleteNonRequiredAppsTask = new DeleteNonRequiredAppsTask(this,
    265                     mParams.deviceAdminComponentName.getPackageName(),
    266                     (isProvisioningManagedUser() ? DeleteNonRequiredAppsTask.MANAGED_USER
    267                             : DeleteNonRequiredAppsTask.PROFILE_OWNER),
    268                     true /* creating new profile */,
    269                     mManagedProfileOrUserInfo.id, false /* delete non-required system apps */,
    270                     new DeleteNonRequiredAppsTask.Callback() {
    271 
    272                         @Override
    273                         public void onSuccess() {
    274                             // Need to explicitly handle exceptions here, as
    275                             // onError() is not invoked for failures in
    276                             // onSuccess().
    277                             try {
    278                                 disableBluetoothSharingTask.run();
    279                                 if (!isProvisioningManagedUser()) {
    280                                     managedProfileSettingsTask.run();
    281                                     disableInstallShortcutListenersTask.run();
    282                                 }
    283                                 setUpUserOrProfile();
    284                             } catch (ProvisioningException e) {
    285                                 error(e.getMessage(), e);
    286                             } catch (Exception e) {
    287                                 error("Provisioning failed", e);
    288                             }
    289                             finish();
    290                         }
    291 
    292                         @Override
    293                         public void onError() {
    294                             // Raise an error with a tracing exception attached.
    295                             error("Delete non required apps task failed.", new Exception());
    296                             finish();
    297                         }
    298                     });
    299 
    300             deleteNonRequiredAppsTask.run();
    301         }
    302     }
    303 
    304     /**
    305      * Called when the new profile or managed user is ready for provisioning (the profile is created
    306      * and all the apps not needed have been deleted).
    307      */
    308     private void setUpUserOrProfile() throws ProvisioningException {
    309         installMdmOnManagedProfile();
    310         setMdmAsActiveAdmin();
    311         setMdmAsManagedProfileOwner();
    312 
    313         if (!isProvisioningManagedUser()) {
    314             setOrganizationColor();
    315             setDefaultUserRestrictions();
    316             CrossProfileIntentFiltersHelper.setFilters(
    317                     getPackageManager(), getUserId(), mManagedProfileOrUserInfo.id);
    318             if (!startManagedProfile(mManagedProfileOrUserInfo.id)) {
    319                 throw raiseError("Could not start user in background");
    320             }
    321             // Wait for ACTION_USER_UNLOCKED to be sent before trying to migrate the account.
    322             // Even if no account is present, we should not send the provisioning complete broadcast
    323             // before the managed profile user is properly started.
    324             if ((mUnlockedReceiver != null) && !mUnlockedReceiver.waitForUserUnlocked()) {
    325                 return;
    326             }
    327 
    328             // Note: account migration must happen after setting the profile owner.
    329             // Otherwise, there will be a time interval where some apps may think that the account
    330             // does not have a profile owner.
    331             mUtils.maybeCopyAccount(this, mParams.accountToMigrate, Process.myUserHandle(),
    332                     mManagedProfileOrUserInfo.getUserHandle());
    333         }
    334     }
    335 
    336     /**
    337      * Notify the calling activity of our final status, perform any cleanup if
    338      * the process didn't succeed.
    339      */
    340     private void finish() {
    341         ProvisionLogger.logi("Finishing provisioning process, status: "
    342                              + mProvisioningStatus);
    343         // Reached the end of the provisioning process, take appropriate action
    344         // based on current mProvisioningStatus.
    345         synchronized (this) {
    346             switch (mProvisioningStatus) {
    347                 case STATUS_STARTED:
    348                     // Provisioning process completed normally.
    349                     notifyMdmAndCleanup();
    350                     mProvisioningStatus = STATUS_DONE;
    351                     break;
    352                 case STATUS_UNKNOWN:
    353                     // No idea how we could end up in finish() in this state,
    354                     // but for safety treat it as an error and fall-through to
    355                     // STATUS_ERROR.
    356                     mLastErrorMessage = "finish() invoked in STATUS_UNKNOWN";
    357                     mProvisioningStatus = STATUS_ERROR;
    358                     break;
    359                 case STATUS_ERROR:
    360                     // Process errored out, cleanup partially created managed
    361                     // profile.
    362                     cleanupUserProfile();
    363                     break;
    364                 case STATUS_CANCELLING:
    365                     // User requested cancellation during processing, remove
    366                     // the successfully created profile.
    367                     cleanupUserProfile();
    368                     mProvisioningStatus = STATUS_CANCELLED;
    369                     break;
    370                 case STATUS_CANCELLED:
    371                 case STATUS_DONE:
    372                     // Shouldn't be possible to already be in this state?!?
    373                     ProvisionLogger.logw("finish() invoked multiple times?");
    374                     break;
    375             }
    376         }
    377 
    378         ProvisionLogger.logi("Finished provisioning process, final status: "
    379                 + mProvisioningStatus);
    380 
    381         // Notify UI activity of final status reached.
    382         reportStatus();
    383     }
    384 
    385     /**
    386      * Initialize the user that underlies the managed profile.
    387      * This is required so that the provisioning complete broadcast can be sent across to the
    388      * profile and apps can run on it.
    389      */
    390     private boolean startManagedProfile(int userId)  {
    391         ProvisionLogger.logd("Starting user in background");
    392         IActivityManager iActivityManager = ActivityManagerNative.getDefault();
    393         // Register a receiver for the Intent.ACTION_USER_UNLOCKED to know when the managed profile
    394         // has been started and unlocked.
    395         mUnlockedReceiver = new UserUnlockedReceiver(this, userId);
    396         try {
    397             return iActivityManager.startUserInBackground(userId);
    398         } catch (RemoteException neverThrown) {
    399             // Never thrown, as we are making local calls.
    400             ProvisionLogger.loge("This should not happen.", neverThrown);
    401         }
    402         return false;
    403     }
    404 
    405     private void notifyActivityOfSuccess() {
    406         Intent successIntent = new Intent(ACTION_PROVISIONING_SUCCESS);
    407         LocalBroadcastManager.getInstance(ProfileOwnerProvisioningService.this)
    408                 .sendBroadcast(successIntent);
    409     }
    410 
    411     /**
    412      * Notify the mdm that provisioning has completed. When the mdm has received the intent, stop
    413      * the service and notify the {@link ProfileOwnerProvisioningActivity} so that it can finish
    414      * itself.
    415      */
    416     private void notifyMdmAndCleanup() {
    417         // Set DPM userProvisioningState appropriately and persist mParams for use during
    418         // FinalizationActivity if necessary.
    419         mUtils.markUserProvisioningStateInitiallyDone(this, mParams);
    420 
    421         if (mParams.provisioningAction.equals(ACTION_PROVISION_MANAGED_PROFILE)) {
    422             // Set the user_setup_complete flag on the managed-profile as setup-wizard is never run
    423             // for that user. This is not relevant for other cases since
    424             // Utils.markUserProvisioningStateInitiallyDone() communicates provisioning state to
    425             // setup-wizard via DPM.setUserProvisioningState() if necessary.
    426             mUtils.markUserSetupComplete(this, mManagedProfileOrUserInfo.id);
    427         }
    428 
    429         // If profile owner provisioning was started after current user setup is completed, then we
    430         // can directly send the ACTION_PROFILE_PROVISIONING_COMPLETE broadcast to the MDM.
    431         // But if the provisioning was started as part of setup wizard flow, we signal setup-wizard
    432         // should shutdown via DPM.setUserProvisioningState(), which will result in a finalization
    433         // intent being sent to us once setup-wizard finishes. As part of the finalization intent
    434         // handling we then broadcast ACTION_PROFILE_PROVISIONING_COMPLETE.
    435         if (mUtils.isUserSetupCompleted(this)) {
    436             UserHandle managedUserHandle = new UserHandle(mManagedProfileOrUserInfo.id);
    437 
    438             // Use an ordered broadcast, so that we only finish when the mdm has received it.
    439             // Avoids a lag in the transition between provisioning and the mdm.
    440             BroadcastReceiver mdmReceivedSuccessReceiver = new MdmReceivedSuccessReceiver(
    441                     mParams.accountToMigrate, mParams.deviceAdminComponentName.getPackageName());
    442 
    443             Intent completeIntent = new Intent(ACTION_PROFILE_PROVISIONING_COMPLETE);
    444             completeIntent.setComponent(mParams.deviceAdminComponentName);
    445             completeIntent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES |
    446                     Intent.FLAG_RECEIVER_FOREGROUND);
    447             if (mParams.adminExtrasBundle != null) {
    448                 completeIntent.putExtra(EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE,
    449                         mParams.adminExtrasBundle);
    450             }
    451 
    452             sendOrderedBroadcastAsUser(completeIntent, managedUserHandle, null,
    453                     mdmReceivedSuccessReceiver, null, Activity.RESULT_OK, null, null);
    454             ProvisionLogger.logd("Provisioning complete broadcast has been sent to user "
    455                     + managedUserHandle.getIdentifier());
    456         }
    457     }
    458 
    459     private void createProfile(String profileName) throws ProvisioningException {
    460 
    461         ProvisionLogger.logd("Creating managed profile with name " + profileName);
    462 
    463         mManagedProfileOrUserInfo = mUserManager.createProfileForUser(profileName,
    464                 UserInfo.FLAG_MANAGED_PROFILE | UserInfo.FLAG_DISABLED,
    465                 Process.myUserHandle().getIdentifier());
    466 
    467         if (mManagedProfileOrUserInfo == null) {
    468             throw raiseError("Couldn't create profile.");
    469         }
    470     }
    471 
    472     private void installMdmOnManagedProfile() throws ProvisioningException {
    473         ProvisionLogger.logd("Installing mobile device management app "
    474                 + mParams.deviceAdminComponentName + " on managed profile");
    475 
    476         try {
    477             int status = mIpm.installExistingPackageAsUser(
    478                 mParams.deviceAdminComponentName.getPackageName(), mManagedProfileOrUserInfo.id);
    479             switch (status) {
    480               case PackageManager.INSTALL_SUCCEEDED:
    481                   return;
    482               case PackageManager.INSTALL_FAILED_USER_RESTRICTED:
    483                   // Should not happen because we're not installing a restricted user
    484                   throw raiseError("Could not install mobile device management app on managed "
    485                           + "profile because the user is restricted");
    486               case PackageManager.INSTALL_FAILED_INVALID_URI:
    487                   // Should not happen because we already checked
    488                   throw raiseError("Could not install mobile device management app on managed "
    489                           + "profile because the package could not be found");
    490               default:
    491                   throw raiseError("Could not install mobile device management app on managed "
    492                           + "profile. Unknown status: " + status);
    493             }
    494         } catch (RemoteException neverThrown) {
    495             // Never thrown, as we are making local calls.
    496             ProvisionLogger.loge("This should not happen.", neverThrown);
    497         }
    498     }
    499 
    500     private void setMdmAsManagedProfileOwner() throws ProvisioningException {
    501         ProvisionLogger.logd("Setting package " + mParams.deviceAdminComponentName
    502                 + " as managed profile owner.");
    503 
    504         DevicePolicyManager dpm =
    505                 (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
    506         if (!dpm.setProfileOwner(
    507                 mParams.deviceAdminComponentName,
    508                 mParams.deviceAdminComponentName.getPackageName(),
    509                 mManagedProfileOrUserInfo.id)) {
    510             ProvisionLogger.logw("Could not set profile owner.");
    511             throw raiseError("Could not set profile owner.");
    512         }
    513     }
    514 
    515     private void setMdmAsActiveAdmin() {
    516         ProvisionLogger.logd("Setting package " + mParams.deviceAdminComponentName
    517                 + " as active admin.");
    518 
    519         DevicePolicyManager dpm =
    520                 (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
    521         dpm.setActiveAdmin(mParams.deviceAdminComponentName, true /* refreshing*/,
    522                 mManagedProfileOrUserInfo.id);
    523     }
    524 
    525     private void setOrganizationColor() {
    526         if (mParams.mainColor != null) {
    527             DevicePolicyManager dpm =
    528                     (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
    529             dpm.setOrganizationColorForUser(mParams.mainColor, mManagedProfileOrUserInfo.id);
    530         }
    531     }
    532 
    533     private ProvisioningException raiseError(String message) throws ProvisioningException {
    534         throw new ProvisioningException(message);
    535     }
    536 
    537     /**
    538      * Record the fact that an error occurred, change mProvisioningStatus to
    539      * reflect the fact the provisioning process failed
    540      */
    541     private void error(String dialogMessage, Exception e) {
    542         synchronized (this) {
    543             // Only case where an error condition should be notified is if we
    544             // are in the normal flow for provisioning. If the process has been
    545             // cancelled or already completed, then the fact there is an error
    546             // is almost irrelevant.
    547             if (mProvisioningStatus == STATUS_STARTED) {
    548                 mProvisioningStatus = STATUS_ERROR;
    549                 mLastErrorMessage = dialogMessage;
    550 
    551                 ProvisionLogger.logw(
    552                         "Error occured during provisioning process: "
    553                         + dialogMessage,
    554                         e);
    555             } else {
    556                 ProvisionLogger.logw(
    557                         "Unexpected error occured in status ["
    558                         + mProvisioningStatus + "]: " + dialogMessage,
    559                         e);
    560             }
    561         }
    562     }
    563 
    564     private void setDefaultUserRestrictions() {
    565         mUserManager.setUserRestriction(UserManager.DISALLOW_WALLPAPER, true,
    566                 mManagedProfileOrUserInfo.getUserHandle());
    567     }
    568 
    569     private void notifyActivityError() {
    570         Intent intent = new Intent(ACTION_PROVISIONING_ERROR);
    571         intent.putExtra(EXTRA_LOG_MESSAGE_KEY, mLastErrorMessage);
    572         LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
    573     }
    574 
    575     private void notifyActivityCancelled() {
    576         Intent cancelIntent = new Intent(ACTION_PROVISIONING_CANCELLED);
    577         LocalBroadcastManager.getInstance(this).sendBroadcast(cancelIntent);
    578     }
    579 
    580     /**
    581      * Performs cleanup of any created user-profile on failure/cancellation.
    582      */
    583     private void cleanupUserProfile() {
    584         if (mManagedProfileOrUserInfo != null && !isProvisioningManagedUser()) {
    585             ProvisionLogger.logd("Removing managed profile");
    586             mUserManager.removeUser(mManagedProfileOrUserInfo.id);
    587         }
    588     }
    589 
    590     @Override
    591     public IBinder onBind(Intent intent) {
    592         return null;
    593     }
    594 
    595     /**
    596      * Internal exception to allow provisioning process to terminal quickly and
    597      * cleanly on first error, rather than continuing to process despite errors
    598      * occurring.
    599      */
    600     private static class ProvisioningException extends Exception {
    601         public ProvisioningException(String detailMessage) {
    602             super(detailMessage);
    603         }
    604     }
    605 
    606     public boolean isProvisioningManagedUser() {
    607         return mParams.provisioningAction.equals(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER);
    608     }
    609 
    610     /**
    611      * BroadcastReceiver that listens to {@link Intent#ACTION_USER_UNLOCKED} in order to provide
    612      * a blocking wait until the managed profile has been started and unlocked.
    613      */
    614     private static class UserUnlockedReceiver extends BroadcastReceiver {
    615         private static final IntentFilter FILTER = new IntentFilter(Intent.ACTION_USER_UNLOCKED);
    616 
    617         private final Semaphore semaphore = new Semaphore(0);
    618         private final Context mContext;
    619         private final int mUserId;
    620 
    621         UserUnlockedReceiver(Context context, int userId) {
    622             mContext = context;
    623             mUserId = userId;
    624             mContext.registerReceiverAsUser(this, new UserHandle(userId), FILTER, null, null);
    625         }
    626 
    627         @Override
    628         public void onReceive(Context context, Intent intent ) {
    629             if (!Intent.ACTION_USER_UNLOCKED.equals(intent.getAction())) {
    630                 ProvisionLogger.logw("Unexpected intent: " + intent);
    631                 return;
    632             }
    633             if (intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL) == mUserId) {
    634                 ProvisionLogger.logd("Received ACTION_USER_UNLOCKED for user " + mUserId);
    635                 semaphore.release();
    636                 mContext.unregisterReceiver(this);
    637             }
    638         }
    639 
    640         public boolean waitForUserUnlocked() {
    641             ProvisionLogger.logd("Waiting for ACTION_USER_UNLOCKED");
    642             try {
    643                 return semaphore.tryAcquire(USER_UNLOCKED_TIMEOUT_SECONDS, TimeUnit.SECONDS);
    644             } catch (InterruptedException ie) {
    645                 mContext.unregisterReceiver(this);
    646                 return false;
    647             }
    648         }
    649     }
    650  }
    651