DeviceOwnerProvisioningService.java revision 91e23dddc899165feb982b181629c23dba310d8e
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 17package com.android.managedprovisioning; 18 19import android.app.AlarmManager; 20import android.app.Service; 21import android.app.admin.DeviceInitializerStatus; 22import android.content.BroadcastReceiver; 23import android.content.ComponentName; 24import android.content.Context; 25import android.content.Intent; 26import android.content.pm.PackageManager; 27import android.os.Bundle; 28import android.os.IBinder; 29import android.os.UserHandle; 30import android.support.v4.content.LocalBroadcastManager; 31import android.text.TextUtils; 32 33import com.android.internal.app.LocalePicker; 34import com.android.managedprovisioning.ProvisioningParams.PackageDownloadInfo; 35import com.android.managedprovisioning.proxy.BluetoothConnectionService; 36import com.android.managedprovisioning.task.AddWifiNetworkTask; 37import com.android.managedprovisioning.task.BluetoothConnectTask; 38import com.android.managedprovisioning.task.DeleteNonRequiredAppsTask; 39import com.android.managedprovisioning.task.DownloadPackageTask; 40import com.android.managedprovisioning.task.InstallPackageTask; 41import com.android.managedprovisioning.task.SetDevicePolicyTask; 42import com.android.managedprovisioning.task.WipeResetProtectionTask; 43 44import java.lang.Runnable; 45import java.util.Locale; 46 47/** 48 * This service does the work for the DeviceOwnerProvisioningActivity. 49 * Feedback is sent back to the activity via intents. 50 * 51 * <p> 52 * If the corresponding activity is killed and restarted, the service is 53 * called twice. The service will not start the provisioning flow a second time, but instead 54 * send a status update to the activity. 55 * </p> 56 */ 57public class DeviceOwnerProvisioningService extends Service { 58 private static final boolean DEBUG = false; // To control logging. 59 60 private static final String DEVICE_OWNER = "deviceOwner"; 61 private static final String DEVICE_INITIALIZER = "deviceInitializer"; 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 EXTRA_PROVISIONING_PARAMS = 73 "ProvisioningParams"; 74 75 // Intent actions and extras for communication from DeviceOwnerProvisioningActivity to Service. 76 protected static final String ACTION_PROVISIONING_SUCCESS = 77 "com.android.managedprovisioning.provisioning_success"; 78 protected static final String ACTION_PROVISIONING_ERROR = 79 "com.android.managedprovisioning.error"; 80 protected static final String EXTRA_USER_VISIBLE_ERROR_ID_KEY = 81 "UserVisibleErrorMessage-Id"; 82 protected static final String ACTION_PROGRESS_UPDATE = 83 "com.android.managedprovisioning.progress_update"; 84 protected static final String EXTRA_PROGRESS_MESSAGE_ID_KEY = 85 "ProgressMessageId"; 86 protected static final String ACTION_REQUEST_WIFI_PICK = 87 "com.android.managedprovisioning.request_wifi_pick"; 88 89 // Intent action used by the HomeReceiverActivity to notify this Service that a HOME intent was 90 // received, which indicates that the Setup wizard has closed after provisioning completed. 91 protected static final String ACTION_HOME_INDIRECT = 92 "com.android.managedprovisioning.home_indirect"; 93 94 // Indicates whether provisioning has started. 95 private boolean mProvisioningInFlight = false; 96 97 // MessageId of the last progress message. 98 private int mLastProgressMessage = -1; 99 100 // MessageId of the last error message. 101 private int mLastErrorMessage = -1; 102 103 // Indicates whether provisioning has finished successfully (service waiting to stop). 104 private volatile boolean mDone = false; 105 106 // Provisioning tasks. 107 private BluetoothConnectTask mBluetoothConnectTask; 108 private AddWifiNetworkTask mAddWifiNetworkTask; 109 private WipeResetProtectionTask mWipeResetProtectionTask; 110 private DownloadPackageTask mDownloadPackageTask; 111 private InstallPackageTask mInstallPackageTask; 112 private SetDevicePolicyTask mSetDevicePolicyTask; 113 private DeleteNonRequiredAppsTask mDeleteNonRequiredAppsTask; 114 115 private ProvisioningParams mParams; 116 117 @Override 118 public int onStartCommand(final Intent intent, int flags, int startId) { 119 if (DEBUG) ProvisionLogger.logd("Device owner provisioning service ONSTARTCOMMAND."); 120 121 synchronized (this) { // Make operations on mProvisioningInFlight atomic. 122 if (mProvisioningInFlight) { 123 if (DEBUG) ProvisionLogger.logd("Provisioning already in flight."); 124 125 sendProgressUpdateToActivity(); 126 127 // Send error message if currently in error state. 128 if (mLastErrorMessage >= 0) { 129 sendError(); 130 } 131 132 // Send success if provisioning was successful. 133 if (mDone) { 134 onProvisioningSuccess(); 135 } 136 } else { 137 mProvisioningInFlight = true; 138 if (DEBUG) ProvisionLogger.logd("First start of the service."); 139 progressUpdate(R.string.progress_data_process); 140 141 // Load the ProvisioningParams (from message in Intent). 142 mParams = (ProvisioningParams) intent.getParcelableExtra(EXTRA_PROVISIONING_PARAMS); 143 144 // Do the work on a separate thread. 145 new Thread(new Runnable() { 146 public void run() { 147 initializeProvisioningEnvironment(mParams); 148 startDeviceOwnerProvisioning(mParams); 149 } 150 }).start(); 151 } 152 } 153 return START_NOT_STICKY; 154 } 155 156 /** 157 * This is the core method of this class. It goes through every provisioning step. 158 * Each task checks if it is required and executes if it is. 159 */ 160 private void startDeviceOwnerProvisioning(final ProvisioningParams params) { 161 if (DEBUG) ProvisionLogger.logd("Starting device owner provisioning"); 162 163 // Construct Tasks. Do not start them yet. 164 mBluetoothConnectTask = new BluetoothConnectTask(this, params.bluetoothInfo, 165 !TextUtils.isEmpty(params.wifiInfo.ssid), 166 new BluetoothConnectTask.Callback() { 167 @Override 168 public void onSuccess() { 169 progressUpdate(R.string.progress_connect_to_wifi); 170 mAddWifiNetworkTask.run(); 171 } 172 @Override 173 public void onError() { 174 error(R.string.device_owner_error_bluetooth); 175 } 176 }); 177 178 mAddWifiNetworkTask = new AddWifiNetworkTask(this, params.wifiInfo, 179 new AddWifiNetworkTask.Callback() { 180 @Override 181 public void onSuccess() { 182 progressUpdate(R.string.progress_wipe_frp); 183 mWipeResetProtectionTask.run(); 184 } 185 186 @Override 187 public void onError(){ 188 error(R.string.device_owner_error_wifi); 189 statusUpdate(DeviceInitializerStatus.STATUS_ERROR_CONNECT_WIFI); 190 } 191 }); 192 193 mWipeResetProtectionTask = new WipeResetProtectionTask(this, params.frpChallengeBundle, 194 new WipeResetProtectionTask.Callback() { 195 @Override 196 public void onSuccess() { 197 progressUpdate(R.string.progress_download); 198 mDownloadPackageTask.run(); 199 } 200 @Override 201 public void onError() { 202 error(R.string.device_owner_error_frp); 203 statusUpdate(DeviceInitializerStatus. 204 STATUS_ERROR_RESET_PROTECTION_BLOCKING_PROVISIONING); 205 } 206 }); 207 208 mDownloadPackageTask = new DownloadPackageTask(this, 209 new DownloadPackageTask.Callback() { 210 @Override 211 public void onSuccess() { 212 progressUpdate(R.string.progress_install); 213 mInstallPackageTask.addInstallIfNecessary( 214 params.inferDeviceAdminPackageName(), 215 mDownloadPackageTask.getDownloadedPackageLocation( 216 DEVICE_OWNER)); 217 mInstallPackageTask.addInstallIfNecessary( 218 params.getDeviceInitializerPackageName(), 219 mDownloadPackageTask.getDownloadedPackageLocation( 220 DEVICE_INITIALIZER)); 221 mInstallPackageTask.run(); 222 } 223 224 @Override 225 public void onError(int errorCode) { 226 switch(errorCode) { 227 case DownloadPackageTask.ERROR_HASH_MISMATCH: 228 error(R.string.device_owner_error_hash_mismatch); 229 break; 230 case DownloadPackageTask.ERROR_DOWNLOAD_FAILED: 231 error(R.string.device_owner_error_download_failed); 232 break; 233 default: 234 error(R.string.device_owner_error_general); 235 break; 236 } 237 statusUpdate(DeviceInitializerStatus.STATUS_ERROR_DOWNLOAD_PACKAGE); 238 } 239 }); 240 241 // Add packages to download to the DownloadPackageTask. 242 mDownloadPackageTask.addDownloadIfNecessary(params.inferDeviceAdminPackageName(), 243 params.deviceAdminDownloadInfo, DEVICE_OWNER); 244 mDownloadPackageTask.addDownloadIfNecessary(params.getDeviceInitializerPackageName(), 245 params.deviceInitializerDownloadInfo, DEVICE_INITIALIZER); 246 247 mInstallPackageTask = new InstallPackageTask(this, 248 new InstallPackageTask.Callback() { 249 @Override 250 public void onSuccess() { 251 progressUpdate(R.string.progress_set_owner); 252 try { 253 // Now that the app has been installed, we can look for the device admin 254 // component in it. 255 mSetDevicePolicyTask.run(mParams.inferDeviceAdminComponentName( 256 DeviceOwnerProvisioningService.this)); 257 } catch (Utils.IllegalProvisioningArgumentException e) { 258 error(R.string.device_owner_error_general); 259 ProvisionLogger.loge("Failed to infer the device admin component name", 260 e); 261 return; 262 } 263 } 264 265 @Override 266 public void onError(int errorCode) { 267 switch(errorCode) { 268 case InstallPackageTask.ERROR_PACKAGE_INVALID: 269 error(R.string.device_owner_error_package_invalid); 270 break; 271 case InstallPackageTask.ERROR_INSTALLATION_FAILED: 272 error(R.string.device_owner_error_installation_failed); 273 break; 274 case InstallPackageTask.ERROR_PACKAGE_NAME_INVALID: 275 error(R.string.device_owner_error_package_name_invalid); 276 break; 277 default: 278 error(R.string.device_owner_error_general); 279 break; 280 } 281 statusUpdate(DeviceInitializerStatus.STATUS_ERROR_INSTALL_PACKAGE); 282 } 283 }); 284 285 mSetDevicePolicyTask = new SetDevicePolicyTask(this, 286 getResources().getString(R.string.default_owned_device_username), 287 params.deviceInitializerComponentName, 288 new SetDevicePolicyTask.Callback() { 289 @Override 290 public void onSuccess() { 291 mDeleteNonRequiredAppsTask.run(); 292 } 293 294 @Override 295 public void onError(int errorCode) { 296 switch(errorCode) { 297 case SetDevicePolicyTask.ERROR_PACKAGE_NOT_INSTALLED: 298 error(R.string.device_owner_error_package_not_installed); 299 break; 300 case SetDevicePolicyTask.ERROR_NO_RECEIVER: 301 error(R.string.device_owner_error_package_invalid); 302 break; 303 default: 304 error(R.string.device_owner_error_general); 305 break; 306 } 307 statusUpdate(DeviceInitializerStatus.STATUS_ERROR_SET_DEVICE_POLICY); 308 } 309 }); 310 311 mDeleteNonRequiredAppsTask = new DeleteNonRequiredAppsTask( 312 this, params.inferDeviceAdminPackageName(), R.array.required_apps_managed_device, 313 R.array.vendor_required_apps_managed_device, true /* creating new profile */, 314 UserHandle.USER_OWNER, params.leaveAllSystemAppsEnabled, 315 new DeleteNonRequiredAppsTask.Callback() { 316 @Override 317 public void onSuccess() { 318 // Done with provisioning. Success. 319 onProvisioningSuccess(); 320 } 321 322 @Override 323 public void onError() { 324 error(R.string.device_owner_error_general); 325 statusUpdate(DeviceInitializerStatus.STATUS_ERROR_DELETE_APPS); 326 } 327 }); 328 329 // Start first task, which starts next task in its callback, etc. 330 progressUpdate(R.string.progress_start_bluetooth); 331 mBluetoothConnectTask.run(); 332 } 333 334 private void error(int dialogMessage) { 335 mLastErrorMessage = dialogMessage; 336 sendError(); 337 // Wait for stopService() call from the activity. 338 } 339 340 private void statusUpdate(int statusCode) { 341 BluetoothConnectionService.sendStatusUpdate(this, statusCode); 342 } 343 344 private void sendError() { 345 if (DEBUG) { 346 ProvisionLogger.logd("Reporting Error: " + getResources() 347 .getString(mLastErrorMessage)); 348 } 349 Intent intent = new Intent(ACTION_PROVISIONING_ERROR); 350 intent.setClass(this, DeviceOwnerProvisioningActivity.ServiceMessageReceiver.class); 351 intent.putExtra(EXTRA_USER_VISIBLE_ERROR_ID_KEY, mLastErrorMessage); 352 LocalBroadcastManager.getInstance(this).sendBroadcast(intent); 353 } 354 355 private void progressUpdate(int progressMessage) { 356 if (DEBUG) { 357 ProvisionLogger.logd("Reporting progress update: " + getResources() 358 .getString(progressMessage)); 359 } 360 mLastProgressMessage = progressMessage; 361 sendProgressUpdateToActivity(); 362 } 363 364 private void sendProgressUpdateToActivity() { 365 Intent intent = new Intent(ACTION_PROGRESS_UPDATE); 366 intent.putExtra(EXTRA_PROGRESS_MESSAGE_ID_KEY, mLastProgressMessage); 367 intent.setClass(this, DeviceOwnerProvisioningActivity.ServiceMessageReceiver.class); 368 LocalBroadcastManager.getInstance(this).sendBroadcast(intent); 369 } 370 371 private void onProvisioningSuccess() { 372 if (DEBUG) ProvisionLogger.logd("Reporting success."); 373 mDone = true; 374 375 // Persist mParams so HomeReceiverActivity can later retrieve them to finalize provisioning. 376 // This is necessary to deal with accidental reboots during DIA setup, which happens between 377 // the end of this method and HomeReceiverActivity captures the home intent. 378 IntentStore store = BootReminder.getDeviceOwnerFinalizingIntentStore(this); 379 Bundle resumeBundle = new Bundle(); 380 (new MessageParser()).addProvisioningParamsToBundle(resumeBundle, mParams); 381 store.save(resumeBundle); 382 383 // Enable the HomeReceiverActivity, since the DeviceOwnerProvisioningActivity will shutdown 384 // the Setup wizard soon, which will result in a home intent that should be caught by the 385 // HomeReceiverActivity. 386 PackageManager pm = getPackageManager(); 387 pm.setComponentEnabledSetting(new ComponentName(DeviceOwnerProvisioningService.this, 388 HomeReceiverActivity.class), PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 389 PackageManager.DONT_KILL_APP); 390 391 Intent successIntent = new Intent(ACTION_PROVISIONING_SUCCESS); 392 successIntent.setClass(this, DeviceOwnerProvisioningActivity.ServiceMessageReceiver.class); 393 LocalBroadcastManager.getInstance(this).sendBroadcast(successIntent); 394 // Wait for stopService() call from the activity. 395 } 396 397 private void initializeProvisioningEnvironment(ProvisioningParams params) { 398 setTimeAndTimezone(params.timeZone, params.localTime); 399 setLocale(params.locale); 400 401 // Start CDMA activation to enable phone calls. 402 final Intent intent = new Intent(ACTION_PERFORM_CDMA_PROVISIONING); 403 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 404 if (DEBUG) ProvisionLogger.logd("Starting cdma activation activity"); 405 startActivity(intent); // Activity will be a Nop if not a CDMA device. 406 } 407 408 private void setTimeAndTimezone(String timeZone, long localTime) { 409 try { 410 final AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE); 411 if (timeZone != null) { 412 if (DEBUG) ProvisionLogger.logd("Setting time zone to " + timeZone); 413 am.setTimeZone(timeZone); 414 } 415 if (localTime > 0) { 416 if (DEBUG) ProvisionLogger.logd("Setting time to " + localTime); 417 am.setTime(localTime); 418 } 419 } catch (Exception e) { 420 ProvisionLogger.loge("Alarm manager failed to set the system time/timezone."); 421 // Do not stop provisioning process, but ignore this error. 422 } 423 } 424 425 private void setLocale(Locale locale) { 426 if (locale == null || locale.equals(Locale.getDefault())) { 427 return; 428 } 429 try { 430 if (DEBUG) ProvisionLogger.logd("Setting locale to " + locale); 431 // If locale is different from current locale this results in a configuration change, 432 // which will trigger the restarting of the activity. 433 LocalePicker.updateLocale(locale); 434 } catch (Exception e) { 435 ProvisionLogger.loge("Failed to set the system locale."); 436 // Do not stop provisioning process, but ignore this error. 437 } 438 } 439 440 @Override 441 public void onCreate () { 442 if (DEBUG) ProvisionLogger.logd("Device owner provisioning service ONCREATE."); 443 } 444 445 @Override 446 public void onDestroy () { 447 if (DEBUG) ProvisionLogger.logd("Device owner provisioning service ONDESTROY"); 448 if (mAddWifiNetworkTask != null) { 449 mAddWifiNetworkTask.cleanUp(); 450 } 451 if (mDownloadPackageTask != null) { 452 mDownloadPackageTask.cleanUp(); 453 } 454 if (mBluetoothConnectTask != null) { 455 mBluetoothConnectTask.cleanUp(); 456 } 457 } 458 459 @Override 460 public IBinder onBind(Intent intent) { 461 return null; 462 } 463} 464 465