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