Loading core/java/com/android/internal/util/Preconditions.java +26 −0 Original line number Diff line number Diff line Loading @@ -186,6 +186,32 @@ public class Preconditions { checkState(expression, null); } /** * Ensures the truth of an expression involving whether the calling identity is authorized to * call the calling method. * * @param expression a boolean expression * @throws SecurityException if {@code expression} is false */ public static void checkCallAuthorization(final boolean expression) { if (!expression) { throw new SecurityException("Calling identity is not authorized"); } } /** * Ensures the truth of an expression involving whether the calling user is authorized to * call the calling method. * * @param expression a boolean expression * @throws SecurityException if {@code expression} is false */ public static void checkCallingUser(final boolean expression) { if (!expression) { throw new SecurityException("Calling user is not authorized"); } } /** * Check the requested flags, throwing if any requested flags are outside * the allowed set. Loading services/devicepolicy/java/com/android/server/devicepolicy/CallerIdentity.java 0 → 100644 +61 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 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 com.android.server.devicepolicy; import android.annotation.Nullable; import android.content.ComponentName; import android.os.UserHandle; /** * Caller identity containing the caller's UID, package name and component name. * All parameters are verified on object creation unless the component name is null and the * caller is a delegate. */ class CallerIdentity { private final int mUid; @Nullable private final String mPackageName; @Nullable private final ComponentName mComponentName; CallerIdentity(int uid, @Nullable String packageName, @Nullable ComponentName componentName) { mUid = uid; mPackageName = packageName; mComponentName = componentName; } public int getUid() { return mUid; } public int getUserId() { return UserHandle.getUserId(mUid); } public UserHandle getUserHandle() { return UserHandle.getUserHandleForUid(mUid); } @Nullable public String getPackageName() { return mPackageName; } @Nullable public ComponentName getComponentName() { return mComponentName; } } services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +48 −7 Original line number Diff line number Diff line Loading @@ -1563,6 +1563,39 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } } /** * Creates a new {@link CallerIdentity} object to represent the caller's identity. */ private CallerIdentity getCallerIdentity(String callerPackage) { final int callerUid = mInjector.binderGetCallingUid(); if (!isCallingFromPackage(callerPackage, callerUid)) { throw new SecurityException( String.format("Caller with uid %d is not %s", callerUid, callerPackage)); } return new CallerIdentity(callerUid, callerPackage, null); } /** * Creates a new {@link CallerIdentity} object to represent the caller's identity. */ private CallerIdentity getCallerIdentity(@NonNull ComponentName componentName) { final int callerUid = mInjector.binderGetCallingUid(); final DevicePolicyData policy = getUserData(UserHandle.getUserId(callerUid)); ActiveAdmin admin = policy.mAdminMap.get(componentName); if (admin == null) { throw new SecurityException(String.format("No active admin for %s", componentName)); } if (admin.getUid() != callerUid) { throw new SecurityException( String.format("Admin %s is not owned by uid %d", componentName, callerUid)); } return new CallerIdentity(callerUid, componentName.getPackageName(), componentName); } /** * Checks if the device is in COMP mode, and if so migrates it to managed profile on a * corporate owned device. Loading Loading @@ -7171,6 +7204,14 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } } private boolean isDeviceOwner(CallerIdentity identity) { synchronized (getLockObject()) { return mOwners.hasDeviceOwner() && mOwners.getDeviceOwnerUserId() == identity.getUserId() && mOwners.getDeviceOwnerComponent().equals(identity.getComponentName()); } } private boolean isDeviceOwnerPackage(String packageName, int userId) { synchronized (getLockObject()) { return mOwners.hasDeviceOwner() Loading Loading @@ -10427,20 +10468,20 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { @Override public void setLocationEnabled(ComponentName who, boolean locationEnabled) { enforceDeviceOwner(Objects.requireNonNull(who)); UserHandle user = mInjector.binderGetCallingUserHandle(); CallerIdentity identity = getCallerIdentity(who); Preconditions.checkCallAuthorization(isDeviceOwner(identity)); mInjector.binderWithCleanCallingIdentity(() -> { boolean wasLocationEnabled = mInjector.getLocationManager().isLocationEnabledForUser( user); mInjector.getLocationManager().setLocationEnabledForUser(locationEnabled, user); identity.getUserHandle()); mInjector.getLocationManager().setLocationEnabledForUser(locationEnabled, identity.getUserHandle()); // make a best effort to only show the notification if the admin is actually enabling // location. this is subject to race conditions with settings changes, but those are // unlikely to realistically interfere if (locationEnabled && (wasLocationEnabled != locationEnabled)) { showLocationSettingsEnabledNotification(user); if (locationEnabled && !wasLocationEnabled) { showLocationSettingsEnabledNotification(identity.getUserHandle()); } }); Loading Loading
core/java/com/android/internal/util/Preconditions.java +26 −0 Original line number Diff line number Diff line Loading @@ -186,6 +186,32 @@ public class Preconditions { checkState(expression, null); } /** * Ensures the truth of an expression involving whether the calling identity is authorized to * call the calling method. * * @param expression a boolean expression * @throws SecurityException if {@code expression} is false */ public static void checkCallAuthorization(final boolean expression) { if (!expression) { throw new SecurityException("Calling identity is not authorized"); } } /** * Ensures the truth of an expression involving whether the calling user is authorized to * call the calling method. * * @param expression a boolean expression * @throws SecurityException if {@code expression} is false */ public static void checkCallingUser(final boolean expression) { if (!expression) { throw new SecurityException("Calling user is not authorized"); } } /** * Check the requested flags, throwing if any requested flags are outside * the allowed set. Loading
services/devicepolicy/java/com/android/server/devicepolicy/CallerIdentity.java 0 → 100644 +61 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 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 com.android.server.devicepolicy; import android.annotation.Nullable; import android.content.ComponentName; import android.os.UserHandle; /** * Caller identity containing the caller's UID, package name and component name. * All parameters are verified on object creation unless the component name is null and the * caller is a delegate. */ class CallerIdentity { private final int mUid; @Nullable private final String mPackageName; @Nullable private final ComponentName mComponentName; CallerIdentity(int uid, @Nullable String packageName, @Nullable ComponentName componentName) { mUid = uid; mPackageName = packageName; mComponentName = componentName; } public int getUid() { return mUid; } public int getUserId() { return UserHandle.getUserId(mUid); } public UserHandle getUserHandle() { return UserHandle.getUserHandleForUid(mUid); } @Nullable public String getPackageName() { return mPackageName; } @Nullable public ComponentName getComponentName() { return mComponentName; } }
services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +48 −7 Original line number Diff line number Diff line Loading @@ -1563,6 +1563,39 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } } /** * Creates a new {@link CallerIdentity} object to represent the caller's identity. */ private CallerIdentity getCallerIdentity(String callerPackage) { final int callerUid = mInjector.binderGetCallingUid(); if (!isCallingFromPackage(callerPackage, callerUid)) { throw new SecurityException( String.format("Caller with uid %d is not %s", callerUid, callerPackage)); } return new CallerIdentity(callerUid, callerPackage, null); } /** * Creates a new {@link CallerIdentity} object to represent the caller's identity. */ private CallerIdentity getCallerIdentity(@NonNull ComponentName componentName) { final int callerUid = mInjector.binderGetCallingUid(); final DevicePolicyData policy = getUserData(UserHandle.getUserId(callerUid)); ActiveAdmin admin = policy.mAdminMap.get(componentName); if (admin == null) { throw new SecurityException(String.format("No active admin for %s", componentName)); } if (admin.getUid() != callerUid) { throw new SecurityException( String.format("Admin %s is not owned by uid %d", componentName, callerUid)); } return new CallerIdentity(callerUid, componentName.getPackageName(), componentName); } /** * Checks if the device is in COMP mode, and if so migrates it to managed profile on a * corporate owned device. Loading Loading @@ -7171,6 +7204,14 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } } private boolean isDeviceOwner(CallerIdentity identity) { synchronized (getLockObject()) { return mOwners.hasDeviceOwner() && mOwners.getDeviceOwnerUserId() == identity.getUserId() && mOwners.getDeviceOwnerComponent().equals(identity.getComponentName()); } } private boolean isDeviceOwnerPackage(String packageName, int userId) { synchronized (getLockObject()) { return mOwners.hasDeviceOwner() Loading Loading @@ -10427,20 +10468,20 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { @Override public void setLocationEnabled(ComponentName who, boolean locationEnabled) { enforceDeviceOwner(Objects.requireNonNull(who)); UserHandle user = mInjector.binderGetCallingUserHandle(); CallerIdentity identity = getCallerIdentity(who); Preconditions.checkCallAuthorization(isDeviceOwner(identity)); mInjector.binderWithCleanCallingIdentity(() -> { boolean wasLocationEnabled = mInjector.getLocationManager().isLocationEnabledForUser( user); mInjector.getLocationManager().setLocationEnabledForUser(locationEnabled, user); identity.getUserHandle()); mInjector.getLocationManager().setLocationEnabledForUser(locationEnabled, identity.getUserHandle()); // make a best effort to only show the notification if the admin is actually enabling // location. this is subject to race conditions with settings changes, but those are // unlikely to realistically interfere if (locationEnabled && (wasLocationEnabled != locationEnabled)) { showLocationSettingsEnabledNotification(user); if (locationEnabled && !wasLocationEnabled) { showLocationSettingsEnabledNotification(identity.getUserHandle()); } }); Loading