Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ae5e7178 authored by Alex Johnston's avatar Alex Johnston Committed by Android (Google) Code Review
Browse files

Merge "Add precondition checks"

parents 7fc13e85 af1c3cb4
Loading
Loading
Loading
Loading
+26 −0
Original line number Diff line number Diff line
@@ -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.
+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;
    }
}
+48 −7
Original line number Diff line number Diff line
@@ -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.
@@ -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()
@@ -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());
            }
        });