DeviceOwnerProvisioningService.java revision 326bcfdd72218a2d3b35d8e1ca80b8e36263402e
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 progressUpdate(R.string.progress_download); 150 mDownloadPackageTask.run(); 151 } 152 153 @Override 154 public void onError(){ 155 error(R.string.device_owner_error_wifi); 156 } 157 }); 158 159 mDownloadPackageTask = new DownloadPackageTask(this, 160 params.mDeviceAdminPackageDownloadLocation, params.mDeviceAdminPackageChecksum, 161 new DownloadPackageTask.Callback() { 162 @Override 163 public void onSuccess() { 164 String downloadLocation = 165 mDownloadPackageTask.getDownloadedPackageLocation(); 166 progressUpdate(R.string.progress_install); 167 mInstallPackageTask.run(downloadLocation); 168 } 169 170 @Override 171 public void onError(int errorCode) { 172 switch(errorCode) { 173 case DownloadPackageTask.ERROR_HASH_MISMATCH: 174 error(R.string.device_owner_error_hash_mismatch); 175 break; 176 case DownloadPackageTask.ERROR_DOWNLOAD_FAILED: 177 error(R.string.device_owner_error_download_failed); 178 break; 179 default: 180 error(R.string.device_owner_error_general); 181 break; 182 } 183 } 184 }); 185 186 mInstallPackageTask = new InstallPackageTask(this, 187 params.mDeviceAdminPackageName, 188 new InstallPackageTask.Callback() { 189 @Override 190 public void onSuccess() { 191 progressUpdate(R.string.progress_set_owner); 192 mSetDevicePolicyTask.run(); 193 } 194 195 @Override 196 public void onError(int errorCode) { 197 switch(errorCode) { 198 case InstallPackageTask.ERROR_PACKAGE_INVALID: 199 error(R.string.device_owner_error_package_invalid); 200 break; 201 case InstallPackageTask.ERROR_INSTALLATION_FAILED: 202 error(R.string.device_owner_error_installation_failed); 203 break; 204 default: 205 error(R.string.device_owner_error_general); 206 break; 207 } 208 } 209 }); 210 211 mSetDevicePolicyTask = new SetDevicePolicyTask(this, 212 params.mDeviceAdminPackageName, 213 getResources().getString(R.string.default_owned_device_username), 214 new SetDevicePolicyTask.Callback() { 215 @Override 216 public void onSuccess() { 217 mDeleteNonRequiredAppsTask.run(); 218 } 219 220 @Override 221 public void onError(int errorCode) { 222 switch(errorCode) { 223 case SetDevicePolicyTask.ERROR_PACKAGE_NOT_INSTALLED: 224 error(R.string.device_owner_error_package_not_installed); 225 break; 226 case SetDevicePolicyTask.ERROR_NO_RECEIVER: 227 error(R.string.device_owner_error_missing_receiver); 228 break; 229 default: 230 error(R.string.device_owner_error_general); 231 break; 232 } 233 } 234 }); 235 236 mDeleteNonRequiredAppsTask = new DeleteNonRequiredAppsTask( 237 this, params.mDeviceAdminPackageName, 0 /* primary user's UserId */, 238 R.array.required_apps_managed_device, R.array.vendor_required_apps_managed_device, 239 new DeleteNonRequiredAppsTask.Callback() { 240 public void onSuccess() { 241 // Done with provisioning. Success. 242 onProvisioningSuccess(params.mDeviceAdminPackageName); 243 } 244 245 @Override 246 public void onError() { 247 error(R.string.device_owner_error_general); 248 }; 249 }); 250 251 // Start first task, which starts next task in its callback, etc. 252 if (!TextUtils.isEmpty(params.mDeviceAdminPackageDownloadLocation)) { 253 // Device Admin has to be downloaded: 254 // Connect to wifi, download, install, set as device owner, delete apps. 255 progressUpdate(R.string.progress_connect_to_wifi); 256 mAddWifiNetworkTask.run(); 257 } else { 258 // Device Admin will not be downloaded (but is already present): 259 // Just set as device owner, delete apps. 260 progressUpdate(R.string.progress_set_owner); 261 mSetDevicePolicyTask.run(); 262 } 263 } 264 265 private void error(int dialogMessage) { 266 mLastErrorMessage = dialogMessage; 267 sendError(); 268 // Wait for stopService() call from the activity. 269 } 270 271 private void sendError() { 272 ProvisionLogger.logd("Reporting Error: " + getResources().getString(mLastErrorMessage)); 273 Intent intent = new Intent(ACTION_PROVISIONING_ERROR); 274 intent.setClass(this, DeviceOwnerProvisioningActivity.ServiceMessageReceiver.class); 275 intent.putExtra(EXTRA_USER_VISIBLE_ERROR_ID_KEY, mLastErrorMessage); 276 LocalBroadcastManager.getInstance(this).sendBroadcast(intent); 277 } 278 279 private void progressUpdate(int progressMessage) { 280 ProvisionLogger.logd("Reporting progress update: " 281 + getResources().getString(progressMessage)); 282 mLastProgressMessage = progressMessage; 283 sendProgressUpdateToActivity(); 284 } 285 286 private void sendProgressUpdateToActivity() { 287 Intent intent = new Intent(ACTION_PROGRESS_UPDATE); 288 intent.putExtra(EXTRA_PROGRESS_MESSAGE_ID_KEY, mLastProgressMessage); 289 intent.setClass(this, DeviceOwnerProvisioningActivity.ServiceMessageReceiver.class); 290 LocalBroadcastManager.getInstance(this).sendBroadcast(intent); 291 } 292 293 private void onProvisioningSuccess(String deviceAdminPackage) { 294 ProvisionLogger.logv("Reporting success."); 295 mDone = true; 296 Intent successIntent = new Intent(ACTION_PROVISIONING_SUCCESS); 297 successIntent.setClass(this, DeviceOwnerProvisioningActivity.ServiceMessageReceiver.class); 298 LocalBroadcastManager.getInstance(this).sendBroadcast(successIntent); 299 // Wait for stopService() call from the activity. 300 } 301 302 private void initializeProvisioningEnvironment(ProvisioningParams params) { 303 setTimeAndTimezone(params.mTimeZone, params.mLocalTime); 304 setLocale(params.mLocale); 305 306 // Start CDMA activation to enable phone calls. 307 final Intent intent = new Intent(ACTION_PERFORM_CDMA_PROVISIONING); 308 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 309 ProvisionLogger.logv("Starting cdma activation activity"); 310 startActivity(intent); // Activity will be a Nop if not a CDMA device. 311 } 312 313 private void setTimeAndTimezone(String timeZone, long localTime) { 314 try { 315 final AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE); 316 if (timeZone != null) { 317 ProvisionLogger.logd("Setting time zone to " + timeZone); 318 am.setTimeZone(timeZone); 319 } 320 if (localTime > 0) { 321 ProvisionLogger.logd("Setting time to " + localTime); 322 am.setTime(localTime); 323 } 324 } catch (Exception e) { 325 ProvisionLogger.loge("Alarm manager failed to set the system time/timezone."); 326 // Do not stop provisioning process, but ignore this error. 327 } 328 } 329 330 private void setLocale(Locale locale) { 331 if (locale == null || locale.equals(Locale.getDefault())) { 332 return; 333 } 334 try { 335 ProvisionLogger.logd("Setting locale to " + locale); 336 // If locale is different from current locale this results in a configuration change, 337 // which will trigger the restarting of the activity. 338 LocalePicker.updateLocale(locale); 339 } catch (Exception e) { 340 ProvisionLogger.loge("Failed to set the system locale."); 341 // Do not stop provisioning process, but ignore this error. 342 } 343 } 344 345 @Override 346 public void onCreate () { 347 ProvisionLogger.logd("Device owner provisioning service ONCREATE."); 348 } 349 350 @Override 351 public void onDestroy () { 352 ProvisionLogger.logd("Device owner provisioning service ONDESTROY"); 353 if (mAddWifiNetworkTask != null) { 354 mAddWifiNetworkTask.cleanUp(); 355 } 356 if (mDownloadPackageTask != null) { 357 mDownloadPackageTask.cleanUp(); 358 } 359 } 360 361 @Override 362 public IBinder onBind(Intent intent) { 363 return null; 364 } 365} 366 367