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

Commit 651e12ed authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "[CDM] Selective permission grants" into main

parents 7da17cf0 d67cf4bf
Loading
Loading
Loading
Loading
+29 −23
Original line number Diff line number Diff line
@@ -281,6 +281,13 @@ public final class AssociationRequest implements Parcelable {
    @Nullable
    private Icon mDeviceIcon;

    /**
     * Requested permissions for profile.
     * @hide
     */
    @Nullable
    private List<Integer> mRequestedPerms = new ArrayList<>();

    /**
     * Creates a new AssociationRequest.
     *
@@ -394,6 +401,12 @@ public final class AssociationRequest implements Parcelable {
        return mDeviceIcon;
    }

    /** @hide */
    @Nullable
    public List<Integer> getRequestedPerms() {
        return mRequestedPerms;
    }

    /** @hide */
    public void setPackageName(@NonNull String packageName) {
        mPackageName = packageName;
@@ -423,11 +436,17 @@ public final class AssociationRequest implements Parcelable {
    public void setAssociatedDevice(AssociatedDevice associatedDevice) {
        mAssociatedDevice = associatedDevice;
    }

    /** @hide */
    public void setDeviceIcon(Icon deviceIcon) {
        mDeviceIcon = deviceIcon;
    }

    /** @hide */
    public void setRequestedPerms(List<Integer> perms) {
        mRequestedPerms = perms;
    }

    /** @hide */
    @NonNull
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
@@ -664,6 +683,7 @@ public final class AssociationRequest implements Parcelable {
                + ", deviceProfilePrivilegesDescription = " + mDeviceProfilePrivilegesDescription
                + ", creationTime = " + mCreationTime
                + ", skipPrompt = " + mSkipPrompt
                + ", requestedPerms = " + mRequestedPerms
                + " }";
    }

@@ -690,27 +710,6 @@ public final class AssociationRequest implements Parcelable {
                : mDeviceIcon.sameAs(that.mDeviceIcon));
    }

    @Override
    public int hashCode() {
        int _hash = 1;
        _hash = 31 * _hash + Boolean.hashCode(mSingleDevice);
        _hash = 31 * _hash + Objects.hashCode(mDeviceFilters);
        _hash = 31 * _hash + Objects.hashCode(mDeviceProfile);
        _hash = 31 * _hash + Objects.hashCode(mDisplayName);
        _hash = 31 * _hash + Objects.hashCode(mAssociatedDevice);
        _hash = 31 * _hash + Boolean.hashCode(mSelfManaged);
        _hash = 31 * _hash + Boolean.hashCode(mForceConfirmation);
        _hash = 31 * _hash + Boolean.hashCode(mSkipRoleGrant);
        _hash = 31 * _hash + Objects.hashCode(mPackageName);
        _hash = 31 * _hash + mUserId;
        _hash = 31 * _hash + Objects.hashCode(mDeviceProfilePrivilegesDescription);
        _hash = 31 * _hash + Long.hashCode(mCreationTime);
        _hash = 31 * _hash + Boolean.hashCode(mSkipPrompt);
        _hash = 31 * _hash + Objects.hashCode(mDeviceIcon);

        return _hash;
    }

    @Override
    public void writeToParcel(@NonNull Parcel dest, int flags) {
        int flg = 0;
@@ -742,6 +741,12 @@ public final class AssociationRequest implements Parcelable {
        } else {
            dest.writeInt(0);
        }
        if (mRequestedPerms != null) {
            dest.writeInt(1);
            dest.writeList(mRequestedPerms);
        } else {
            dest.writeInt(0);
        }
    }

    @Override
@@ -790,8 +795,9 @@ public final class AssociationRequest implements Parcelable {
        this.mSkipPrompt = skipPrompt;
        if (in.readInt() == 1) {
            mDeviceIcon = Icon.CREATOR.createFromParcel(in);
        } else {
            mDeviceIcon = null;
        }
        if (in.readInt() == 1) {
            in.readList(mRequestedPerms, Integer.class.getClassLoader(), Integer.class);
        }
    }

+7 −17
Original line number Diff line number Diff line
@@ -16,7 +16,6 @@

package com.android.companiondevicemanager;

import static android.companion.CompanionDeviceManager.RESULT_CANCELED;
import static android.companion.CompanionDeviceManager.RESULT_INTERNAL_ERROR;
import static android.companion.CompanionDeviceManager.RESULT_SECURITY_ERROR;
import static android.companion.CompanionDeviceManager.RESULT_USER_REJECTED;
@@ -27,7 +26,6 @@ import static com.android.companiondevicemanager.CompanionDeviceDiscoveryService
import static com.android.companiondevicemanager.CompanionDeviceDiscoveryService.sDiscoveryStarted;
import static com.android.companiondevicemanager.CompanionDeviceResources.PROFILE_ICONS;
import static com.android.companiondevicemanager.CompanionDeviceResources.PROFILE_NAMES;
import static com.android.companiondevicemanager.CompanionDeviceResources.PROFILE_PERMISSIONS;
import static com.android.companiondevicemanager.CompanionDeviceResources.PROFILE_SUMMARIES;
import static com.android.companiondevicemanager.CompanionDeviceResources.PROFILE_TITLES;
import static com.android.companiondevicemanager.CompanionDeviceResources.SUPPORTED_PROFILES;
@@ -87,7 +85,8 @@ import androidx.fragment.app.FragmentManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import java.util.ArrayList;
import com.android.net.module.util.CollectionUtils;

import java.util.List;

/**
@@ -526,7 +525,7 @@ public class CompanionAssociationActivity extends FragmentActivity implements
            mSummary.setVisibility(View.GONE);
        }

        setupPermissionList(deviceProfile);
        setupPermissionList(mRequest.getRequestedPerms());

        mTitle.setText(title);
        mVendorHeaderName.setText(vendorName);
@@ -678,7 +677,7 @@ public class CompanionAssociationActivity extends FragmentActivity implements
            summary = getHtmlFromResources(
                    this, summaryResourceId, getString(R.string.device_type), mAppLabel,
                    remoteDeviceName);
            setupPermissionList(deviceProfile);
            setupPermissionList(mRequest.getRequestedPerms());
        }

        mTitle.setText(title);
@@ -749,20 +748,11 @@ public class CompanionAssociationActivity extends FragmentActivity implements
    // initiate the layoutManager for the recyclerview, add listeners for monitoring the scrolling
    // and when mPermissionListRecyclerView is fully populated.
    // Lastly, disable the Allow and Don't allow buttons.
    private void setupPermissionList(String deviceProfile) {
        if (!PROFILE_PERMISSIONS.containsKey(deviceProfile)) {
            // Nothing to do if there are no permission types.
    private void setupPermissionList(List<Integer> perms) {
        if (CollectionUtils.isEmpty(perms)) {
            return;
        }

        final List<Integer> permissionTypes = new ArrayList<>(
                PROFILE_PERMISSIONS.get(deviceProfile));
        if (permissionTypes.isEmpty()) {
            // Nothing to do if there are no permission types.
            return;
        }

        mPermissionListAdapter.setPermissionType(permissionTypes);
        mPermissionListAdapter.setPermissionType(perms);
        mPermissionListRecyclerView.setAdapter(mPermissionListAdapter);
        mPermissionListRecyclerView.setLayoutManager(mPermissionsLayoutManager);

+1 −26
Original line number Diff line number Diff line
@@ -24,17 +24,13 @@ import static android.companion.AssociationRequest.DEVICE_PROFILE_NEARBY_DEVICE_
import static android.companion.AssociationRequest.DEVICE_PROFILE_VIRTUAL_DEVICE;
import static android.companion.AssociationRequest.DEVICE_PROFILE_WATCH;
import static android.companion.AssociationRequest.DEVICE_PROFILE_WEARABLE_SENSING;
import static android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE;

import static java.util.Collections.unmodifiableMap;
import static java.util.Collections.unmodifiableSet;

import android.os.Build;
import android.util.ArrayMap;
import android.util.ArraySet;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;

@@ -44,7 +40,7 @@ import java.util.Set;
 */
final class CompanionDeviceResources {

    // Permission resources
    // Permissions - in sync with PermissionUtils
    private static final int PERMISSION_NOTIFICATION_LISTENER_ACCESS = 0;
    private static final int PERMISSION_STORAGE = 1;
    private static final int PERMISSION_PHONE = 2;
@@ -150,27 +146,6 @@ final class CompanionDeviceResources {
        PROFILE_HELPER_SUMMARIES = unmodifiableMap(map);
    }

    static final Map<String, List<Integer>> PROFILE_PERMISSIONS;
    static {
        final Map<String, List<Integer>> map = new ArrayMap<>();
        map.put(DEVICE_PROFILE_COMPUTER, Arrays.asList(
                PERMISSION_NOTIFICATION_LISTENER_ACCESS, PERMISSION_STORAGE));
        if (Build.VERSION.SDK_INT > UPSIDE_DOWN_CAKE) {
            map.put(DEVICE_PROFILE_WATCH, Arrays.asList(PERMISSION_NOTIFICATIONS, PERMISSION_PHONE,
                    PERMISSION_CALL_LOGS, PERMISSION_SMS, PERMISSION_CONTACTS, PERMISSION_CALENDAR,
                    PERMISSION_NEARBY_DEVICES, PERMISSION_CHANGE_MEDIA_OUTPUT));
        } else {
            map.put(DEVICE_PROFILE_WATCH, Arrays.asList(PERMISSION_NOTIFICATION_LISTENER_ACCESS,
                    PERMISSION_PHONE, PERMISSION_CALL_LOGS, PERMISSION_SMS, PERMISSION_CONTACTS,
                    PERMISSION_CALENDAR, PERMISSION_NEARBY_DEVICES));
        }
        map.put(DEVICE_PROFILE_GLASSES, Arrays.asList(PERMISSION_NOTIFICATION_LISTENER_ACCESS,
                PERMISSION_PHONE, PERMISSION_SMS, PERMISSION_CONTACTS, PERMISSION_MICROPHONE,
                PERMISSION_NEARBY_DEVICES));

        PROFILE_PERMISSIONS = unmodifiableMap(map);
    }

    static final Map<String, Integer> PROFILE_NAMES;
    static {
        final Map<String, Integer> map = new ArrayMap<>();
+45 −0
Original line number Diff line number Diff line
@@ -25,7 +25,11 @@ import static android.content.ComponentName.createRelative;
import static android.content.pm.PackageManager.FEATURE_WATCH;

import static com.android.server.companion.utils.PackageUtils.enforceUsesCompanionDeviceFeature;
import static com.android.server.companion.utils.PermissionsUtils.PERMISSION_NOTIFICATIONS;
import static com.android.server.companion.utils.PermissionsUtils.PERMISSION_NOTIFICATION_LISTENER_ACCESS;
import static com.android.server.companion.utils.PermissionsUtils.PERM_SET_TO_PERMS;
import static com.android.server.companion.utils.PermissionsUtils.enforcePermissionForCreatingAssociation;
import static com.android.server.companion.utils.RolesUtils.PROFILE_PERMISSION_SETS;
import static com.android.server.companion.utils.RolesUtils.addRoleHolderForAssociation;
import static com.android.server.companion.utils.RolesUtils.isRoleHolder;
import static com.android.server.companion.utils.RolesUtils.isRolelessProfile;
@@ -49,6 +53,7 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentSender;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManagerInternal;
import android.graphics.drawable.Icon;
import android.net.MacAddress;
@@ -65,6 +70,7 @@ import com.android.internal.R;
import com.android.server.companion.CompanionDeviceManagerService;
import com.android.server.companion.utils.PackageUtils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
@@ -214,6 +220,8 @@ public class AssociationRequestsProcessor {
        request.setPackageName(packageName);
        request.setUserId(userId);
        request.setSkipPrompt(mayAssociateWithoutPrompt(packageName, userId));
        request.setRequestedPerms(getRequestedPermsForProfile(userId, packageName,
                request.getDeviceProfile()));

        // 2b.2. Prepare extras and create an Intent.
        final Bundle extras = new Bundle();
@@ -520,4 +528,41 @@ public class AssociationRequestsProcessor {

        return PackageUtils.isPackageAllowlisted(mContext, mPackageManagerInternal, packageName);
    }

    private ArrayList<Integer> getRequestedPermsForProfile(int userId, String packageName,
                                                           String profile) {
        if (profile == null || !PROFILE_PERMISSION_SETS.containsKey(profile)) {
            return null;
        }
        ArrayList<Integer> requestedPermsForProfile = new ArrayList<>(
                PROFILE_PERMISSION_SETS.get(profile));
        PackageInfo packageInfo = PackageUtils.getPackageInfo(mContext, userId, packageName);
        if (packageInfo != null) {
            List<String> requestedPermissions = Arrays.asList(packageInfo.requestedPermissions);
            // Loop thru profile perm sets and check if the app requested one of the perms per set.
            for (Integer permSet : PROFILE_PERMISSION_SETS.get(profile)) {
                if (!PERM_SET_TO_PERMS.containsKey(permSet)) {
                    continue;
                }
                boolean atLeastOnePermInSetRequested = false;
                for (String perm : PERM_SET_TO_PERMS.get(permSet)) {
                    if (requestedPermissions.contains(perm)) {
                        atLeastOnePermInSetRequested = true;
                        break;
                    }
                }
                if (!atLeastOnePermInSetRequested) {
                    requestedPermsForProfile.remove(permSet);
                }
            }

            // Special logic: If the profile contains both NLA and NOTIFICATIONS, just leave
            // the NOTIFICATIONS because the desc contains both perms already.
            if (requestedPermsForProfile.contains(PERMISSION_NOTIFICATION_LISTENER_ACCESS)
                    && requestedPermsForProfile.contains(PERMISSION_NOTIFICATIONS)) {
                requestedPermsForProfile.remove(PERMISSION_NOTIFICATION_LISTENER_ACCESS);
            }
        }
        return requestedPermsForProfile;
    }
}
+63 −0
Original line number Diff line number Diff line
@@ -16,12 +16,43 @@

package com.android.server.companion.utils;

import static android.Manifest.permission.ADD_VOICEMAIL;
import static android.Manifest.permission.ANSWER_PHONE_CALLS;
import static android.Manifest.permission.BLUETOOTH_ADVERTISE;
import static android.Manifest.permission.BLUETOOTH_CONNECT;
import static android.Manifest.permission.BLUETOOTH_SCAN;
import static android.Manifest.permission.CALL_PHONE;
import static android.Manifest.permission.GET_ACCOUNTS;
import static android.Manifest.permission.INTERACT_ACROSS_USERS;
import static android.Manifest.permission.MANAGE_COMPANION_DEVICES;
import static android.Manifest.permission.NEARBY_WIFI_DEVICES;
import static android.Manifest.permission.POST_NOTIFICATIONS;
import static android.Manifest.permission.PROCESS_OUTGOING_CALLS;
import static android.Manifest.permission.READ_CALENDAR;
import static android.Manifest.permission.READ_CALL_LOG;
import static android.Manifest.permission.READ_CELL_BROADCASTS;
import static android.Manifest.permission.READ_CONTACTS;
import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
import static android.Manifest.permission.READ_MEDIA_AUDIO;
import static android.Manifest.permission.READ_MEDIA_IMAGES;
import static android.Manifest.permission.READ_MEDIA_VIDEO;
import static android.Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED;
import static android.Manifest.permission.READ_PHONE_STATE;
import static android.Manifest.permission.READ_SMS;
import static android.Manifest.permission.READ_VOICEMAIL;
import static android.Manifest.permission.RECEIVE_MMS;
import static android.Manifest.permission.RECEIVE_SMS;
import static android.Manifest.permission.RECEIVE_WAP_PUSH;
import static android.Manifest.permission.RECORD_AUDIO;
import static android.Manifest.permission.REQUEST_COMPANION_SELF_MANAGED;
import static android.Manifest.permission.REQUEST_OBSERVE_DEVICE_UUID_PRESENCE;
import static android.Manifest.permission.SEND_SMS;
import static android.Manifest.permission.USE_SIP;
import static android.Manifest.permission.WRITE_CALENDAR;
import static android.Manifest.permission.WRITE_CALL_LOG;
import static android.Manifest.permission.WRITE_CONTACTS;
import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
import static android.Manifest.permission.WRITE_VOICEMAIL;
import static android.app.AppOpsManager.MODE_ALLOWED;
import static android.companion.AssociationRequest.DEVICE_PROFILE_APP_STREAMING;
import static android.companion.AssociationRequest.DEVICE_PROFILE_AUTOMOTIVE_PROJECTION;
@@ -57,6 +88,8 @@ import android.util.ArraySet;

import com.android.internal.app.IAppOpsService;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;

@@ -67,6 +100,36 @@ import java.util.Set;
 * {@link Manifest.permission#REQUEST_COMPANION_SELF_MANAGED} etc.)
 */
public final class PermissionsUtils {
    // Permissions - in sync with CompanionDeviceResources
    public static final int PERMISSION_NOTIFICATION_LISTENER_ACCESS = 0;
    public static final int PERMISSION_STORAGE = 1;
    public static final int PERMISSION_PHONE = 2;
    public static final int PERMISSION_SMS = 3;
    public static final int PERMISSION_CONTACTS = 4;
    public static final int PERMISSION_CALENDAR = 5;
    public static final int PERMISSION_NEARBY_DEVICES = 6;
    public static final int PERMISSION_MICROPHONE = 7;
    public static final int PERMISSION_CALL_LOGS = 8;
    // Notification Listener Access & POST_NOTIFICATION permission
    public static final int PERMISSION_NOTIFICATIONS = 9;
    public static final int PERMISSION_CHANGE_MEDIA_OUTPUT = 10;

    public static final Map<Integer, List<String>> PERM_SET_TO_PERMS = Map.of(
            PERMISSION_CALENDAR, Arrays.asList(READ_CALENDAR, WRITE_CALENDAR),
            PERMISSION_CALL_LOGS, Arrays.asList(READ_CALL_LOG, WRITE_CALL_LOG),
            PERMISSION_CONTACTS, Arrays.asList(READ_CONTACTS, WRITE_CONTACTS, GET_ACCOUNTS),
            PERMISSION_MICROPHONE, Arrays.asList(RECORD_AUDIO),
            PERMISSION_NOTIFICATIONS, Arrays.asList(POST_NOTIFICATIONS),
            PERMISSION_NEARBY_DEVICES, Arrays.asList(BLUETOOTH_ADVERTISE, BLUETOOTH_CONNECT,
                    BLUETOOTH_SCAN, NEARBY_WIFI_DEVICES),
            PERMISSION_PHONE, Arrays.asList(READ_PHONE_STATE, CALL_PHONE, ADD_VOICEMAIL,
                    READ_VOICEMAIL, WRITE_VOICEMAIL, USE_SIP, PROCESS_OUTGOING_CALLS,
                    ANSWER_PHONE_CALLS),
            PERMISSION_SMS, Arrays.asList(SEND_SMS, RECEIVE_SMS, READ_SMS, RECEIVE_WAP_PUSH,
                    RECEIVE_MMS, READ_CELL_BROADCASTS),
            PERMISSION_STORAGE, Arrays.asList(READ_EXTERNAL_STORAGE, WRITE_EXTERNAL_STORAGE,
                    READ_MEDIA_AUDIO, READ_MEDIA_VIDEO, READ_MEDIA_IMAGES,
                    READ_MEDIA_VISUAL_USER_SELECTED));

    private static final Set<String> SYSTEM_ONLY_DEVICE_PROFILES;
    static {
Loading