UserRestrictionsUtils.java revision 6c9116a6430ca5cd55b1b926213a5e8de77e4fc6
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.service.persistentdata.PersistentDataBlockManager; 34import android.telephony.SubscriptionInfo; 35import android.telephony.SubscriptionManager; 36import android.util.Log; 37import android.util.Slog; 38 39import org.xmlpull.v1.XmlPullParser; 40import org.xmlpull.v1.XmlSerializer; 41 42import java.io.IOException; 43import java.io.PrintWriter; 44import java.util.List; 45import java.util.Set; 46 47/** 48 * Utility methods for user restrictions. 49 * 50 * <p>See {@link UserManagerService} for the method suffixes. 51 */ 52public class UserRestrictionsUtils { 53 private static final String TAG = "UserRestrictionsUtils"; 54 55 private UserRestrictionsUtils() { 56 } 57 58 private static Set<String> newSetWithUniqueCheck(String[] strings) { 59 final Set<String> ret = Sets.newArraySet(strings); 60 61 // Make sure there's no overlap. 62 Preconditions.checkState(ret.size() == strings.length); 63 return ret; 64 } 65 66 public static final Set<String> USER_RESTRICTIONS = newSetWithUniqueCheck(new String[] { 67 UserManager.DISALLOW_CONFIG_WIFI, 68 UserManager.DISALLOW_MODIFY_ACCOUNTS, 69 UserManager.DISALLOW_INSTALL_APPS, 70 UserManager.DISALLOW_UNINSTALL_APPS, 71 UserManager.DISALLOW_SHARE_LOCATION, 72 UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, 73 UserManager.DISALLOW_CONFIG_BLUETOOTH, 74 UserManager.DISALLOW_BLUETOOTH, 75 UserManager.DISALLOW_USB_FILE_TRANSFER, 76 UserManager.DISALLOW_CONFIG_CREDENTIALS, 77 UserManager.DISALLOW_REMOVE_USER, 78 UserManager.DISALLOW_REMOVE_MANAGED_PROFILE, 79 UserManager.DISALLOW_DEBUGGING_FEATURES, 80 UserManager.DISALLOW_CONFIG_VPN, 81 UserManager.DISALLOW_CONFIG_TETHERING, 82 UserManager.DISALLOW_NETWORK_RESET, 83 UserManager.DISALLOW_FACTORY_RESET, 84 UserManager.DISALLOW_ADD_USER, 85 UserManager.DISALLOW_ADD_MANAGED_PROFILE, 86 UserManager.ENSURE_VERIFY_APPS, 87 UserManager.DISALLOW_CONFIG_CELL_BROADCASTS, 88 UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS, 89 UserManager.DISALLOW_APPS_CONTROL, 90 UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA, 91 UserManager.DISALLOW_UNMUTE_MICROPHONE, 92 UserManager.DISALLOW_ADJUST_VOLUME, 93 UserManager.DISALLOW_OUTGOING_CALLS, 94 UserManager.DISALLOW_SMS, 95 UserManager.DISALLOW_FUN, 96 UserManager.DISALLOW_CREATE_WINDOWS, 97 UserManager.DISALLOW_CROSS_PROFILE_COPY_PASTE, 98 UserManager.DISALLOW_OUTGOING_BEAM, 99 UserManager.DISALLOW_WALLPAPER, 100 UserManager.DISALLOW_SAFE_BOOT, 101 UserManager.ALLOW_PARENT_PROFILE_APP_LINKING, 102 UserManager.DISALLOW_RECORD_AUDIO, 103 UserManager.DISALLOW_CAMERA, 104 UserManager.DISALLOW_RUN_IN_BACKGROUND, 105 UserManager.DISALLOW_DATA_ROAMING, 106 UserManager.DISALLOW_SET_USER_ICON, 107 UserManager.DISALLOW_SET_WALLPAPER, 108 UserManager.DISALLOW_OEM_UNLOCK, 109 UserManager.DISALLLOW_UNMUTE_DEVICE, 110 }); 111 112 /** 113 * Set of user restriction which we don't want to persist. 114 */ 115 private static final Set<String> NON_PERSIST_USER_RESTRICTIONS = Sets.newArraySet( 116 UserManager.DISALLOW_RECORD_AUDIO 117 ); 118 119 /** 120 * User restrictions that can not be set by profile owners. 121 */ 122 private static final Set<String> DEVICE_OWNER_ONLY_RESTRICTIONS = Sets.newArraySet( 123 UserManager.DISALLOW_BLUETOOTH, 124 UserManager.DISALLOW_USB_FILE_TRANSFER, 125 UserManager.DISALLOW_CONFIG_TETHERING, 126 UserManager.DISALLOW_NETWORK_RESET, 127 UserManager.DISALLOW_FACTORY_RESET, 128 UserManager.DISALLOW_ADD_USER, 129 UserManager.DISALLOW_ADD_MANAGED_PROFILE, 130 UserManager.DISALLOW_REMOVE_MANAGED_PROFILE, 131 UserManager.DISALLOW_CONFIG_CELL_BROADCASTS, 132 UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS, 133 UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA, 134 UserManager.DISALLOW_SMS, 135 UserManager.DISALLOW_FUN, 136 UserManager.DISALLOW_SAFE_BOOT, 137 UserManager.DISALLOW_CREATE_WINDOWS, 138 UserManager.DISALLOW_DATA_ROAMING 139 ); 140 141 /** 142 * User restrictions that can't be changed by device owner or profile owner. 143 */ 144 private static final Set<String> IMMUTABLE_BY_OWNERS = Sets.newArraySet( 145 UserManager.DISALLOW_RECORD_AUDIO, 146 UserManager.DISALLOW_WALLPAPER, 147 UserManager.DISALLOW_OEM_UNLOCK 148 ); 149 150 /** 151 * Special user restrictions that can be applied to a user as well as to all users globally, 152 * depending on callers. When device owner sets them, they'll be applied to all users. 153 */ 154 private static final Set<String> GLOBAL_RESTRICTIONS = Sets.newArraySet( 155 UserManager.DISALLOW_ADJUST_VOLUME, 156 UserManager.DISALLOW_RUN_IN_BACKGROUND, 157 UserManager.DISALLOW_UNMUTE_MICROPHONE, 158 UserManager.DISALLLOW_UNMUTE_DEVICE 159 ); 160 161 /** 162 * User restrictions that default to {@code true} for device owners. 163 */ 164 private static final Set<String> DEFAULT_ENABLED_FOR_DEVICE_OWNERS = Sets.newArraySet( 165 UserManager.DISALLOW_ADD_MANAGED_PROFILE 166 ); 167 168 /** 169 * Throws {@link IllegalArgumentException} if the given restriction name is invalid. 170 */ 171 public static boolean isValidRestriction(@NonNull String restriction) { 172 if (!USER_RESTRICTIONS.contains(restriction)) { 173 Slog.e(TAG, "Unknown restriction: " + restriction); 174 return false; 175 } 176 return true; 177 } 178 179 public static void writeRestrictions(@NonNull XmlSerializer serializer, 180 @Nullable Bundle restrictions, @NonNull String tag) throws IOException { 181 if (restrictions == null) { 182 return; 183 } 184 185 serializer.startTag(null, tag); 186 for (String key : restrictions.keySet()) { 187 if (NON_PERSIST_USER_RESTRICTIONS.contains(key)) { 188 continue; // Don't persist. 189 } 190 if (USER_RESTRICTIONS.contains(key)) { 191 if (restrictions.getBoolean(key)) { 192 serializer.attribute(null, key, "true"); 193 } 194 continue; 195 } 196 Log.w(TAG, "Unknown user restriction detected: " + key); 197 } 198 serializer.endTag(null, tag); 199 } 200 201 public static void readRestrictions(XmlPullParser parser, Bundle restrictions) { 202 for (String key : USER_RESTRICTIONS) { 203 final String value = parser.getAttributeValue(null, key); 204 if (value != null) { 205 restrictions.putBoolean(key, Boolean.parseBoolean(value)); 206 } 207 } 208 } 209 210 /** 211 * @return {@code in} itself when it's not null, or an empty bundle (which can writable). 212 */ 213 public static Bundle nonNull(@Nullable Bundle in) { 214 return in != null ? in : new Bundle(); 215 } 216 217 public static boolean isEmpty(@Nullable Bundle in) { 218 return (in == null) || (in.size() == 0); 219 } 220 221 /** 222 * Creates a copy of the {@code in} Bundle. If {@code in} is null, it'll return an empty 223 * bundle. 224 * 225 * <p>The resulting {@link Bundle} is always writable. (i.e. it won't return 226 * {@link Bundle#EMPTY}) 227 */ 228 public static @NonNull Bundle clone(@Nullable Bundle in) { 229 return (in != null) ? new Bundle(in) : new Bundle(); 230 } 231 232 public static void merge(@NonNull Bundle dest, @Nullable Bundle in) { 233 Preconditions.checkNotNull(dest); 234 Preconditions.checkArgument(dest != in); 235 if (in == null) { 236 return; 237 } 238 for (String key : in.keySet()) { 239 if (in.getBoolean(key, false)) { 240 dest.putBoolean(key, true); 241 } 242 } 243 } 244 245 /** 246 * @return true if a restriction is settable by device owner. 247 */ 248 public static boolean canDeviceOwnerChange(String restriction) { 249 return !IMMUTABLE_BY_OWNERS.contains(restriction); 250 } 251 252 /** 253 * @return true if a restriction is settable by profile owner. Note it takes a user ID because 254 * some restrictions can be changed by PO only when it's running on the system user. 255 */ 256 public static boolean canProfileOwnerChange(String restriction, int userId) { 257 return !IMMUTABLE_BY_OWNERS.contains(restriction) 258 && !(userId != UserHandle.USER_SYSTEM 259 && DEVICE_OWNER_ONLY_RESTRICTIONS.contains(restriction)); 260 } 261 262 /** 263 * Returns the user restrictions that default to {@code true} for device owners. 264 */ 265 public static @NonNull Set<String> getDefaultEnabledForDeviceOwner() { 266 return DEFAULT_ENABLED_FOR_DEVICE_OWNERS; 267 } 268 269 /** 270 * Takes restrictions that can be set by device owner, and sort them into what should be applied 271 * globally and what should be applied only on the current user. 272 */ 273 public static void sortToGlobalAndLocal(@Nullable Bundle in, @NonNull Bundle global, 274 @NonNull Bundle local) { 275 if (in == null || in.size() == 0) { 276 return; 277 } 278 for (String key : in.keySet()) { 279 if (!in.getBoolean(key)) { 280 continue; 281 } 282 if (DEVICE_OWNER_ONLY_RESTRICTIONS.contains(key) || GLOBAL_RESTRICTIONS.contains(key)) { 283 global.putBoolean(key, true); 284 } else { 285 local.putBoolean(key, true); 286 } 287 } 288 } 289 290 /** 291 * @return true if two Bundles contain the same user restriction. 292 * A null bundle and an empty bundle are considered to be equal. 293 */ 294 public static boolean areEqual(@Nullable Bundle a, @Nullable Bundle b) { 295 if (a == b) { 296 return true; 297 } 298 if (isEmpty(a)) { 299 return isEmpty(b); 300 } 301 if (isEmpty(b)) { 302 return false; 303 } 304 for (String key : a.keySet()) { 305 if (a.getBoolean(key) != b.getBoolean(key)) { 306 return false; 307 } 308 } 309 for (String key : b.keySet()) { 310 if (a.getBoolean(key) != b.getBoolean(key)) { 311 return false; 312 } 313 } 314 return true; 315 } 316 317 /** 318 * Takes a new use restriction set and the previous set, and apply the restrictions that have 319 * changed. 320 * 321 * <p>Note this method is called by {@link UserManagerService} without holding any locks. 322 */ 323 public static void applyUserRestrictions(Context context, int userId, 324 Bundle newRestrictions, Bundle prevRestrictions) { 325 for (String key : USER_RESTRICTIONS) { 326 final boolean newValue = newRestrictions.getBoolean(key); 327 final boolean prevValue = prevRestrictions.getBoolean(key); 328 329 if (newValue != prevValue) { 330 applyUserRestriction(context, userId, key, newValue); 331 } 332 } 333 } 334 335 /** 336 * Apply each user restriction. 337 * 338 * <p>See also {@link 339 * com.android.providers.settings.SettingsProvider#isGlobalOrSecureSettingRestrictedForUser}, 340 * which should be in sync with this method. 341 */ 342 private static void applyUserRestriction(Context context, int userId, String key, 343 boolean newValue) { 344 if (UserManagerService.DBG) { 345 Log.d(TAG, "Applying user restriction: userId=" + userId 346 + " key=" + key + " value=" + newValue); 347 } 348 // When certain restrictions are cleared, we don't update the system settings, 349 // because these settings are changeable on the Settings UI and we don't know the original 350 // value -- for example LOCATION_MODE might have been off already when the restriction was 351 // set, and in that case even if the restriction is lifted, changing it to ON would be 352 // wrong. So just don't do anything in such a case. If the user hopes to enable location 353 // later, they can do it on the Settings UI. 354 // WARNING: Remember that Settings.Global and Settings.Secure are changeable via adb. 355 // To prevent this from happening for a given user restriction, you have to add a check to 356 // SettingsProvider.isGlobalOrSecureSettingRestrictedForUser. 357 358 final ContentResolver cr = context.getContentResolver(); 359 final long id = Binder.clearCallingIdentity(); 360 try { 361 switch (key) { 362 case UserManager.DISALLOW_CONFIG_WIFI: 363 if (newValue) { 364 android.provider.Settings.Secure.putIntForUser(cr, 365 android.provider.Settings.Global 366 .WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 0, userId); 367 } 368 break; 369 case UserManager.DISALLOW_DATA_ROAMING: 370 if (newValue) { 371 // DISALLOW_DATA_ROAMING user restriction is set. 372 373 // Multi sim device. 374 SubscriptionManager subscriptionManager = new SubscriptionManager(context); 375 final List<SubscriptionInfo> subscriptionInfoList = 376 subscriptionManager.getActiveSubscriptionInfoList(); 377 if (subscriptionInfoList != null) { 378 for (SubscriptionInfo subInfo : subscriptionInfoList) { 379 android.provider.Settings.Global.putStringForUser(cr, 380 android.provider.Settings.Global.DATA_ROAMING 381 + subInfo.getSubscriptionId(), "0", userId); 382 } 383 } 384 385 // Single sim device. 386 android.provider.Settings.Global.putStringForUser(cr, 387 android.provider.Settings.Global.DATA_ROAMING, "0", userId); 388 } 389 break; 390 case UserManager.DISALLOW_SHARE_LOCATION: 391 if (newValue) { 392 android.provider.Settings.Secure.putIntForUser(cr, 393 android.provider.Settings.Secure.LOCATION_MODE, 394 android.provider.Settings.Secure.LOCATION_MODE_OFF, 395 userId); 396 } 397 break; 398 case UserManager.DISALLOW_DEBUGGING_FEATURES: 399 if (newValue) { 400 // Only disable adb if changing for system user, since it is global 401 // TODO: should this be admin user? 402 if (userId == UserHandle.USER_SYSTEM) { 403 android.provider.Settings.Global.putStringForUser(cr, 404 android.provider.Settings.Global.ADB_ENABLED, "0", 405 userId); 406 } 407 } 408 break; 409 case UserManager.ENSURE_VERIFY_APPS: 410 if (newValue) { 411 android.provider.Settings.Global.putStringForUser( 412 context.getContentResolver(), 413 android.provider.Settings.Global.PACKAGE_VERIFIER_ENABLE, "1", 414 userId); 415 android.provider.Settings.Global.putStringForUser( 416 context.getContentResolver(), 417 android.provider.Settings.Global.PACKAGE_VERIFIER_INCLUDE_ADB, "1", 418 userId); 419 } 420 break; 421 case UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES: 422 if (newValue) { 423 android.provider.Settings.Secure.putIntForUser(cr, 424 android.provider.Settings.Secure.INSTALL_NON_MARKET_APPS, 0, 425 userId); 426 } 427 break; 428 case UserManager.DISALLOW_RUN_IN_BACKGROUND: 429 if (newValue) { 430 int currentUser = ActivityManager.getCurrentUser(); 431 if (currentUser != userId && userId != UserHandle.USER_SYSTEM) { 432 try { 433 ActivityManager.getService().stopUser(userId, false, null); 434 } catch (RemoteException e) { 435 throw e.rethrowAsRuntimeException(); 436 } 437 } 438 } 439 break; 440 case UserManager.DISALLOW_SAFE_BOOT: 441 // Unlike with the other restrictions, we want to propagate the new value to 442 // the system settings even if it is false. The other restrictions modify 443 // settings which could be manually changed by the user from the Settings app 444 // after the policies enforcing these restrictions have been revoked, so we 445 // leave re-setting of those settings to the user. 446 android.provider.Settings.Global.putInt( 447 context.getContentResolver(), 448 android.provider.Settings.Global.SAFE_BOOT_DISALLOWED, 449 newValue ? 1 : 0); 450 break; 451 case UserManager.DISALLOW_FACTORY_RESET: 452 case UserManager.DISALLOW_OEM_UNLOCK: 453 if (newValue) { 454 PersistentDataBlockManager manager = (PersistentDataBlockManager) context 455 .getSystemService(Context.PERSISTENT_DATA_BLOCK_SERVICE); 456 if (manager != null 457 && manager.getOemUnlockEnabled() 458 && manager.getFlashLockState() 459 != PersistentDataBlockManager.FLASH_LOCK_UNLOCKED) { 460 // Only disable OEM unlock if the bootloader is locked. If it's already 461 // unlocked, setting the OEM unlock enabled flag to false has no effect 462 // (the bootloader would remain unlocked). 463 manager.setOemUnlockEnabled(false); 464 } 465 } 466 break; 467 } 468 } finally { 469 Binder.restoreCallingIdentity(id); 470 } 471 } 472 473 public static void dumpRestrictions(PrintWriter pw, String prefix, Bundle restrictions) { 474 boolean noneSet = true; 475 if (restrictions != null) { 476 for (String key : restrictions.keySet()) { 477 if (restrictions.getBoolean(key, false)) { 478 pw.println(prefix + key); 479 noneSet = false; 480 } 481 } 482 if (noneSet) { 483 pw.println(prefix + "none"); 484 } 485 } else { 486 pw.println(prefix + "null"); 487 } 488 } 489} 490