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_ADMIN_EXTRAS_BUNDLE; 21 22 import android.app.AlarmManager; 23 import android.app.Service; 24 import android.content.BroadcastReceiver; 25 import android.content.ComponentName; 26 import android.content.Context; 27 import android.content.Intent; 28 import android.content.IntentFilter; 29 import android.content.pm.PackageManager; 30 import android.os.Bundle; 31 import android.os.IBinder; 32 import android.os.UserHandle; 33 import android.support.v4.content.LocalBroadcastManager; 34 import android.text.TextUtils; 35 36 import com.android.internal.app.LocalePicker; 37 import com.android.managedprovisioning.task.AddWifiNetworkTask; 38 import com.android.managedprovisioning.task.DeleteNonRequiredAppsTask; 39 import com.android.managedprovisioning.task.DownloadPackageTask; 40 import com.android.managedprovisioning.task.InstallPackageTask; 41 import com.android.managedprovisioning.task.SetDevicePolicyTask; 42 43 import java.lang.Runnable; 44 import 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 */ 56 public 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 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 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. registerHomeIntentReceiver()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 onReceive(Context context, Intent intent)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 */ startDeviceOwnerProvisioning(final ProvisioningParams params)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 if (TextUtils.isEmpty(params.mWifiSsid)) { 201 mAddWifiNetworkTask = null; 202 } else { 203 mAddWifiNetworkTask = new AddWifiNetworkTask(this, params.mWifiSsid, 204 params.mWifiHidden, params.mWifiSecurityType, params.mWifiPassword, 205 params.mWifiProxyHost, params.mWifiProxyPort, params.mWifiProxyBypassHosts, 206 params.mWifiPacUrl, new AddWifiNetworkTask.Callback() { 207 @Override 208 public void onSuccess() { 209 if (!TextUtils.isEmpty(params.mDeviceAdminPackageDownloadLocation)) { 210 // Download, install, set as device owner, delete apps. 211 progressUpdate(R.string.progress_download); 212 mDownloadPackageTask.run(); 213 } else { 214 // Device Admin will not be downloaded (but is already present): 215 // Just set as device owner, delete apps. 216 progressUpdate(R.string.progress_set_owner); 217 mSetDevicePolicyTask.run(); 218 } 219 } 220 221 @Override 222 public void onError(){ 223 error(R.string.device_owner_error_wifi); 224 } 225 }); 226 } 227 228 mDownloadPackageTask = new DownloadPackageTask(this, 229 params.mDeviceAdminPackageDownloadLocation, params.mDeviceAdminPackageChecksum, 230 params.mDeviceAdminPackageDownloadCookieHeader, new DownloadPackageTask.Callback() { 231 @Override 232 public void onSuccess() { 233 String downloadLocation = 234 mDownloadPackageTask.getDownloadedPackageLocation(); 235 progressUpdate(R.string.progress_install); 236 mInstallPackageTask.run(downloadLocation); 237 } 238 239 @Override 240 public void onError(int errorCode) { 241 switch(errorCode) { 242 case DownloadPackageTask.ERROR_HASH_MISMATCH: 243 error(R.string.device_owner_error_hash_mismatch); 244 break; 245 case DownloadPackageTask.ERROR_DOWNLOAD_FAILED: 246 error(R.string.device_owner_error_download_failed); 247 break; 248 default: 249 error(R.string.device_owner_error_general); 250 break; 251 } 252 } 253 }); 254 255 mInstallPackageTask = new InstallPackageTask(this, 256 params.mDeviceAdminPackageName, 257 new InstallPackageTask.Callback() { 258 @Override 259 public void onSuccess() { 260 progressUpdate(R.string.progress_set_owner); 261 mSetDevicePolicyTask.run(); 262 } 263 264 @Override 265 public void onError(int errorCode) { 266 switch(errorCode) { 267 case InstallPackageTask.ERROR_PACKAGE_INVALID: 268 error(R.string.device_owner_error_package_invalid); 269 break; 270 case InstallPackageTask.ERROR_INSTALLATION_FAILED: 271 error(R.string.device_owner_error_installation_failed); 272 break; 273 default: 274 error(R.string.device_owner_error_general); 275 break; 276 } 277 } 278 }); 279 280 mSetDevicePolicyTask = new SetDevicePolicyTask(this, 281 params.mDeviceAdminPackageName, 282 getResources().getString(R.string.default_owned_device_username), 283 new SetDevicePolicyTask.Callback() { 284 @Override 285 public void onSuccess() { 286 if (params.mLeaveAllSystemAppsEnabled) { 287 onProvisioningSuccess(params.mDeviceAdminPackageName); 288 } else { 289 mDeleteNonRequiredAppsTask.run(); 290 } 291 } 292 293 @Override 294 public void onError(int errorCode) { 295 switch(errorCode) { 296 case SetDevicePolicyTask.ERROR_PACKAGE_NOT_INSTALLED: 297 error(R.string.device_owner_error_package_not_installed); 298 break; 299 case SetDevicePolicyTask.ERROR_NO_RECEIVER: 300 error(R.string.device_owner_error_package_invalid); 301 break; 302 default: 303 error(R.string.device_owner_error_general); 304 break; 305 } 306 } 307 }); 308 309 mDeleteNonRequiredAppsTask = new DeleteNonRequiredAppsTask( 310 this, params.mDeviceAdminPackageName, UserHandle.USER_OWNER, 311 R.array.required_apps_managed_device, R.array.vendor_required_apps_managed_device, 312 true /* We are creating a new profile */, 313 false /* Do not disable INSTALL_SHORTCUT listeners */, 314 new DeleteNonRequiredAppsTask.Callback() { 315 public void onSuccess() { 316 // Done with provisioning. Success. 317 onProvisioningSuccess(params.mDeviceAdminPackageName); 318 } 319 320 @Override 321 public void onError() { 322 error(R.string.device_owner_error_general); 323 }; 324 }); 325 326 // Start first task, which starts next task in its callback, etc. 327 startFirstTask(params); 328 } 329 startFirstTask(final ProvisioningParams params)330 private void startFirstTask(final ProvisioningParams params) { 331 if (mAddWifiNetworkTask != null) { 332 333 // Connect to wifi. 334 progressUpdate(R.string.progress_connect_to_wifi); 335 mAddWifiNetworkTask.run(); 336 } else if (!TextUtils.isEmpty(params.mDeviceAdminPackageDownloadLocation)) { 337 338 // Download, install, set as device owner, delete apps. 339 progressUpdate(R.string.progress_download); 340 mDownloadPackageTask.run(); 341 } else { 342 343 // Device Admin will not be downloaded (but is already present): 344 // Just set as device owner, delete apps. 345 progressUpdate(R.string.progress_set_owner); 346 mSetDevicePolicyTask.run(); 347 } 348 } 349 error(int dialogMessage)350 private void error(int dialogMessage) { 351 mLastErrorMessage = dialogMessage; 352 sendError(); 353 // Wait for stopService() call from the activity. 354 } 355 sendError()356 private void sendError() { 357 if (DEBUG) { 358 ProvisionLogger.logd("Reporting Error: " + getResources() 359 .getString(mLastErrorMessage)); 360 } 361 Intent intent = new Intent(ACTION_PROVISIONING_ERROR); 362 intent.setClass(this, DeviceOwnerProvisioningActivity.ServiceMessageReceiver.class); 363 intent.putExtra(EXTRA_USER_VISIBLE_ERROR_ID_KEY, mLastErrorMessage); 364 LocalBroadcastManager.getInstance(this).sendBroadcast(intent); 365 } 366 progressUpdate(int progressMessage)367 private void progressUpdate(int progressMessage) { 368 if (DEBUG) { 369 ProvisionLogger.logd("Reporting progress update: " + getResources() 370 .getString(progressMessage)); 371 } 372 mLastProgressMessage = progressMessage; 373 sendProgressUpdateToActivity(); 374 } 375 sendProgressUpdateToActivity()376 private void sendProgressUpdateToActivity() { 377 Intent intent = new Intent(ACTION_PROGRESS_UPDATE); 378 intent.putExtra(EXTRA_PROGRESS_MESSAGE_ID_KEY, mLastProgressMessage); 379 intent.setClass(this, DeviceOwnerProvisioningActivity.ServiceMessageReceiver.class); 380 LocalBroadcastManager.getInstance(this).sendBroadcast(intent); 381 } 382 onProvisioningSuccess(String deviceAdminPackage)383 private void onProvisioningSuccess(String deviceAdminPackage) { 384 if (DEBUG) ProvisionLogger.logd("Reporting success."); 385 mDone = true; 386 387 // Enable the HomeReceiverActivity, since the DeviceOwnerProvisioningActivity will shutdown 388 // the Setup wizard soon, which will result in a home intent that should be caught by the 389 // HomeReceiverActivity. 390 PackageManager pm = getPackageManager(); 391 pm.setComponentEnabledSetting(new ComponentName(DeviceOwnerProvisioningService.this, 392 HomeReceiverActivity.class), PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 393 PackageManager.DONT_KILL_APP); 394 395 Intent successIntent = new Intent(ACTION_PROVISIONING_SUCCESS); 396 successIntent.setClass(this, DeviceOwnerProvisioningActivity.ServiceMessageReceiver.class); 397 LocalBroadcastManager.getInstance(this).sendBroadcast(successIntent); 398 // Wait for stopService() call from the activity. 399 } 400 initializeProvisioningEnvironment(ProvisioningParams params)401 private void initializeProvisioningEnvironment(ProvisioningParams params) { 402 setTimeAndTimezone(params.mTimeZone, params.mLocalTime); 403 setLocale(params.mLocale); 404 405 // Start CDMA activation to enable phone calls. 406 final Intent intent = new Intent(ACTION_PERFORM_CDMA_PROVISIONING); 407 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 408 if (DEBUG) ProvisionLogger.logd("Starting cdma activation activity"); 409 startActivity(intent); // Activity will be a Nop if not a CDMA device. 410 } 411 setTimeAndTimezone(String timeZone, long localTime)412 private void setTimeAndTimezone(String timeZone, long localTime) { 413 try { 414 final AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE); 415 if (timeZone != null) { 416 if (DEBUG) ProvisionLogger.logd("Setting time zone to " + timeZone); 417 am.setTimeZone(timeZone); 418 } 419 if (localTime > 0) { 420 if (DEBUG) ProvisionLogger.logd("Setting time to " + localTime); 421 am.setTime(localTime); 422 } 423 } catch (Exception e) { 424 ProvisionLogger.loge("Alarm manager failed to set the system time/timezone."); 425 // Do not stop provisioning process, but ignore this error. 426 } 427 } 428 setLocale(Locale locale)429 private void setLocale(Locale locale) { 430 if (locale == null || locale.equals(Locale.getDefault())) { 431 return; 432 } 433 try { 434 if (DEBUG) ProvisionLogger.logd("Setting locale to " + locale); 435 // If locale is different from current locale this results in a configuration change, 436 // which will trigger the restarting of the activity. 437 LocalePicker.updateLocale(locale); 438 } catch (Exception e) { 439 ProvisionLogger.loge("Failed to set the system locale."); 440 // Do not stop provisioning process, but ignore this error. 441 } 442 } 443 444 @Override onCreate()445 public void onCreate () { 446 if (DEBUG) ProvisionLogger.logd("Device owner provisioning service ONCREATE."); 447 } 448 449 @Override onDestroy()450 public void onDestroy () { 451 if (DEBUG) ProvisionLogger.logd("Device owner provisioning service ONDESTROY"); 452 if (mAddWifiNetworkTask != null) { 453 mAddWifiNetworkTask.cleanUp(); 454 } 455 if (mDownloadPackageTask != null) { 456 mDownloadPackageTask.cleanUp(); 457 } 458 if (mIndirectHomeReceiver != null) { 459 LocalBroadcastManager.getInstance(this).unregisterReceiver(mIndirectHomeReceiver); 460 mIndirectHomeReceiver = null; 461 } 462 463 } 464 465 @Override onBind(Intent intent)466 public IBinder onBind(Intent intent) { 467 return null; 468 } 469 } 470 471