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