Home | History | Annotate | Download | only in managedprovisioning
      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