ExtrasProvisioningDataParser.java revision 7079df5a3fb155947004843ee8ec25b36127e3ed
1/* 2 * Copyright 2016, 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.parser; 18 19import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE; 20import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE; 21import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE; 22import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE; 23import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_USER; 24import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE; 25import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE; 26import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME; 27import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_MINIMUM_VERSION_CODE; 28import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM; 29import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER; 30import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION; 31import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME; 32import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_SIGNATURE_CHECKSUM; 33import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED; 34import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_LOCALE; 35import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_LOCAL_TIME; 36import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_MAIN_COLOR; 37import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_SKIP_ENCRYPTION; 38import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_SKIP_USER_SETUP; 39import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_TIME_ZONE; 40import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_WIFI_HIDDEN; 41import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_WIFI_PAC_URL; 42import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_WIFI_PASSWORD; 43import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_WIFI_PROXY_BYPASS; 44import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_WIFI_PROXY_HOST; 45import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_WIFI_PROXY_PORT; 46import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_WIFI_SECURITY_TYPE; 47import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_WIFI_SSID; 48import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_LOGO_URI; 49import static com.android.internal.util.Preconditions.checkNotNull; 50import static com.android.managedprovisioning.common.Globals.ACTION_RESUME_PROVISIONING; 51import static com.android.managedprovisioning.parser.MessageParser.EXTRA_PROVISIONING_ACTION; 52import static com.android.managedprovisioning.parser.MessageParser.EXTRA_PROVISIONING_DEVICE_ADMIN_SUPPORT_SHA1_PACKAGE_CHECKSUM; 53import static com.android.managedprovisioning.parser.MessageParser.EXTRA_PROVISIONING_STARTED_BY_TRUSTED_SOURCE; 54 55import android.accounts.Account; 56import android.content.ComponentName; 57import android.content.Context; 58import android.content.Intent; 59import android.net.Uri; 60import android.graphics.Color; 61import android.os.Bundle; 62import android.os.PersistableBundle; 63import android.support.annotation.Nullable; 64import android.support.annotation.VisibleForTesting; 65 66import com.android.managedprovisioning.LogoUtils; 67import com.android.managedprovisioning.ProvisionLogger; 68import com.android.managedprovisioning.common.IllegalProvisioningArgumentException; 69import com.android.managedprovisioning.common.Utils; 70import com.android.managedprovisioning.model.PackageDownloadInfo; 71import com.android.managedprovisioning.model.ProvisioningParams; 72import com.android.managedprovisioning.model.WifiInfo; 73 74import java.util.Arrays; 75import java.util.HashSet; 76import java.util.IllformedLocaleException; 77import java.util.Locale; 78import java.util.Properties; 79import java.util.Set; 80 81/** 82 * A parser which parses provisioning data from intent which stores in {@link Bundle} extras. 83 */ 84 85@VisibleForTesting 86public class ExtrasProvisioningDataParser implements ProvisioningDataParser { 87 private static final Set<String> PROVISIONING_ACTIONS_SUPPORT_ALL_PROVISIONING_DATA = 88 new HashSet(Arrays.asList( 89 ACTION_RESUME_PROVISIONING, 90 ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE)); 91 92 private static final Set<String> PROVISIONING_ACTIONS_SUPPORT_MIN_PROVISIONING_DATA = 93 new HashSet(Arrays.asList( 94 ACTION_PROVISION_MANAGED_DEVICE, 95 ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE, 96 ACTION_PROVISION_MANAGED_USER, 97 ACTION_PROVISION_MANAGED_PROFILE)); 98 99 private final Utils mUtils; 100 101 ExtrasProvisioningDataParser(Utils utils) { 102 mUtils = checkNotNull(utils); 103 } 104 105 @Override 106 public ProvisioningParams parse(Intent provisioningIntent, Context context) 107 throws IllegalProvisioningArgumentException{ 108 String provisioningAction = provisioningIntent.getAction(); 109 110 if (PROVISIONING_ACTIONS_SUPPORT_MIN_PROVISIONING_DATA.contains(provisioningAction)) { 111 ProvisionLogger.logi("Processing mininalist extras intent."); 112 return parseMinimalistSupportedProvisioningDataInternal(provisioningIntent, context) 113 .build(); 114 } else if (PROVISIONING_ACTIONS_SUPPORT_ALL_PROVISIONING_DATA.contains( 115 provisioningAction)) { 116 return parseAllSupportedProvisioningData(provisioningIntent, context); 117 } else { 118 throw new IllegalProvisioningArgumentException("Unsupported provisioning action: " 119 + provisioningAction); 120 } 121 } 122 123 /** 124 * Parses minimal supported set of parameters from bundle extras of a provisioning intent. 125 * 126 * <p>Here is the list of supported parameters. 127 * <ul> 128 * <li>{@link EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME}</li> 129 * <li> 130 * {@link EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME} only in 131 * {@link ACTION_PROVISION_MANAGED_PROFILE}. 132 * </li> 133 * <li>{@link EXTRA_PROVISIONING_LOGO_URI}</li> 134 * <li>{@link EXTRA_PROVISIONING_MAIN_COLOR}</li> 135 * <li> 136 * {@link EXTRA_PROVISIONING_SKIP_USER_SETUP} only in 137 * {@link ACTION_PROVISION_MANAGED_USER} and {@link ACTION_PROVISION_MANAGED_DEVICE}. 138 * </li> 139 * <li>{@link EXTRA_PROVISIONING_SKIP_ENCRYPTION}</li> 140 * <li>{@link EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED}</li> 141 * <li>{@link EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE}</li> 142 * <li>{@link EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE}</li> 143 * </ul> 144 */ 145 private ProvisioningParams.Builder parseMinimalistSupportedProvisioningDataInternal( 146 Intent intent, Context context) 147 throws IllegalProvisioningArgumentException { 148 149 try { 150 String provisioningAction = isResumeProvisioningIntent(intent) 151 ? intent.getStringExtra(EXTRA_PROVISIONING_ACTION) 152 : mUtils.mapIntentToDpmAction(intent); 153 154 // Parse device admin package name and component name. 155 ComponentName deviceAdminComponentName = (ComponentName) intent.getParcelableExtra( 156 EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME); 157 // Device admin package name is deprecated. It is only supported in Profile Owner 158 // provisioning and NFC provisioning (parsing logic is not in this parser). 159 String deviceAdminPackageName = null; 160 if (ACTION_PROVISION_MANAGED_PROFILE.equals(provisioningAction)) { 161 // In L, we only support package name. This means some DPC may still send us the 162 // device admin package name only. Attempts to obtain the package name from extras. 163 deviceAdminPackageName = intent.getStringExtra( 164 EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME); 165 // For profile owner, the device admin package should be installed. Verify the 166 // device admin package. 167 deviceAdminComponentName = mUtils.findDeviceAdmin( 168 deviceAdminPackageName, deviceAdminComponentName, context); 169 // Since the device admin package must be installed at this point and its component 170 // name has been obtained, it should be safe to set the deprecated package name 171 // value to null. 172 deviceAdminPackageName = null; 173 } 174 175 // Parse main color 176 Integer mainColor = ProvisioningParams.DEFAULT_MAIN_COLOR; 177 if (intent.hasExtra(EXTRA_PROVISIONING_MAIN_COLOR)) { 178 mainColor = intent.getIntExtra(EXTRA_PROVISIONING_MAIN_COLOR, 0 /* not used */); 179 } 180 181 // Parse skip user setup in ACTION_PROVISION_MANAGED_USER and 182 // ACTION_PROVISION_MANAGED_DEVICE only. 183 boolean skipUserSetup = ProvisioningParams.DEFAULT_SKIP_USER_SETUP; 184 if (provisioningAction.equals(ACTION_PROVISION_MANAGED_USER) 185 || provisioningAction.equals(ACTION_PROVISION_MANAGED_DEVICE)) { 186 skipUserSetup = intent.getBooleanExtra(EXTRA_PROVISIONING_SKIP_USER_SETUP, 187 ProvisioningParams.DEFAULT_SKIP_USER_SETUP); 188 } 189 190 parseOrganizationLogoUrlFromExtras(context, intent); 191 192 return ProvisioningParams.Builder.builder() 193 .setProvisioningAction(provisioningAction) 194 .setDeviceAdminComponentName(deviceAdminComponentName) 195 .setDeviceAdminPackageName(deviceAdminPackageName) 196 .setSkipEncryption(intent.getBooleanExtra(EXTRA_PROVISIONING_SKIP_ENCRYPTION, 197 ProvisioningParams.DEFAULT_EXTRA_PROVISIONING_SKIP_ENCRYPTION)) 198 .setLeaveAllSystemAppsEnabled(intent.getBooleanExtra( 199 EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED, 200 ProvisioningParams.DEFAULT_LEAVE_ALL_SYSTEM_APPS_ENABLED)) 201 .setAdminExtrasBundle((PersistableBundle) intent.getParcelableExtra( 202 EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE)) 203 .setMainColor(mainColor) 204 .setSkipUserSetup(skipUserSetup) 205 .setAccountToMigrate((Account) intent.getParcelableExtra( 206 EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE)); 207 } catch (ClassCastException e) { 208 throw new IllegalProvisioningArgumentException("Extra " 209 + EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE 210 + " must be of type PersistableBundle.", e); 211 } catch (IllegalArgumentException e) { 212 throw new IllegalProvisioningArgumentException("Invalid parameter found!", e); 213 } catch (NullPointerException e) { 214 throw new IllegalProvisioningArgumentException("Compulsory parameter not found!", e); 215 } 216 } 217 218 /** 219 * Parses an intent and return a corresponding {@link ProvisioningParams} object. 220 * 221 * @param intent intent to be parsed. 222 * @param context a context 223 */ 224 private ProvisioningParams parseAllSupportedProvisioningData(Intent intent, Context context) 225 throws IllegalProvisioningArgumentException { 226 try { 227 ProvisionLogger.logi("Processing all supported extras intent: " + intent.getAction()); 228 return parseMinimalistSupportedProvisioningDataInternal(intent, context) 229 // Parse time zone, local time and locale. 230 .setTimeZone(intent.getStringExtra(EXTRA_PROVISIONING_TIME_ZONE)) 231 .setLocalTime(intent.getLongExtra(EXTRA_PROVISIONING_LOCAL_TIME, 232 ProvisioningParams.DEFAULT_LOCAL_TIME)) 233 .setLocale(MessageParser.stringToLocale( 234 intent.getStringExtra(EXTRA_PROVISIONING_LOCALE))) 235 // Parse WiFi configuration. 236 .setWifiInfo(parseWifiInfoFromExtras(intent)) 237 // Parse device admin package download info. 238 .setDeviceAdminDownloadInfo(parsePackageDownloadInfoFromExtras(intent)) 239 // Cases where startedByTrustedSource can be true are 240 // 1. We are reloading a stored provisioning intent, either Nfc bump or 241 // PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE, after encryption reboot, 242 // which is a self-originated intent. 243 // 2. the intent is from a trusted source, for example QR provisioning. 244 .setStartedByTrustedSource(isResumeProvisioningIntent(intent) 245 ? intent.getBooleanExtra(EXTRA_PROVISIONING_STARTED_BY_TRUSTED_SOURCE, 246 ProvisioningParams.DEFAULT_STARTED_BY_TRUSTED_SOURCE) 247 : ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE.equals( 248 intent.getAction())) 249 .build(); 250 } catch (IllegalArgumentException e) { 251 throw new IllegalProvisioningArgumentException("Invalid parameter found!", e); 252 } catch (NullPointerException e) { 253 throw new IllegalProvisioningArgumentException("Compulsory parameter not found!", e); 254 } 255 } 256 257 /** 258 * Parses Wifi configuration from an Intent and returns the result in {@link WifiInfo}. 259 */ 260 @Nullable 261 private WifiInfo parseWifiInfoFromExtras(Intent intent) { 262 if (intent.getStringExtra(EXTRA_PROVISIONING_WIFI_SSID) == null) { 263 return null; 264 } 265 return WifiInfo.Builder.builder() 266 .setSsid(intent.getStringExtra(EXTRA_PROVISIONING_WIFI_SSID)) 267 .setSecurityType(intent.getStringExtra(EXTRA_PROVISIONING_WIFI_SECURITY_TYPE)) 268 .setPassword(intent.getStringExtra(EXTRA_PROVISIONING_WIFI_PASSWORD)) 269 .setProxyHost(intent.getStringExtra(EXTRA_PROVISIONING_WIFI_PROXY_HOST)) 270 .setProxyBypassHosts(intent.getStringExtra(EXTRA_PROVISIONING_WIFI_PROXY_BYPASS)) 271 .setPacUrl(intent.getStringExtra(EXTRA_PROVISIONING_WIFI_PAC_URL)) 272 .setProxyPort(intent.getIntExtra(EXTRA_PROVISIONING_WIFI_PROXY_PORT, 273 WifiInfo.DEFAULT_WIFI_PROXY_PORT)) 274 .setHidden(intent.getBooleanExtra(EXTRA_PROVISIONING_WIFI_HIDDEN, 275 WifiInfo.DEFAULT_WIFI_HIDDEN)) 276 .build(); 277 } 278 279 /** 280 * Parses device admin package download info configuration from an Intent and returns the result 281 * in {@link PackageDownloadInfo}. 282 */ 283 @Nullable 284 private PackageDownloadInfo parsePackageDownloadInfoFromExtras(Intent intent) { 285 if (intent.getStringExtra(EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION) 286 == null) { 287 return null; 288 } 289 PackageDownloadInfo.Builder downloadInfoBuilder = PackageDownloadInfo.Builder.builder() 290 .setMinVersion(intent.getIntExtra( 291 EXTRA_PROVISIONING_DEVICE_ADMIN_MINIMUM_VERSION_CODE, 292 PackageDownloadInfo.DEFAULT_MINIMUM_VERSION)) 293 .setLocation(intent.getStringExtra( 294 EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION)) 295 .setCookieHeader(intent.getStringExtra( 296 EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER)); 297 String packageHash = 298 intent.getStringExtra(EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM); 299 if (packageHash != null) { 300 downloadInfoBuilder.setPackageChecksum(mUtils.stringToByteArray(packageHash)); 301 if (isResumeProvisioningIntent(intent)) { 302 // PackageChecksumSupportsSha1 is only supported in NFC provisioning. But if the 303 // device is rebooted after encryption as part of the NFC provisioning flow, the 304 // value should be restored. 305 downloadInfoBuilder.setPackageChecksumSupportsSha1( 306 intent.getBooleanExtra( 307 EXTRA_PROVISIONING_DEVICE_ADMIN_SUPPORT_SHA1_PACKAGE_CHECKSUM, 308 false)); 309 } 310 } 311 String sigHash = intent.getStringExtra(EXTRA_PROVISIONING_DEVICE_ADMIN_SIGNATURE_CHECKSUM); 312 if (sigHash != null) { 313 downloadInfoBuilder.setSignatureChecksum(mUtils.stringToByteArray(sigHash)); 314 } 315 return downloadInfoBuilder.build(); 316 } 317 318 /** 319 * Parses the organization logo url from intent. 320 */ 321 private void parseOrganizationLogoUrlFromExtras(Context context, Intent intent) { 322 Uri logoUri = intent.getParcelableExtra(EXTRA_PROVISIONING_LOGO_URI); 323 if (logoUri != null) { 324 // If we go through encryption, and if the uri is a content uri: 325 // We'll lose the grant to this uri. So we need to save it to a local file. 326 LogoUtils.saveOrganisationLogo(context, logoUri); 327 } else if (!isResumeProvisioningIntent(intent)) { 328 // If the intent is not from managed provisioning app, there is a slight possibility 329 // that the logo is still kept on the file system from a previous provisioning. In 330 // this case, remove it. 331 LogoUtils.cleanUp(context); 332 } 333 } 334 335 private boolean isResumeProvisioningIntent(Intent intent) { 336 return ACTION_RESUME_PROVISIONING.equals(intent.getAction()); 337 } 338} 339