1/* 2 * Copyright (C) 2015 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.server.pm; 18 19import com.google.android.collect.Sets; 20 21import com.android.internal.util.Preconditions; 22 23import android.annotation.NonNull; 24import android.annotation.Nullable; 25import android.app.ActivityManager; 26import android.content.ContentResolver; 27import android.content.Context; 28import android.os.Binder; 29import android.os.Bundle; 30import android.os.RemoteException; 31import android.os.UserHandle; 32import android.os.UserManager; 33import android.os.UserManagerInternal; 34import android.telephony.SubscriptionInfo; 35import android.telephony.SubscriptionManager; 36import android.util.Log; 37import android.util.Slog; 38import android.util.SparseArray; 39 40import org.xmlpull.v1.XmlPullParser; 41import org.xmlpull.v1.XmlSerializer; 42 43import java.io.IOException; 44import java.io.PrintWriter; 45import java.util.List; 46import java.util.Set; 47 48/** 49 * Utility methods for user restrictions. 50 * 51 * <p>See {@link UserManagerService} for the method suffixes. 52 */ 53public class UserRestrictionsUtils { 54 private static final String TAG = "UserRestrictionsUtils"; 55 56 private UserRestrictionsUtils() { 57 } 58 59 private static Set<String> newSetWithUniqueCheck(String[] strings) { 60 final Set<String> ret = Sets.newArraySet(strings); 61 62 // Make sure there's no overlap. 63 Preconditions.checkState(ret.size() == strings.length); 64 return ret; 65 } 66 67 public static final Set<String> USER_RESTRICTIONS = newSetWithUniqueCheck(new String[] { 68 UserManager.DISALLOW_CONFIG_WIFI, 69 UserManager.DISALLOW_MODIFY_ACCOUNTS, 70 UserManager.DISALLOW_INSTALL_APPS, 71 UserManager.DISALLOW_UNINSTALL_APPS, 72 UserManager.DISALLOW_SHARE_LOCATION, 73 UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, 74 UserManager.DISALLOW_CONFIG_BLUETOOTH, 75 UserManager.DISALLOW_BLUETOOTH, 76 UserManager.DISALLOW_BLUETOOTH_SHARING, 77 UserManager.DISALLOW_USB_FILE_TRANSFER, 78 UserManager.DISALLOW_CONFIG_CREDENTIALS, 79 UserManager.DISALLOW_REMOVE_USER, 80 UserManager.DISALLOW_REMOVE_MANAGED_PROFILE, 81 UserManager.DISALLOW_DEBUGGING_FEATURES, 82 UserManager.DISALLOW_CONFIG_VPN, 83 UserManager.DISALLOW_CONFIG_TETHERING, 84 UserManager.DISALLOW_NETWORK_RESET, 85 UserManager.DISALLOW_FACTORY_RESET, 86 UserManager.DISALLOW_ADD_USER, 87 UserManager.DISALLOW_ADD_MANAGED_PROFILE, 88 UserManager.ENSURE_VERIFY_APPS, 89 UserManager.DISALLOW_CONFIG_CELL_BROADCASTS, 90 UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS, 91 UserManager.DISALLOW_APPS_CONTROL, 92 UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA, 93 UserManager.DISALLOW_UNMUTE_MICROPHONE, 94 UserManager.DISALLOW_ADJUST_VOLUME, 95 UserManager.DISALLOW_OUTGOING_CALLS, 96 UserManager.DISALLOW_SMS, 97 UserManager.DISALLOW_FUN, 98 UserManager.DISALLOW_CREATE_WINDOWS, 99 UserManager.DISALLOW_CROSS_PROFILE_COPY_PASTE, 100 UserManager.DISALLOW_OUTGOING_BEAM, 101 UserManager.DISALLOW_WALLPAPER, 102 UserManager.DISALLOW_SAFE_BOOT, 103 UserManager.ALLOW_PARENT_PROFILE_APP_LINKING, 104 UserManager.DISALLOW_RECORD_AUDIO, 105 UserManager.DISALLOW_CAMERA, 106 UserManager.DISALLOW_RUN_IN_BACKGROUND, 107 UserManager.DISALLOW_DATA_ROAMING, 108 UserManager.DISALLOW_SET_USER_ICON, 109 UserManager.DISALLOW_SET_WALLPAPER, 110 UserManager.DISALLOW_OEM_UNLOCK, 111 UserManager.DISALLOW_UNMUTE_DEVICE, 112 UserManager.DISALLOW_AUTOFILL, 113 }); 114 115 /** 116 * Set of user restriction which we don't want to persist. 117 */ 118 private static final Set<String> NON_PERSIST_USER_RESTRICTIONS = Sets.newArraySet( 119 UserManager.DISALLOW_RECORD_AUDIO 120 ); 121 122 /** 123 * User restrictions that cannot be set by profile owners of secondary users. When set by DO 124 * they will be applied to all users. 125 */ 126 private static final Set<String> PRIMARY_USER_ONLY_RESTRICTIONS = Sets.newArraySet( 127 UserManager.DISALLOW_BLUETOOTH, 128 UserManager.DISALLOW_USB_FILE_TRANSFER, 129 UserManager.DISALLOW_CONFIG_TETHERING, 130 UserManager.DISALLOW_NETWORK_RESET, 131 UserManager.DISALLOW_FACTORY_RESET, 132 UserManager.DISALLOW_ADD_USER, 133 UserManager.DISALLOW_CONFIG_CELL_BROADCASTS, 134 UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS, 135 UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA, 136 UserManager.DISALLOW_SMS, 137 UserManager.DISALLOW_FUN, 138 UserManager.DISALLOW_SAFE_BOOT, 139 UserManager.DISALLOW_CREATE_WINDOWS, 140 UserManager.DISALLOW_DATA_ROAMING 141 ); 142 143 /** 144 * User restrictions that can't be changed by device owner or profile owner. 145 */ 146 private static final Set<String> IMMUTABLE_BY_OWNERS = Sets.newArraySet( 147 UserManager.DISALLOW_RECORD_AUDIO, 148 UserManager.DISALLOW_WALLPAPER, 149 UserManager.DISALLOW_OEM_UNLOCK 150 ); 151 152 /** 153 * Special user restrictions that can be applied to a user as well as to all users globally, 154 * depending on callers. When device owner sets them, they'll be applied to all users. 155 */ 156 private static final Set<String> GLOBAL_RESTRICTIONS = Sets.newArraySet( 157 UserManager.DISALLOW_ADJUST_VOLUME, 158 UserManager.DISALLOW_BLUETOOTH_SHARING, 159 UserManager.DISALLOW_RUN_IN_BACKGROUND, 160 UserManager.DISALLOW_UNMUTE_MICROPHONE, 161 UserManager.DISALLOW_UNMUTE_DEVICE 162 ); 163 164 /** 165 * User restrictions that default to {@code true} for device owners. 166 */ 167 private static final Set<String> DEFAULT_ENABLED_FOR_DEVICE_OWNERS = Sets.newArraySet( 168 UserManager.DISALLOW_ADD_MANAGED_PROFILE 169 ); 170 171 /** 172 * User restrictions that default to {@code true} for managed profile owners. 173 * 174 * NB: {@link UserManager#DISALLOW_INSTALL_UNKNOWN_SOURCES} is also set by default but it is 175 * not set to existing profile owners unless they used to have INSTALL_NON_MARKET_APPS disabled 176 * in settings. So it is handled separately. 177 */ 178 private static final Set<String> DEFAULT_ENABLED_FOR_MANAGED_PROFILES = Sets.newArraySet( 179 UserManager.DISALLOW_BLUETOOTH_SHARING 180 ); 181 182 /* 183 * Special user restrictions that are always applied to all users no matter who sets them. 184 */ 185 private static final Set<String> PROFILE_GLOBAL_RESTRICTIONS = Sets.newArraySet( 186 UserManager.ENSURE_VERIFY_APPS 187 ); 188 189 /** 190 * Throws {@link IllegalArgumentException} if the given restriction name is invalid. 191 */ 192 public static boolean isValidRestriction(@NonNull String restriction) { 193 if (!USER_RESTRICTIONS.contains(restriction)) { 194 Slog.e(TAG, "Unknown restriction: " + restriction); 195 return false; 196 } 197 return true; 198 } 199 200 public static void writeRestrictions(@NonNull XmlSerializer serializer, 201 @Nullable Bundle restrictions, @NonNull String tag) throws IOException { 202 if (restrictions == null) { 203 return; 204 } 205 206 serializer.startTag(null, tag); 207 for (String key : restrictions.keySet()) { 208 if (NON_PERSIST_USER_RESTRICTIONS.contains(key)) { 209 continue; // Don't persist. 210 } 211 if (USER_RESTRICTIONS.contains(key)) { 212 if (restrictions.getBoolean(key)) { 213 serializer.attribute(null, key, "true"); 214 } 215 continue; 216 } 217 Log.w(TAG, "Unknown user restriction detected: " + key); 218 } 219 serializer.endTag(null, tag); 220 } 221 222 public static void readRestrictions(XmlPullParser parser, Bundle restrictions) { 223 restrictions.clear(); 224 for (String key : USER_RESTRICTIONS) { 225 final String value = parser.getAttributeValue(null, key); 226 if (value != null) { 227 restrictions.putBoolean(key, Boolean.parseBoolean(value)); 228 } 229 } 230 } 231 232 public static Bundle readRestrictions(XmlPullParser parser) { 233 final Bundle result = new Bundle(); 234 readRestrictions(parser, result); 235 return result; 236 } 237 238 /** 239 * @return {@code in} itself when it's not null, or an empty bundle (which can writable). 240 */ 241 public static Bundle nonNull(@Nullable Bundle in) { 242 return in != null ? in : new Bundle(); 243 } 244 245 public static boolean isEmpty(@Nullable Bundle in) { 246 return (in == null) || (in.size() == 0); 247 } 248 249 /** 250 * Returns {@code true} if given bundle is not null and contains {@code true} for a given 251 * restriction. 252 */ 253 public static boolean contains(@Nullable Bundle in, String restriction) { 254 return in != null && in.getBoolean(restriction); 255 } 256 257 /** 258 * Creates a copy of the {@code in} Bundle. If {@code in} is null, it'll return an empty 259 * bundle. 260 * 261 * <p>The resulting {@link Bundle} is always writable. (i.e. it won't return 262 * {@link Bundle#EMPTY}) 263 */ 264 public static @NonNull Bundle clone(@Nullable Bundle in) { 265 return (in != null) ? new Bundle(in) : new Bundle(); 266 } 267 268 public static void merge(@NonNull Bundle dest, @Nullable Bundle in) { 269 Preconditions.checkNotNull(dest); 270 Preconditions.checkArgument(dest != in); 271 if (in == null) { 272 return; 273 } 274 for (String key : in.keySet()) { 275 if (in.getBoolean(key, false)) { 276 dest.putBoolean(key, true); 277 } 278 } 279 } 280 281 /** 282 * Merges a sparse array of restrictions bundles into one. 283 */ 284 @Nullable 285 public static Bundle mergeAll(SparseArray<Bundle> restrictions) { 286 if (restrictions.size() == 0) { 287 return null; 288 } else { 289 final Bundle result = new Bundle(); 290 for (int i = 0; i < restrictions.size(); i++) { 291 merge(result, restrictions.valueAt(i)); 292 } 293 return result; 294 } 295 } 296 297 /** 298 * @return true if a restriction is settable by device owner. 299 */ 300 public static boolean canDeviceOwnerChange(String restriction) { 301 return !IMMUTABLE_BY_OWNERS.contains(restriction); 302 } 303 304 /** 305 * @return true if a restriction is settable by profile owner. Note it takes a user ID because 306 * some restrictions can be changed by PO only when it's running on the system user. 307 */ 308 public static boolean canProfileOwnerChange(String restriction, int userId) { 309 return !IMMUTABLE_BY_OWNERS.contains(restriction) 310 && !(userId != UserHandle.USER_SYSTEM 311 && PRIMARY_USER_ONLY_RESTRICTIONS.contains(restriction)); 312 } 313 314 /** 315 * Returns the user restrictions that default to {@code true} for device owners. 316 * These user restrictions are local, though. ie only for the device owner's user id. 317 */ 318 public static @NonNull Set<String> getDefaultEnabledForDeviceOwner() { 319 return DEFAULT_ENABLED_FOR_DEVICE_OWNERS; 320 } 321 322 /** 323 * Returns the user restrictions that default to {@code true} for managed profile owners. 324 */ 325 public static @NonNull Set<String> getDefaultEnabledForManagedProfiles() { 326 return DEFAULT_ENABLED_FOR_MANAGED_PROFILES; 327 } 328 329 /** 330 * Takes restrictions that can be set by device owner, and sort them into what should be applied 331 * globally and what should be applied only on the current user. 332 */ 333 public static void sortToGlobalAndLocal(@Nullable Bundle in, boolean isDeviceOwner, 334 int cameraRestrictionScope, 335 @NonNull Bundle global, @NonNull Bundle local) { 336 // Camera restriction (as well as all others) goes to at most one bundle. 337 if (cameraRestrictionScope == UserManagerInternal.CAMERA_DISABLED_GLOBALLY) { 338 global.putBoolean(UserManager.DISALLOW_CAMERA, true); 339 } else if (cameraRestrictionScope == UserManagerInternal.CAMERA_DISABLED_LOCALLY) { 340 local.putBoolean(UserManager.DISALLOW_CAMERA, true); 341 } 342 if (in == null || in.size() == 0) { 343 return; 344 } 345 for (String key : in.keySet()) { 346 if (!in.getBoolean(key)) { 347 continue; 348 } 349 if (isGlobal(isDeviceOwner, key)) { 350 global.putBoolean(key, true); 351 } else { 352 local.putBoolean(key, true); 353 } 354 } 355 } 356 357 /** 358 * Whether given user restriction should be enforced globally. 359 */ 360 private static boolean isGlobal(boolean isDeviceOwner, String key) { 361 return (isDeviceOwner && 362 (PRIMARY_USER_ONLY_RESTRICTIONS.contains(key)|| GLOBAL_RESTRICTIONS.contains(key))) 363 || PROFILE_GLOBAL_RESTRICTIONS.contains(key); 364 } 365 366 /** 367 * @return true if two Bundles contain the same user restriction. 368 * A null bundle and an empty bundle are considered to be equal. 369 */ 370 public static boolean areEqual(@Nullable Bundle a, @Nullable Bundle b) { 371 if (a == b) { 372 return true; 373 } 374 if (isEmpty(a)) { 375 return isEmpty(b); 376 } 377 if (isEmpty(b)) { 378 return false; 379 } 380 for (String key : a.keySet()) { 381 if (a.getBoolean(key) != b.getBoolean(key)) { 382 return false; 383 } 384 } 385 for (String key : b.keySet()) { 386 if (a.getBoolean(key) != b.getBoolean(key)) { 387 return false; 388 } 389 } 390 return true; 391 } 392 393 /** 394 * Takes a new use restriction set and the previous set, and apply the restrictions that have 395 * changed. 396 * 397 * <p>Note this method is called by {@link UserManagerService} without holding any locks. 398 */ 399 public static void applyUserRestrictions(Context context, int userId, 400 Bundle newRestrictions, Bundle prevRestrictions) { 401 for (String key : USER_RESTRICTIONS) { 402 final boolean newValue = newRestrictions.getBoolean(key); 403 final boolean prevValue = prevRestrictions.getBoolean(key); 404 405 if (newValue != prevValue) { 406 applyUserRestriction(context, userId, key, newValue); 407 } 408 } 409 } 410 411 /** 412 * Apply each user restriction. 413 * 414 * <p>See also {@link 415 * com.android.providers.settings.SettingsProvider#isGlobalOrSecureSettingRestrictedForUser}, 416 * which should be in sync with this method. 417 */ 418 private static void applyUserRestriction(Context context, int userId, String key, 419 boolean newValue) { 420 if (UserManagerService.DBG) { 421 Log.d(TAG, "Applying user restriction: userId=" + userId 422 + " key=" + key + " value=" + newValue); 423 } 424 // When certain restrictions are cleared, we don't update the system settings, 425 // because these settings are changeable on the Settings UI and we don't know the original 426 // value -- for example LOCATION_MODE might have been off already when the restriction was 427 // set, and in that case even if the restriction is lifted, changing it to ON would be 428 // wrong. So just don't do anything in such a case. If the user hopes to enable location 429 // later, they can do it on the Settings UI. 430 // WARNING: Remember that Settings.Global and Settings.Secure are changeable via adb. 431 // To prevent this from happening for a given user restriction, you have to add a check to 432 // SettingsProvider.isGlobalOrSecureSettingRestrictedForUser. 433 434 final ContentResolver cr = context.getContentResolver(); 435 final long id = Binder.clearCallingIdentity(); 436 try { 437 switch (key) { 438 case UserManager.DISALLOW_DATA_ROAMING: 439 if (newValue) { 440 // DISALLOW_DATA_ROAMING user restriction is set. 441 442 // Multi sim device. 443 SubscriptionManager subscriptionManager = new SubscriptionManager(context); 444 final List<SubscriptionInfo> subscriptionInfoList = 445 subscriptionManager.getActiveSubscriptionInfoList(); 446 if (subscriptionInfoList != null) { 447 for (SubscriptionInfo subInfo : subscriptionInfoList) { 448 android.provider.Settings.Global.putStringForUser(cr, 449 android.provider.Settings.Global.DATA_ROAMING 450 + subInfo.getSubscriptionId(), "0", userId); 451 } 452 } 453 454 // Single sim device. 455 android.provider.Settings.Global.putStringForUser(cr, 456 android.provider.Settings.Global.DATA_ROAMING, "0", userId); 457 } 458 break; 459 case UserManager.DISALLOW_SHARE_LOCATION: 460 if (newValue) { 461 android.provider.Settings.Secure.putIntForUser(cr, 462 android.provider.Settings.Secure.LOCATION_MODE, 463 android.provider.Settings.Secure.LOCATION_MODE_OFF, 464 userId); 465 } 466 break; 467 case UserManager.DISALLOW_DEBUGGING_FEATURES: 468 if (newValue) { 469 // Only disable adb if changing for system user, since it is global 470 // TODO: should this be admin user? 471 if (userId == UserHandle.USER_SYSTEM) { 472 android.provider.Settings.Global.putStringForUser(cr, 473 android.provider.Settings.Global.ADB_ENABLED, "0", 474 userId); 475 } 476 } 477 break; 478 case UserManager.ENSURE_VERIFY_APPS: 479 if (newValue) { 480 android.provider.Settings.Global.putStringForUser( 481 context.getContentResolver(), 482 android.provider.Settings.Global.PACKAGE_VERIFIER_ENABLE, "1", 483 userId); 484 android.provider.Settings.Global.putStringForUser( 485 context.getContentResolver(), 486 android.provider.Settings.Global.PACKAGE_VERIFIER_INCLUDE_ADB, "1", 487 userId); 488 } 489 break; 490 case UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES: 491 // Since Android O, the secure setting is not available to be changed by the 492 // user. Hence, when the restriction is cleared, we need to reset the state of 493 // the setting to its default value which is now 1. 494 android.provider.Settings.Secure.putIntForUser(cr, 495 android.provider.Settings.Secure.INSTALL_NON_MARKET_APPS, 496 newValue ? 0 : 1, userId); 497 break; 498 case UserManager.DISALLOW_RUN_IN_BACKGROUND: 499 if (newValue) { 500 int currentUser = ActivityManager.getCurrentUser(); 501 if (currentUser != userId && userId != UserHandle.USER_SYSTEM) { 502 try { 503 ActivityManager.getService().stopUser(userId, false, null); 504 } catch (RemoteException e) { 505 throw e.rethrowAsRuntimeException(); 506 } 507 } 508 } 509 break; 510 case UserManager.DISALLOW_SAFE_BOOT: 511 // Unlike with the other restrictions, we want to propagate the new value to 512 // the system settings even if it is false. The other restrictions modify 513 // settings which could be manually changed by the user from the Settings app 514 // after the policies enforcing these restrictions have been revoked, so we 515 // leave re-setting of those settings to the user. 516 android.provider.Settings.Global.putInt( 517 context.getContentResolver(), 518 android.provider.Settings.Global.SAFE_BOOT_DISALLOWED, 519 newValue ? 1 : 0); 520 break; 521 } 522 } finally { 523 Binder.restoreCallingIdentity(id); 524 } 525 } 526 527 public static void dumpRestrictions(PrintWriter pw, String prefix, Bundle restrictions) { 528 boolean noneSet = true; 529 if (restrictions != null) { 530 for (String key : restrictions.keySet()) { 531 if (restrictions.getBoolean(key, false)) { 532 pw.println(prefix + key); 533 noneSet = false; 534 } 535 } 536 if (noneSet) { 537 pw.println(prefix + "none"); 538 } 539 } else { 540 pw.println(prefix + "null"); 541 } 542 } 543 544 /** 545 * Moves a particular restriction from one array of bundles to another, e.g. for all users. 546 */ 547 public static void moveRestriction(String restrictionKey, SparseArray<Bundle> srcRestrictions, 548 SparseArray<Bundle> destRestrictions) { 549 for (int i = 0; i < srcRestrictions.size(); i++) { 550 final int key = srcRestrictions.keyAt(i); 551 final Bundle from = srcRestrictions.valueAt(i); 552 if (contains(from, restrictionKey)) { 553 from.remove(restrictionKey); 554 Bundle to = destRestrictions.get(key); 555 if (to == null) { 556 to = new Bundle(); 557 destRestrictions.append(key, to); 558 } 559 to.putBoolean(restrictionKey, true); 560 // Don't keep empty bundles. 561 if (from.isEmpty()) { 562 srcRestrictions.removeAt(i); 563 i--; 564 } 565 } 566 } 567 } 568 569 /** 570 * Returns whether restrictions differ between two bundles. 571 * @param oldRestrictions old bundle of restrictions. 572 * @param newRestrictions new bundle of restrictions 573 * @param restrictions restrictions of interest, if empty, all restrictions are checked. 574 */ 575 public static boolean restrictionsChanged(Bundle oldRestrictions, Bundle newRestrictions, 576 String... restrictions) { 577 if (restrictions.length == 0) { 578 return areEqual(oldRestrictions, newRestrictions); 579 } 580 for (final String restriction : restrictions) { 581 if (oldRestrictions.getBoolean(restriction, false) != 582 newRestrictions.getBoolean(restriction, false)) { 583 return true; 584 } 585 } 586 return false; 587 } 588} 589