ExtrasProvisioningDataParser.java revision 349f226ff616048752c693d42fd7ae4d74fbc97d
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_LOGO_URI; 37import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_MAIN_COLOR; 38import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_SKIP_ENCRYPTION; 39import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_SKIP_USER_CONSENT; 40import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_SKIP_USER_SETUP; 41import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_TIME_ZONE; 42import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_WIFI_HIDDEN; 43import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_WIFI_PAC_URL; 44import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_WIFI_PASSWORD; 45import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_WIFI_PROXY_BYPASS; 46import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_WIFI_PROXY_HOST; 47import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_WIFI_PROXY_PORT; 48import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_WIFI_SECURITY_TYPE; 49import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_WIFI_SSID; 50import static com.android.internal.util.Preconditions.checkNotNull; 51import static com.android.managedprovisioning.common.Globals.ACTION_RESUME_PROVISIONING; 52import static com.android.managedprovisioning.model.ProvisioningParams.inferStaticDeviceAdminPackageName; 53 54import android.accounts.Account; 55import android.app.admin.DevicePolicyManager; 56import android.content.ComponentName; 57import android.content.Context; 58import android.content.Intent; 59import android.net.Uri; 60import android.os.Bundle; 61import android.os.PersistableBundle; 62import android.support.annotation.Nullable; 63import android.support.annotation.VisibleForTesting; 64 65import com.android.managedprovisioning.common.LogoUtils; 66import com.android.managedprovisioning.common.ProvisionLogger; 67import com.android.managedprovisioning.common.IllegalProvisioningArgumentException; 68import com.android.managedprovisioning.common.StoreUtils; 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.Set; 77 78/** 79 * A parser which parses provisioning data from intent which stores in {@link Bundle} extras. 80 */ 81 82@VisibleForTesting 83public class ExtrasProvisioningDataParser implements ProvisioningDataParser { 84 private static final Set<String> PROVISIONING_ACTIONS_SUPPORT_ALL_PROVISIONING_DATA = 85 new HashSet(Arrays.asList( 86 ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE)); 87 88 private static final Set<String> PROVISIONING_ACTIONS_SUPPORT_MIN_PROVISIONING_DATA = 89 new HashSet(Arrays.asList( 90 ACTION_PROVISION_MANAGED_DEVICE, 91 ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE, 92 ACTION_PROVISION_MANAGED_USER, 93 ACTION_PROVISION_MANAGED_PROFILE)); 94 95 private final Utils mUtils; 96 97 ExtrasProvisioningDataParser(Utils utils) { 98 mUtils = checkNotNull(utils); 99 } 100 101 @Override 102 public ProvisioningParams parse(Intent provisioningIntent, Context context) 103 throws IllegalProvisioningArgumentException{ 104 String provisioningAction = provisioningIntent.getAction(); 105 if (ACTION_RESUME_PROVISIONING.equals(provisioningAction)) { 106 return provisioningIntent.getParcelableExtra( 107 ProvisioningParams.EXTRA_PROVISIONING_PARAMS); 108 } 109 if (PROVISIONING_ACTIONS_SUPPORT_MIN_PROVISIONING_DATA.contains(provisioningAction)) { 110 ProvisionLogger.logi("Processing mininalist extras intent."); 111 return parseMinimalistSupportedProvisioningDataInternal(provisioningIntent, context) 112 .build(); 113 } else if (PROVISIONING_ACTIONS_SUPPORT_ALL_PROVISIONING_DATA.contains( 114 provisioningAction)) { 115 return parseAllSupportedProvisioningData(provisioningIntent, context); 116 } else { 117 throw new IllegalProvisioningArgumentException("Unsupported provisioning action: " 118 + provisioningAction); 119 } 120 } 121 122 /** 123 * Parses minimal supported set of parameters from bundle extras of a provisioning intent. 124 * 125 * <p>Here is the list of supported parameters. 126 * <ul> 127 * <li>{@link EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME}</li> 128 * <li> 129 * {@link EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME} only in 130 * {@link ACTION_PROVISION_MANAGED_PROFILE}. 131 * </li> 132 * <li>{@link EXTRA_PROVISIONING_LOGO_URI}</li> 133 * <li>{@link EXTRA_PROVISIONING_MAIN_COLOR}</li> 134 * <li> 135 * {@link EXTRA_PROVISIONING_SKIP_USER_SETUP} only in 136 * {@link ACTION_PROVISION_MANAGED_USER} and {@link ACTION_PROVISION_MANAGED_DEVICE}. 137 * </li> 138 * <li>{@link EXTRA_PROVISIONING_SKIP_ENCRYPTION}</li> 139 * <li>{@link EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED}</li> 140 * <li>{@link EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE}</li> 141 * <li>{@link EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE}</li> 142 * <li>{@link EXTRA_PROVISIONING_SKIP_USER_CONSENT}</li> 143 * </ul> 144 */ 145 private ProvisioningParams.Builder parseMinimalistSupportedProvisioningDataInternal( 146 Intent intent, Context context) 147 throws IllegalProvisioningArgumentException { 148 final DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class); 149 boolean isProvisionManagedDeviceFromTrustedSourceIntent = 150 ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE.equals(intent.getAction()); 151 try { 152 String provisioningAction = 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 when resuming NFC provisioning. 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 skip user setup in ACTION_PROVISION_MANAGED_USER and 176 // ACTION_PROVISION_MANAGED_DEVICE (sync auth) only. This extra is not supported if 177 // provisioning was started by trusted source, as it is not clear where SUW should 178 // continue from. 179 boolean skipUserSetup = ProvisioningParams.DEFAULT_SKIP_USER_SETUP; 180 if (!isProvisionManagedDeviceFromTrustedSourceIntent 181 && (provisioningAction.equals(ACTION_PROVISION_MANAGED_USER) 182 || provisioningAction.equals(ACTION_PROVISION_MANAGED_DEVICE))) { 183 skipUserSetup = intent.getBooleanExtra(EXTRA_PROVISIONING_SKIP_USER_SETUP, 184 ProvisioningParams.DEFAULT_SKIP_USER_SETUP); 185 } 186 187 // Only current DeviceOwner can specify EXTRA_PROVISIONING_SKIP_USER_CONSENT when 188 // provisioning PO with ACTION_PROVISION_MANAGED_PROFILE 189 final ComponentName deviceOwner = dpm.getDeviceOwnerComponentOnCallingUser(); 190 final boolean skipUserConsent = 191 ACTION_PROVISION_MANAGED_PROFILE.equals(provisioningAction) 192 && intent.getBooleanExtra(EXTRA_PROVISIONING_SKIP_USER_CONSENT, 193 ProvisioningParams.DEFAULT_EXTRA_PROVISIONING_SKIP_USER_CONSENT) 194 && deviceOwner != null 195 && deviceOwner.getPackageName() 196 .equals(inferStaticDeviceAdminPackageName( 197 deviceAdminComponentName, deviceAdminPackageName)); 198 199 // Parse main color and organization's logo. This is not supported in managed device 200 // from trusted source provisioning because, currently, there is no way to send 201 // organization logo to the device at this stage. 202 Integer mainColor = ProvisioningParams.DEFAULT_MAIN_COLOR; 203 if (!isProvisionManagedDeviceFromTrustedSourceIntent) { 204 if (intent.hasExtra(EXTRA_PROVISIONING_MAIN_COLOR)) { 205 mainColor = intent.getIntExtra(EXTRA_PROVISIONING_MAIN_COLOR, 0 /* not used */); 206 } 207 parseOrganizationLogoUrlFromExtras(context, intent); 208 } 209 210 return ProvisioningParams.Builder.builder() 211 .setProvisioningAction(provisioningAction) 212 .setDeviceAdminComponentName(deviceAdminComponentName) 213 .setDeviceAdminPackageName(deviceAdminPackageName) 214 .setSkipEncryption(intent.getBooleanExtra(EXTRA_PROVISIONING_SKIP_ENCRYPTION, 215 ProvisioningParams.DEFAULT_EXTRA_PROVISIONING_SKIP_ENCRYPTION)) 216 .setLeaveAllSystemAppsEnabled(intent.getBooleanExtra( 217 EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED, 218 ProvisioningParams.DEFAULT_LEAVE_ALL_SYSTEM_APPS_ENABLED)) 219 .setAdminExtrasBundle((PersistableBundle) intent.getParcelableExtra( 220 EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE)) 221 .setMainColor(mainColor) 222 .setSkipUserConsent(skipUserConsent) 223 .setSkipUserSetup(skipUserSetup) 224 .setAccountToMigrate((Account) intent.getParcelableExtra( 225 EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE)); 226 } catch (ClassCastException e) { 227 throw new IllegalProvisioningArgumentException("Extra " 228 + EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE 229 + " must be of type PersistableBundle.", e); 230 } catch (IllegalArgumentException e) { 231 throw new IllegalProvisioningArgumentException("Invalid parameter found!", e); 232 } catch (NullPointerException e) { 233 throw new IllegalProvisioningArgumentException("Compulsory parameter not found!", e); 234 } 235 } 236 237 /** 238 * Parses an intent and return a corresponding {@link ProvisioningParams} object. 239 * 240 * @param intent intent to be parsed. 241 * @param context a context 242 */ 243 private ProvisioningParams parseAllSupportedProvisioningData(Intent intent, Context context) 244 throws IllegalProvisioningArgumentException { 245 try { 246 ProvisionLogger.logi("Processing all supported extras intent: " + intent.getAction()); 247 return parseMinimalistSupportedProvisioningDataInternal(intent, context) 248 // Parse time zone, local time and locale. 249 .setTimeZone(intent.getStringExtra(EXTRA_PROVISIONING_TIME_ZONE)) 250 .setLocalTime(intent.getLongExtra(EXTRA_PROVISIONING_LOCAL_TIME, 251 ProvisioningParams.DEFAULT_LOCAL_TIME)) 252 .setLocale(StoreUtils.stringToLocale( 253 intent.getStringExtra(EXTRA_PROVISIONING_LOCALE))) 254 // Parse WiFi configuration. 255 .setWifiInfo(parseWifiInfoFromExtras(intent)) 256 // Parse device admin package download info. 257 .setDeviceAdminDownloadInfo(parsePackageDownloadInfoFromExtras(intent)) 258 // Cases where startedByTrustedSource can be true are 259 // 1. We are reloading a stored provisioning intent, either Nfc bump or 260 // PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE, after encryption reboot, 261 // which is a self-originated intent. 262 // 2. the intent is from a trusted source, for example QR provisioning. 263 .setStartedByTrustedSource(ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE 264 .equals(intent.getAction())) 265 .build(); 266 } catch (IllegalArgumentException e) { 267 throw new IllegalProvisioningArgumentException("Invalid parameter found!", e); 268 } catch (NullPointerException e) { 269 throw new IllegalProvisioningArgumentException("Compulsory parameter not found!", e); 270 } 271 } 272 273 /** 274 * Parses Wifi configuration from an Intent and returns the result in {@link WifiInfo}. 275 */ 276 @Nullable 277 private WifiInfo parseWifiInfoFromExtras(Intent intent) { 278 if (intent.getStringExtra(EXTRA_PROVISIONING_WIFI_SSID) == null) { 279 return null; 280 } 281 return WifiInfo.Builder.builder() 282 .setSsid(intent.getStringExtra(EXTRA_PROVISIONING_WIFI_SSID)) 283 .setSecurityType(intent.getStringExtra(EXTRA_PROVISIONING_WIFI_SECURITY_TYPE)) 284 .setPassword(intent.getStringExtra(EXTRA_PROVISIONING_WIFI_PASSWORD)) 285 .setProxyHost(intent.getStringExtra(EXTRA_PROVISIONING_WIFI_PROXY_HOST)) 286 .setProxyBypassHosts(intent.getStringExtra(EXTRA_PROVISIONING_WIFI_PROXY_BYPASS)) 287 .setPacUrl(intent.getStringExtra(EXTRA_PROVISIONING_WIFI_PAC_URL)) 288 .setProxyPort(intent.getIntExtra(EXTRA_PROVISIONING_WIFI_PROXY_PORT, 289 WifiInfo.DEFAULT_WIFI_PROXY_PORT)) 290 .setHidden(intent.getBooleanExtra(EXTRA_PROVISIONING_WIFI_HIDDEN, 291 WifiInfo.DEFAULT_WIFI_HIDDEN)) 292 .build(); 293 } 294 295 /** 296 * Parses device admin package download info configuration from an Intent and returns the result 297 * in {@link PackageDownloadInfo}. 298 */ 299 @Nullable 300 private PackageDownloadInfo parsePackageDownloadInfoFromExtras(Intent intent) { 301 if (intent.getStringExtra(EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION) 302 == null) { 303 return null; 304 } 305 PackageDownloadInfo.Builder downloadInfoBuilder = PackageDownloadInfo.Builder.builder() 306 .setMinVersion(intent.getIntExtra( 307 EXTRA_PROVISIONING_DEVICE_ADMIN_MINIMUM_VERSION_CODE, 308 PackageDownloadInfo.DEFAULT_MINIMUM_VERSION)) 309 .setLocation(intent.getStringExtra( 310 EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION)) 311 .setCookieHeader(intent.getStringExtra( 312 EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER)); 313 String packageHash = 314 intent.getStringExtra(EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM); 315 if (packageHash != null) { 316 downloadInfoBuilder.setPackageChecksum(StoreUtils.stringToByteArray(packageHash)); 317 } 318 String sigHash = intent.getStringExtra(EXTRA_PROVISIONING_DEVICE_ADMIN_SIGNATURE_CHECKSUM); 319 if (sigHash != null) { 320 downloadInfoBuilder.setSignatureChecksum(StoreUtils.stringToByteArray(sigHash)); 321 } 322 return downloadInfoBuilder.build(); 323 } 324 325 /** 326 * Parses the organization logo url from intent. 327 */ 328 private void parseOrganizationLogoUrlFromExtras(Context context, Intent intent) { 329 Uri logoUri = intent.getParcelableExtra(EXTRA_PROVISIONING_LOGO_URI); 330 if (logoUri != null) { 331 // If we go through encryption, and if the uri is a content uri: 332 // We'll lose the grant to this uri. So we need to save it to a local file. 333 LogoUtils.saveOrganisationLogo(context, logoUri); 334 } 335 } 336} 337