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.DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE; 20 21 import android.app.AlarmManager; 22 import android.app.Service; 23 import android.app.admin.DevicePolicyManager; 24 import android.content.ComponentName; 25 import android.content.Context; 26 import android.content.Intent; 27 import android.content.pm.PackageManager; 28 import android.os.Bundle; 29 import android.os.IBinder; 30 import android.os.Process; 31 import android.os.UserHandle; 32 import android.os.UserManager; 33 import android.support.v4.content.LocalBroadcastManager; 34 35 import com.android.internal.app.LocalePicker; 36 import com.android.managedprovisioning.common.IllegalProvisioningArgumentException; 37 import com.android.managedprovisioning.common.Utils; 38 import com.android.managedprovisioning.model.ProvisioningParams; 39 import com.android.managedprovisioning.task.AddWifiNetworkTask; 40 import com.android.managedprovisioning.task.DeleteNonRequiredAppsTask; 41 import com.android.managedprovisioning.task.DisallowAddUserTask; 42 import com.android.managedprovisioning.task.DownloadPackageTask; 43 import com.android.managedprovisioning.task.InstallPackageTask; 44 import com.android.managedprovisioning.task.SetDevicePolicyTask; 45 46 import java.util.Locale; 47 48 /** 49 * This service does the work for the DeviceOwnerProvisioningActivity. 50 * Feedback is sent back to the activity via intents. 51 * 52 * <p> 53 * If the corresponding activity is killed and restarted, the service is 54 * called twice. The service will not start the provisioning flow a second time, but instead 55 * send a status update to the activity. 56 * </p> 57 */ 58 public class DeviceOwnerProvisioningService extends Service { 59 private static final boolean DEBUG = false; // To control logging. 60 61 private static final String DEVICE_OWNER = "deviceOwner"; 62 63 /** 64 * Intent action to activate the CDMA phone connection by OTASP. 65 * This is not necessary for a GSM phone connection, which is activated automatically. 66 * String must agree with the constants in com.android.phone.InCallScreenShowActivation. 67 */ 68 private static final String ACTION_PERFORM_CDMA_PROVISIONING = 69 "com.android.phone.PERFORM_CDMA_PROVISIONING"; 70 71 // Intent actions and extras for communication from DeviceOwnerProvisioningService to Activity. 72 protected static final String ACTION_PROVISIONING_SUCCESS = 73 "com.android.managedprovisioning.provisioning_success"; 74 protected static final String ACTION_PROVISIONING_ERROR = 75 "com.android.managedprovisioning.error"; 76 protected static final String EXTRA_USER_VISIBLE_ERROR_ID_KEY = 77 "UserVisibleErrorMessage-Id"; 78 protected static final String EXTRA_FACTORY_RESET_REQUIRED = 79 "FactoryResetRequired"; 80 protected static final String ACTION_PROGRESS_UPDATE = 81 "com.android.managedprovisioning.progress_update"; 82 protected static final String EXTRA_PROGRESS_MESSAGE_ID_KEY = 83 "ProgressMessageId"; 84 protected static final String ACTION_REQUEST_WIFI_PICK = 85 "com.android.managedprovisioning.request_wifi_pick"; 86 87 // Indicates whether provisioning has started. 88 private boolean mProvisioningInFlight = false; 89 90 // MessageId of the last progress message. 91 private int mLastProgressMessage = -1; 92 93 // MessageId of the last error message. 94 private int mLastErrorMessage = -1; 95 96 // Indicates whether reverting the provisioning process up till now requires a factory reset. 97 // Is false at the start and flips to true after the first irrevertible action. 98 private boolean mFactoryResetRequired = false; 99 100 // Indicates whether provisioning has finished successfully (service waiting to stop). 101 private volatile boolean mDone = false; 102 103 // Provisioning tasks. 104 private AddWifiNetworkTask mAddWifiNetworkTask; 105 private DownloadPackageTask mDownloadPackageTask; 106 private InstallPackageTask mInstallPackageTask; 107 private SetDevicePolicyTask mSetDevicePolicyTask; 108 private DeleteNonRequiredAppsTask mDeleteNonRequiredAppsTask; 109 private DisallowAddUserTask mDisallowAddUserTask; 110 111 private ProvisioningParams mParams; 112 113 private final Utils mUtils = new Utils(); 114 115 @Override onStartCommand(final Intent intent, int flags, int startId)116 public int onStartCommand(final Intent intent, int flags, int startId) { 117 if (DEBUG) ProvisionLogger.logd("Device owner provisioning service ONSTARTCOMMAND."); 118 119 synchronized (this) { // Make operations on mProvisioningInFlight atomic. 120 if (mProvisioningInFlight) { 121 if (DEBUG) ProvisionLogger.logd("Provisioning already in flight."); 122 123 sendProgressUpdateToActivity(); 124 125 // Send error message if currently in error state. 126 if (mLastErrorMessage >= 0) { 127 sendError(); 128 } 129 130 // Send success if provisioning was successful. 131 if (mDone) { 132 onProvisioningSuccess(); 133 } 134 } else { 135 mProvisioningInFlight = true; 136 if (DEBUG) ProvisionLogger.logd("First start of the service."); 137 progressUpdate(R.string.progress_data_process); 138 139 // Load the ProvisioningParams (from message in Intent). 140 mParams = (ProvisioningParams) intent.getParcelableExtra( 141 ProvisioningParams.EXTRA_PROVISIONING_PARAMS); 142 143 // Do the work on a separate thread. 144 new Thread(new Runnable() { 145 public void run() { 146 initializeProvisioningEnvironment(mParams); 147 startDeviceOwnerProvisioning(mParams); 148 } 149 }).start(); 150 } 151 } 152 return START_NOT_STICKY; 153 } 154 155 /** 156 * This is the core method of this class. It goes through every provisioning step. 157 * Each task checks if it is required and executes if it is. 158 */ startDeviceOwnerProvisioning(final ProvisioningParams params)159 private void startDeviceOwnerProvisioning(final ProvisioningParams params) { 160 if (DEBUG) ProvisionLogger.logd("Starting device owner provisioning"); 161 162 // Construct Tasks. Do not start them yet. 163 mAddWifiNetworkTask = new AddWifiNetworkTask(this, params.wifiInfo, 164 new AddWifiNetworkTask.Callback() { 165 @Override 166 public void onSuccess() { 167 progressUpdate(R.string.progress_download); 168 mDownloadPackageTask.run(); 169 } 170 171 @Override 172 public void onError(){ 173 error(R.string.device_owner_error_wifi, 174 false /* do not require factory reset */); 175 } 176 }); 177 178 mDownloadPackageTask = new DownloadPackageTask(this, 179 new DownloadPackageTask.Callback() { 180 @Override 181 public void onSuccess() { 182 progressUpdate(R.string.progress_install); 183 mInstallPackageTask.addInstallIfNecessary( 184 params.inferDeviceAdminPackageName(), 185 mDownloadPackageTask.getDownloadedPackageLocation(DEVICE_OWNER)); 186 mInstallPackageTask.run(); 187 } 188 189 @Override 190 public void onError(int errorCode) { 191 switch(errorCode) { 192 case DownloadPackageTask.ERROR_HASH_MISMATCH: 193 error(R.string.device_owner_error_hash_mismatch); 194 break; 195 case DownloadPackageTask.ERROR_DOWNLOAD_FAILED: 196 error(R.string.device_owner_error_download_failed); 197 break; 198 default: 199 error(R.string.device_owner_error_general); 200 break; 201 } 202 } 203 }); 204 205 // Add packages to download to the DownloadPackageTask. 206 mDownloadPackageTask.addDownloadIfNecessary(params.inferDeviceAdminPackageName(), 207 params.deviceAdminDownloadInfo, DEVICE_OWNER); 208 209 mInstallPackageTask = new InstallPackageTask(this, 210 new InstallPackageTask.Callback() { 211 @Override 212 public void onSuccess() { 213 progressUpdate(R.string.progress_set_owner); 214 try { 215 // Now that the app has been installed, we can look for the device admin 216 // component in it. 217 mSetDevicePolicyTask.run(mParams.inferDeviceAdminComponentName( 218 DeviceOwnerProvisioningService.this)); 219 } catch (IllegalProvisioningArgumentException e) { 220 error(R.string.device_owner_error_general); 221 ProvisionLogger.loge("Failed to infer the device admin component name", 222 e); 223 return; 224 } 225 } 226 227 @Override 228 public void onError(int errorCode) { 229 switch(errorCode) { 230 case InstallPackageTask.ERROR_PACKAGE_INVALID: 231 error(R.string.device_owner_error_package_invalid); 232 break; 233 case InstallPackageTask.ERROR_INSTALLATION_FAILED: 234 error(R.string.device_owner_error_installation_failed); 235 break; 236 default: 237 error(R.string.device_owner_error_general); 238 break; 239 } 240 } 241 }); 242 243 mSetDevicePolicyTask = new SetDevicePolicyTask(this, 244 getResources().getString(R.string.default_owned_device_username), 245 new SetDevicePolicyTask.Callback() { 246 @Override 247 public void onSuccess() { 248 mDeleteNonRequiredAppsTask.run(); 249 } 250 251 @Override 252 public void onError() { 253 error(R.string.device_owner_error_general); 254 } 255 }); 256 257 // For split system user devices that will have a system device owner, don't adjust the set 258 // of enabled packages in the system user as we expect the right set of packages to be 259 // enabled for the system user out of the box. For other devices, the set of available 260 // packages can vary depending on management state. 261 boolean leaveAllSystemAppsEnabled = params.leaveAllSystemAppsEnabled || 262 params.provisioningAction.equals(ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE); 263 mDeleteNonRequiredAppsTask = new DeleteNonRequiredAppsTask( 264 this, params.inferDeviceAdminPackageName(), 265 DeleteNonRequiredAppsTask.DEVICE_OWNER, true /* creating new profile */, 266 UserHandle.myUserId(), leaveAllSystemAppsEnabled, 267 new DeleteNonRequiredAppsTask.Callback() { 268 @Override 269 public void onSuccess() { 270 mDisallowAddUserTask.maybeDisallowAddUsers(); 271 272 // Done with provisioning. Success. 273 onProvisioningSuccess(); 274 } 275 276 @Override 277 public void onError() { 278 error(R.string.device_owner_error_general); 279 } 280 }); 281 282 mDisallowAddUserTask = new DisallowAddUserTask((UserManager) getSystemService(USER_SERVICE), 283 UserHandle.myUserId(), UserManager.isSplitSystemUser()); 284 285 // Start first task, which starts next task in its callback, etc. 286 progressUpdate(R.string.progress_connect_to_wifi); 287 mAddWifiNetworkTask.run(); 288 } 289 error(int dialogMessage)290 private void error(int dialogMessage) { 291 error(dialogMessage, true /* require factory reset */); 292 } 293 error(int dialogMessage, boolean factoryResetRequired)294 private void error(int dialogMessage, boolean factoryResetRequired) { 295 mLastErrorMessage = dialogMessage; 296 if (factoryResetRequired) { 297 mFactoryResetRequired = true; 298 } 299 sendError(); 300 // Wait for stopService() call from the activity. 301 } 302 sendError()303 private void sendError() { 304 if (DEBUG) { 305 ProvisionLogger.logd("Reporting Error: " + getResources() 306 .getString(mLastErrorMessage)); 307 } 308 Intent intent = new Intent(ACTION_PROVISIONING_ERROR); 309 intent.setClass(this, DeviceOwnerProvisioningActivity.ServiceMessageReceiver.class); 310 intent.putExtra(EXTRA_USER_VISIBLE_ERROR_ID_KEY, mLastErrorMessage); 311 intent.putExtra(EXTRA_FACTORY_RESET_REQUIRED, mFactoryResetRequired); 312 LocalBroadcastManager.getInstance(this).sendBroadcast(intent); 313 } 314 progressUpdate(int progressMessage)315 private void progressUpdate(int progressMessage) { 316 if (DEBUG) { 317 ProvisionLogger.logd("Reporting progress update: " + getResources() 318 .getString(progressMessage)); 319 } 320 mLastProgressMessage = progressMessage; 321 sendProgressUpdateToActivity(); 322 } 323 sendProgressUpdateToActivity()324 private void sendProgressUpdateToActivity() { 325 Intent intent = new Intent(ACTION_PROGRESS_UPDATE); 326 intent.putExtra(EXTRA_PROGRESS_MESSAGE_ID_KEY, mLastProgressMessage); 327 intent.setClass(this, DeviceOwnerProvisioningActivity.ServiceMessageReceiver.class); 328 LocalBroadcastManager.getInstance(this).sendBroadcast(intent); 329 } 330 onProvisioningSuccess()331 private void onProvisioningSuccess() { 332 // Copying an account needs to happen late in the provisioning process to allow the current 333 // user to be started, but before we tell the MDM that provisioning succeeded. 334 maybeCopyAccount(); 335 336 if (DEBUG) ProvisionLogger.logd("Reporting success."); 337 mDone = true; 338 339 // Set DPM userProvisioningState appropriately and persists mParams for use during 340 // FinalizationActivity if necessary. 341 mUtils.markUserProvisioningStateInitiallyDone(this, mParams); 342 343 Intent successIntent = new Intent(ACTION_PROVISIONING_SUCCESS); 344 successIntent.setClass(this, DeviceOwnerProvisioningActivity.ServiceMessageReceiver.class); 345 LocalBroadcastManager.getInstance(this).sendBroadcast(successIntent); 346 // Wait for stopService() call from the activity. 347 } 348 maybeCopyAccount()349 private void maybeCopyAccount() { 350 if (!UserManager.isSplitSystemUser()) { 351 // Only one user involved in this case. 352 return; 353 } 354 355 mUtils.maybeCopyAccount(DeviceOwnerProvisioningService.this, 356 mParams.accountToMigrate, UserHandle.SYSTEM, 357 Process.myUserHandle()); 358 } 359 initializeProvisioningEnvironment(ProvisioningParams params)360 private void initializeProvisioningEnvironment(ProvisioningParams params) { 361 setTimeAndTimezone(params.timeZone, params.localTime); 362 setLocale(params.locale); 363 364 // Start CDMA activation to enable phone calls. 365 final Intent intent = new Intent(ACTION_PERFORM_CDMA_PROVISIONING); 366 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 367 if (DEBUG) ProvisionLogger.logd("Starting cdma activation activity"); 368 startActivity(intent); // Activity will be a Nop if not a CDMA device. 369 } 370 setTimeAndTimezone(String timeZone, long localTime)371 private void setTimeAndTimezone(String timeZone, long localTime) { 372 try { 373 final AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE); 374 if (timeZone != null) { 375 if (DEBUG) ProvisionLogger.logd("Setting time zone to " + timeZone); 376 am.setTimeZone(timeZone); 377 } 378 if (localTime > 0) { 379 if (DEBUG) ProvisionLogger.logd("Setting time to " + localTime); 380 am.setTime(localTime); 381 } 382 } catch (Exception e) { 383 ProvisionLogger.loge("Alarm manager failed to set the system time/timezone."); 384 // Do not stop provisioning process, but ignore this error. 385 } 386 } 387 setLocale(Locale locale)388 private void setLocale(Locale locale) { 389 if (locale == null || locale.equals(Locale.getDefault())) { 390 return; 391 } 392 try { 393 if (DEBUG) ProvisionLogger.logd("Setting locale to " + locale); 394 // If locale is different from current locale this results in a configuration change, 395 // which will trigger the restarting of the activity. 396 LocalePicker.updateLocale(locale); 397 } catch (Exception e) { 398 ProvisionLogger.loge("Failed to set the system locale."); 399 // Do not stop provisioning process, but ignore this error. 400 } 401 } 402 403 @Override onCreate()404 public void onCreate () { 405 if (DEBUG) ProvisionLogger.logd("Device owner provisioning service ONCREATE."); 406 } 407 408 @Override onDestroy()409 public void onDestroy () { 410 if (DEBUG) ProvisionLogger.logd("Device owner provisioning service ONDESTROY"); 411 if (mAddWifiNetworkTask != null) { 412 mAddWifiNetworkTask.cleanUp(); 413 } 414 if (mDownloadPackageTask != null) { 415 mDownloadPackageTask.cleanUp(); 416 } 417 } 418 419 @Override onBind(Intent intent)420 public IBinder onBind(Intent intent) { 421 return null; 422 } 423 } 424