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