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