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

Commit 58a645b8 authored by Eugene Susla's avatar Eugene Susla
Browse files

Grant device profile if the device is already connected at the time of association

This also removes the logic to un-grant the role when device is disconnected
as it was decided to drop that behavior

Test: manual
Bug: 165951651
Change-Id: I7ece6ba04f097d4a0919e499fa0a8d0152c3c3ca
parent 0c5f84eb
Loading
Loading
Loading
Loading
+98 −82
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@
package com.android.server.companion;

import static com.android.internal.util.CollectionUtils.emptyIfNull;
import static com.android.internal.util.CollectionUtils.find;
import static com.android.internal.util.CollectionUtils.forEach;
import static com.android.internal.util.FunctionalUtils.uncheckExceptions;
import static com.android.internal.util.Preconditions.checkArgument;
@@ -130,9 +131,6 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
            CompanionDeviceManager.COMPANION_DEVICE_DISCOVERY_PACKAGE_NAME,
            ".DeviceDiscoveryService");

    // 10 min
    public static final int DEVICE_DISCONNECT_PROFILE_REVOKE_DELAY_MS = 10 * 60 * 1000;

    private static final boolean DEBUG = false;
    private static final String LOG_TAG = "CompanionDeviceManagerService";

@@ -555,12 +553,45 @@ public class CompanionDeviceManagerService extends SystemService implements Bind

    void removeAssociation(int userId, String pkg, String deviceMacAddress) {
        updateAssociations(associations -> CollectionUtils.filter(associations, association -> {
            return association.getUserId() != userId
            boolean notMatch = association.getUserId() != userId
                    || !Objects.equals(association.getDeviceMacAddress(), deviceMacAddress)
                    || !Objects.equals(association.getPackageName(), pkg);
            if (!notMatch) {
                onAssociationPreRemove(association);
            }
            return notMatch;
        }));
    }

    void onAssociationPreRemove(Association association) {
        String deviceProfile = association.getDeviceProfile();
        if (deviceProfile != null) {
            Association otherAssociationWithDeviceProfile = find(
                    getAllAssociations(association.getUserId()),
                    a -> !a.equals(association) && deviceProfile.equals(a.getDeviceProfile()));
            if (otherAssociationWithDeviceProfile != null) {
                Log.i(LOG_TAG, "Not revoking " + deviceProfile
                        + " for " + association
                        + " - profile still present in " + otherAssociationWithDeviceProfile);
            } else {
                mRoleManager.removeRoleHolderAsUser(
                        association.getDeviceProfile(),
                        association.getPackageName(),
                        RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP,
                        UserHandle.of(association.getUserId()),
                        getContext().getMainExecutor(),
                        success -> {
                            if (!success) {
                                Log.e(LOG_TAG, "Failed to revoke device profile role "
                                        + association.getDeviceProfile()
                                        + " to " + association.getPackageName()
                                        + " for user " + association.getUserId());
                            }
                        });
            }
        }
    }

    private void updateSpecialAccessPermissionForAssociatedPackage(Association association) {
        PackageInfo packageInfo = getPackageInfo(
                association.getPackageName(),
@@ -598,6 +629,10 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
        }

        exemptFromAutoRevoke(packageInfo.packageName, packageInfo.applicationInfo.uid);

        if (mCurrentlyConnectedDevices.contains(association.getDeviceMacAddress())) {
            grantDeviceProfile(association);
        }
    }

    private void exemptFromAutoRevoke(String packageName, int uid) {
@@ -779,49 +814,22 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
    void onDeviceConnected(String address) {
        mCurrentlyConnectedDevices.add(address);

        Handler.getMain().removeCallbacksAndMessages(getDisconnectJobHandlerId(address));

        for (UserInfo user : getAllUsers()) {
            for (Association association : getAllAssociations(user.id)) {
                if (Objects.equals(address, association.getDeviceMacAddress())) {
                    if (association.getDeviceProfile() != null) {
                        Log.i(LOG_TAG, "Granting role " + association.getDeviceProfile()
                                + " to " + association.getPackageName()
                                + " due to device connected: " + address);
                        mRoleManager.addRoleHolderAsUser(
                                association.getDeviceProfile(),
                                association.getPackageName(),
                                RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP,
                                UserHandle.of(association.getUserId()),
                                getContext().getMainExecutor(),
                                success -> {
                                    if (!success) {
                                        Log.e(LOG_TAG, "Failed to grant device profile role "
                                                + association.getDeviceProfile()
                                                + " to " + association.getPackageName()
                                                + " for user " + association.getUserId());
                                    }
                                });
                                + " due to device connected: " + association.getDeviceMacAddress());
                        grantDeviceProfile(association);
                    }
                }
            }
        }
    }

    void onDeviceDisconnected(String address) {
        mCurrentlyConnectedDevices.remove(address);

        Handler.getMain().postDelayed(() -> {
            if (!mCurrentlyConnectedDevices.contains(address)) {
                for (UserInfo user : getAllUsers()) {
                    for (Association association : getAllAssociations(user.id)) {
                        if (association.getDeviceProfile() != null
                                && Objects.equals(address, association.getDeviceMacAddress())
                                && !association.isKeepProfilePrivilegesWhenDeviceAway()) {
                            Log.i(LOG_TAG, "Revoking role " + association.getDeviceProfile()
                                    + " to " + association.getPackageName()
                                    + " due to device disconnected: " + address);
                            mRoleManager.removeRoleHolderAsUser(
    private void grantDeviceProfile(Association association) {
        mRoleManager.addRoleHolderAsUser(
                association.getDeviceProfile(),
                association.getPackageName(),
                RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP,
@@ -829,22 +837,16 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
                getContext().getMainExecutor(),
                success -> {
                    if (!success) {
                                            Log.e(LOG_TAG, "Failed to revoke device profile role "
                        Log.e(LOG_TAG, "Failed to grant device profile role "
                                + association.getDeviceProfile()
                                + " to " + association.getPackageName()
                                + " for user " + association.getUserId());
                    }
                });
    }
                    }
                }
            }
        }, getDisconnectJobHandlerId(address), DEVICE_DISCONNECT_PROFILE_REVOKE_DELAY_MS);
    }

    @NonNull
    private String getDisconnectJobHandlerId(String address) {
        return "CDM_onDisconnected_" + address;
    void onDeviceDisconnected(String address) {
        mCurrentlyConnectedDevices.remove(address);
    }

    private class ShellCmd extends ShellCommand {
@@ -860,34 +862,48 @@ public class CompanionDeviceManagerService extends SystemService implements Bind

        @Override
        public int onCommand(String cmd) {
            try {
                switch (cmd) {
                    case "list": {
                        forEach(
                                getAllAssociations(getNextArgInt()),
                                a -> getOutPrintWriter()
                                    .println(a.getPackageName() + " " + a.getDeviceMacAddress()));
                } break;
                                        .println(a.getPackageName() + " "
                                                + a.getDeviceMacAddress()));
                    }
                    break;

                    case "associate": {
                        addAssociation(new Association(getNextArgInt(), getNextArgRequired(),
                                getNextArgRequired(), null, false));
                } break;
                    }
                    break;

                    case "disassociate": {
                    removeAssociation(getNextArgInt(), getNextArgRequired(), getNextArgRequired());
                } break;
                        removeAssociation(getNextArgInt(), getNextArgRequired(),
                                getNextArgRequired());
                    }
                    break;

                    case "simulate_connect": {
                        onDeviceConnected(getNextArgRequired());
                } break;
                    }
                    break;

                    case "simulate_disconnect": {
                        onDeviceDisconnected(getNextArgRequired());
                } break;
                    }
                    break;

                default: return handleDefaultCommands(cmd);
                    default:
                        return handleDefaultCommands(cmd);
                }
                return 0;
            } catch (Throwable t) {
                Log.e(LOG_TAG, "Error running a command: $ " + cmd, t);
                getErrPrintWriter().println(Log.getStackTraceString(t));
                return 1;
            }
        }

        private int getNextArgInt() {