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