All Downloads are FREE. Search and download functionalities are using the official Maven repository.

src.android.media.permission.PermissionUtil Maven / Gradle / Ivy

Go to download

A library jar that provides APIs for Applications written for the Google Android Platform.

There is a newer version: 15-robolectric-12650502
Show newest version
/*
 * 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 android.media.permission;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityThread;
import android.content.Context;
import android.content.PermissionChecker;
import android.os.Binder;
import android.os.Process;

import java.util.Objects;

/**
 * This module provides some utility methods for facilitating our permission enforcement patterns.
 * 

*

Intended usage:

* Close to the client-facing edge of the server, first authenticate the client, using {@link * #establishIdentityDirect(Identity)}, or {@link #establishIdentityIndirect(Context, String, * Identity, Identity)}, depending on whether the client is trying to authenticate as the * originator or a middleman. Those methods will establish a scope with the originator in the * {@link android.media.permission.IdentityContext} and a cleared binder calling identity. * Typically there would be two distinct API methods for the two different options, and typically * those API methods would be used to establish a client session which is associated with the * originator for the lifetime of the session. *

* When performing an operation that requires permissions, use {@link * #checkPermissionForPreflight(Context, Identity, String)} or {@link * #checkPermissionForDataDelivery(Context, Identity, String, String)} on the originator * identity. Note that this won't typically be the identity pulled from the {@link * android.media.permission.IdentityContext}, since we are working with a session-based approach, * the originator identity will be established once upon creation of a session, and then all * interactions with this session will using the identity attached to the session. This also covers * performing checks prior to invoking client callbacks for data delivery. * * @hide */ public class PermissionUtil { /** * Authenticate an originator, where the binder call is coming from a middleman. * * The middleman is expected to hold a special permission to act as such, or else a * {@link SecurityException} will be thrown. If the call succeeds: *

    *
  • The passed middlemanIdentity argument will have its uid/pid fields overridden with * those provided by binder. *
  • An {@link SafeCloseable} is returned, used to established a scope in which the * originator identity is available via {@link android.media.permission.IdentityContext} * and in which the binder * calling ID is cleared. *
* Example usage: *
     *     try (SafeCloseable ignored = PermissionUtil.establishIdentityIndirect(...)) {
     *         // Within this scope we have the identity context established, and the binder calling
     *         // identity cleared.
     *         ...
     *         Identity originator = IdentityContext.getNonNull();
     *         ...
     *     }
     *     // outside the scope, everything is back to the prior state.
     * 
*

* Important note: The binder calling ID will be used to securely establish the identity * of the middleman. However, if the middleman is on the same process as the server, * the middleman must remember to clear the binder calling identity, or else the binder calling * ID will reflect the process calling into the middleman, not the middleman process itself. If * the middleman itself is using this API, this is typically not an issue, since this method * will take care of that. * * @param context A {@link Context}, used for permission checks. * @param middlemanPermission The permission that will be checked in order to authorize the * middleman to act as such (i.e. be trusted to convey the * originator * identity reliably). * @param middlemanIdentity The identity of the middleman. * @param originatorIdentity The identity of the originator. * @return A {@link SafeCloseable}, used to establish a scope, as mentioned above. */ public static @NonNull SafeCloseable establishIdentityIndirect( @NonNull Context context, @NonNull String middlemanPermission, @NonNull Identity middlemanIdentity, @NonNull Identity originatorIdentity) { Objects.requireNonNull(context); Objects.requireNonNull(middlemanPermission); Objects.requireNonNull(middlemanIdentity); Objects.requireNonNull(originatorIdentity); // Override uid/pid with the secure values provided by binder. middlemanIdentity.pid = Binder.getCallingPid(); middlemanIdentity.uid = Binder.getCallingUid(); // Authorize middleman to delegate identity. context.enforcePermission(middlemanPermission, middlemanIdentity.pid, middlemanIdentity.uid, String.format("Middleman must have the %s permision.", middlemanPermission)); return new CompositeSafeCloseable(IdentityContext.create(originatorIdentity), ClearCallingIdentityContext.create()); } /** * Authenticate an originator, where the binder call is coming directly from the originator. * * If the call succeeds: *

    *
  • The passed originatorIdentity argument will have its uid/pid fields overridden with * those provided by binder. *
  • A {@link SafeCloseable} is returned, used to established a scope in which the * originator identity is available via {@link IdentityContext} and in which the binder * calling ID is cleared. *
* Example usage: *
     *     try (AutoClosable ignored = PermissionUtil.establishIdentityDirect(...)) {
     *         // Within this scope we have the identity context established, and the binder calling
     *         // identity cleared.
     *         ...
     *         Identity originator = IdentityContext.getNonNull();
     *         ...
     *     }
     *     // outside the scope, everything is back to the prior state.
     * 
*

* Important note: The binder calling ID will be used to securely establish the identity * of the client. However, if the client is on the same process as the server, and is itself a * binder server, it must remember to clear the binder calling identity, or else the binder * calling ID will reflect the process calling into the client, not the client process itself. * If the client itself is using this API, this is typically not an issue, since this method * will take care of that. * * @param originatorIdentity The identity of the originator. * @return A {@link SafeCloseable}, used to establish a scope, as mentioned above. */ public static @NonNull SafeCloseable establishIdentityDirect(@NonNull Identity originatorIdentity) { Objects.requireNonNull(originatorIdentity); originatorIdentity.uid = Binder.getCallingUid(); originatorIdentity.pid = Binder.getCallingPid(); return new CompositeSafeCloseable( IdentityContext.create(originatorIdentity), ClearCallingIdentityContext.create()); } /** * Checks whether the given identity has the given permission to receive data. * * @param context A {@link Context}, used for permission checks. * @param identity The identity to check. * @param permission The identifier of the permission we want to check. * @param reason The reason why we're requesting the permission, for auditing purposes. * @return The permission check result which is either * {@link PermissionChecker#PERMISSION_GRANTED} * or {@link PermissionChecker#PERMISSION_SOFT_DENIED} or * {@link PermissionChecker#PERMISSION_HARD_DENIED}. */ public static int checkPermissionForDataDelivery(@NonNull Context context, @NonNull Identity identity, @NonNull String permission, @NonNull String reason) { return PermissionChecker.checkPermissionForDataDelivery(context, permission, identity.pid, identity.uid, identity.packageName, identity.attributionTag, reason); } /** * Checks whether the given identity has the given permission. * * @param context A {@link Context}, used for permission checks. * @param identity The identity to check. * @param permission The identifier of the permission we want to check. * @return The permission check result which is either * {@link PermissionChecker#PERMISSION_GRANTED} * or {@link PermissionChecker#PERMISSION_SOFT_DENIED} or * {@link PermissionChecker#PERMISSION_HARD_DENIED}. */ public static int checkPermissionForPreflight(@NonNull Context context, @NonNull Identity identity, @NonNull String permission) { return PermissionChecker.checkPermissionForPreflight(context, permission, identity.pid, identity.uid, identity.packageName); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy