blob: 85453a8fbd8b35214481625ad957df82b225b0ca [file] [log] [blame]
Makoto Onukia4f11972015-10-01 13:19:58 -07001/*
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
Makoto Onuki1a2cd742015-11-16 13:51:27 -080021import com.android.internal.util.Preconditions;
22
23import android.annotation.NonNull;
24import android.annotation.Nullable;
Makoto Onuki4f160732015-10-27 17:15:38 -070025import android.content.ContentResolver;
26import android.content.Context;
Makoto Onuki4f160732015-10-27 17:15:38 -070027import android.net.Uri;
28import android.os.Binder;
Makoto Onukia4f11972015-10-01 13:19:58 -070029import android.os.Bundle;
Makoto Onuki4f160732015-10-27 17:15:38 -070030import android.os.SystemProperties;
31import android.os.UserHandle;
Makoto Onukia4f11972015-10-01 13:19:58 -070032import android.os.UserManager;
Makoto Onuki1a2cd742015-11-16 13:51:27 -080033import android.util.Log;
Makoto Onukia4f11972015-10-01 13:19:58 -070034
35import org.xmlpull.v1.XmlPullParser;
36import org.xmlpull.v1.XmlSerializer;
37
38import java.io.IOException;
39import java.io.PrintWriter;
40import java.util.Set;
41
Makoto Onukid45a4a22015-11-02 17:17:38 -080042/**
43 * Utility methods for uesr restrictions.
44 *
45 * <p>See {@link UserManagerService} for the method suffixes.
46 */
Makoto Onukia4f11972015-10-01 13:19:58 -070047public class UserRestrictionsUtils {
Makoto Onuki4f160732015-10-27 17:15:38 -070048 private static final String TAG = "UserRestrictionsUtils";
49
Makoto Onukia4f11972015-10-01 13:19:58 -070050 private UserRestrictionsUtils() {
51 }
52
Makoto Onukiac65e1e2015-11-20 15:33:17 -080053 public static final Set<String> USER_RESTRICTIONS = Sets.newArraySet(
Makoto Onukia4f11972015-10-01 13:19:58 -070054 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,
Makoto Onukiac65e1e2015-11-20 15:33:17 -080087 UserManager.DISALLOW_CAMERA
Makoto Onuki1a2cd742015-11-16 13:51:27 -080088 );
Makoto Onukia4f11972015-10-01 13:19:58 -070089
90 /**
91 * Set of user restriction which we don't want to persist.
92 */
Makoto Onuki1a2cd742015-11-16 13:51:27 -080093 private static final Set<String> NON_PERSIST_USER_RESTRICTIONS = Sets.newArraySet(
94 UserManager.DISALLOW_RECORD_AUDIO
95 );
Makoto Onukia4f11972015-10-01 13:19:58 -070096
Makoto Onuki1a2cd742015-11-16 13:51:27 -080097 /**
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
Makoto Onukia4f11972015-10-01 13:19:58 -0700138 serializer.startTag(null, tag);
Makoto Onukiac65e1e2015-11-20 15:33:17 -0800139 for (String key : restrictions.keySet()) {
140 if (NON_PERSIST_USER_RESTRICTIONS.contains(key)) {
141 continue; // Don't persist.
Makoto Onukia4f11972015-10-01 13:19:58 -0700142 }
Makoto Onukiac65e1e2015-11-20 15:33:17 -0800143 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);
Makoto Onukia4f11972015-10-01 13:19:58 -0700150 }
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
Makoto Onuki1a2cd742015-11-16 13:51:27 -0800164 /**
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);
Makoto Onuki068c54a2015-10-13 14:34:03 -0700189 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
Makoto Onuki4f160732015-10-27 17:15:38 -0700199 /**
Makoto Onuki1a2cd742015-11-16 13:51:27 -0800200 * @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 /**
Makoto Onuki4f160732015-10-27 17:15:38 -0700263 * Takes a new use restriction set and the previous set, and apply the restrictions that have
264 * changed.
Makoto Onukid45a4a22015-11-02 17:17:38 -0800265 *
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.
Makoto Onuki4f160732015-10-27 17:15:38 -0700269 */
Makoto Onukid45a4a22015-11-02 17:17:38 -0800270 public static void applyUserRestrictionsLR(Context context, int userId,
271 Bundle newRestrictions, Bundle prevRestrictions) {
Makoto Onuki4f160732015-10-27 17:15:38 -0700272 for (String key : USER_RESTRICTIONS) {
273 final boolean newValue = newRestrictions.getBoolean(key);
274 final boolean prevValue = prevRestrictions.getBoolean(key);
275
276 if (newValue != prevValue) {
Makoto Onukid45a4a22015-11-02 17:17:38 -0800277 applyUserRestrictionLR(context, userId, key, newValue);
Makoto Onuki4f160732015-10-27 17:15:38 -0700278 }
279 }
280 }
Makoto Onuki1a2cd742015-11-16 13:51:27 -0800281
Makoto Onukid45a4a22015-11-02 17:17:38 -0800282 /**
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,
Makoto Onuki4f160732015-10-27 17:15:38 -0700290 boolean newValue) {
Makoto Onuki1a2cd742015-11-16 13:51:27 -0800291 if (UserManagerService.DBG) {
292 Log.d(TAG, "Applying user restriction: userId=" + userId
293 + " key=" + key + " value=" + newValue);
294 }
Makoto Onuki4f160732015-10-27 17:15:38 -0700295 // 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) {
Makoto Onuki4f160732015-10-27 17:15:38 -0700306 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 }
Makoto Onuki4f160732015-10-27 17:15:38 -0700368 } finally {
369 Binder.restoreCallingIdentity(id);
370 }
371 }
372
Makoto Onukia4f11972015-10-01 13:19:58 -0700373 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 }
Makoto Onuki068c54a2015-10-13 14:34:03 -0700382 if (noneSet) {
383 pw.println(prefix + "none");
384 }
385 } else {
386 pw.println(prefix + "null");
Makoto Onukia4f11972015-10-01 13:19:58 -0700387 }
388 }
389}