Utils.java revision d2aa11e5484f3e56cea4ac328b2a0a58c28d4047
1/* 2 * Copyright 2014, The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.managedprovisioning.common; 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.MIME_TYPE_PROVISIONING_NFC; 25import static android.nfc.NfcAdapter.ACTION_NDEF_DISCOVERED; 26import static java.nio.charset.StandardCharsets.UTF_8; 27 28import android.accounts.Account; 29import android.accounts.AccountManager; 30import android.accounts.AccountManagerFuture; 31import android.accounts.AuthenticatorException; 32import android.accounts.OperationCanceledException; 33import android.app.admin.DevicePolicyManager; 34import android.content.ComponentName; 35import android.content.Context; 36import android.content.Intent; 37import android.content.pm.ActivityInfo; 38import android.content.pm.ApplicationInfo; 39import android.content.pm.IPackageManager; 40import android.content.pm.PackageInfo; 41import android.content.pm.PackageManager; 42import android.content.pm.PackageManager.NameNotFoundException; 43import android.content.pm.ResolveInfo; 44import android.content.pm.UserInfo; 45import android.graphics.Color; 46import android.net.ConnectivityManager; 47import android.net.NetworkInfo; 48import android.net.wifi.WifiManager; 49import android.nfc.NdefMessage; 50import android.nfc.NdefRecord; 51import android.nfc.NfcAdapter; 52import android.os.Build; 53import android.os.Bundle; 54import android.os.Parcelable; 55import android.os.Process; 56import android.os.RemoteException; 57import android.os.ServiceManager; 58import android.os.SystemProperties; 59import android.os.UserHandle; 60import android.os.UserManager; 61import android.os.storage.StorageManager; 62import android.provider.Settings.Global; 63import android.provider.Settings.Secure; 64import android.text.TextUtils; 65import android.util.Base64; 66 67import java.io.FileInputStream; 68import java.io.IOException; 69import java.io.InputStream; 70import java.lang.Integer; 71import java.lang.Math; 72import java.lang.String; 73import java.nio.charset.StandardCharsets; 74import java.security.MessageDigest; 75import java.security.NoSuchAlgorithmException; 76import java.util.HashSet; 77import java.util.List; 78import java.util.Set; 79import java.util.concurrent.TimeUnit; 80 81import com.android.internal.annotations.VisibleForTesting; 82import com.android.managedprovisioning.FinalizationActivity; 83import com.android.managedprovisioning.ProvisionLogger; 84import com.android.managedprovisioning.TrampolineActivity; 85import com.android.managedprovisioning.model.ProvisioningParams; 86import com.android.managedprovisioning.model.PackageDownloadInfo; 87 88/** 89 * Class containing various auxiliary methods. 90 */ 91public class Utils { 92 private static final int ACCOUNT_COPY_TIMEOUT_SECONDS = 60 * 3; // 3 minutes 93 94 private static final int THRESHOLD_BRIGHT_COLOR = 160; // A color needs a brightness of at least 95 // this value to be considered bright. (brightness being between 0 and 255). 96 97 public static final String SHA256_TYPE = "SHA-256"; 98 public static final String SHA1_TYPE = "SHA-1"; 99 100 public Utils() {} 101 102 /** 103 * Returns the currently installed system apps on a given user. 104 * 105 * <p>Calls into the {@link IPackageManager} to retrieve all installed packages on the given 106 * user and returns the package names of all system apps. 107 * 108 * @param ipm an {@link IPackageManager} object 109 * @param userId the id of the user we are interested in 110 */ 111 public Set<String> getCurrentSystemApps(IPackageManager ipm, int userId) { 112 Set<String> apps = new HashSet<String>(); 113 List<ApplicationInfo> aInfos = null; 114 try { 115 aInfos = ipm.getInstalledApplications( 116 PackageManager.GET_UNINSTALLED_PACKAGES, userId).getList(); 117 } catch (RemoteException neverThrown) { 118 ProvisionLogger.loge("This should not happen.", neverThrown); 119 } 120 for (ApplicationInfo aInfo : aInfos) { 121 if ((aInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { 122 apps.add(aInfo.packageName); 123 } 124 } 125 return apps; 126 } 127 128 /** 129 * Disables a given component in a given user. 130 * 131 * @param toDisable the component that should be disabled 132 * @param userId the id of the user where the component should be disabled. 133 */ 134 public void disableComponent(ComponentName toDisable, int userId) { 135 setComponentEnabledSetting( 136 IPackageManager.Stub.asInterface(ServiceManager.getService("package")), 137 toDisable, 138 PackageManager.COMPONENT_ENABLED_STATE_DISABLED, 139 userId); 140 } 141 142 /** 143 * Enables a given component in a given user. 144 * 145 * @param toEnable the component that should be enabled 146 * @param userId the id of the user where the component should be disabled. 147 */ 148 public void enableComponent(ComponentName toEnable, int userId) { 149 setComponentEnabledSetting( 150 IPackageManager.Stub.asInterface(ServiceManager.getService("package")), 151 toEnable, 152 PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 153 userId); 154 } 155 156 /** 157 * Disables a given component in a given user. 158 * 159 * @param ipm an {@link IPackageManager} object 160 * @param toDisable the component that should be disabled 161 * @param userId the id of the user where the component should be disabled. 162 */ 163 @VisibleForTesting 164 void setComponentEnabledSetting(IPackageManager ipm, ComponentName toDisable, 165 int enabledSetting, int userId) { 166 try { 167 ipm.setComponentEnabledSetting(toDisable, 168 enabledSetting, PackageManager.DONT_KILL_APP, 169 userId); 170 } catch (RemoteException neverThrown) { 171 ProvisionLogger.loge("This should not happen.", neverThrown); 172 } catch (Exception e) { 173 ProvisionLogger.logw("Component not found, not changing enabled setting: " 174 + toDisable.toShortString()); 175 } 176 } 177 178 /** 179 * Check the validity of the admin component name supplied, or try to infer this componentName 180 * from the package. 181 * 182 * We are supporting lookup by package name for legacy reasons. 183 * 184 * If mdmComponentName is supplied (not null): 185 * mdmPackageName is ignored. 186 * Check that the package of mdmComponentName is installed, that mdmComponentName is a 187 * receiver in this package, and return it. The receiver can be in disabled state. 188 * 189 * Otherwise: 190 * mdmPackageName must be supplied (not null). 191 * Check that this package is installed, try to infer a potential device admin in this package, 192 * and return it. 193 */ 194 // TODO: Add unit tests 195 public ComponentName findDeviceAdmin(String mdmPackageName, 196 ComponentName mdmComponentName, Context c) throws IllegalProvisioningArgumentException { 197 if (mdmComponentName != null) { 198 mdmPackageName = mdmComponentName.getPackageName(); 199 } 200 if (mdmPackageName == null) { 201 throw new IllegalProvisioningArgumentException("Neither the package name nor the" 202 + " component name of the admin are supplied"); 203 } 204 PackageInfo pi; 205 try { 206 pi = c.getPackageManager().getPackageInfo(mdmPackageName, 207 PackageManager.GET_RECEIVERS | PackageManager.MATCH_DISABLED_COMPONENTS); 208 } catch (NameNotFoundException e) { 209 throw new IllegalProvisioningArgumentException("Mdm "+ mdmPackageName 210 + " is not installed. ", e); 211 } 212 if (mdmComponentName != null) { 213 // If the component was specified in the intent: check that it is in the manifest. 214 checkAdminComponent(mdmComponentName, pi); 215 return mdmComponentName; 216 } else { 217 // Otherwise: try to find a potential device admin in the manifest. 218 return findDeviceAdminInPackage(mdmPackageName, pi); 219 } 220 } 221 222 /** 223 * Verifies that an admin component is part of a given package. 224 * 225 * @param mdmComponentName the admin component to be checked 226 * @param pi the {@link PackageInfo} of the package to be checked. 227 * 228 * @throws IllegalProvisioningArgumentException if the given component is not part of the 229 * package 230 */ 231 private void checkAdminComponent(ComponentName mdmComponentName, PackageInfo pi) 232 throws IllegalProvisioningArgumentException{ 233 for (ActivityInfo ai : pi.receivers) { 234 if (mdmComponentName.getClassName().equals(ai.name)) { 235 return; 236 } 237 } 238 throw new IllegalProvisioningArgumentException("The component " + mdmComponentName 239 + " cannot be found"); 240 } 241 242 private ComponentName findDeviceAdminInPackage(String mdmPackageName, PackageInfo pi) 243 throws IllegalProvisioningArgumentException { 244 ComponentName mdmComponentName = null; 245 for (ActivityInfo ai : pi.receivers) { 246 if (!TextUtils.isEmpty(ai.permission) && 247 ai.permission.equals(android.Manifest.permission.BIND_DEVICE_ADMIN)) { 248 if (mdmComponentName != null) { 249 throw new IllegalProvisioningArgumentException("There are several " 250 + "device admins in " + mdmPackageName + " but no one in specified"); 251 } else { 252 mdmComponentName = new ComponentName(mdmPackageName, ai.name); 253 } 254 } 255 } 256 if (mdmComponentName == null) { 257 throw new IllegalProvisioningArgumentException("There are no device admins in" 258 + mdmPackageName); 259 } 260 return mdmComponentName; 261 } 262 263 /** 264 * Returns whether the current user is the system user. 265 */ 266 public boolean isCurrentUserSystem() { 267 return UserHandle.myUserId() == UserHandle.USER_SYSTEM; 268 } 269 270 /** 271 * Returns whether the device is currently managed. 272 */ 273 public boolean isDeviceManaged(Context context) { 274 DevicePolicyManager dpm = 275 (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE); 276 return dpm.isDeviceManaged(); 277 } 278 279 /** 280 * Returns whether the calling user is a managed profile. 281 */ 282 public boolean isManagedProfile(Context context) { 283 UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE); 284 UserInfo user = um.getUserInfo(UserHandle.myUserId()); 285 return user != null ? user.isManagedProfile() : false; 286 } 287 288 /** 289 * Returns true if the given package requires an update. 290 * 291 * <p>There are two cases where an update is required: 292 * 1. The package is not currently present on the device. 293 * 2. The package is present, but the version is below the minimum supported version. 294 * 295 * @param packageName the package to be checked for updates 296 * @param minSupportedVersion the minimum supported version 297 * @param context a {@link Context} object 298 */ 299 public boolean packageRequiresUpdate(String packageName, int minSupportedVersion, 300 Context context) { 301 try { 302 PackageInfo packageInfo = context.getPackageManager().getPackageInfo(packageName, 0); 303 // Always download packages if no minimum version given. 304 if (minSupportedVersion != PackageDownloadInfo.DEFAULT_MINIMUM_VERSION 305 && packageInfo.versionCode >= minSupportedVersion) { 306 return false; 307 } 308 } catch (NameNotFoundException e) { 309 // Package not on device. 310 } 311 312 return true; 313 } 314 315 /** 316 * Sets user setup complete on a given user. 317 * 318 * <p>This will set USER_SETUP_COMPLETE to 1 on the given user. 319 */ 320 public void markUserSetupComplete(Context context, int userId) { 321 ProvisionLogger.logd("Setting USER_SETUP_COMPLETE to 1 for user " + userId); 322 Secure.putIntForUser(context.getContentResolver(), Secure.USER_SETUP_COMPLETE, 1, userId); 323 } 324 325 /** 326 * Returns whether USER_SETUP_COMPLETE is set on the calling user. 327 */ 328 public boolean isUserSetupCompleted(Context context) { 329 return Secure.getInt(context.getContentResolver(), Secure.USER_SETUP_COMPLETE, 0) != 0; 330 } 331 332 /** 333 * Returns whether DEVICE_PROVISIONED is set. 334 */ 335 public boolean isDeviceProvisioned(Context context) { 336 return Global.getInt(context.getContentResolver(), Global.DEVICE_PROVISIONED, 0) != 0; 337 } 338 339 /** 340 * Sets whether package verification is enabled or not. 341 */ 342 public void setPackageVerifierEnabled(Context context, boolean packageVerifierEnabled) { 343 Global.putInt(context.getContentResolver(), Global.PACKAGE_VERIFIER_ENABLE, 344 packageVerifierEnabled ? 1 : 0); 345 } 346 347 /** 348 * Returns whether package verification is enabled or not. 349 */ 350 public boolean isPackageVerifierEnabled(Context context) { 351 return Global.getInt(context.getContentResolver(), Global.PACKAGE_VERIFIER_ENABLE, 0) != 0; 352 } 353 354 /** 355 * Set the current users userProvisioningState depending on the following factors: 356 * <ul> 357 * <li>We're setting up a managed-profile - need to set state on two users.</li> 358 * <li>User-setup has previously been completed or not - skip states relating to 359 * communicating with setup-wizard</li> 360 * <li>DPC requested we skip the rest of setup-wizard.</li> 361 * </ul> 362 * 363 * @param context a {@link Context} object 364 * @param params configuration for current provisioning attempt 365 */ 366 // TODO: Add unit tests 367 public void markUserProvisioningStateInitiallyDone(Context context, 368 ProvisioningParams params) { 369 int currentUserId = UserHandle.myUserId(); 370 int managedProfileUserId = UserHandle.USER_NULL; 371 DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class); 372 373 // new provisioning state for current user, if non-null 374 Integer newState = null; 375 // New provisioning state for managed-profile of current user, if non-null. 376 Integer newProfileState = null; 377 378 boolean userSetupCompleted = isUserSetupCompleted(context); 379 if (params.provisioningAction.equals(ACTION_PROVISION_MANAGED_PROFILE)) { 380 // Managed profiles are a special case as two users are involved. 381 managedProfileUserId = getManagedProfile(context).getIdentifier(); 382 if (userSetupCompleted) { 383 // SUW on current user is complete, so nothing much to do beyond indicating we're 384 // all done. 385 newProfileState = DevicePolicyManager.STATE_USER_SETUP_FINALIZED; 386 } else { 387 // We're still in SUW, so indicate that a managed-profile was setup on current user, 388 // and that we're awaiting finalization on both. 389 newState = DevicePolicyManager.STATE_USER_PROFILE_COMPLETE; 390 newProfileState = DevicePolicyManager.STATE_USER_SETUP_COMPLETE; 391 } 392 } else if (userSetupCompleted) { 393 // User setup was previously completed this is an unexpected case. 394 ProvisionLogger.logw("user_setup_complete set, but provisioning was started"); 395 } else if (params.skipUserSetup) { 396 // DPC requested setup-wizard is skipped, indicate this to SUW. 397 newState = DevicePolicyManager.STATE_USER_SETUP_COMPLETE; 398 } else { 399 // DPC requested setup-wizard is not skipped, indicate this to SUW. 400 newState = DevicePolicyManager.STATE_USER_SETUP_INCOMPLETE; 401 } 402 403 if (newState != null) { 404 setUserProvisioningState(dpm, newState, currentUserId); 405 } 406 if (newProfileState != null) { 407 setUserProvisioningState(dpm, newProfileState, managedProfileUserId); 408 } 409 if (!userSetupCompleted) { 410 // We expect a PROVISIONING_FINALIZATION intent to finish setup if we're still in 411 // user-setup. 412 FinalizationActivity.storeProvisioningParams(context, params); 413 } 414 } 415 416 /** 417 * Finalize the current users userProvisioningState depending on the following factors: 418 * <ul> 419 * <li>We're setting up a managed-profile - need to set state on two users.</li> 420 * </ul> 421 * 422 * @param context a {@link Context} object 423 * @param params configuration for current provisioning attempt - if null (because 424 * ManagedProvisioning wasn't used for first phase of provisioning) aassumes we 425 * can just mark current user as being in finalized provisioning state 426 */ 427 // TODO: Add unit tests 428 public void markUserProvisioningStateFinalized(Context context, 429 ProvisioningParams params) { 430 int currentUserId = UserHandle.myUserId(); 431 int managedProfileUserId = -1; 432 DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class); 433 Integer newState = null; 434 Integer newProfileState = null; 435 436 if (params != null && params.provisioningAction.equals(ACTION_PROVISION_MANAGED_PROFILE)) { 437 // Managed profiles are a special case as two users are involved. 438 managedProfileUserId = getManagedProfile(context).getIdentifier(); 439 440 newState = DevicePolicyManager.STATE_USER_UNMANAGED; 441 newProfileState = DevicePolicyManager.STATE_USER_SETUP_FINALIZED; 442 } else { 443 newState = DevicePolicyManager.STATE_USER_SETUP_FINALIZED; 444 } 445 446 if (newState != null) { 447 setUserProvisioningState(dpm, newState, currentUserId); 448 } 449 if (newProfileState != null) { 450 setUserProvisioningState(dpm, newProfileState, managedProfileUserId); 451 } 452 } 453 454 private void setUserProvisioningState(DevicePolicyManager dpm, int state, int userId) { 455 ProvisionLogger.logi("Setting userProvisioningState for user " + userId + " to: " + state); 456 dpm.setUserProvisioningState(state, userId); 457 } 458 459 /** 460 * Returns the first existing managed profile if any present, null otherwise. 461 * 462 * <p>Note that we currently only support one managed profile per device. 463 */ 464 // TODO: Add unit tests 465 public UserHandle getManagedProfile(Context context) { 466 UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE); 467 int currentUserId = userManager.getUserHandle(); 468 List<UserInfo> userProfiles = userManager.getProfiles(currentUserId); 469 for (UserInfo profile : userProfiles) { 470 if (profile.isManagedProfile()) { 471 return new UserHandle(profile.id); 472 } 473 } 474 return null; 475 } 476 477 /** 478 * Returns the user id of an already existing managed profile or -1 if none exists. 479 */ 480 // TODO: Add unit tests 481 public int alreadyHasManagedProfile(Context context) { 482 UserHandle managedUser = getManagedProfile(context); 483 if (managedUser != null) { 484 return managedUser.getIdentifier(); 485 } else { 486 return -1; 487 } 488 } 489 490 /** 491 * Removes an account. 492 * 493 * <p>This removes the given account from the calling user's list of accounts. 494 * 495 * @param context a {@link Context} object 496 * @param account the account to be removed 497 */ 498 // TODO: Add unit tests 499 public void removeAccount(Context context, Account account) { 500 try { 501 AccountManager accountManager = 502 (AccountManager) context.getSystemService(Context.ACCOUNT_SERVICE); 503 AccountManagerFuture<Bundle> bundle = accountManager.removeAccount(account, 504 null, null /* callback */, null /* handler */); 505 // Block to get the result of the removeAccount operation 506 if (bundle.getResult().getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) { 507 ProvisionLogger.logw("Account removed from the primary user."); 508 } else { 509 Intent removeIntent = (Intent) bundle.getResult().getParcelable( 510 AccountManager.KEY_INTENT); 511 if (removeIntent != null) { 512 ProvisionLogger.logi("Starting activity to remove account"); 513 TrampolineActivity.startActivity(context, removeIntent); 514 } else { 515 ProvisionLogger.logw("Could not remove account from the primary user."); 516 } 517 } 518 } catch (OperationCanceledException | AuthenticatorException | IOException e) { 519 ProvisionLogger.logw("Exception removing account from the primary user.", e); 520 } 521 } 522 523 /** 524 * Copies an account to a given user. 525 * 526 * <p>Copies a given account form {@code sourceUser} to {@code targetUser}. This call is 527 * blocking until the operation has succeeded. If within a timeout the account hasn't been 528 * successfully copied to the new user, we give up. 529 * 530 * @param context a {@link Context} object 531 * @param accountToMigrate the account to be migrated 532 * @param sourceUser the {@link UserHandle} of the user to copy from 533 * @param targetUser the {@link UserHandle} of the user to copy to 534 * @return whether account migration successfully completed 535 */ 536 public boolean maybeCopyAccount(Context context, Account accountToMigrate, 537 UserHandle sourceUser, UserHandle targetUser) { 538 if (accountToMigrate == null) { 539 ProvisionLogger.logd("No account to migrate."); 540 return false; 541 } 542 if (sourceUser.equals(targetUser)) { 543 ProvisionLogger.loge("sourceUser and targetUser are the same, won't migrate account."); 544 return false; 545 } 546 ProvisionLogger.logd("Attempting to copy account from " + sourceUser + " to " + targetUser); 547 try { 548 AccountManager accountManager = 549 (AccountManager) context.getSystemService(Context.ACCOUNT_SERVICE); 550 boolean copySucceeded = accountManager.copyAccountToUser( 551 accountToMigrate, 552 sourceUser, 553 targetUser, 554 /* callback= */ null, /* handler= */ null) 555 .getResult(ACCOUNT_COPY_TIMEOUT_SECONDS, TimeUnit.SECONDS); 556 if (copySucceeded) { 557 ProvisionLogger.logi("Copied account to " + targetUser); 558 return true; 559 } else { 560 ProvisionLogger.loge("Could not copy account to " + targetUser); 561 } 562 } catch (OperationCanceledException | AuthenticatorException | IOException e) { 563 ProvisionLogger.loge("Exception copying account to " + targetUser, e); 564 } 565 return false; 566 } 567 568 /** 569 * Returns whether FRP is supported on the device. 570 */ 571 public boolean isFrpSupported(Context context) { 572 Object pdbManager = context.getSystemService(Context.PERSISTENT_DATA_BLOCK_SERVICE); 573 return pdbManager != null; 574 } 575 576 /** 577 * Translates a given managed provisioning intent to its corresponding provisioning flow, using 578 * the action from the intent. 579 * 580 * <p/>This is necessary because, unlike other provisioning actions which has 1:1 mapping, there 581 * are multiple actions that can trigger the device owner provisioning flow. This includes 582 * {@link ACTION_PROVISION_MANAGED_DEVICE}, {@link ACTION_NDEF_DISCOVERED} and 583 * {@link ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE}. These 3 actions are equivalent 584 * excepts they are sent from a different source. 585 * 586 * @return the appropriate DevicePolicyManager declared action for the given incoming intent. 587 * @throws IllegalProvisioningArgumentException if intent is malformed 588 */ 589 // TODO: Add unit tests 590 public String mapIntentToDpmAction(Intent intent) 591 throws IllegalProvisioningArgumentException { 592 if (intent == null || intent.getAction() == null) { 593 throw new IllegalProvisioningArgumentException("Null intent action."); 594 } 595 596 // Map the incoming intent to a DevicePolicyManager.ACTION_*, as there is a N:1 mapping in 597 // some cases. 598 String dpmProvisioningAction; 599 switch (intent.getAction()) { 600 // Trivial cases. 601 case ACTION_PROVISION_MANAGED_DEVICE: 602 case ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE: 603 case ACTION_PROVISION_MANAGED_USER: 604 case ACTION_PROVISION_MANAGED_PROFILE: 605 dpmProvisioningAction = intent.getAction(); 606 break; 607 608 // NFC cases which need to take mime-type into account. 609 case ACTION_NDEF_DISCOVERED: 610 String mimeType = intent.getType(); 611 switch (mimeType) { 612 case MIME_TYPE_PROVISIONING_NFC: 613 dpmProvisioningAction = ACTION_PROVISION_MANAGED_DEVICE; 614 break; 615 616 default: 617 throw new IllegalProvisioningArgumentException( 618 "Unknown NFC bump mime-type: " + mimeType); 619 } 620 break; 621 622 // Device owner provisioning from a trusted app. 623 // TODO (b/27217042): review for new management modes in split system-user model 624 case ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE: 625 dpmProvisioningAction = ACTION_PROVISION_MANAGED_DEVICE; 626 break; 627 628 default: 629 throw new IllegalProvisioningArgumentException("Unknown intent action " 630 + intent.getAction()); 631 } 632 return dpmProvisioningAction; 633 } 634 635 /** 636 * Sends an intent to trigger a factory reset. 637 */ 638 // TODO: Move the FR intent into a Globals class. 639 public void sendFactoryResetBroadcast(Context context, String reason) { 640 Intent intent = new Intent(Intent.ACTION_MASTER_CLEAR); 641 intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); 642 intent.putExtra(Intent.EXTRA_REASON, reason); 643 context.sendBroadcast(intent); 644 } 645 646 /** 647 * Returns whether the given provisioning action is a profile owner action. 648 */ 649 // TODO: Move the list of device owner actions into a Globals class. 650 public final boolean isProfileOwnerAction(String action) { 651 return action.equals(ACTION_PROVISION_MANAGED_PROFILE) 652 || action.equals(ACTION_PROVISION_MANAGED_USER); 653 } 654 655 /** 656 * Returns whether the given provisioning action is a device owner action. 657 */ 658 // TODO: Move the list of device owner actions into a Globals class. 659 public final boolean isDeviceOwnerAction(String action) { 660 return action.equals(ACTION_PROVISION_MANAGED_DEVICE) 661 || action.equals(ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE); 662 } 663 664 /** 665 * Returns whether the device currently has connectivity. 666 */ 667 public boolean isConnectedToNetwork(Context context) { 668 NetworkInfo info = getActiveNetworkInfo(context); 669 return info != null && info.isConnected(); 670 } 671 672 /** 673 * Returns whether the device is currently connected to a wifi. 674 */ 675 public boolean isConnectedToWifi(Context context) { 676 NetworkInfo info = getActiveNetworkInfo(context); 677 return info != null 678 && info.isConnected() 679 && info.getType() == ConnectivityManager.TYPE_WIFI; 680 } 681 682 private NetworkInfo getActiveNetworkInfo(Context context) { 683 ConnectivityManager cm = 684 (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); 685 if (cm != null) { 686 return cm.getActiveNetworkInfo(); 687 } 688 return null; 689 } 690 691 /** 692 * Returns whether encryption is required on this device. 693 * 694 * <p>Encryption is required if the device is not currently encrypted and the persistent 695 * system flag {@code persist.sys.no_req_encrypt} is not set. 696 */ 697 public boolean isEncryptionRequired() { 698 return !isPhysicalDeviceEncrypted() 699 && !SystemProperties.getBoolean("persist.sys.no_req_encrypt", false); 700 } 701 702 /** 703 * Returns whether the device is currently encrypted. 704 */ 705 public boolean isPhysicalDeviceEncrypted() { 706 return StorageManager.isEncrypted(); 707 } 708 709 /** 710 * Returns the wifi pick intent. 711 */ 712 // TODO: Move this intent into a Globals class. 713 public Intent getWifiPickIntent() { 714 Intent wifiIntent = new Intent(WifiManager.ACTION_PICK_WIFI_NETWORK); 715 wifiIntent.putExtra("extra_prefs_show_button_bar", true); 716 wifiIntent.putExtra("wifi_enable_next_on_connect", true); 717 return wifiIntent; 718 } 719 720 /** 721 * Returns whether the device has a split system user. 722 * 723 * <p>Split system user means that user 0 is system only and all meat users are separate from 724 * the system user. 725 */ 726 public boolean isSplitSystemUser() { 727 return UserManager.isSplitSystemUser(); 728 } 729 730 /** 731 * Returns whether the currently chosen launcher supports managed profiles. 732 * 733 * <p>A launcher is deemed to support managed profiles when its target API version is at least 734 * {@link Build.VERSION_CODES#LOLLIPOP}. 735 */ 736 public boolean currentLauncherSupportsManagedProfiles(Context context) { 737 Intent intent = new Intent(Intent.ACTION_MAIN); 738 intent.addCategory(Intent.CATEGORY_HOME); 739 740 PackageManager pm = context.getPackageManager(); 741 ResolveInfo launcherResolveInfo = pm.resolveActivity(intent, 742 PackageManager.MATCH_DEFAULT_ONLY); 743 if (launcherResolveInfo == null) { 744 return false; 745 } 746 try { 747 // If the user has not chosen a default launcher, then launcherResolveInfo will be 748 // referring to the resolver activity. It is fine to create a managed profile in 749 // this case since there will always be at least one launcher on the device that 750 // supports managed profile feature. 751 ApplicationInfo launcherAppInfo = pm.getApplicationInfo( 752 launcherResolveInfo.activityInfo.packageName, 0 /* default flags */); 753 return versionNumberAtLeastL(launcherAppInfo.targetSdkVersion); 754 } catch (PackageManager.NameNotFoundException e) { 755 return false; 756 } 757 } 758 759 /** 760 * Returns whether the given version number is at least lollipop. 761 * 762 * @param versionNumber the version number to be verified. 763 */ 764 private boolean versionNumberAtLeastL(int versionNumber) { 765 return versionNumber >= Build.VERSION_CODES.LOLLIPOP; 766 } 767 768 /** 769 * Computes the sha 256 hash of a byte array. 770 */ 771 public byte[] computeHashOfByteArray(byte[] bytes) throws NoSuchAlgorithmException { 772 MessageDigest md = MessageDigest.getInstance(SHA256_TYPE); 773 md.update(bytes); 774 return md.digest(); 775 } 776 777 /** 778 * Computes a hash of a file with a spcific hash algorithm. 779 */ 780 public byte[] computeHashOfFile(String fileLocation, String hashType) { 781 InputStream fis = null; 782 MessageDigest md; 783 byte hash[] = null; 784 try { 785 md = MessageDigest.getInstance(hashType); 786 } catch (NoSuchAlgorithmException e) { 787 ProvisionLogger.loge("Hashing algorithm " + hashType + " not supported.", e); 788 return null; 789 } 790 try { 791 fis = new FileInputStream(fileLocation); 792 793 byte[] buffer = new byte[256]; 794 int n = 0; 795 while (n != -1) { 796 n = fis.read(buffer); 797 if (n > 0) { 798 md.update(buffer, 0, n); 799 } 800 } 801 hash = md.digest(); 802 } catch (IOException e) { 803 ProvisionLogger.loge("IO error.", e); 804 } finally { 805 // Close input stream quietly. 806 try { 807 if (fis != null) { 808 fis.close(); 809 } 810 } catch (IOException e) { 811 // Ignore. 812 } 813 } 814 return hash; 815 } 816} 817