DeviceOwnerProvisioningService.java revision fd134872830d02440e91ea99605fe10928dedc03
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 static android.app.admin.DeviceAdminReceiver.ACTION_PROFILE_PROVISIONING_COMPLETE; 20import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE; 21 22import android.app.AlarmManager; 23import android.app.Service; 24import android.content.BroadcastReceiver; 25import android.content.ComponentName; 26import android.content.Context; 27import android.content.Intent; 28import android.content.IntentFilter; 29import android.content.pm.PackageManager; 30import android.os.Bundle; 31import android.os.IBinder; 32import android.os.UserHandle; 33import android.support.v4.content.LocalBroadcastManager; 34import android.text.TextUtils; 35 36import com.android.internal.app.LocalePicker; 37import com.android.managedprovisioning.task.AddWifiNetworkTask; 38import com.android.managedprovisioning.task.DeleteNonRequiredAppsTask; 39import com.android.managedprovisioning.task.DownloadPackageTask; 40import com.android.managedprovisioning.task.InstallPackageTask; 41import com.android.managedprovisioning.task.SetDevicePolicyTask; 42 43import java.lang.Runnable; 44import java.util.Locale; 45 46/** 47 * This service does the work for the DeviceOwnerProvisioningActivity. 48 * Feedback is sent back to the activity via intents. 49 * 50 * <p> 51 * If the corresponding activity is killed and restarted, the service is 52 * called twice. The service will not start the provisioning flow a second time, but instead 53 * send a status update to the activity. 54 * </p> 55 */ 56public class DeviceOwnerProvisioningService extends Service { 57 private static final boolean DEBUG = false; // To control logging. 58 59 /** 60 * Intent action to activate the CDMA phone connection by OTASP. 61 * This is not necessary for a GSM phone connection, which is activated automatically. 62 * String must agree with the constants in com.android.phone.InCallScreenShowActivation. 63 */ 64 private static final String ACTION_PERFORM_CDMA_PROVISIONING = 65 "com.android.phone.PERFORM_CDMA_PROVISIONING"; 66 67 // Intent actions and extras for communication from DeviceOwnerProvisioningService to Activity. 68 protected static final String EXTRA_PROVISIONING_PARAMS = 69 "ProvisioningParams"; 70 71 // Intent actions and extras for communication from DeviceOwnerProvisioningActivity to Service. 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 ACTION_PROGRESS_UPDATE = 79 "com.android.managedprovisioning.progress_update"; 80 protected static final String EXTRA_PROGRESS_MESSAGE_ID_KEY = 81 "ProgressMessageId"; 82 protected static final String ACTION_REQUEST_WIFI_PICK = 83 "com.android.managedprovisioning.request_wifi_pick"; 84 85 // Intent action used by the HomeReceiverActivity to notify this Service that a HOME intent was 86 // received, which indicates that the Setup wizard has closed after provisioning completed. 87 protected static final String ACTION_HOME_INDIRECT = 88 "com.android.managedprovisioning.home_indirect"; 89 90 // Indicates whether provisioning has started. 91 private boolean mProvisioningInFlight = false; 92 93 // MessageId of the last progress message. 94 private int mLastProgressMessage = -1; 95 96 // MessageId of the last error message. 97 private int mLastErrorMessage = -1; 98 99 // Indicates whether provisioning has finished succesfully (service waiting to stop). 100 private boolean mDone = false; 101 102 // Provisioning tasks. 103 private AddWifiNetworkTask mAddWifiNetworkTask; 104 private DownloadPackageTask mDownloadPackageTask; 105 private InstallPackageTask mInstallPackageTask; 106 private SetDevicePolicyTask mSetDevicePolicyTask; 107 private DeleteNonRequiredAppsTask mDeleteNonRequiredAppsTask; 108 109 private ProvisioningParams mParams; 110 111 private BroadcastReceiver mIndirectHomeReceiver; 112 113 @Override 114 public int onStartCommand(final Intent intent, int flags, int startId) { 115 if (DEBUG) ProvisionLogger.logd("Device owner provisioning service ONSTARTCOMMAND."); 116 117 synchronized (this) { // Make operations on mProvisioningInFlight atomic. 118 if (mProvisioningInFlight) { 119 if (DEBUG) ProvisionLogger.logd("Provisioning already in flight."); 120 121 sendProgressUpdateToActivity(); 122 123 // Send error message if currently in error state. 124 if (mLastErrorMessage >= 0) { 125 sendError(); 126 } 127 128 // Send success if provisioning was succesful. 129 if (mDone) { 130 onProvisioningSuccess(mParams.mDeviceAdminPackageName); 131 } 132 } else { 133 mProvisioningInFlight = true; 134 if (DEBUG) ProvisionLogger.logd("First start of the service."); 135 progressUpdate(R.string.progress_data_process); 136 137 // Load the ProvisioningParams (from message in Intent). 138 mParams = (ProvisioningParams) intent.getParcelableExtra(EXTRA_PROVISIONING_PARAMS); 139 140 registerHomeIntentReceiver(); 141 142 // Do the work on a separate thread. 143 new Thread(new Runnable() { 144 public void run() { 145 initializeProvisioningEnvironment(mParams); 146 startDeviceOwnerProvisioning(mParams); 147 } 148 }).start(); 149 } 150 } 151 return START_NOT_STICKY; 152 } 153 154 // Register the receiver for the ACTION_HOME_INDIRECT intent. 155 // The ACTION_HOME_INDIRECT intent is used to notify this service that the home intent was send. 156 // After receiving that intent we send the complete intent to the mdm. 157 // Note: if we would send the complete intent earlier, the home intent can close the mdm. 158 private void registerHomeIntentReceiver() { 159 mIndirectHomeReceiver = new IndirectHomeReceiver(); 160 IntentFilter filter = new IntentFilter(); 161 filter.addAction(DeviceOwnerProvisioningService.ACTION_HOME_INDIRECT); 162 LocalBroadcastManager.getInstance(this).registerReceiver(mIndirectHomeReceiver, filter); 163 } 164 165 class IndirectHomeReceiver extends BroadcastReceiver { 166 @Override 167 public void onReceive(Context context, Intent intent) { 168 if (!mDone) { 169 return; 170 } 171 172 // Disable the HomeReceiverActivity. It's no longer of use. 173 PackageManager pm = getPackageManager(); 174 pm.setComponentEnabledSetting(new ComponentName(DeviceOwnerProvisioningService.this, 175 HomeReceiverActivity.class), PackageManager 176 .COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP); 177 178 // Send complete intent to mdm. 179 Intent result = new Intent(ACTION_PROFILE_PROVISIONING_COMPLETE); 180 result.setPackage(mParams.mDeviceAdminPackageName); 181 result.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES | 182 Intent.FLAG_RECEIVER_FOREGROUND); 183 if (mParams.mAdminExtrasBundle != null) { 184 result.putExtra(EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE, 185 mParams.mAdminExtrasBundle); 186 } 187 sendBroadcast(result); 188 stopSelf(); 189 } 190 } 191 192 193 /** 194 * This is the core method of this class. It goes through every provisioning step. 195 */ 196 private void startDeviceOwnerProvisioning(final ProvisioningParams params) { 197 if (DEBUG) ProvisionLogger.logd("Starting device owner provisioning"); 198 199 // Construct Tasks. Do not start them yet. 200 mAddWifiNetworkTask = new AddWifiNetworkTask(this, params.mWifiSsid, 201 params.mWifiHidden, params.mWifiSecurityType, params.mWifiPassword, 202 params.mWifiProxyHost, params.mWifiProxyPort, params.mWifiProxyBypassHosts, 203 params.mWifiPacUrl, new AddWifiNetworkTask.Callback() { 204 @Override 205 public void onSuccess() { 206 if (!TextUtils.isEmpty(params.mDeviceAdminPackageDownloadLocation)) { 207 // Download, install, set as device owner, delete apps. 208 progressUpdate(R.string.progress_download); 209 mDownloadPackageTask.run(); 210 } else { 211 // Device Admin will not be downloaded (but is already present): 212 // Just set as device owner, delete apps. 213 progressUpdate(R.string.progress_set_owner); 214 mSetDevicePolicyTask.run(); 215 } 216 } 217 218 @Override 219 public void onError(){ 220 error(R.string.device_owner_error_wifi); 221 } 222 }); 223 224 mDownloadPackageTask = new DownloadPackageTask(this, 225 params.mDeviceAdminPackageDownloadLocation, params.mDeviceAdminPackageChecksum, 226 params.mDeviceAdminPackageDownloadCookieHeader, new DownloadPackageTask.Callback() { 227 @Override 228 public void onSuccess() { 229 String downloadLocation = 230 mDownloadPackageTask.getDownloadedPackageLocation(); 231 progressUpdate(R.string.progress_install); 232 mInstallPackageTask.run(downloadLocation); 233 } 234 235 @Override 236 public void onError(int errorCode) { 237 switch(errorCode) { 238 case DownloadPackageTask.ERROR_HASH_MISMATCH: 239 error(R.string.device_owner_error_hash_mismatch); 240 break; 241 case DownloadPackageTask.ERROR_DOWNLOAD_FAILED: 242 error(R.string.device_owner_error_download_failed); 243 break; 244 default: 245 error(R.string.device_owner_error_general); 246 break; 247 } 248 } 249 }); 250 251 mInstallPackageTask = new InstallPackageTask(this, 252 params.mDeviceAdminPackageName, 253 new InstallPackageTask.Callback() { 254 @Override 255 public void onSuccess() { 256 progressUpdate(R.string.progress_set_owner); 257 mSetDevicePolicyTask.run(); 258 } 259 260 @Override 261 public void onError(int errorCode) { 262 switch(errorCode) { 263 case InstallPackageTask.ERROR_PACKAGE_INVALID: 264 error(R.string.device_owner_error_package_invalid); 265 break; 266 case InstallPackageTask.ERROR_INSTALLATION_FAILED: 267 error(R.string.device_owner_error_installation_failed); 268 break; 269 default: 270 error(R.string.device_owner_error_general); 271 break; 272 } 273 } 274 }); 275 276 mSetDevicePolicyTask = new SetDevicePolicyTask(this, 277 params.mDeviceAdminPackageName, 278 getResources().getString(R.string.default_owned_device_username), 279 new SetDevicePolicyTask.Callback() { 280 @Override 281 public void onSuccess() { 282 if (params.mLeaveAllSystemAppsEnabled) { 283 onProvisioningSuccess(params.mDeviceAdminPackageName); 284 } else { 285 mDeleteNonRequiredAppsTask.run(); 286 } 287 } 288 289 @Override 290 public void onError(int errorCode) { 291 switch(errorCode) { 292 case SetDevicePolicyTask.ERROR_PACKAGE_NOT_INSTALLED: 293 error(R.string.device_owner_error_package_not_installed); 294 break; 295 case SetDevicePolicyTask.ERROR_NO_RECEIVER: 296 error(R.string.device_owner_error_package_invalid); 297 break; 298 default: 299 error(R.string.device_owner_error_general); 300 break; 301 } 302 } 303 }); 304 305 mDeleteNonRequiredAppsTask = new DeleteNonRequiredAppsTask( 306 this, params.mDeviceAdminPackageName, UserHandle.USER_OWNER, 307 R.array.required_apps_managed_device, R.array.vendor_required_apps_managed_device, 308 true /* We are creating a new profile */, 309 false /* Do not disable INSTALL_SHORTCUT listeners */, 310 new DeleteNonRequiredAppsTask.Callback() { 311 public void onSuccess() { 312 // Done with provisioning. Success. 313 onProvisioningSuccess(params.mDeviceAdminPackageName); 314 } 315 316 @Override 317 public void onError() { 318 error(R.string.device_owner_error_general); 319 }; 320 }); 321 322 // Start first task, which starts next task in its callback, etc. 323 startFirstTask(params); 324 } 325 326 private void startFirstTask(final ProvisioningParams params) { 327 if (!TextUtils.isEmpty(params.mWifiSsid)) { 328 329 // Connect to wifi. 330 progressUpdate(R.string.progress_connect_to_wifi); 331 mAddWifiNetworkTask.run(); 332 } else if (!TextUtils.isEmpty(params.mDeviceAdminPackageDownloadLocation)) { 333 334 // Download, install, set as device owner, delete apps. 335 progressUpdate(R.string.progress_download); 336 mDownloadPackageTask.run(); 337 } else { 338 339 // Device Admin will not be downloaded (but is already present): 340 // Just set as device owner, delete apps. 341 progressUpdate(R.string.progress_set_owner); 342 mSetDevicePolicyTask.run(); 343 } 344 } 345 346 private void error(int dialogMessage) { 347 mLastErrorMessage = dialogMessage; 348 sendError(); 349 // Wait for stopService() call from the activity. 350 } 351 352 private void sendError() { 353 if (DEBUG) { 354 ProvisionLogger.logd("Reporting Error: " + getResources() 355 .getString(mLastErrorMessage)); 356 } 357 Intent intent = new Intent(ACTION_PROVISIONING_ERROR); 358 intent.setClass(this, DeviceOwnerProvisioningActivity.ServiceMessageReceiver.class); 359 intent.putExtra(EXTRA_USER_VISIBLE_ERROR_ID_KEY, mLastErrorMessage); 360 LocalBroadcastManager.getInstance(this).sendBroadcast(intent); 361 } 362 363 private void progressUpdate(int progressMessage) { 364 if (DEBUG) { 365 ProvisionLogger.logd("Reporting progress update: " + getResources() 366 .getString(progressMessage)); 367 } 368 mLastProgressMessage = progressMessage; 369 sendProgressUpdateToActivity(); 370 } 371 372 private void sendProgressUpdateToActivity() { 373 Intent intent = new Intent(ACTION_PROGRESS_UPDATE); 374 intent.putExtra(EXTRA_PROGRESS_MESSAGE_ID_KEY, mLastProgressMessage); 375 intent.setClass(this, DeviceOwnerProvisioningActivity.ServiceMessageReceiver.class); 376 LocalBroadcastManager.getInstance(this).sendBroadcast(intent); 377 } 378 379 private void onProvisioningSuccess(String deviceAdminPackage) { 380 if (DEBUG) ProvisionLogger.logd("Reporting success."); 381 mDone = true; 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.mTimeZone, params.mLocalTime); 399 setLocale(params.mLocale); 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 (mIndirectHomeReceiver != null) { 455 LocalBroadcastManager.getInstance(this).unregisterReceiver(mIndirectHomeReceiver); 456 mIndirectHomeReceiver = null; 457 } 458 459 } 460 461 @Override 462 public IBinder onBind(Intent intent) { 463 return null; 464 } 465} 466 467