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 /** 58 * Intent action to activate the CDMA phone connection by OTASP. 59 * This is not necessary for a GSM phone connection, which is activated automatically. 60 * String must agree with the constants in com.android.phone.InCallScreenShowActivation. 61 */ 62 private static final String ACTION_PERFORM_CDMA_PROVISIONING = 63 "com.android.phone.PERFORM_CDMA_PROVISIONING"; 64 65 // Intent actions and extras for communication from DeviceOwnerProvisioningService to Activity. 66 protected static final String EXTRA_PROVISIONING_PARAMS = 67 "ProvisioningParams"; 68 69 // Intent actions and extras for communication from DeviceOwnerProvisioningActivity to Service. 70 protected static final String ACTION_PROVISIONING_SUCCESS = 71 "com.android.managedprovisioning.provisioning_success"; 72 protected static final String ACTION_PROVISIONING_ERROR = 73 "com.android.managedprovisioning.error"; 74 protected static final String EXTRA_USER_VISIBLE_ERROR_ID_KEY = 75 "UserVisibleErrorMessage-Id"; 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 provisioning has finished succesfully (service waiting to stop). 98 private boolean mDone = false; 99 100 // Provisioning tasks. 101 private AddWifiNetworkTask mAddWifiNetworkTask; 102 private DownloadPackageTask mDownloadPackageTask; 103 private InstallPackageTask mInstallPackageTask; 104 private SetDevicePolicyTask mSetDevicePolicyTask; 105 private DeleteNonRequiredAppsTask mDeleteNonRequiredAppsTask; 106 107 private ProvisioningParams mParams; 108 109 private BroadcastReceiver mIndirectHomeReceiver; 110 111 @Override 112 public int onStartCommand(final Intent intent, int flags, int startId) { 113 ProvisionLogger.logd("Device owner provisioning service ONSTARTCOMMAND."); 114 115 synchronized (this) { // Make operations on mProvisioningInFlight atomic. 116 if (mProvisioningInFlight) { 117 ProvisionLogger.logd("Provisioning already in flight."); 118 119 sendProgressUpdateToActivity(); 120 121 // Send error message if currently in error state. 122 if (mLastErrorMessage >= 0) { 123 sendError(); 124 } 125 126 // Send success if provisioning was succesful. 127 if (mDone) { 128 onProvisioningSuccess(mParams.mDeviceAdminPackageName); 129 } 130 } else { 131 mProvisioningInFlight = true; 132 ProvisionLogger.logd("First start of the service."); 133 progressUpdate(R.string.progress_data_process); 134 135 // Load the ProvisioningParams (from message in Intent). 136 mParams = (ProvisioningParams) intent.getParcelableExtra(EXTRA_PROVISIONING_PARAMS); 137 138 registerHomeIntentReceiver(); 139 140 // Do the work on a separate thread. 141 new Thread(new Runnable() { 142 public void run() { 143 initializeProvisioningEnvironment(mParams); 144 startDeviceOwnerProvisioning(mParams); 145 } 146 }).start(); 147 } 148 } 149 return START_NOT_STICKY; 150 } 151 152 // Register the receiver for the ACTION_HOME_INDIRECT intent. 153 // The ACTION_HOME_INDIRECT intent is used to notify this service that the home intent was send. 154 // After receiving that intent we send the complete intent to the mdm. 155 // Note: if we would send the complete intent earlier, the home intent can close the mdm. 156 private void registerHomeIntentReceiver() { 157 mIndirectHomeReceiver = new IndirectHomeReceiver(); 158 IntentFilter filter = new IntentFilter(); 159 filter.addAction(DeviceOwnerProvisioningService.ACTION_HOME_INDIRECT); 160 LocalBroadcastManager.getInstance(this).registerReceiver(mIndirectHomeReceiver, filter); 161 } 162 163 class IndirectHomeReceiver extends BroadcastReceiver { 164 @Override 165 public void onReceive(Context context, Intent intent) { 166 if (!mDone) { 167 return; 168 } 169 170 // Disable the HomeReceiverActivity. It's no longer of use. 171 PackageManager pm = getPackageManager(); 172 pm.setComponentEnabledSetting(new ComponentName(DeviceOwnerProvisioningService.this, 173 HomeReceiverActivity.class), PackageManager 174 .COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP); 175 176 // Send complete intent to mdm. 177 Intent result = new Intent(ACTION_PROFILE_PROVISIONING_COMPLETE); 178 result.setPackage(mParams.mDeviceAdminPackageName); 179 result.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES | 180 Intent.FLAG_RECEIVER_FOREGROUND); 181 if (mParams.mAdminExtrasBundle != null) { 182 result.putExtra(EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE, 183 mParams.mAdminExtrasBundle); 184 } 185 sendBroadcast(result); 186 stopSelf(); 187 } 188 } 189 190 191 /** 192 * This is the core method of this class. It goes through every provisioning step. 193 */ 194 private void startDeviceOwnerProvisioning(final ProvisioningParams params) { 195 ProvisionLogger.logd("Starting device owner provisioning"); 196 197 // Construct Tasks. Do not start them yet. 198 mAddWifiNetworkTask = new AddWifiNetworkTask(this, params.mWifiSsid, 199 params.mWifiHidden, params.mWifiSecurityType, params.mWifiPassword, 200 params.mWifiProxyHost, params.mWifiProxyPort, params.mWifiProxyBypassHosts, 201 params.mWifiPacUrl, new AddWifiNetworkTask.Callback() { 202 @Override 203 public void onSuccess() { 204 if (!TextUtils.isEmpty(params.mDeviceAdminPackageDownloadLocation)) { 205 // Download, install, set as device owner, delete apps. 206 progressUpdate(R.string.progress_download); 207 mDownloadPackageTask.run(); 208 } else { 209 // Device Admin will not be downloaded (but is already present): 210 // Just set as device owner, delete apps. 211 progressUpdate(R.string.progress_set_owner); 212 mSetDevicePolicyTask.run(); 213 } 214 } 215 216 @Override 217 public void onError(){ 218 error(R.string.device_owner_error_wifi); 219 } 220 }); 221 222 mDownloadPackageTask = new DownloadPackageTask(this, 223 params.mDeviceAdminPackageDownloadLocation, params.mDeviceAdminPackageChecksum, 224 params.mDeviceAdminPackageDownloadCookieHeader, new DownloadPackageTask.Callback() { 225 @Override 226 public void onSuccess() { 227 String downloadLocation = 228 mDownloadPackageTask.getDownloadedPackageLocation(); 229 progressUpdate(R.string.progress_install); 230 mInstallPackageTask.run(downloadLocation); 231 } 232 233 @Override 234 public void onError(int errorCode) { 235 switch(errorCode) { 236 case DownloadPackageTask.ERROR_HASH_MISMATCH: 237 error(R.string.device_owner_error_hash_mismatch); 238 break; 239 case DownloadPackageTask.ERROR_DOWNLOAD_FAILED: 240 error(R.string.device_owner_error_download_failed); 241 break; 242 default: 243 error(R.string.device_owner_error_general); 244 break; 245 } 246 } 247 }); 248 249 mInstallPackageTask = new InstallPackageTask(this, 250 params.mDeviceAdminPackageName, 251 new InstallPackageTask.Callback() { 252 @Override 253 public void onSuccess() { 254 progressUpdate(R.string.progress_set_owner); 255 mSetDevicePolicyTask.run(); 256 } 257 258 @Override 259 public void onError(int errorCode) { 260 switch(errorCode) { 261 case InstallPackageTask.ERROR_PACKAGE_INVALID: 262 error(R.string.device_owner_error_package_invalid); 263 break; 264 case InstallPackageTask.ERROR_INSTALLATION_FAILED: 265 error(R.string.device_owner_error_installation_failed); 266 break; 267 default: 268 error(R.string.device_owner_error_general); 269 break; 270 } 271 } 272 }); 273 274 mSetDevicePolicyTask = new SetDevicePolicyTask(this, 275 params.mDeviceAdminPackageName, 276 getResources().getString(R.string.default_owned_device_username), 277 new SetDevicePolicyTask.Callback() { 278 @Override 279 public void onSuccess() { 280 mDeleteNonRequiredAppsTask.run(); 281 } 282 283 @Override 284 public void onError(int errorCode) { 285 switch(errorCode) { 286 case SetDevicePolicyTask.ERROR_PACKAGE_NOT_INSTALLED: 287 error(R.string.device_owner_error_package_not_installed); 288 break; 289 case SetDevicePolicyTask.ERROR_NO_RECEIVER: 290 error(R.string.device_owner_error_package_invalid); 291 break; 292 default: 293 error(R.string.device_owner_error_general); 294 break; 295 } 296 } 297 }); 298 299 mDeleteNonRequiredAppsTask = new DeleteNonRequiredAppsTask( 300 this, params.mDeviceAdminPackageName, UserHandle.USER_OWNER, 301 R.array.required_apps_managed_device, R.array.vendor_required_apps_managed_device, 302 true /* We are creating a new profile */, 303 false /* Do not disable INSTALL_SHORTCUT listeners */, 304 new DeleteNonRequiredAppsTask.Callback() { 305 public void onSuccess() { 306 // Done with provisioning. Success. 307 onProvisioningSuccess(params.mDeviceAdminPackageName); 308 } 309 310 @Override 311 public void onError() { 312 error(R.string.device_owner_error_general); 313 }; 314 }); 315 316 // Start first task, which starts next task in its callback, etc. 317 startFirstTask(params); 318 } 319 320 private void startFirstTask(final ProvisioningParams params) { 321 if (!TextUtils.isEmpty(params.mWifiSsid)) { 322 323 // Connect to wifi. 324 progressUpdate(R.string.progress_connect_to_wifi); 325 mAddWifiNetworkTask.run(); 326 } else if (!TextUtils.isEmpty(params.mDeviceAdminPackageDownloadLocation)) { 327 328 // Download, install, set as device owner, delete apps. 329 progressUpdate(R.string.progress_download); 330 mDownloadPackageTask.run(); 331 } else { 332 333 // Device Admin will not be downloaded (but is already present): 334 // Just set as device owner, delete apps. 335 progressUpdate(R.string.progress_set_owner); 336 mSetDevicePolicyTask.run(); 337 } 338 } 339 340 private void error(int dialogMessage) { 341 mLastErrorMessage = dialogMessage; 342 sendError(); 343 // Wait for stopService() call from the activity. 344 } 345 346 private void sendError() { 347 ProvisionLogger.logd("Reporting Error: " + getResources().getString(mLastErrorMessage)); 348 Intent intent = new Intent(ACTION_PROVISIONING_ERROR); 349 intent.setClass(this, DeviceOwnerProvisioningActivity.ServiceMessageReceiver.class); 350 intent.putExtra(EXTRA_USER_VISIBLE_ERROR_ID_KEY, mLastErrorMessage); 351 LocalBroadcastManager.getInstance(this).sendBroadcast(intent); 352 } 353 354 private void progressUpdate(int progressMessage) { 355 ProvisionLogger.logd("Reporting progress update: " 356 + getResources().getString(progressMessage)); 357 mLastProgressMessage = progressMessage; 358 sendProgressUpdateToActivity(); 359 } 360 361 private void sendProgressUpdateToActivity() { 362 Intent intent = new Intent(ACTION_PROGRESS_UPDATE); 363 intent.putExtra(EXTRA_PROGRESS_MESSAGE_ID_KEY, mLastProgressMessage); 364 intent.setClass(this, DeviceOwnerProvisioningActivity.ServiceMessageReceiver.class); 365 LocalBroadcastManager.getInstance(this).sendBroadcast(intent); 366 } 367 368 private void onProvisioningSuccess(String deviceAdminPackage) { 369 ProvisionLogger.logv("Reporting success."); 370 mDone = true; 371 372 // Enable the HomeReceiverActivity, since the DeviceOwnerProvisioningActivity will shutdown 373 // the Setup wizard soon, which will result in a home intent that should be caught by the 374 // HomeReceiverActivity. 375 PackageManager pm = getPackageManager(); 376 pm.setComponentEnabledSetting(new ComponentName(DeviceOwnerProvisioningService.this, 377 HomeReceiverActivity.class), PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 378 PackageManager.DONT_KILL_APP); 379 380 Intent successIntent = new Intent(ACTION_PROVISIONING_SUCCESS); 381 successIntent.setClass(this, DeviceOwnerProvisioningActivity.ServiceMessageReceiver.class); 382 LocalBroadcastManager.getInstance(this).sendBroadcast(successIntent); 383 // Wait for stopService() call from the activity. 384 } 385 386 private void initializeProvisioningEnvironment(ProvisioningParams params) { 387 setTimeAndTimezone(params.mTimeZone, params.mLocalTime); 388 setLocale(params.mLocale); 389 390 // Start CDMA activation to enable phone calls. 391 final Intent intent = new Intent(ACTION_PERFORM_CDMA_PROVISIONING); 392 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 393 ProvisionLogger.logv("Starting cdma activation activity"); 394 startActivity(intent); // Activity will be a Nop if not a CDMA device. 395 } 396 397 private void setTimeAndTimezone(String timeZone, long localTime) { 398 try { 399 final AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE); 400 if (timeZone != null) { 401 ProvisionLogger.logd("Setting time zone to " + timeZone); 402 am.setTimeZone(timeZone); 403 } 404 if (localTime > 0) { 405 ProvisionLogger.logd("Setting time to " + localTime); 406 am.setTime(localTime); 407 } 408 } catch (Exception e) { 409 ProvisionLogger.loge("Alarm manager failed to set the system time/timezone."); 410 // Do not stop provisioning process, but ignore this error. 411 } 412 } 413 414 private void setLocale(Locale locale) { 415 if (locale == null || locale.equals(Locale.getDefault())) { 416 return; 417 } 418 try { 419 ProvisionLogger.logd("Setting locale to " + locale); 420 // If locale is different from current locale this results in a configuration change, 421 // which will trigger the restarting of the activity. 422 LocalePicker.updateLocale(locale); 423 } catch (Exception e) { 424 ProvisionLogger.loge("Failed to set the system locale."); 425 // Do not stop provisioning process, but ignore this error. 426 } 427 } 428 429 @Override 430 public void onCreate () { 431 ProvisionLogger.logd("Device owner provisioning service ONCREATE."); 432 } 433 434 @Override 435 public void onDestroy () { 436 ProvisionLogger.logd("Device owner provisioning service ONDESTROY"); 437 if (mAddWifiNetworkTask != null) { 438 mAddWifiNetworkTask.cleanUp(); 439 } 440 if (mDownloadPackageTask != null) { 441 mDownloadPackageTask.cleanUp(); 442 } 443 if (mIndirectHomeReceiver != null) { 444 LocalBroadcastManager.getInstance(this).unregisterReceiver(mIndirectHomeReceiver); 445 mIndirectHomeReceiver = null; 446 } 447 448 } 449 450 @Override 451 public IBinder onBind(Intent intent) { 452 return null; 453 } 454} 455 456