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 17 package com.android.managedprovisioning; 18 19 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE; 20 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_TIME_ZONE; 21 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_LOCAL_TIME; 22 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_LOCALE; 23 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_WIFI_SSID; 24 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_WIFI_HIDDEN; 25 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_WIFI_SECURITY_TYPE; 26 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_WIFI_PASSWORD; 27 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_WIFI_PROXY_HOST; 28 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_WIFI_PROXY_PORT; 29 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_WIFI_PROXY_BYPASS; 30 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_WIFI_PAC_URL; 31 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE; 32 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE; 33 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME; 34 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_MINIMUM_VERSION_CODE; 35 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM; 36 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION; 37 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER; 38 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME; 39 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM; 40 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_SIGNATURE_CHECKSUM; 41 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_INITIALIZER_COMPONENT_NAME; 42 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_INITIALIZER_MINIMUM_VERSION_CODE; 43 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_LOCATION; 44 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_COOKIE_HEADER; 45 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_CHECKSUM; 46 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_INITIALIZER_SIGNATURE_CHECKSUM; 47 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED; 48 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_SKIP_ENCRYPTION; 49 import static android.app.admin.DevicePolicyManager.MIME_TYPE_PROVISIONING_NFC; 50 import static android.app.admin.DevicePolicyManager.MIME_TYPE_PROVISIONING_NFC_V2; 51 import static java.nio.charset.StandardCharsets.UTF_8; 52 53 import android.accounts.Account; 54 import android.content.ComponentName; 55 import android.content.Context; 56 import android.content.Intent; 57 import android.nfc.NdefMessage; 58 import android.nfc.NdefRecord; 59 import android.nfc.NfcAdapter; 60 import android.os.Bundle; 61 import android.os.Parcelable; 62 import android.os.PersistableBundle; 63 import android.text.TextUtils; 64 65 import com.android.managedprovisioning.Utils.IllegalProvisioningArgumentException; 66 67 import java.io.IOException; 68 import java.io.StringReader; 69 import java.util.Enumeration; 70 import java.util.HashMap; 71 import java.util.IllformedLocaleException; 72 import java.util.Locale; 73 import java.util.Properties; 74 75 /** 76 * This class can initialize a {@link ProvisioningParams} object from an intent. 77 * A {@link ProvisioningParams} object stores various parameters both for the device owner 78 * provisioning and profile owner provisioning. 79 * There are two kinds of intents that can be parsed it into {@link ProvisioningParams}: 80 * 81 * <p> 82 * Intent was received via Nfc. 83 * The intent contains the extra {@link NfcAdapter.EXTRA_NDEF_MESSAGES}, which indicates that 84 * provisioning was started via Nfc bump. This extra contains an NDEF message, which contains an 85 * NfcRecord with mime type {@link MIME_TYPE_PROVISIONING_NFC}. This record stores a serialized 86 * properties object, which contains the serialized extra's described in the next option. 87 * A typical use case would be a programmer application that sends an Nfc bump to start Nfc 88 * provisioning from a programmer device. 89 * 90 * <p> 91 * Intent was received directly. 92 * The intent contains the extra {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME} or 93 * {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME} (which is deprecated and supported for 94 * legacy reasons only), and may contain {@link #EXTRA_PROVISIONING_TIME_ZONE}, 95 * {@link #EXTRA_PROVISIONING_LOCAL_TIME}, and {@link #EXTRA_PROVISIONING_LOCALE}. A download 96 * location for the device admin may be specified in 97 * {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION}, together with an optional 98 * {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_MINIMUM_VERSION_CODE}, an optional 99 * http cookie header {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER}, and 100 * the SHA-256 hash of the target file {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM} or 101 * the SHA-256 hash of any signature of the android package in the target file 102 * {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_CERTIFICATE_CHECKSUM}. 103 * Additional information to send through to the device initializer and admin may be specified in 104 * {@link #EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE}. 105 * The optional boolean {@link #EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED} indicates whether 106 * system apps should not be disabled. The optional boolean 107 * {@link #EXTRA_PROVISIONING_SKIP_ENCRYPTION} specifies whether the device should be encrypted. 108 * Furthermore a wifi network may be specified in {@link #EXTRA_PROVISIONING_WIFI_SSID}, and if 109 * applicable {@link #EXTRA_PROVISIONING_WIFI_HIDDEN}, 110 * {@link #EXTRA_PROVISIONING_WIFI_SECURITY_TYPE}, {@link #EXTRA_PROVISIONING_WIFI_PASSWORD}, 111 * {@link #EXTRA_PROVISIONING_WIFI_PROXY_HOST}, {@link #EXTRA_PROVISIONING_WIFI_PROXY_PORT}, 112 * {@link #EXTRA_PROVISIONING_WIFI_PROXY_BYPASS}, 113 * The optional parcelable account {@link #EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE} specifies the 114 * account that has to be migrated from primary user to managed user in case of 115 * profile owner provisioning. 116 * A typical use case would be the {@link BootReminder} sending the intent after device encryption 117 * and reboot. 118 * 119 * <p> 120 * Furthermore this class can construct the bundle of extras for the second kind of intent given a 121 * {@link ProvisioningParams}, and it keeps track of the types of the extras in the 122 * DEVICE_OWNER_x_EXTRAS and PROFILE_OWNER_x_EXTRAS, with x the appropriate type. 123 */ 124 public class MessageParser { 125 private static final String EXTRA_PROVISIONING_STARTED_BY_NFC = 126 "com.android.managedprovisioning.extra.started_by_nfc"; 127 private static final String EXTRA_PROVISIONING_DEVICE_ADMIN_SUPPORT_SHA1_PACKAGE_CHECKSUM = 128 "com.android.managedprovisioning.extra.device_admin_support_sha1_package_checksum"; 129 130 /* package */ static final String[] PROFILE_OWNER_STRING_EXTRAS = { 131 // Key for the device admin package name 132 EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME 133 }; 134 135 /* package */ static final String[] PROFILE_OWNER_ACCOUNT_EXTRAS = { 136 // Key for the account extras 137 EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE 138 }; 139 140 /* package */ static final String[] PROFILE_OWNER_PERSISTABLE_BUNDLE_EXTRAS = { 141 // Key for the admin extras bundle 142 EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE 143 }; 144 145 /* package */ static final String[] PROFILE_OWNER_COMPONENT_NAME_EXTRAS = { 146 // Key for the device admin component name 147 EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME 148 }; 149 150 /* package */ static final String[] DEVICE_OWNER_STRING_EXTRAS = { 151 EXTRA_PROVISIONING_TIME_ZONE, 152 EXTRA_PROVISIONING_LOCALE, 153 EXTRA_PROVISIONING_WIFI_SSID, 154 EXTRA_PROVISIONING_WIFI_SECURITY_TYPE, 155 EXTRA_PROVISIONING_WIFI_PASSWORD, 156 EXTRA_PROVISIONING_WIFI_PROXY_HOST, 157 EXTRA_PROVISIONING_WIFI_PROXY_BYPASS, 158 EXTRA_PROVISIONING_WIFI_PAC_URL, 159 EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME, 160 EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION, 161 EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER, 162 EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM, 163 EXTRA_PROVISIONING_DEVICE_ADMIN_SIGNATURE_CHECKSUM, 164 EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_LOCATION, 165 EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_COOKIE_HEADER, 166 EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_CHECKSUM, 167 EXTRA_PROVISIONING_DEVICE_INITIALIZER_SIGNATURE_CHECKSUM 168 }; 169 170 /* package */ static final String[] DEVICE_OWNER_LONG_EXTRAS = { 171 EXTRA_PROVISIONING_LOCAL_TIME 172 }; 173 174 /* package */ static final String[] DEVICE_OWNER_INT_EXTRAS = { 175 EXTRA_PROVISIONING_WIFI_PROXY_PORT, 176 EXTRA_PROVISIONING_DEVICE_ADMIN_MINIMUM_VERSION_CODE, 177 EXTRA_PROVISIONING_DEVICE_INITIALIZER_MINIMUM_VERSION_CODE 178 }; 179 180 /* package */ static final String[] DEVICE_OWNER_BOOLEAN_EXTRAS = { 181 EXTRA_PROVISIONING_WIFI_HIDDEN, 182 EXTRA_PROVISIONING_STARTED_BY_NFC, 183 EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED, 184 EXTRA_PROVISIONING_SKIP_ENCRYPTION, 185 EXTRA_PROVISIONING_DEVICE_ADMIN_SUPPORT_SHA1_PACKAGE_CHECKSUM 186 }; 187 188 /* package */ static final String[] DEVICE_OWNER_PERSISTABLE_BUNDLE_EXTRAS = { 189 EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE 190 }; 191 192 /* package */ static final String[] DEVICE_OWNER_COMPONENT_NAME_EXTRAS = { 193 EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME, 194 EXTRA_PROVISIONING_DEVICE_INITIALIZER_COMPONENT_NAME 195 }; 196 197 public void addProvisioningParamsToBundle(Bundle bundle, ProvisioningParams params) { 198 bundle.putString(EXTRA_PROVISIONING_TIME_ZONE, params.timeZone); 199 bundle.putString(EXTRA_PROVISIONING_LOCALE, localeToString(params.locale)); 200 bundle.putString(EXTRA_PROVISIONING_WIFI_SSID, params.wifiInfo.ssid); 201 bundle.putString(EXTRA_PROVISIONING_WIFI_SECURITY_TYPE, params.wifiInfo.securityType); 202 bundle.putString(EXTRA_PROVISIONING_WIFI_PASSWORD, params.wifiInfo.password); 203 bundle.putString(EXTRA_PROVISIONING_WIFI_PROXY_HOST, params.wifiInfo.proxyHost); 204 bundle.putString(EXTRA_PROVISIONING_WIFI_PROXY_BYPASS, params.wifiInfo.proxyBypassHosts); 205 bundle.putString(EXTRA_PROVISIONING_WIFI_PAC_URL, params.wifiInfo.pacUrl); 206 bundle.putInt(EXTRA_PROVISIONING_WIFI_PROXY_PORT, params.wifiInfo.proxyPort); 207 bundle.putBoolean(EXTRA_PROVISIONING_WIFI_HIDDEN, params.wifiInfo.hidden); 208 bundle.putString(EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME, 209 params.deviceAdminPackageName); 210 bundle.putParcelable(EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME, 211 params.deviceAdminComponentName); 212 bundle.putInt(EXTRA_PROVISIONING_DEVICE_ADMIN_MINIMUM_VERSION_CODE, 213 params.deviceAdminDownloadInfo.minVersion); 214 bundle.putString(EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION, 215 params.deviceAdminDownloadInfo.location); 216 bundle.putString(EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER, 217 params.deviceAdminDownloadInfo.cookieHeader); 218 bundle.putString(EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM, 219 Utils.byteArrayToString(params.deviceAdminDownloadInfo.packageChecksum)); 220 bundle.putBoolean(EXTRA_PROVISIONING_DEVICE_ADMIN_SUPPORT_SHA1_PACKAGE_CHECKSUM, 221 params.deviceAdminDownloadInfo.packageChecksumSupportsSha1); 222 bundle.putString(EXTRA_PROVISIONING_DEVICE_ADMIN_SIGNATURE_CHECKSUM, 223 Utils.byteArrayToString(params.deviceAdminDownloadInfo.signatureChecksum)); 224 bundle.putParcelable(EXTRA_PROVISIONING_DEVICE_INITIALIZER_COMPONENT_NAME, 225 params.deviceInitializerComponentName); 226 bundle.putInt(EXTRA_PROVISIONING_DEVICE_INITIALIZER_MINIMUM_VERSION_CODE, 227 params.deviceInitializerDownloadInfo.minVersion); 228 bundle.putString(EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_LOCATION, 229 params.deviceInitializerDownloadInfo.location); 230 bundle.putString(EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_COOKIE_HEADER, 231 params.deviceInitializerDownloadInfo.cookieHeader); 232 bundle.putString(EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_CHECKSUM, 233 Utils.byteArrayToString(params.deviceInitializerDownloadInfo.packageChecksum)); 234 bundle.putString(EXTRA_PROVISIONING_DEVICE_INITIALIZER_SIGNATURE_CHECKSUM, 235 Utils.byteArrayToString(params.deviceInitializerDownloadInfo.signatureChecksum)); 236 237 bundle.putLong(EXTRA_PROVISIONING_LOCAL_TIME, params.localTime); 238 bundle.putBoolean(EXTRA_PROVISIONING_STARTED_BY_NFC, params.startedByNfc); 239 bundle.putBoolean(EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED, 240 params.leaveAllSystemAppsEnabled); 241 bundle.putParcelable(EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE, params.adminExtrasBundle); 242 bundle.putBoolean(EXTRA_PROVISIONING_SKIP_ENCRYPTION, params.skipEncryption); 243 bundle.putParcelable(EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE, params.accountToMigrate); 244 } 245 246 public ProvisioningParams parseNfcIntent(Intent nfcIntent) 247 throws IllegalProvisioningArgumentException { 248 ProvisionLogger.logi("Processing Nfc Payload."); 249 // Only one first message with NFC_MIME_TYPE is used. 250 for (Parcelable rawMsg : nfcIntent 251 .getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES)) { 252 NdefMessage msg = (NdefMessage) rawMsg; 253 254 // Assume only first record of message is used. 255 NdefRecord firstRecord = msg.getRecords()[0]; 256 String mimeType = new String(firstRecord.getType(), UTF_8); 257 258 if (MIME_TYPE_PROVISIONING_NFC.equals(mimeType) || 259 MIME_TYPE_PROVISIONING_NFC_V2.equals(mimeType)) { 260 ProvisioningParams params = parseProperties(new String(firstRecord.getPayload() 261 , UTF_8)); 262 params.startedByNfc = true; 263 ProvisionLogger.logi("End processing Nfc Payload."); 264 return params; 265 } 266 } 267 throw new IllegalProvisioningArgumentException( 268 "Intent does not contain NfcRecord with the correct MIME type."); 269 } 270 271 // Note: EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE property contains a Properties object 272 // serialized into String. See Properties.store() and Properties.load() for more details. 273 // The property value is optional. 274 private ProvisioningParams parseProperties(String data) 275 throws IllegalProvisioningArgumentException { 276 ProvisioningParams params = new ProvisioningParams(); 277 try { 278 Properties props = new Properties(); 279 props.load(new StringReader(data)); 280 281 String s; // Used for parsing non-Strings. 282 params.timeZone 283 = props.getProperty(EXTRA_PROVISIONING_TIME_ZONE); 284 if ((s = props.getProperty(EXTRA_PROVISIONING_LOCALE)) != null) { 285 params.locale = stringToLocale(s); 286 } 287 params.wifiInfo.ssid = props.getProperty(EXTRA_PROVISIONING_WIFI_SSID); 288 params.wifiInfo.securityType = props.getProperty(EXTRA_PROVISIONING_WIFI_SECURITY_TYPE); 289 params.wifiInfo.password = props.getProperty(EXTRA_PROVISIONING_WIFI_PASSWORD); 290 params.wifiInfo.proxyHost = props.getProperty(EXTRA_PROVISIONING_WIFI_PROXY_HOST); 291 params.wifiInfo.proxyBypassHosts = 292 props.getProperty(EXTRA_PROVISIONING_WIFI_PROXY_BYPASS); 293 params.wifiInfo.pacUrl = props.getProperty(EXTRA_PROVISIONING_WIFI_PAC_URL); 294 if ((s = props.getProperty(EXTRA_PROVISIONING_WIFI_PROXY_PORT)) != null) { 295 params.wifiInfo.proxyPort = Integer.parseInt(s); 296 } 297 if ((s = props.getProperty(EXTRA_PROVISIONING_WIFI_HIDDEN)) != null) { 298 params.wifiInfo.hidden = Boolean.parseBoolean(s); 299 } 300 301 params.deviceAdminPackageName 302 = props.getProperty(EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME); 303 String componentNameString = props.getProperty( 304 EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME); 305 if (componentNameString != null) { 306 params.deviceAdminComponentName = ComponentName.unflattenFromString( 307 componentNameString); 308 } 309 if ((s = props.getProperty( 310 EXTRA_PROVISIONING_DEVICE_ADMIN_MINIMUM_VERSION_CODE)) != null) { 311 params.deviceAdminDownloadInfo.minVersion = Integer.parseInt(s); 312 } else { 313 params.deviceAdminDownloadInfo.minVersion = 314 ProvisioningParams.DEFAULT_MINIMUM_VERSION; 315 } 316 params.deviceAdminDownloadInfo.location 317 = props.getProperty(EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION); 318 params.deviceAdminDownloadInfo.cookieHeader = props.getProperty( 319 EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER); 320 if ((s = props.getProperty(EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM)) != null) { 321 params.deviceAdminDownloadInfo.packageChecksum = Utils.stringToByteArray(s); 322 // Still support SHA-1 for device admin package hash if we are provisioned by a Nfc 323 // programmer. 324 // TODO: remove once SHA-1 is fully deprecated. 325 params.deviceAdminDownloadInfo.packageChecksumSupportsSha1 = true; 326 } 327 if ((s = props.getProperty(EXTRA_PROVISIONING_DEVICE_ADMIN_SIGNATURE_CHECKSUM)) 328 != null) { 329 params.deviceAdminDownloadInfo.signatureChecksum = Utils.stringToByteArray(s); 330 } 331 String name = props.getProperty( 332 EXTRA_PROVISIONING_DEVICE_INITIALIZER_COMPONENT_NAME); 333 if (name != null) { 334 params.deviceInitializerComponentName = ComponentName.unflattenFromString(name); 335 } 336 if ((s = props.getProperty( 337 EXTRA_PROVISIONING_DEVICE_INITIALIZER_MINIMUM_VERSION_CODE)) != null) { 338 params.deviceInitializerDownloadInfo.minVersion = Integer.parseInt(s); 339 } else { 340 params.deviceInitializerDownloadInfo.minVersion = 341 ProvisioningParams.DEFAULT_MINIMUM_VERSION; 342 } 343 params.deviceInitializerDownloadInfo.location = props.getProperty( 344 EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_LOCATION); 345 params.deviceInitializerDownloadInfo.cookieHeader = props.getProperty( 346 EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_COOKIE_HEADER); 347 if ((s = props.getProperty( 348 EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_CHECKSUM)) != null) { 349 params.deviceInitializerDownloadInfo.packageChecksum = Utils.stringToByteArray(s); 350 } 351 if ((s = props.getProperty(EXTRA_PROVISIONING_DEVICE_INITIALIZER_SIGNATURE_CHECKSUM)) 352 != null) { 353 params.deviceInitializerDownloadInfo.signatureChecksum = 354 Utils.stringToByteArray(s); 355 } 356 357 if ((s = props.getProperty(EXTRA_PROVISIONING_LOCAL_TIME)) != null) { 358 params.localTime = Long.parseLong(s); 359 } 360 361 if ((s = props.getProperty(EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED)) != null) { 362 params.leaveAllSystemAppsEnabled = Boolean.parseBoolean(s); 363 } 364 if ((s = props.getProperty(EXTRA_PROVISIONING_SKIP_ENCRYPTION)) != null) { 365 params.skipEncryption = Boolean.parseBoolean(s); 366 } 367 368 params.adminExtrasBundle = deserializeExtrasBundle(props, 369 EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE); 370 371 checkValidityOfProvisioningParams(params); 372 return params; 373 } catch (IOException e) { 374 throw new Utils.IllegalProvisioningArgumentException("Couldn't load payload", e); 375 } catch (NumberFormatException e) { 376 throw new Utils.IllegalProvisioningArgumentException("Incorrect numberformat.", e); 377 } catch (IllformedLocaleException e) { 378 throw new Utils.IllegalProvisioningArgumentException("Invalid locale.", e); 379 } 380 } 381 382 /** 383 * Get a {@link PersistableBundle} from a String property in a Properties object. 384 * @param props the source of the extra 385 * @param extraName key into the Properties object 386 * @return the bundle or {@code null} if there was no property with the given name 387 * @throws IOException if there was an error parsing the propery 388 */ 389 private PersistableBundle deserializeExtrasBundle(Properties props, String extraName) 390 throws IOException { 391 PersistableBundle extrasBundle = null; 392 String serializedExtras = props.getProperty(extraName); 393 if (serializedExtras != null) { 394 Properties extrasProp = new Properties(); 395 extrasProp.load(new StringReader(serializedExtras)); 396 extrasBundle = new PersistableBundle(extrasProp.size()); 397 for (String propName : extrasProp.stringPropertyNames()) { 398 extrasBundle.putString(propName, extrasProp.getProperty(propName)); 399 } 400 } 401 return extrasBundle; 402 } 403 404 public ProvisioningParams parseMinimalistNonNfcIntent(Intent intent) 405 throws IllegalProvisioningArgumentException { 406 ProvisionLogger.logi("Processing mininalist non-nfc intent."); 407 ProvisioningParams params = parseMinimalistNonNfcIntentInternal(intent); 408 if (params.deviceAdminComponentName == null) { 409 throw new IllegalProvisioningArgumentException("Must provide the component name of the" 410 + " device admin"); 411 } 412 return params; 413 } 414 415 private ProvisioningParams parseMinimalistNonNfcIntentInternal(Intent intent) 416 throws IllegalProvisioningArgumentException { 417 ProvisioningParams params = new ProvisioningParams(); 418 params.deviceAdminComponentName = (ComponentName) intent.getParcelableExtra( 419 EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME); 420 params.skipEncryption = intent.getBooleanExtra( 421 EXTRA_PROVISIONING_SKIP_ENCRYPTION, 422 ProvisioningParams.DEFAULT_EXTRA_PROVISIONING_SKIP_ENCRYPTION); 423 params.leaveAllSystemAppsEnabled = intent.getBooleanExtra( 424 EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED, 425 ProvisioningParams.DEFAULT_LEAVE_ALL_SYSTEM_APPS_ENABLED); 426 params.accountToMigrate = (Account) intent.getParcelableExtra( 427 EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE); 428 try { 429 params.adminExtrasBundle = (PersistableBundle) intent.getParcelableExtra( 430 EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE); 431 } catch (ClassCastException e) { 432 throw new IllegalProvisioningArgumentException("Extra " 433 + EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE 434 + " must be of type PersistableBundle.", e); 435 } 436 return params; 437 } 438 439 /** 440 * Parse an intent and return a corresponding {@link ProvisioningParams} object. 441 * 442 * @param intent intent to be parsed. 443 * @param trusted whether the intent is trusted or not. A trusted intent can contain internal 444 * extras which are not part of the public API. These extras often control sensitive aspects of 445 * ManagedProvisioning such as whether deprecated SHA-1 is supported, or whether MP was started 446 * from NFC (hence no user consent dialog). Intents used by other apps to start MP should always 447 * be untrusted. 448 */ 449 public ProvisioningParams parseNonNfcIntent(Intent intent, boolean trusted) 450 throws IllegalProvisioningArgumentException { 451 ProvisionLogger.logi("Processing non-nfc intent."); 452 ProvisioningParams params = parseMinimalistNonNfcIntentInternal(intent); 453 454 params.timeZone = intent.getStringExtra(EXTRA_PROVISIONING_TIME_ZONE); 455 String localeString = intent.getStringExtra(EXTRA_PROVISIONING_LOCALE); 456 if (localeString != null) { 457 params.locale = stringToLocale(localeString); 458 } 459 params.wifiInfo.ssid = intent.getStringExtra(EXTRA_PROVISIONING_WIFI_SSID); 460 params.wifiInfo.securityType = intent.getStringExtra(EXTRA_PROVISIONING_WIFI_SECURITY_TYPE); 461 params.wifiInfo.password = intent.getStringExtra(EXTRA_PROVISIONING_WIFI_PASSWORD); 462 params.wifiInfo.proxyHost = intent.getStringExtra(EXTRA_PROVISIONING_WIFI_PROXY_HOST); 463 params.wifiInfo.proxyBypassHosts = 464 intent.getStringExtra(EXTRA_PROVISIONING_WIFI_PROXY_BYPASS); 465 params.wifiInfo.pacUrl = intent.getStringExtra(EXTRA_PROVISIONING_WIFI_PAC_URL); 466 params.wifiInfo.proxyPort = intent.getIntExtra(EXTRA_PROVISIONING_WIFI_PROXY_PORT, 467 ProvisioningParams.DEFAULT_WIFI_PROXY_PORT); 468 params.wifiInfo.hidden = intent.getBooleanExtra(EXTRA_PROVISIONING_WIFI_HIDDEN, 469 ProvisioningParams.DEFAULT_WIFI_HIDDEN); 470 471 params.deviceAdminPackageName 472 = intent.getStringExtra(EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME); 473 params.deviceAdminDownloadInfo.minVersion = intent.getIntExtra( 474 EXTRA_PROVISIONING_DEVICE_ADMIN_MINIMUM_VERSION_CODE, 475 ProvisioningParams.DEFAULT_MINIMUM_VERSION); 476 params.deviceAdminDownloadInfo.location 477 = intent.getStringExtra(EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION); 478 params.deviceAdminDownloadInfo.cookieHeader = intent.getStringExtra( 479 EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER); 480 String packageHash = 481 intent.getStringExtra(EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM); 482 if (packageHash != null) { 483 params.deviceAdminDownloadInfo.packageChecksum = Utils.stringToByteArray(packageHash); 484 // If we are restarted after an encryption reboot, use stored (trusted) value for this. 485 if (trusted) { 486 params.deviceAdminDownloadInfo.packageChecksumSupportsSha1 = intent.getBooleanExtra( 487 EXTRA_PROVISIONING_DEVICE_ADMIN_SUPPORT_SHA1_PACKAGE_CHECKSUM, false); 488 } else { 489 // legacy action (activation code flow) still uses SHA-1. 490 // TODO: remove once that flow is deprecated. 491 params.deviceAdminDownloadInfo.packageChecksumSupportsSha1 = 492 DeviceOwnerPreProvisioningActivity.LEGACY_ACTION_PROVISION_MANAGED_DEVICE 493 .equals(intent.getAction()); 494 } 495 } 496 String sigHash = 497 intent.getStringExtra(EXTRA_PROVISIONING_DEVICE_ADMIN_SIGNATURE_CHECKSUM); 498 if (sigHash != null) { 499 params.deviceAdminDownloadInfo.signatureChecksum = Utils.stringToByteArray(sigHash); 500 } 501 params.deviceInitializerComponentName = (ComponentName) intent.getParcelableExtra( 502 EXTRA_PROVISIONING_DEVICE_INITIALIZER_COMPONENT_NAME); 503 params.deviceInitializerDownloadInfo.minVersion = intent.getIntExtra( 504 EXTRA_PROVISIONING_DEVICE_INITIALIZER_MINIMUM_VERSION_CODE, 505 ProvisioningParams.DEFAULT_MINIMUM_VERSION); 506 params.deviceInitializerDownloadInfo.location = intent.getStringExtra( 507 EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_LOCATION); 508 params.deviceInitializerDownloadInfo.cookieHeader = intent.getStringExtra( 509 EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_COOKIE_HEADER); 510 packageHash = intent.getStringExtra(EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_CHECKSUM); 511 if (packageHash != null) { 512 params.deviceInitializerDownloadInfo.packageChecksum = 513 Utils.stringToByteArray(packageHash); 514 } 515 sigHash = 516 intent.getStringExtra(EXTRA_PROVISIONING_DEVICE_INITIALIZER_SIGNATURE_CHECKSUM); 517 if (sigHash != null) { 518 params.deviceInitializerDownloadInfo.signatureChecksum = 519 Utils.stringToByteArray(sigHash); 520 } 521 522 params.localTime = intent.getLongExtra(EXTRA_PROVISIONING_LOCAL_TIME, 523 ProvisioningParams.DEFAULT_LOCAL_TIME); 524 if (trusted) { 525 // The only case where startedByNfc can be true in this code path is we are reloading 526 // a stored Nfc bump intent after encryption reboot, which is a trusted intent. 527 params.startedByNfc = intent.getBooleanExtra(EXTRA_PROVISIONING_STARTED_BY_NFC, 528 false); 529 } 530 531 params.accountToMigrate = (Account) intent.getParcelableExtra( 532 EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE); 533 params.deviceAdminComponentName = (ComponentName) intent.getParcelableExtra( 534 EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME); 535 536 checkValidityOfProvisioningParams(params); 537 return params; 538 } 539 540 /** 541 * Check whether necessary fields are set. 542 */ 543 private void checkValidityOfProvisioningParams(ProvisioningParams params) 544 throws IllegalProvisioningArgumentException { 545 if (TextUtils.isEmpty(params.deviceAdminPackageName) 546 && params.deviceAdminComponentName == null) { 547 throw new IllegalProvisioningArgumentException("Must provide the name of the device" 548 + " admin package or component name"); 549 } 550 checkDownloadInfoHasChecksum(params.deviceAdminDownloadInfo, "device admin"); 551 checkDownloadInfoHasChecksum(params.deviceInitializerDownloadInfo, "device initializer"); 552 } 553 554 private void checkDownloadInfoHasChecksum(ProvisioningParams.PackageDownloadInfo info, 555 String downloadName) throws IllegalProvisioningArgumentException { 556 if (!TextUtils.isEmpty(info.location)) { 557 if ((info.packageChecksum == null || info.packageChecksum.length == 0) 558 && (info.signatureChecksum == null || info.signatureChecksum.length == 0)) { 559 throw new IllegalProvisioningArgumentException("Checksum of installer file" 560 + " or its signature is required for downloading " + downloadName 561 + ", but neither is provided."); 562 } 563 } 564 } 565 566 public static Locale stringToLocale(String string) 567 throws IllformedLocaleException { 568 return new Locale.Builder().setLanguageTag(string.replace("_", "-")).build(); 569 } 570 571 public static String localeToString(Locale locale) { 572 if (locale != null) { 573 return locale.getLanguage() + "_" + locale.getCountry(); 574 } else { 575 return null; 576 } 577 } 578 } 579