UserRestrictionsUtils.java revision ac65e1e1dba1cf0ea237a389220ec818ade07a16
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.content.ContentResolver; 26import android.content.Context; 27import android.net.Uri; 28import android.os.Binder; 29import android.os.Bundle; 30import android.os.SystemProperties; 31import android.os.UserHandle; 32import android.os.UserManager; 33import android.util.Log; 34 35import org.xmlpull.v1.XmlPullParser; 36import org.xmlpull.v1.XmlSerializer; 37 38import java.io.IOException; 39import java.io.PrintWriter; 40import java.util.Set; 41 42/** 43 * Utility methods for uesr restrictions. 44 * 45 * <p>See {@link UserManagerService} for the method suffixes. 46 */ 47public class UserRestrictionsUtils { 48 private static final String TAG = "UserRestrictionsUtils"; 49 50 private UserRestrictionsUtils() { 51 } 52 53 public static final Set<String> USER_RESTRICTIONS = Sets.newArraySet( 54 UserManager.DISALLOW_CONFIG_WIFI, 55 UserManager.DISALLOW_MODIFY_ACCOUNTS, 56 UserManager.DISALLOW_INSTALL_APPS, 57 UserManager.DISALLOW_UNINSTALL_APPS, 58 UserManager.DISALLOW_SHARE_LOCATION, 59 UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, 60 UserManager.DISALLOW_CONFIG_BLUETOOTH, 61 UserManager.DISALLOW_USB_FILE_TRANSFER, 62 UserManager.DISALLOW_CONFIG_CREDENTIALS, 63 UserManager.DISALLOW_REMOVE_USER, 64 UserManager.DISALLOW_DEBUGGING_FEATURES, 65 UserManager.DISALLOW_CONFIG_VPN, 66 UserManager.DISALLOW_CONFIG_TETHERING, 67 UserManager.DISALLOW_NETWORK_RESET, 68 UserManager.DISALLOW_FACTORY_RESET, 69 UserManager.DISALLOW_ADD_USER, 70 UserManager.ENSURE_VERIFY_APPS, 71 UserManager.DISALLOW_CONFIG_CELL_BROADCASTS, 72 UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS, 73 UserManager.DISALLOW_APPS_CONTROL, 74 UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA, 75 UserManager.DISALLOW_UNMUTE_MICROPHONE, 76 UserManager.DISALLOW_ADJUST_VOLUME, 77 UserManager.DISALLOW_OUTGOING_CALLS, 78 UserManager.DISALLOW_SMS, 79 UserManager.DISALLOW_FUN, 80 UserManager.DISALLOW_CREATE_WINDOWS, 81 UserManager.DISALLOW_CROSS_PROFILE_COPY_PASTE, 82 UserManager.DISALLOW_OUTGOING_BEAM, 83 UserManager.DISALLOW_WALLPAPER, 84 UserManager.DISALLOW_SAFE_BOOT, 85 UserManager.ALLOW_PARENT_PROFILE_APP_LINKING, 86 UserManager.DISALLOW_RECORD_AUDIO, 87 UserManager.DISALLOW_CAMERA 88 ); 89 90 /** 91 * Set of user restriction which we don't want to persist. 92 */ 93 private static final Set<String> NON_PERSIST_USER_RESTRICTIONS = Sets.newArraySet( 94 UserManager.DISALLOW_RECORD_AUDIO 95 ); 96 97 /** 98 * User restrictions that can not be set by profile owners. 99 */ 100 private static final Set<String> DEVICE_OWNER_ONLY_RESTRICTIONS = Sets.newArraySet( 101 UserManager.DISALLOW_USB_FILE_TRANSFER, 102 UserManager.DISALLOW_CONFIG_TETHERING, 103 UserManager.DISALLOW_NETWORK_RESET, 104 UserManager.DISALLOW_FACTORY_RESET, 105 UserManager.DISALLOW_ADD_USER, 106 UserManager.DISALLOW_CONFIG_CELL_BROADCASTS, 107 UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS, 108 UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA, 109 UserManager.DISALLOW_SMS, 110 UserManager.DISALLOW_FUN, 111 UserManager.DISALLOW_SAFE_BOOT, 112 UserManager.DISALLOW_CREATE_WINDOWS 113 ); 114 115 /** 116 * User restrictions that can't be changed by device owner or profile owner. 117 */ 118 private static final Set<String> IMMUTABLE_BY_OWNERS = Sets.newArraySet( 119 UserManager.DISALLOW_RECORD_AUDIO, 120 UserManager.DISALLOW_WALLPAPER 121 ); 122 123 /** 124 * Special user restrictions that can be applied to a user as well as to all users globally, 125 * depending on callers. When device owner sets them, they'll be applied to all users. 126 */ 127 private static final Set<String> GLOBAL_RESTRICTIONS = Sets.newArraySet( 128 UserManager.DISALLOW_ADJUST_VOLUME, 129 UserManager.DISALLOW_UNMUTE_MICROPHONE 130 ); 131 132 public static void writeRestrictions(@NonNull XmlSerializer serializer, 133 @Nullable Bundle restrictions, @NonNull String tag) throws IOException { 134 if (restrictions == null) { 135 return; 136 } 137 138 serializer.startTag(null, tag); 139 for (String key : restrictions.keySet()) { 140 if (NON_PERSIST_USER_RESTRICTIONS.contains(key)) { 141 continue; // Don't persist. 142 } 143 if (USER_RESTRICTIONS.contains(key)) { 144 if (restrictions.getBoolean(key)) { 145 serializer.attribute(null, key, "true"); 146 } 147 continue; 148 } 149 Log.w(TAG, "Unknown user restriction detected: " + key); 150 } 151 serializer.endTag(null, tag); 152 } 153 154 public static void readRestrictions(XmlPullParser parser, Bundle restrictions) 155 throws IOException { 156 for (String key : USER_RESTRICTIONS) { 157 final String value = parser.getAttributeValue(null, key); 158 if (value != null) { 159 restrictions.putBoolean(key, Boolean.parseBoolean(value)); 160 } 161 } 162 } 163 164 /** 165 * @return {@code in} itself when it's not null, or an empty bundle (which can writable). 166 */ 167 public static Bundle nonNull(@Nullable Bundle in) { 168 return in != null ? in : new Bundle(); 169 } 170 171 public static boolean isEmpty(@Nullable Bundle in) { 172 return (in == null) || (in.size() == 0); 173 } 174 175 /** 176 * Creates a copy of the {@code in} Bundle. If {@code in} is null, it'll return an empty 177 * bundle. 178 * 179 * <p>The resulting {@link Bundle} is always writable. (i.e. it won't return 180 * {@link Bundle#EMPTY}) 181 */ 182 public static @NonNull Bundle clone(@Nullable Bundle in) { 183 return (in != null) ? new Bundle(in) : new Bundle(); 184 } 185 186 public static void merge(@NonNull Bundle dest, @Nullable Bundle in) { 187 Preconditions.checkNotNull(dest); 188 Preconditions.checkArgument(dest != in); 189 if (in == null) { 190 return; 191 } 192 for (String key : in.keySet()) { 193 if (in.getBoolean(key, false)) { 194 dest.putBoolean(key, true); 195 } 196 } 197 } 198 199 /** 200 * @return true if a restriction is settable by device owner. 201 */ 202 public static boolean canDeviceOwnerChange(String restriction) { 203 return !IMMUTABLE_BY_OWNERS.contains(restriction); 204 } 205 206 /** 207 * @return true if a restriction is settable by profile owner. 208 */ 209 public static boolean canProfileOwnerChange(String restriction) { 210 return !(IMMUTABLE_BY_OWNERS.contains(restriction) 211 || DEVICE_OWNER_ONLY_RESTRICTIONS.contains(restriction)); 212 } 213 214 /** 215 * Takes restrictions that can be set by device owner, and sort them into what should be applied 216 * globally and what should be applied only on the current user. 217 */ 218 public static void sortToGlobalAndLocal(@Nullable Bundle in, @NonNull Bundle global, 219 @NonNull Bundle local) { 220 if (in == null || in.size() == 0) { 221 return; 222 } 223 for (String key : in.keySet()) { 224 if (!in.getBoolean(key)) { 225 continue; 226 } 227 if (DEVICE_OWNER_ONLY_RESTRICTIONS.contains(key) || GLOBAL_RESTRICTIONS.contains(key)) { 228 global.putBoolean(key, true); 229 } else { 230 local.putBoolean(key, true); 231 } 232 } 233 } 234 235 /** 236 * @return true if two Bundles contain the same user restriction. 237 * A null bundle and an empty bundle are considered to be equal. 238 */ 239 public static boolean areEqual(@Nullable Bundle a, @Nullable Bundle b) { 240 if (a == b) { 241 return true; 242 } 243 if (isEmpty(a)) { 244 return isEmpty(b); 245 } 246 if (isEmpty(b)) { 247 return false; 248 } 249 for (String key : a.keySet()) { 250 if (a.getBoolean(key) != b.getBoolean(key)) { 251 return false; 252 } 253 } 254 for (String key : b.keySet()) { 255 if (a.getBoolean(key) != b.getBoolean(key)) { 256 return false; 257 } 258 } 259 return true; 260 } 261 262 /** 263 * Takes a new use restriction set and the previous set, and apply the restrictions that have 264 * changed. 265 * 266 * <p>Note this method is called by {@link UserManagerService} while holding 267 * {@code mRestrictionLock}. Be aware when calling into other services, which could cause 268 * a deadlock. 269 */ 270 public static void applyUserRestrictionsLR(Context context, int userId, 271 Bundle newRestrictions, Bundle prevRestrictions) { 272 for (String key : USER_RESTRICTIONS) { 273 final boolean newValue = newRestrictions.getBoolean(key); 274 final boolean prevValue = prevRestrictions.getBoolean(key); 275 276 if (newValue != prevValue) { 277 applyUserRestrictionLR(context, userId, key, newValue); 278 } 279 } 280 } 281 282 /** 283 * Apply each user restriction. 284 * 285 * <p>Note this method is called by {@link UserManagerService} while holding 286 * {@code mRestrictionLock}. Be aware when calling into other services, which could cause 287 * a deadlock. 288 */ 289 private static void applyUserRestrictionLR(Context context, int userId, String key, 290 boolean newValue) { 291 if (UserManagerService.DBG) { 292 Log.d(TAG, "Applying user restriction: userId=" + userId 293 + " key=" + key + " value=" + newValue); 294 } 295 // When certain restrictions are cleared, we don't update the system settings, 296 // because these settings are changeable on the Settings UI and we don't know the original 297 // value -- for example LOCATION_MODE might have been off already when the restriction was 298 // set, and in that case even if the restriction is lifted, changing it to ON would be 299 // wrong. So just don't do anything in such a case. If the user hopes to enable location 300 // later, they can do it on the Settings UI. 301 302 final ContentResolver cr = context.getContentResolver(); 303 final long id = Binder.clearCallingIdentity(); 304 try { 305 switch (key) { 306 case UserManager.DISALLOW_CONFIG_WIFI: 307 if (newValue) { 308 android.provider.Settings.Secure.putIntForUser(cr, 309 android.provider.Settings.Secure 310 .WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 0, userId); 311 } 312 break; 313 case UserManager.DISALLOW_SHARE_LOCATION: 314 if (newValue) { 315 android.provider.Settings.Secure.putIntForUser(cr, 316 android.provider.Settings.Secure.LOCATION_MODE, 317 android.provider.Settings.Secure.LOCATION_MODE_OFF, 318 userId); 319 android.provider.Settings.Secure.putStringForUser(cr, 320 android.provider.Settings.Secure.LOCATION_PROVIDERS_ALLOWED, "", 321 userId); 322 } 323 // Send out notifications as some clients may want to reread the 324 // value which actually changed due to a restriction having been 325 // applied. 326 final String property = 327 android.provider.Settings.Secure.SYS_PROP_SETTING_VERSION; 328 long version = SystemProperties.getLong(property, 0) + 1; 329 SystemProperties.set(property, Long.toString(version)); 330 331 final String name = android.provider.Settings.Secure.LOCATION_PROVIDERS_ALLOWED; 332 final Uri url = Uri.withAppendedPath( 333 android.provider.Settings.Secure.CONTENT_URI, name); 334 context.getContentResolver().notifyChange(url, null, true, userId); 335 336 break; 337 case UserManager.DISALLOW_DEBUGGING_FEATURES: 338 if (newValue) { 339 // Only disable adb if changing for system user, since it is global 340 // TODO: should this be admin user? 341 if (userId == UserHandle.USER_SYSTEM) { 342 android.provider.Settings.Global.putStringForUser(cr, 343 android.provider.Settings.Global.ADB_ENABLED, "0", 344 userId); 345 } 346 } 347 break; 348 case UserManager.ENSURE_VERIFY_APPS: 349 if (newValue) { 350 android.provider.Settings.Global.putStringForUser( 351 context.getContentResolver(), 352 android.provider.Settings.Global.PACKAGE_VERIFIER_ENABLE, "1", 353 userId); 354 android.provider.Settings.Global.putStringForUser( 355 context.getContentResolver(), 356 android.provider.Settings.Global.PACKAGE_VERIFIER_INCLUDE_ADB, "1", 357 userId); 358 } 359 break; 360 case UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES: 361 if (newValue) { 362 android.provider.Settings.Secure.putIntForUser(cr, 363 android.provider.Settings.Secure.INSTALL_NON_MARKET_APPS, 0, 364 userId); 365 } 366 break; 367 } 368 } finally { 369 Binder.restoreCallingIdentity(id); 370 } 371 } 372 373 public static void dumpRestrictions(PrintWriter pw, String prefix, Bundle restrictions) { 374 boolean noneSet = true; 375 if (restrictions != null) { 376 for (String key : restrictions.keySet()) { 377 if (restrictions.getBoolean(key, false)) { 378 pw.println(prefix + key); 379 noneSet = false; 380 } 381 } 382 if (noneSet) { 383 pw.println(prefix + "none"); 384 } 385 } else { 386 pw.println(prefix + "null"); 387 } 388 } 389} 390