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
doInBackground(Intent .... intents)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
onCreate()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
onStartCommand(final Intent intent, int flags, int startId)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 
reportStatus()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 
cancelProvisioning()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 
initialize(Intent intent)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      */
startManagedProfileOrUserProvisioning()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      */
setUpUserOrProfile()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      */
finish()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      */
startManagedProfile(int userId)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 
notifyActivityOfSuccess()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      */
notifyMdmAndCleanup()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 
createProfile(String profileName)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 
installMdmOnManagedProfile()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 
setMdmAsManagedProfileOwner()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 
setMdmAsActiveAdmin()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 
setOrganizationColor()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 
raiseError(String message)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      */
error(String dialogMessage, Exception e)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 
setDefaultUserRestrictions()564     private void setDefaultUserRestrictions() {
565         mUserManager.setUserRestriction(UserManager.DISALLOW_WALLPAPER, true,
566                 mManagedProfileOrUserInfo.getUserHandle());
567     }
568 
notifyActivityError()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 
notifyActivityCancelled()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      */
cleanupUserProfile()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
onBind(Intent intent)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 {
ProvisioningException(String detailMessage)601         public ProvisioningException(String detailMessage) {
602             super(detailMessage);
603         }
604     }
605 
isProvisioningManagedUser()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 
UserUnlockedReceiver(Context context, int userId)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
onReceive(Context context, Intent intent )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 
waitForUserUnlocked()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