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.EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE; 21 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE; 22 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME; 23 import static android.Manifest.permission.BIND_DEVICE_ADMIN; 24 25 import android.accounts.Account; 26 import android.accounts.AccountManager; 27 import android.accounts.AuthenticatorException; 28 import android.accounts.OperationCanceledException; 29 import android.app.Activity; 30 import android.app.ActivityManagerNative; 31 import android.app.IActivityManager; 32 import android.app.Service; 33 import android.app.admin.DevicePolicyManager; 34 import android.content.BroadcastReceiver; 35 import android.content.ComponentName; 36 import android.content.Context; 37 import android.content.Intent; 38 import android.content.pm.ActivityInfo; 39 import android.content.pm.IPackageManager; 40 import android.content.pm.PackageInfo; 41 import android.content.pm.PackageManager; 42 import android.content.pm.PackageManager.NameNotFoundException; 43 import android.content.pm.UserInfo; 44 import android.os.AsyncTask; 45 import android.os.IBinder; 46 import android.os.Parcelable; 47 import android.os.PersistableBundle; 48 import android.os.Process; 49 import android.os.RemoteException; 50 import android.os.ServiceManager; 51 import android.os.UserHandle; 52 import android.os.UserManager; 53 import android.provider.MediaStore; 54 import android.support.v4.content.LocalBroadcastManager; 55 import android.text.TextUtils; 56 57 import com.android.managedprovisioning.CrossProfileIntentFiltersHelper; 58 import com.android.managedprovisioning.task.DeleteNonRequiredAppsTask; 59 60 import java.io.IOException; 61 62 /** 63 * Service that runs the profile owner provisioning. 64 * 65 * <p>This service is started from and sends updates to the {@link ProfileOwnerProvisioningActivity}, 66 * which contains the provisioning UI. 67 */ 68 public class ProfileOwnerProvisioningService extends Service { 69 // Extra keys for reporting back success to the activity. 70 public static final String EXTRA_PROFILE_USER_ID = 71 "com.android.managedprovisioning.extra.profile_user_id"; 72 public static final String EXTRA_PROFILE_USER_SERIAL_NUMBER = 73 "com.android.managedprovisioning.extra.profile_user_serial_number"; 74 public static final String EXTRA_PENDING_SUCCESS_INTENT = 75 "com.android.managedprovisioning.extra.pending_success_intent"; 76 77 // Intent actions for communication with DeviceOwnerProvisioningService. 78 public static final String ACTION_PROVISIONING_SUCCESS = 79 "com.android.managedprovisioning.provisioning_success"; 80 public static final String ACTION_PROVISIONING_ERROR = 81 "com.android.managedprovisioning.error"; 82 public static final String ACTION_PROVISIONING_CANCELLED = 83 "com.android.managedprovisioning.cancelled"; 84 public static final String EXTRA_LOG_MESSAGE_KEY = "ProvisioingErrorLogMessage"; 85 86 private String mMdmPackageName; 87 private ComponentName mActiveAdminComponentName; 88 89 // PersistableBundle extra received in starting intent. 90 // Should be passed through to device management application when provisioning is complete. 91 private PersistableBundle mAdminExtrasBundle; 92 private Account mAccountToMigrate; 93 94 private IPackageManager mIpm; 95 private UserInfo mManagedProfileUserInfo; 96 private AccountManager mAccountManager; 97 private UserManager mUserManager; 98 99 private int mStartIdProvisioning; 100 private AsyncTask<Intent, Void, Void> runnerTask; 101 102 // MessageId of the last error message. 103 private String mLastErrorMessage = null; 104 105 private boolean mDone = false; 106 private boolean mCancelInFuture = false; 107 108 private class RunnerTask extends AsyncTask<Intent, Void, Void> { 109 @Override doInBackground(Intent .... intents)110 protected Void doInBackground(Intent ... intents) { 111 initialize(intents[0]); 112 startManagedProfileProvisioning(); 113 return null; 114 } 115 } 116 117 @Override onCreate()118 public void onCreate() { 119 super.onCreate(); 120 121 mIpm = IPackageManager.Stub.asInterface(ServiceManager.getService("package")); 122 mAccountManager = (AccountManager) getSystemService(Context.ACCOUNT_SERVICE); 123 mUserManager = (UserManager) getSystemService(Context.USER_SERVICE); 124 125 runnerTask = new RunnerTask(); 126 } 127 128 @Override onStartCommand(final Intent intent, int flags, int startId)129 public int onStartCommand(final Intent intent, int flags, int startId) { 130 if (ProfileOwnerProvisioningActivity.ACTION_CANCEL_PROVISIONING.equals(intent.getAction())) { 131 ProvisionLogger.logd("Cancelling profile owner provisioning service"); 132 cancelProvisioning(); 133 return START_NOT_STICKY; 134 } 135 136 ProvisionLogger.logd("Starting profile owner provisioning service"); 137 138 try { 139 runnerTask.execute(intent); 140 } catch (IllegalStateException e) { 141 // runnerTask is either in progress, or finished. 142 ProvisionLogger.logd( 143 "ProfileOwnerProvisioningService: Provisioning already started, " 144 + "second provisioning intent not being processed, only reporting status."); 145 reportStatus(); 146 } 147 return START_NOT_STICKY; 148 } 149 reportStatus()150 private void reportStatus() { 151 if (mLastErrorMessage != null) { 152 sendError(); 153 } 154 synchronized (this) { 155 if (mDone) { 156 notifyActivityOfSuccess(); 157 } 158 } 159 } 160 cancelProvisioning()161 private void cancelProvisioning() { 162 synchronized (this) { 163 if (!mDone) { 164 mCancelInFuture = true; 165 return; 166 } 167 cleanup(); 168 } 169 } 170 initialize(Intent intent)171 private void initialize(Intent intent) { 172 mMdmPackageName = intent.getStringExtra(EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME); 173 mAccountToMigrate = (Account) intent.getParcelableExtra( 174 EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE); 175 if (mAccountToMigrate != null) { 176 ProvisionLogger.logi("Migrating account to managed profile"); 177 } 178 179 // Cast is guaranteed by check in Activity. 180 mAdminExtrasBundle = (PersistableBundle) intent.getParcelableExtra( 181 EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE); 182 183 mActiveAdminComponentName = getAdminReceiverComponent(mMdmPackageName); 184 } 185 186 /** 187 * Find the Device admin receiver component from the manifest. 188 */ getAdminReceiverComponent(String packageName)189 private ComponentName getAdminReceiverComponent(String packageName) { 190 ComponentName adminReceiverComponent = null; 191 192 try { 193 PackageInfo pi = getPackageManager().getPackageInfo(packageName, 194 PackageManager.GET_RECEIVERS); 195 for (ActivityInfo ai : pi.receivers) { 196 if (!TextUtils.isEmpty(ai.permission) && 197 ai.permission.equals(BIND_DEVICE_ADMIN)) { 198 adminReceiverComponent = new ComponentName(packageName, ai.name); 199 200 } 201 } 202 } catch (NameNotFoundException e) { 203 error("Error: The provided mobile device management package does not define a device" 204 + "admin receiver component in its manifest."); 205 } 206 return adminReceiverComponent; 207 } 208 209 /** 210 * This is the core method of this class. It goes through every provisioning step. 211 */ startManagedProfileProvisioning()212 private void startManagedProfileProvisioning() { 213 214 ProvisionLogger.logd("Starting managed profile provisioning"); 215 216 // Work through the provisioning steps in their corresponding order 217 createProfile(getString(R.string.default_managed_profile_name)); 218 if (mManagedProfileUserInfo != null) { 219 new DeleteNonRequiredAppsTask(this, 220 mMdmPackageName, mManagedProfileUserInfo.id, 221 R.array.required_apps_managed_profile, 222 R.array.vendor_required_apps_managed_profile, 223 true /* We are creating a new profile */, 224 true /* Disable INSTALL_SHORTCUT listeners */, 225 new DeleteNonRequiredAppsTask.Callback() { 226 227 @Override 228 public void onSuccess() { 229 setUpProfileAndFinish(); 230 } 231 232 @Override 233 public void onError() { 234 error("Delete non required apps task failed."); 235 } 236 }).run(); 237 } 238 } 239 240 /** 241 * Called when the new profile is ready for provisioning (the profile is created and all the 242 * apps not needed have been deleted). 243 */ setUpProfileAndFinish()244 private void setUpProfileAndFinish() { 245 installMdmOnManagedProfile(); 246 setMdmAsActiveAdmin(); 247 setMdmAsManagedProfileOwner(); 248 CrossProfileIntentFiltersHelper.setFilters( 249 getPackageManager(), getUserId(), mManagedProfileUserInfo.id); 250 251 if (!startManagedProfile(mManagedProfileUserInfo.id)) { 252 error("Could not start user in background"); 253 return; 254 } 255 copyAccount(mAccountToMigrate); 256 synchronized (this) { 257 mDone = true; 258 if (mCancelInFuture) { 259 cleanup(); 260 } else { 261 // Notify activity of success. 262 notifyActivityOfSuccess(); 263 } 264 } 265 } 266 267 /** 268 * Initialize the user that underlies the managed profile. 269 * This is required so that the provisioning complete broadcast can be sent across to the 270 * profile and apps can run on it. 271 */ startManagedProfile(int userId)272 private boolean startManagedProfile(int userId) { 273 ProvisionLogger.logd("Starting user in background"); 274 IActivityManager iActivityManager = ActivityManagerNative.getDefault(); 275 try { 276 return iActivityManager.startUserInBackground(userId); 277 } catch (RemoteException neverThrown) { 278 // Never thrown, as we are making local calls. 279 ProvisionLogger.loge("This should not happen.", neverThrown); 280 } 281 return false; 282 } 283 notifyActivityOfSuccess()284 private void notifyActivityOfSuccess() { 285 // Compose the intent that will be fired by the activity. 286 Intent completeIntent = new Intent(ACTION_PROFILE_PROVISIONING_COMPLETE); 287 completeIntent.setComponent(mActiveAdminComponentName); 288 completeIntent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES | 289 Intent.FLAG_RECEIVER_FOREGROUND); 290 if (mAdminExtrasBundle != null) { 291 completeIntent.putExtra(EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE, 292 mAdminExtrasBundle); 293 } 294 295 Intent successIntent = new Intent(ACTION_PROVISIONING_SUCCESS); 296 successIntent.putExtra(EXTRA_PROFILE_USER_ID, mManagedProfileUserInfo.id); 297 successIntent.putExtra(EXTRA_PENDING_SUCCESS_INTENT, completeIntent); 298 successIntent.putExtra(EXTRA_PROFILE_USER_SERIAL_NUMBER, 299 mManagedProfileUserInfo.serialNumber); 300 LocalBroadcastManager.getInstance(ProfileOwnerProvisioningService.this) 301 .sendBroadcast(successIntent); 302 } 303 copyAccount(Account account)304 private void copyAccount(Account account) { 305 if (account == null) { 306 ProvisionLogger.logd("No account to migrate to the managed profile."); 307 return; 308 } 309 ProvisionLogger.logd("Attempting to copy account to user " + mManagedProfileUserInfo.id); 310 try { 311 if (mAccountManager.copyAccountToUser(account, mManagedProfileUserInfo.getUserHandle(), 312 /* callback= */ null, /* handler= */ null).getResult()) { 313 ProvisionLogger.logi("Copied account to user " + mManagedProfileUserInfo.id); 314 } else { 315 ProvisionLogger.loge("Could not copy account to user " 316 + mManagedProfileUserInfo.id); 317 } 318 } catch (OperationCanceledException | AuthenticatorException | IOException e) { 319 ProvisionLogger.logw("Exception copying account to user " + mManagedProfileUserInfo.id, 320 e); 321 } 322 } 323 createProfile(String profileName)324 private void createProfile(String profileName) { 325 326 ProvisionLogger.logd("Creating managed profile with name " + profileName); 327 328 mManagedProfileUserInfo = mUserManager.createProfileForUser(profileName, 329 UserInfo.FLAG_MANAGED_PROFILE | UserInfo.FLAG_DISABLED, 330 Process.myUserHandle().getIdentifier()); 331 332 if (mManagedProfileUserInfo == null) { 333 if (UserManager.getMaxSupportedUsers() == mUserManager.getUserCount()) { 334 error("Profile creation failed, maximum number of users reached."); 335 } else { 336 error("Couldn't create profile. Reason unknown."); 337 } 338 } 339 } 340 installMdmOnManagedProfile()341 private void installMdmOnManagedProfile() { 342 ProvisionLogger.logd("Installing mobile device management app " + mMdmPackageName + 343 " on managed profile"); 344 345 try { 346 int status = mIpm.installExistingPackageAsUser( 347 mMdmPackageName, mManagedProfileUserInfo.id); 348 switch (status) { 349 case PackageManager.INSTALL_SUCCEEDED: 350 return; 351 case PackageManager.INSTALL_FAILED_USER_RESTRICTED: 352 // Should not happen because we're not installing a restricted user 353 error("Could not install mobile device management app on managed " 354 + "profile because the user is restricted"); 355 case PackageManager.INSTALL_FAILED_INVALID_URI: 356 // Should not happen because we already checked 357 error("Could not install mobile device management app on managed " 358 + "profile because the package could not be found"); 359 default: 360 error("Could not install mobile device management app on managed " 361 + "profile. Unknown status: " + status); 362 } 363 } catch (RemoteException neverThrown) { 364 // Never thrown, as we are making local calls. 365 ProvisionLogger.loge("This should not happen.", neverThrown); 366 } 367 } 368 setMdmAsManagedProfileOwner()369 private void setMdmAsManagedProfileOwner() { 370 ProvisionLogger.logd("Setting package " + mMdmPackageName + " as managed profile owner."); 371 372 DevicePolicyManager dpm = 373 (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE); 374 if (!dpm.setProfileOwner(mActiveAdminComponentName, mMdmPackageName, 375 mManagedProfileUserInfo.id)) { 376 ProvisionLogger.logw("Could not set profile owner."); 377 error("Could not set profile owner."); 378 } 379 } 380 setMdmAsActiveAdmin()381 private void setMdmAsActiveAdmin() { 382 ProvisionLogger.logd("Setting package " + mMdmPackageName + " as active admin."); 383 384 DevicePolicyManager dpm = 385 (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE); 386 dpm.setActiveAdmin(mActiveAdminComponentName, true /* refreshing*/, 387 mManagedProfileUserInfo.id); 388 } 389 error(String dialogMessage)390 private void error(String dialogMessage) { 391 mLastErrorMessage = dialogMessage; 392 sendError(); 393 } 394 sendError()395 private void sendError() { 396 Intent intent = new Intent(ACTION_PROVISIONING_ERROR); 397 intent.putExtra(EXTRA_LOG_MESSAGE_KEY, mLastErrorMessage); 398 LocalBroadcastManager.getInstance(this).sendBroadcast(intent); 399 } 400 401 /** 402 * Performs cleanup of the device on failure. 403 */ cleanup()404 private void cleanup() { 405 // The only cleanup we need to do is remove the profile we created. 406 if (mManagedProfileUserInfo != null) { 407 ProvisionLogger.logd("Removing managed profile"); 408 mUserManager.removeUser(mManagedProfileUserInfo.id); 409 } 410 Intent cancelIntent = new Intent(ACTION_PROVISIONING_CANCELLED); 411 LocalBroadcastManager.getInstance(ProfileOwnerProvisioningService.this) 412 .sendBroadcast(cancelIntent); 413 } 414 415 @Override onBind(Intent intent)416 public IBinder onBind(Intent intent) { 417 return null; 418 } 419 } 420