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