From 65fb2e4e40329856b07fb84e35e0ffb61e53f419 Mon Sep 17 00:00:00 2001 From: Christopher Tate Date: Fri, 11 Oct 2019 17:00:23 -0700 Subject: Move UserManagerInternal into services.jar Because SettingsProvider needs to call through the IUserManager interface there is now a method to provide restricted-access information via that route. It has the same protection as the implicit local service call surface that was previously used: only system-uid callers can invoke it. Bug: 140833849 Test: system boots & runs normally Change-Id: I05823ca57240ab10feb382c45590541212e406c1 --- core/java/android/os/IUserManager.aidl | 3 + .../java/android/os/IUserRestrictionsListener.aidl | 26 +++ core/java/android/os/UserManager.java | 32 +++ core/java/android/os/UserManagerInternal.java | 250 --------------------- .../providers/settings/SettingsProvider.java | 187 +++++++-------- .../core/java/android/os/UserManagerInternal.java | 250 +++++++++++++++++++++ .../com/android/server/pm/UserManagerService.java | 33 ++- 7 files changed, 441 insertions(+), 340 deletions(-) create mode 100644 core/java/android/os/IUserRestrictionsListener.aidl delete mode 100644 core/java/android/os/UserManagerInternal.java create mode 100644 services/core/java/android/os/UserManagerInternal.java diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl index c30491a3965c..e8cc73f43a3d 100644 --- a/core/java/android/os/IUserManager.aidl +++ b/core/java/android/os/IUserManager.aidl @@ -18,6 +18,7 @@ package android.os; import android.os.Bundle; +import android.os.IUserRestrictionsListener; import android.os.PersistableBundle; import android.os.UserManager; import android.content.pm.UserInfo; @@ -75,6 +76,8 @@ interface IUserManager { boolean hasBaseUserRestriction(String restrictionKey, int userHandle); boolean hasUserRestriction(in String restrictionKey, int userHandle); boolean hasUserRestrictionOnAnyUser(in String restrictionKey); + boolean isSettingRestrictedForUser(in String setting, int userId, in String value, int callingUid); + void addUserRestrictionsListener(IUserRestrictionsListener listener); void setUserRestriction(String key, boolean value, int userHandle); void setApplicationRestrictions(in String packageName, in Bundle restrictions, int userHandle); diff --git a/core/java/android/os/IUserRestrictionsListener.aidl b/core/java/android/os/IUserRestrictionsListener.aidl new file mode 100644 index 000000000000..e7d027ff6ac7 --- /dev/null +++ b/core/java/android/os/IUserRestrictionsListener.aidl @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.os; + +import android.os.Bundle; + +/** + * @hide + */ +oneway interface IUserRestrictionsListener { + void onUserRestrictionsChanged(int userId, in Bundle newRestrictions, in Bundle prevRestrictions); +} diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index 3296f11298c8..c6b63cadd7d1 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -1985,6 +1985,38 @@ public class UserManager { } } + /** + * @hide + * + * Checks whether changing the given setting to the given value is prohibited + * by the corresponding user restriction in the given user. + * + * May only be called by the OS itself. + * + * @return {@code true} if the change is prohibited, {@code false} if the change is allowed. + */ + public boolean isSettingRestrictedForUser(String setting, @UserIdInt int userId, + String value, int callingUid) { + try { + return mService.isSettingRestrictedForUser(setting, userId, value, callingUid); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } + } + + /** + * @hide + * Register a binder callback for user restrictions changes. + * May only be called by the OS itself. + */ + public void addUserRestrictionsListener(final IUserRestrictionsListener listener) { + try { + mService.addUserRestrictionsListener(listener); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } + } + /** * Return the serial number for a user. This is a device-unique * number assigned to that user; if the user is deleted and then a new diff --git a/core/java/android/os/UserManagerInternal.java b/core/java/android/os/UserManagerInternal.java deleted file mode 100644 index 59fb3d9fcdad..000000000000 --- a/core/java/android/os/UserManagerInternal.java +++ /dev/null @@ -1,250 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ -package android.os; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.UserIdInt; -import android.content.Context; -import android.content.pm.UserInfo; -import android.graphics.Bitmap; - -/** - * @hide Only for use within the system server. - */ -public abstract class UserManagerInternal { - public static final int CAMERA_NOT_DISABLED = 0; - public static final int CAMERA_DISABLED_LOCALLY = 1; - public static final int CAMERA_DISABLED_GLOBALLY = 2; - - public interface UserRestrictionsListener { - /** - * Called when a user restriction changes. - * - * @param userId target user id - * @param newRestrictions new user restrictions - * @param prevRestrictions user restrictions that were previously set - */ - void onUserRestrictionsChanged(int userId, Bundle newRestrictions, Bundle prevRestrictions); - } - - /** - * Called by {@link com.android.server.devicepolicy.DevicePolicyManagerService} to set - * restrictions enforced by the user. - * - * @param userId target user id for the local restrictions. - * @param restrictions a bundle of user restrictions. - * @param isDeviceOwner whether {@code userId} corresponds to device owner user id. - * @param cameraRestrictionScope is camera disabled and if so what is the scope of restriction. - * Should be one of {@link #CAMERA_NOT_DISABLED}, {@link #CAMERA_DISABLED_LOCALLY} or - * {@link #CAMERA_DISABLED_GLOBALLY} - */ - public abstract void setDevicePolicyUserRestrictions(int userId, @Nullable Bundle restrictions, - boolean isDeviceOwner, int cameraRestrictionScope); - - /** - * Returns the "base" user restrictions. - * - * Used by {@link com.android.server.devicepolicy.DevicePolicyManagerService} for upgrading - * from MNC. - */ - public abstract Bundle getBaseUserRestrictions(int userId); - - /** - * Called by {@link com.android.server.devicepolicy.DevicePolicyManagerService} for upgrading - * from MNC. - */ - public abstract void setBaseUserRestrictionsByDpmsForMigration(int userId, - Bundle baseRestrictions); - - /** Return a user restriction. */ - public abstract boolean getUserRestriction(int userId, String key); - - /** Adds a listener to user restriction changes. */ - public abstract void addUserRestrictionsListener(UserRestrictionsListener listener); - - /** Remove a {@link UserRestrictionsListener}. */ - public abstract void removeUserRestrictionsListener(UserRestrictionsListener listener); - - /** - * Called by {@link com.android.server.devicepolicy.DevicePolicyManagerService} to update - * whether the device is managed by device owner. - */ - public abstract void setDeviceManaged(boolean isManaged); - - /** - * Returns whether the device is managed by device owner. - */ - public abstract boolean isDeviceManaged(); - - /** - * Called by {@link com.android.server.devicepolicy.DevicePolicyManagerService} to update - * whether the user is managed by profile owner. - */ - public abstract void setUserManaged(int userId, boolean isManaged); - - /** - * whether a profile owner manages this user. - */ - public abstract boolean isUserManaged(int userId); - - /** - * Called by {@link com.android.server.devicepolicy.DevicePolicyManagerService} to omit - * restriction check, because DevicePolicyManager must always be able to set user icon - * regardless of any restriction. - * Also called by {@link com.android.server.pm.UserManagerService} because the logic of setting - * the icon is in this method. - */ - public abstract void setUserIcon(int userId, Bitmap bitmap); - - /** - * Called by {@link com.android.server.devicepolicy.DevicePolicyManagerService} to inform the - * user manager whether all users should be created ephemeral. - */ - public abstract void setForceEphemeralUsers(boolean forceEphemeralUsers); - - /** - * Switches to the system user and deletes all other users. - * - *

Called by the {@link com.android.server.devicepolicy.DevicePolicyManagerService} when - * the force-ephemeral-users policy is toggled on to make sure there are no pre-existing - * non-ephemeral users left. - */ - public abstract void removeAllUsers(); - - /** - * Called by the activity manager when the ephemeral user goes to background and its removal - * starts as a result. - * - *

It marks the ephemeral user as disabled in order to prevent it from being re-entered - * before its removal finishes. - * - * @param userId the ID of the ephemeral user. - */ - public abstract void onEphemeralUserStop(int userId); - - /** - * Same as UserManager.createUser(), but bypasses the check for - * {@link UserManager#DISALLOW_ADD_USER} and {@link UserManager#DISALLOW_ADD_MANAGED_PROFILE} - * - *

Called by the {@link com.android.server.devicepolicy.DevicePolicyManagerService} when - * createAndManageUser is called by the device owner. - */ - public abstract UserInfo createUserEvenWhenDisallowed(String name, int flags, - String[] disallowedPackages); - - /** - * Same as {@link UserManager#removeUser(int userId)}, but bypasses the check for - * {@link UserManager#DISALLOW_REMOVE_USER} and - * {@link UserManager#DISALLOW_REMOVE_MANAGED_PROFILE} and does not require the - * {@link android.Manifest.permission#MANAGE_USERS} permission. - */ - public abstract boolean removeUserEvenWhenDisallowed(int userId); - - /** - * Return whether the given user is running in an - * {@code UserState.STATE_RUNNING_UNLOCKING} or - * {@code UserState.STATE_RUNNING_UNLOCKED} state. - */ - public abstract boolean isUserUnlockingOrUnlocked(int userId); - - /** - * Return whether the given user is running in an - * {@code UserState.STATE_RUNNING_UNLOCKED} state. - */ - public abstract boolean isUserUnlocked(int userId); - - /** - * Returns whether the given user is running - */ - public abstract boolean isUserRunning(int userId); - - /** - * Returns whether the given user is initialized - */ - public abstract boolean isUserInitialized(int userId); - - /** - * Returns whether the given user exists - */ - public abstract boolean exists(int userId); - - /** - * Set user's running state - */ - public abstract void setUserState(int userId, int userState); - - /** - * Remove user's running state - */ - public abstract void removeUserState(int userId); - - /** - * Returns an array of user ids. This array is cached in UserManagerService and passed as a - * reference, so do not modify the returned array. - * - * @return the array of user ids. - */ - public abstract int[] getUserIds(); - - /** - * Checks if the {@code callingUserId} and {@code targetUserId} are same or in same group - * and that the {@code callingUserId} is not a managed profile and - * {@code targetUserId} is enabled. - * - * @return TRUE if the {@code callingUserId} can access {@code targetUserId}. FALSE - * otherwise - * - * @throws SecurityException if the calling user and {@code targetUser} are not in the same - * group and {@code throwSecurityException} is true, otherwise if will simply return false. - */ - public abstract boolean isProfileAccessible(int callingUserId, int targetUserId, - String debugMsg, boolean throwSecurityException); - - /** - * If {@code userId} is of a managed profile, return the parent user ID. Otherwise return - * itself. - */ - public abstract int getProfileParentId(int userId); - - /** - * Checks whether changing a setting to a value is prohibited by the corresponding user - * restriction. - * - *

See also {@link com.android.server.pm.UserRestrictionsUtils#applyUserRestriction( - * Context, int, String, boolean)}, which should be in sync with this method. - * - * @return {@code true} if the change is prohibited, {@code false} if the change is allowed. - * - * @hide - */ - public abstract boolean isSettingRestrictedForUser(String setting, int userId, String value, - int callingUid); - - /** @return a specific user restriction that's in effect currently. */ - public abstract boolean hasUserRestriction(String restriction, int userId); - - /** - * Gets an {@link UserInfo} for the given {@code userId}, or {@code null} if not - * found. - */ - public abstract @Nullable UserInfo getUserInfo(@UserIdInt int userId); - - /** - * Gets all {@link UserInfo UserInfos}. - */ - public abstract @NonNull UserInfo[] getUserInfos(); -} diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java index a9c466ed7e9f..a0410024f2e9 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java @@ -56,6 +56,7 @@ import android.os.DropBoxManager; import android.os.Environment; import android.os.Handler; import android.os.HandlerThread; +import android.os.IUserRestrictionsListener; import android.os.Looper; import android.os.Message; import android.os.ParcelFileDescriptor; @@ -65,7 +66,6 @@ import android.os.SELinux; import android.os.ServiceManager; import android.os.UserHandle; import android.os.UserManager; -import android.os.UserManagerInternal; import android.provider.DeviceConfig; import android.provider.Settings; import android.provider.Settings.Global; @@ -84,7 +84,6 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.content.PackageMonitor; import com.android.internal.os.BackgroundThread; import com.android.providers.settings.SettingsState.Setting; -import com.android.server.LocalServices; import com.android.server.SystemConfig; import com.google.android.collect.Sets; @@ -286,8 +285,6 @@ public class SettingsProvider extends ContentProvider { // We have to call in the user manager with no lock held, private volatile UserManager mUserManager; - private UserManagerInternal mUserManagerInternal; - // We have to call in the package manager with no lock held, private volatile IPackageManager mPackageManager; @@ -317,7 +314,6 @@ public class SettingsProvider extends ContentProvider { synchronized (mLock) { mUserManager = UserManager.get(getContext()); - mUserManagerInternal = LocalServices.getService(UserManagerInternal.class); mPackageManager = AppGlobals.getPackageManager(); mHandlerThread = new HandlerThread(LOG_TAG, Process.THREAD_PRIORITY_BACKGROUND); @@ -902,95 +898,100 @@ public class SettingsProvider extends ContentProvider { // TODO: The current design of settings looking different based on user restrictions // should be reworked to keep them separate and system code should check the setting // first followed by checking the user restriction before performing an operation. - UserManagerInternal userManager = LocalServices.getService(UserManagerInternal.class); - userManager.addUserRestrictionsListener((int userId, Bundle newRestrictions, - Bundle prevRestrictions) -> { - Set changedRestrictions = getRestrictionDiff(prevRestrictions, newRestrictions); - // We are changing the settings affected by restrictions to their current - // value with a forced update to ensure that all cross profile dependencies - // are taken into account. Also make sure the settings update to.. the same - // value passes the security checks, so clear binder calling id. - if (changedRestrictions.contains(UserManager.DISALLOW_SHARE_LOCATION)) { - final long identity = Binder.clearCallingIdentity(); - try { - synchronized (mLock) { - Setting setting = getSecureSetting( - Settings.Secure.LOCATION_MODE, userId); - updateSecureSetting(Settings.Secure.LOCATION_MODE, - setting != null ? setting.getValue() : null, null, - true, userId, true); - setting = getSecureSetting( - Settings.Secure.LOCATION_PROVIDERS_ALLOWED, userId); - updateSecureSetting(Settings.Secure.LOCATION_PROVIDERS_ALLOWED, - setting != null ? setting.getValue() : null, null, - true, userId, true); + IUserRestrictionsListener listener = new IUserRestrictionsListener.Stub() { + @Override + public void onUserRestrictionsChanged(int userId, + Bundle newRestrictions, Bundle prevRestrictions) { + Set changedRestrictions = + getRestrictionDiff(prevRestrictions, newRestrictions); + // We are changing the settings affected by restrictions to their current + // value with a forced update to ensure that all cross profile dependencies + // are taken into account. Also make sure the settings update to.. the same + // value passes the security checks, so clear binder calling id. + if (changedRestrictions.contains(UserManager.DISALLOW_SHARE_LOCATION)) { + final long identity = Binder.clearCallingIdentity(); + try { + synchronized (mLock) { + Setting setting = getSecureSetting( + Settings.Secure.LOCATION_MODE, userId); + updateSecureSetting(Settings.Secure.LOCATION_MODE, + setting != null ? setting.getValue() : null, null, + true, userId, true); + setting = getSecureSetting( + Settings.Secure.LOCATION_PROVIDERS_ALLOWED, userId); + updateSecureSetting(Settings.Secure.LOCATION_PROVIDERS_ALLOWED, + setting != null ? setting.getValue() : null, null, + true, userId, true); + } + } finally { + Binder.restoreCallingIdentity(identity); } - } finally { - Binder.restoreCallingIdentity(identity); } - } - if (changedRestrictions.contains(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES) - || changedRestrictions.contains( - UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY)) { - final long identity = Binder.clearCallingIdentity(); - try { - synchronized (mLock) { - Setting setting = getGlobalSetting(Settings.Global.INSTALL_NON_MARKET_APPS); - String value = setting != null ? setting.getValue() : null; - updateGlobalSetting(Settings.Global.INSTALL_NON_MARKET_APPS, - value, null, true, userId, true); + if (changedRestrictions.contains(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES) + || changedRestrictions.contains( + UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY)) { + final long identity = Binder.clearCallingIdentity(); + try { + synchronized (mLock) { + Setting setting = getGlobalSetting( + Settings.Global.INSTALL_NON_MARKET_APPS); + String value = setting != null ? setting.getValue() : null; + updateGlobalSetting(Settings.Global.INSTALL_NON_MARKET_APPS, + value, null, true, userId, true); + } + } finally { + Binder.restoreCallingIdentity(identity); } - } finally { - Binder.restoreCallingIdentity(identity); } - } - if (changedRestrictions.contains(UserManager.DISALLOW_DEBUGGING_FEATURES)) { - final long identity = Binder.clearCallingIdentity(); - try { - synchronized (mLock) { - Setting setting = getGlobalSetting(Settings.Global.ADB_ENABLED); - String value = setting != null ? setting.getValue() : null; - updateGlobalSetting(Settings.Global.ADB_ENABLED, - value, null, true, userId, true); + if (changedRestrictions.contains(UserManager.DISALLOW_DEBUGGING_FEATURES)) { + final long identity = Binder.clearCallingIdentity(); + try { + synchronized (mLock) { + Setting setting = getGlobalSetting(Settings.Global.ADB_ENABLED); + String value = setting != null ? setting.getValue() : null; + updateGlobalSetting(Settings.Global.ADB_ENABLED, + value, null, true, userId, true); + } + } finally { + Binder.restoreCallingIdentity(identity); } - } finally { - Binder.restoreCallingIdentity(identity); } - } - if (changedRestrictions.contains(UserManager.ENSURE_VERIFY_APPS)) { - final long identity = Binder.clearCallingIdentity(); - try { - synchronized (mLock) { - Setting enable = getGlobalSetting( - Settings.Global.PACKAGE_VERIFIER_ENABLE); - String enableValue = enable != null ? enable.getValue() : null; - updateGlobalSetting(Settings.Global.PACKAGE_VERIFIER_ENABLE, - enableValue, null, true, userId, true); - Setting include = getGlobalSetting( - Settings.Global.PACKAGE_VERIFIER_INCLUDE_ADB); - String includeValue = include != null ? include.getValue() : null; - updateGlobalSetting(Settings.Global.PACKAGE_VERIFIER_INCLUDE_ADB, - includeValue, null, true, userId, true); + if (changedRestrictions.contains(UserManager.ENSURE_VERIFY_APPS)) { + final long identity = Binder.clearCallingIdentity(); + try { + synchronized (mLock) { + Setting enable = getGlobalSetting( + Settings.Global.PACKAGE_VERIFIER_ENABLE); + String enableValue = enable != null ? enable.getValue() : null; + updateGlobalSetting(Settings.Global.PACKAGE_VERIFIER_ENABLE, + enableValue, null, true, userId, true); + Setting include = getGlobalSetting( + Settings.Global.PACKAGE_VERIFIER_INCLUDE_ADB); + String includeValue = include != null ? include.getValue() : null; + updateGlobalSetting(Settings.Global.PACKAGE_VERIFIER_INCLUDE_ADB, + includeValue, null, true, userId, true); + } + } finally { + Binder.restoreCallingIdentity(identity); } - } finally { - Binder.restoreCallingIdentity(identity); } - } - if (changedRestrictions.contains(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS)) { - final long identity = Binder.clearCallingIdentity(); - try { - synchronized (mLock) { - Setting setting = getGlobalSetting( - Settings.Global.PREFERRED_NETWORK_MODE); - String value = setting != null ? setting.getValue() : null; - updateGlobalSetting(Settings.Global.PREFERRED_NETWORK_MODE, - value, null, true, userId, true); + if (changedRestrictions.contains(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS)) { + final long identity = Binder.clearCallingIdentity(); + try { + synchronized (mLock) { + Setting setting = getGlobalSetting( + Settings.Global.PREFERRED_NETWORK_MODE); + String value = setting != null ? setting.getValue() : null; + updateGlobalSetting(Settings.Global.PREFERRED_NETWORK_MODE, + value, null, true, userId, true); + } + } finally { + Binder.restoreCallingIdentity(identity); } - } finally { - Binder.restoreCallingIdentity(identity); } } - }); + }; + mUserManager.addUserRestrictionsListener(listener); } private static Set getRestrictionDiff(Bundle prevRestrictions, Bundle newRestrictions) { @@ -1185,6 +1186,17 @@ public class SettingsProvider extends ContentProvider { MUTATION_OPERATION_RESET, false, mode); } + private boolean isSettingRestrictedForUser(String name, int userId, + String value, int callerUid) { + final long oldId = Binder.clearCallingIdentity(); + try { + return (name != null + && mUserManager.isSettingRestrictedForUser(name, userId, value, callerUid)); + } finally { + Binder.restoreCallingIdentity(oldId); + } + } + private boolean mutateGlobalSetting(String name, String value, String tag, boolean makeDefault, int requestingUserId, int operation, boolean forceNotify, int mode) { @@ -1196,8 +1208,7 @@ public class SettingsProvider extends ContentProvider { // If this is a setting that is currently restricted for this user, do not allow // unrestricting changes. - if (name != null && mUserManagerInternal.isSettingRestrictedForUser( - name, callingUserId, value, Binder.getCallingUid())) { + if (isSettingRestrictedForUser(name, callingUserId, value, Binder.getCallingUid())) { return false; } @@ -1505,8 +1516,7 @@ public class SettingsProvider extends ContentProvider { // If this is a setting that is currently restricted for this user, do not allow // unrestricting changes. - if (name != null && mUserManagerInternal.isSettingRestrictedForUser( - name, callingUserId, value, Binder.getCallingUid())) { + if (isSettingRestrictedForUser(name, callingUserId, value, Binder.getCallingUid())) { return false; } @@ -1646,8 +1656,7 @@ public class SettingsProvider extends ContentProvider { // Resolve the userId on whose behalf the call is made. final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(runAsUserId); - if (name != null && mUserManagerInternal.isSettingRestrictedForUser( - name, callingUserId, value, Binder.getCallingUid())) { + if (isSettingRestrictedForUser(name, callingUserId, value, Binder.getCallingUid())) { return false; } diff --git a/services/core/java/android/os/UserManagerInternal.java b/services/core/java/android/os/UserManagerInternal.java new file mode 100644 index 000000000000..e5f8b49c3f0c --- /dev/null +++ b/services/core/java/android/os/UserManagerInternal.java @@ -0,0 +1,250 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.os; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.UserIdInt; +import android.content.Context; +import android.content.pm.UserInfo; +import android.graphics.Bitmap; + +/** + * @hide Only for use within the system server. + */ +public abstract class UserManagerInternal { + public static final int CAMERA_NOT_DISABLED = 0; + public static final int CAMERA_DISABLED_LOCALLY = 1; + public static final int CAMERA_DISABLED_GLOBALLY = 2; + + public interface UserRestrictionsListener { + /** + * Called when a user restriction changes. + * + * @param userId target user id + * @param newRestrictions new user restrictions + * @param prevRestrictions user restrictions that were previously set + */ + void onUserRestrictionsChanged(int userId, Bundle newRestrictions, Bundle prevRestrictions); + } + + /** + * Called by {@link com.android.server.devicepolicy.DevicePolicyManagerService} to set + * restrictions enforced by the user. + * + * @param userId target user id for the local restrictions. + * @param restrictions a bundle of user restrictions. + * @param isDeviceOwner whether {@code userId} corresponds to device owner user id. + * @param cameraRestrictionScope is camera disabled and if so what is the scope of restriction. + * Should be one of {@link #CAMERA_NOT_DISABLED}, {@link #CAMERA_DISABLED_LOCALLY} or + * {@link #CAMERA_DISABLED_GLOBALLY} + */ + public abstract void setDevicePolicyUserRestrictions(int userId, @Nullable Bundle restrictions, + boolean isDeviceOwner, int cameraRestrictionScope); + + /** + * Returns the "base" user restrictions. + * + * Used by {@link com.android.server.devicepolicy.DevicePolicyManagerService} for upgrading + * from MNC. + */ + public abstract Bundle getBaseUserRestrictions(int userId); + + /** + * Called by {@link com.android.server.devicepolicy.DevicePolicyManagerService} for upgrading + * from MNC. + */ + public abstract void setBaseUserRestrictionsByDpmsForMigration(int userId, + Bundle baseRestrictions); + + /** Return a user restriction. */ + public abstract boolean getUserRestriction(int userId, String key); + + /** Adds a listener to user restriction changes. */ + public abstract void addUserRestrictionsListener(UserRestrictionsListener listener); + + /** Remove a {@link UserRestrictionsListener}. */ + public abstract void removeUserRestrictionsListener(UserRestrictionsListener listener); + + /** + * Called by {@link com.android.server.devicepolicy.DevicePolicyManagerService} to update + * whether the device is managed by device owner. + */ + public abstract void setDeviceManaged(boolean isManaged); + + /** + * Returns whether the device is managed by device owner. + */ + public abstract boolean isDeviceManaged(); + + /** + * Called by {@link com.android.server.devicepolicy.DevicePolicyManagerService} to update + * whether the user is managed by profile owner. + */ + public abstract void setUserManaged(int userId, boolean isManaged); + + /** + * whether a profile owner manages this user. + */ + public abstract boolean isUserManaged(int userId); + + /** + * Called by {@link com.android.server.devicepolicy.DevicePolicyManagerService} to omit + * restriction check, because DevicePolicyManager must always be able to set user icon + * regardless of any restriction. + * Also called by {@link com.android.server.pm.UserManagerService} because the logic of setting + * the icon is in this method. + */ + public abstract void setUserIcon(int userId, Bitmap bitmap); + + /** + * Called by {@link com.android.server.devicepolicy.DevicePolicyManagerService} to inform the + * user manager whether all users should be created ephemeral. + */ + public abstract void setForceEphemeralUsers(boolean forceEphemeralUsers); + + /** + * Switches to the system user and deletes all other users. + * + *

Called by the {@link com.android.server.devicepolicy.DevicePolicyManagerService} when + * the force-ephemeral-users policy is toggled on to make sure there are no pre-existing + * non-ephemeral users left. + */ + public abstract void removeAllUsers(); + + /** + * Called by the activity manager when the ephemeral user goes to background and its removal + * starts as a result. + * + *

It marks the ephemeral user as disabled in order to prevent it from being re-entered + * before its removal finishes. + * + * @param userId the ID of the ephemeral user. + */ + public abstract void onEphemeralUserStop(int userId); + + /** + * Same as UserManager.createUser(), but bypasses the check for + * {@link UserManager#DISALLOW_ADD_USER} and {@link UserManager#DISALLOW_ADD_MANAGED_PROFILE} + * + *

Called by the {@link com.android.server.devicepolicy.DevicePolicyManagerService} when + * createAndManageUser is called by the device owner. + */ + public abstract UserInfo createUserEvenWhenDisallowed(String name, int flags, + String[] disallowedPackages); + + /** + * Same as {@link UserManager#removeUser(int userId)}, but bypasses the check for + * {@link UserManager#DISALLOW_REMOVE_USER} and + * {@link UserManager#DISALLOW_REMOVE_MANAGED_PROFILE} and does not require the + * {@link android.Manifest.permission#MANAGE_USERS} permission. + */ + public abstract boolean removeUserEvenWhenDisallowed(int userId); + + /** + * Return whether the given user is running in an + * {@code UserState.STATE_RUNNING_UNLOCKING} or + * {@code UserState.STATE_RUNNING_UNLOCKED} state. + */ + public abstract boolean isUserUnlockingOrUnlocked(int userId); + + /** + * Return whether the given user is running in an + * {@code UserState.STATE_RUNNING_UNLOCKED} state. + */ + public abstract boolean isUserUnlocked(int userId); + + /** + * Returns whether the given user is running + */ + public abstract boolean isUserRunning(int userId); + + /** + * Returns whether the given user is initialized + */ + public abstract boolean isUserInitialized(int userId); + + /** + * Returns whether the given user exists + */ + public abstract boolean exists(int userId); + + /** + * Set user's running state + */ + public abstract void setUserState(int userId, int userState); + + /** + * Remove user's running state + */ + public abstract void removeUserState(int userId); + + /** + * Returns an array of user ids. This array is cached in UserManagerService and passed as a + * reference, so do not modify the returned array. + * + * @return the array of user ids. + */ + public abstract int[] getUserIds(); + + /** + * Checks if the {@code callingUserId} and {@code targetUserId} are same or in same group + * and that the {@code callingUserId} is not a managed profile and + * {@code targetUserId} is enabled. + * + * @return TRUE if the {@code callingUserId} can access {@code targetUserId}. FALSE + * otherwise + * + * @throws SecurityException if the calling user and {@code targetUser} are not in the same + * group and {@code throwSecurityException} is true, otherwise if will simply return false. + */ + public abstract boolean isProfileAccessible(int callingUserId, int targetUserId, + String debugMsg, boolean throwSecurityException); + + /** + * If {@code userId} is of a managed profile, return the parent user ID. Otherwise return + * itself. + */ + public abstract int getProfileParentId(int userId); + + /** + * Checks whether changing a setting to a value is prohibited by the corresponding user + * restriction. + * + *

See also {@link com.android.server.pm.UserRestrictionsUtils#applyUserRestriction( + * Context, int, String, boolean)}, which should be in sync with this method. + * + * @return {@code true} if the change is prohibited, {@code false} if the change is allowed. + * + * @hide + */ + public abstract boolean isSettingRestrictedForUser(String setting, int userId, String value, + int callingUid); + + /** @return a specific user restriction that's in effect currently. */ + public abstract boolean hasUserRestriction(String restriction, int userId); + + /** + * Gets an {@link UserInfo} for the given {@code userId}, or {@code null} if not + * found. + */ + public abstract @Nullable UserInfo getUserInfo(@UserIdInt int userId); + + /** + * Gets all {@link UserInfo UserInfos}. + */ + public abstract @NonNull UserInfo[] getUserInfos(); +} diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index 95baa01923f5..8814f6dae7c3 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -54,6 +54,7 @@ import android.os.Handler; import android.os.IBinder; import android.os.IProgressListener; import android.os.IUserManager; +import android.os.IUserRestrictionsListener; import android.os.Message; import android.os.ParcelFileDescriptor; import android.os.Parcelable; @@ -1606,6 +1607,36 @@ public class UserManagerService extends IUserManager.Stub { return false; } + @Override + public boolean isSettingRestrictedForUser(String setting, @UserIdInt int userId, + String value, int callingUid) { + if (Binder.getCallingUid() != Process.SYSTEM_UID) { + throw new SecurityException("Non-system caller"); + } + return UserRestrictionsUtils.isSettingRestrictedForUser(mContext, setting, userId, + value, callingUid); + } + + @Override + public void addUserRestrictionsListener(final IUserRestrictionsListener listener) { + if (Binder.getCallingUid() != Process.SYSTEM_UID) { + throw new SecurityException("Non-system caller"); + } + + // NOTE: unregistering not supported; only client is the settings provider, + // which installs a single static permanent listener. If that listener goes + // bad it implies the whole system process is going to crash. + mLocalService.addUserRestrictionsListener( + (int userId, Bundle newRestrict, Bundle prevRestrict) -> { + try { + listener.onUserRestrictionsChanged(userId, newRestrict, prevRestrict); + } catch (RemoteException re) { + Slog.e("IUserRestrictionsListener", + "Unable to invoke listener: " + re.getMessage()); + } + }); + } + /** * @hide * @@ -4410,7 +4441,7 @@ public class UserManagerService extends IUserManager.Stub { @Override public boolean isSettingRestrictedForUser(String setting, @UserIdInt int userId, String value, int callingUid) { - return UserRestrictionsUtils.isSettingRestrictedForUser(mContext, setting, userId, + return UserManagerService.this.isSettingRestrictedForUser(setting, userId, value, callingUid); } -- cgit v1.2.3-59-g8ed1b