Home | History | Annotate | Download | only in pm
      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 
     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_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      */
    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 
    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 
    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      */
    201     public static Bundle nonNull(@Nullable Bundle in) {
    202         return in != null ? in : new Bundle();
    203     }
    204 
    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      */
    216     public static @NonNull Bundle clone(@Nullable Bundle in) {
    217         return (in != null) ? new Bundle(in) : new Bundle();
    218     }
    219 
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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 
    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