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

Commit acc5a3e2 authored by Christine Franks's avatar Christine Franks
Browse files

Update uniqueId association methods

Change from associating via name to associating via physical input port.
This is more robust as there is less likely to be a chance of collision,
as well as less likely to have problems as the userspace language changes
(and therefore the user-visible name should also change).

Bug: 202273865
Test: atest FrameworksServicesTests:com.android.server.companion.virtual

Change-Id: Ieae349e20f66df1490351c85a99d2efa5910d08b
parent 8ba7b768
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -122,9 +122,9 @@ interface IInputManager {
    void removePortAssociation(in String inputPort);

    // Add a runtime association between the input device and display.
    void addUniqueIdAssociation(in String inputDeviceName, in String displayUniqueId);
    void addUniqueIdAssociation(in String inputPort, in String displayUniqueId);
    // Remove the runtime association between the input device and display.
    void removeUniqueIdAssociation(in String inputDeviceName);
    void removeUniqueIdAssociation(in String inputPort);

    InputSensorInfo[] getSensorList(int deviceId);

+8 −9
Original line number Diff line number Diff line
@@ -1359,19 +1359,18 @@ public final class InputManager {
    }

    /**
     * Add a runtime association between the input device name and display, by unique id. Input
     * device names are expected to be unique.
     * @param inputDeviceName The name of the input device.
     * Add a runtime association between the input port and display, by unique id. Input ports are
     * expected to be unique.
     * @param inputPort The port of the input device.
     * @param displayUniqueId The unique id of the associated display.
     * <p>
     * Requires {@link android.Manifest.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY}.
     * </p>
     * @hide
     */
    public void addUniqueIdAssociation(@NonNull String inputDeviceName,
            @NonNull String displayUniqueId) {
    public void addUniqueIdAssociation(@NonNull String inputPort, @NonNull String displayUniqueId) {
        try {
            mIm.addUniqueIdAssociation(inputDeviceName, displayUniqueId);
            mIm.addUniqueIdAssociation(inputPort, displayUniqueId);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
@@ -1379,15 +1378,15 @@ public final class InputManager {

    /**
     * Removes a runtime association between the input device and display.
     * @param inputDeviceName The name of the input device.
     * @param inputPort The port of the input device.
     * <p>
     * Requires {@link android.Manifest.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY}.
     * </p>
     * @hide
     */
    public void removeUniqueIdAssociation(@NonNull String inputDeviceName) {
    public void removeUniqueIdAssociation(@NonNull String inputPort) {
        try {
            mIm.removeUniqueIdAssociation(inputDeviceName);
            mIm.removeUniqueIdAssociation(inputPort);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
+69 −33
Original line number Diff line number Diff line
@@ -18,8 +18,11 @@ package com.android.server.companion.virtual;

import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.StringDef;
import android.graphics.Point;
import android.graphics.PointF;
import android.hardware.display.DisplayManagerInternal;
import android.hardware.input.InputManager;
import android.hardware.input.InputManagerInternal;
import android.hardware.input.VirtualKeyEvent;
import android.hardware.input.VirtualMouseButtonEvent;
@@ -48,6 +51,20 @@ class InputController {

    private static final String TAG = "VirtualInputController";

    private static final AtomicLong sNextPhysId = new AtomicLong(1);

    static final String PHYS_TYPE_KEYBOARD = "Keyboard";
    static final String PHYS_TYPE_MOUSE = "Mouse";
    static final String PHYS_TYPE_TOUCHSCREEN = "Touchscreen";
    @StringDef(prefix = { "PHYS_TYPE_" }, value = {
            PHYS_TYPE_KEYBOARD,
            PHYS_TYPE_MOUSE,
            PHYS_TYPE_TOUCHSCREEN,
    })
    @Retention(RetentionPolicy.SOURCE)
    @interface PhysType {
    }

    private final Object mLock;

    /* Token -> file descriptor associations. */
@@ -56,6 +73,8 @@ class InputController {
    final Map<IBinder, InputDeviceDescriptor> mInputDeviceDescriptors = new ArrayMap<>();

    private final NativeWrapper mNativeWrapper;
    private final DisplayManagerInternal mDisplayManagerInternal;
    private final InputManagerInternal mInputManagerInternal;

    /**
     * Because the pointer is a singleton, it can only be targeted at one display at a time. Because
@@ -73,6 +92,8 @@ class InputController {
        mLock = lock;
        mNativeWrapper = nativeWrapper;
        mActivePointerDisplayId = Display.INVALID_DISPLAY;
        mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
        mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
    }

    void close() {
@@ -90,7 +111,9 @@ class InputController {
            int productId,
            @NonNull IBinder deviceToken,
            int displayId) {
        final int fd = mNativeWrapper.openUinputKeyboard(deviceName, vendorId, productId);
        final String phys = createPhys(PHYS_TYPE_KEYBOARD);
        setUniqueIdAssociation(displayId, phys);
        final int fd = mNativeWrapper.openUinputKeyboard(deviceName, vendorId, productId, phys);
        if (fd < 0) {
            throw new RuntimeException(
                    "A native error occurred when creating keyboard: " + -fd);
@@ -99,7 +122,7 @@ class InputController {
        synchronized (mLock) {
            mInputDeviceDescriptors.put(deviceToken,
                    new InputDeviceDescriptor(fd, binderDeathRecipient,
                            InputDeviceDescriptor.TYPE_KEYBOARD, displayId));
                            InputDeviceDescriptor.TYPE_KEYBOARD, displayId, phys));
        }
        try {
            deviceToken.linkToDeath(binderDeathRecipient, /* flags= */ 0);
@@ -114,7 +137,9 @@ class InputController {
            int productId,
            @NonNull IBinder deviceToken,
            int displayId) {
        final int fd = mNativeWrapper.openUinputMouse(deviceName, vendorId, productId);
        final String phys = createPhys(PHYS_TYPE_MOUSE);
        setUniqueIdAssociation(displayId, phys);
        final int fd = mNativeWrapper.openUinputMouse(deviceName, vendorId, productId, phys);
        if (fd < 0) {
            throw new RuntimeException(
                    "A native error occurred when creating mouse: " + -fd);
@@ -123,11 +148,9 @@ class InputController {
        synchronized (mLock) {
            mInputDeviceDescriptors.put(deviceToken,
                    new InputDeviceDescriptor(fd, binderDeathRecipient,
                            InputDeviceDescriptor.TYPE_MOUSE, displayId));
            final InputManagerInternal inputManagerInternal =
                    LocalServices.getService(InputManagerInternal.class);
            inputManagerInternal.setVirtualMousePointerDisplayId(displayId);
            inputManagerInternal.setPointerAcceleration(1);
                            InputDeviceDescriptor.TYPE_MOUSE, displayId, phys));
            mInputManagerInternal.setVirtualMousePointerDisplayId(displayId);
            mInputManagerInternal.setPointerAcceleration(1);
            mActivePointerDisplayId = displayId;
        }
        try {
@@ -144,7 +167,9 @@ class InputController {
            @NonNull IBinder deviceToken,
            int displayId,
            @NonNull Point screenSize) {
        final int fd = mNativeWrapper.openUinputTouchscreen(deviceName, vendorId, productId,
        final String phys = createPhys(PHYS_TYPE_TOUCHSCREEN);
        setUniqueIdAssociation(displayId, phys);
        final int fd = mNativeWrapper.openUinputTouchscreen(deviceName, vendorId, productId, phys,
                screenSize.y, screenSize.x);
        if (fd < 0) {
            throw new RuntimeException(
@@ -154,7 +179,7 @@ class InputController {
        synchronized (mLock) {
            mInputDeviceDescriptors.put(deviceToken,
                    new InputDeviceDescriptor(fd, binderDeathRecipient,
                            InputDeviceDescriptor.TYPE_TOUCHSCREEN, displayId));
                            InputDeviceDescriptor.TYPE_TOUCHSCREEN, displayId, phys));
        }
        try {
            deviceToken.linkToDeath(binderDeathRecipient, /* flags= */ 0);
@@ -174,6 +199,7 @@ class InputController {
            }
            token.unlinkToDeath(inputDeviceDescriptor.getDeathRecipient(), /* flags= */ 0);
            mNativeWrapper.closeUinput(inputDeviceDescriptor.getFileDescriptor());
            InputManager.getInstance().removeUniqueIdAssociation(inputDeviceDescriptor.getPhys());

            // Reset values to the default if all virtual mice are unregistered, or set display
            // id if there's another mouse (choose the most recent).
@@ -197,9 +223,7 @@ class InputController {
            }
        }
        if (mostRecentlyCreatedMouse != null) {
            final InputManagerInternal inputManagerInternal =
                    LocalServices.getService(InputManagerInternal.class);
            inputManagerInternal.setVirtualMousePointerDisplayId(
            mInputManagerInternal.setVirtualMousePointerDisplayId(
                    mostRecentlyCreatedMouse.getDisplayId());
            mActivePointerDisplayId = mostRecentlyCreatedMouse.getDisplayId();
        } else {
@@ -209,14 +233,21 @@ class InputController {
    }

    private void resetMouseValuesLocked() {
        final InputManagerInternal inputManagerInternal =
                LocalServices.getService(InputManagerInternal.class);
        inputManagerInternal.setVirtualMousePointerDisplayId(Display.INVALID_DISPLAY);
        inputManagerInternal.setPointerAcceleration(
        mInputManagerInternal.setVirtualMousePointerDisplayId(Display.INVALID_DISPLAY);
        mInputManagerInternal.setPointerAcceleration(
                IInputConstants.DEFAULT_POINTER_ACCELERATION);
        mActivePointerDisplayId = Display.INVALID_DISPLAY;
    }

    private static String createPhys(@PhysType String type) {
        return String.format("virtual%s:%d", type, sNextPhysId.getAndIncrement());
    }

    private void setUniqueIdAssociation(int displayId, String phys) {
        final String displayUniqueId = mDisplayManagerInternal.getDisplayInfo(displayId).uniqueId;
        InputManager.getInstance().addUniqueIdAssociation(phys, displayUniqueId);
    }

    boolean sendKeyEvent(@NonNull IBinder token, @NonNull VirtualKeyEvent event) {
        synchronized (mLock) {
            final InputDeviceDescriptor inputDeviceDescriptor = mInputDeviceDescriptors.get(
@@ -321,17 +352,18 @@ class InputController {
                fout.println("          creationOrder: "
                        + inputDeviceDescriptor.getCreationOrderNumber());
                fout.println("          type: " + inputDeviceDescriptor.getType());
                fout.println("          phys: " + inputDeviceDescriptor.getPhys());
            }
            fout.println("      Active mouse display id: " + mActivePointerDisplayId);
        }
    }

    private static native int nativeOpenUinputKeyboard(String deviceName, int vendorId,
            int productId);
    private static native int nativeOpenUinputMouse(String deviceName, int vendorId,
            int productId);
            int productId, String phys);
    private static native int nativeOpenUinputMouse(String deviceName, int vendorId, int productId,
            String phys);
    private static native int nativeOpenUinputTouchscreen(String deviceName, int vendorId,
            int productId, int height, int width);
            int productId, String phys, int height, int width);
    private static native boolean nativeCloseUinput(int fd);
    private static native boolean nativeWriteKeyEvent(int fd, int androidKeyCode, int action);
    private static native boolean nativeWriteButtonEvent(int fd, int buttonCode, int action);
@@ -345,20 +377,18 @@ class InputController {
    /** Wrapper around the static native methods for tests. */
    @VisibleForTesting
    protected static class NativeWrapper {
        public int openUinputKeyboard(String deviceName, int vendorId, int productId) {
            return nativeOpenUinputKeyboard(deviceName, vendorId,
                    productId);
        public int openUinputKeyboard(String deviceName, int vendorId, int productId, String phys) {
            return nativeOpenUinputKeyboard(deviceName, vendorId, productId, phys);
        }

        public int openUinputMouse(String deviceName, int vendorId, int productId) {
            return nativeOpenUinputMouse(deviceName, vendorId,
                    productId);
        public int openUinputMouse(String deviceName, int vendorId, int productId, String phys) {
            return nativeOpenUinputMouse(deviceName, vendorId, productId, phys);
        }

        public int openUinputTouchscreen(String deviceName, int vendorId, int productId, int height,
                int width) {
            return nativeOpenUinputTouchscreen(deviceName, vendorId,
                    productId, height, width);
        public int openUinputTouchscreen(String deviceName, int vendorId,
                int productId, String phys, int height, int width) {
            return nativeOpenUinputTouchscreen(deviceName, vendorId, productId, phys, height,
                    width);
        }

        public boolean closeUinput(int fd) {
@@ -410,15 +440,17 @@ class InputController {
        private final IBinder.DeathRecipient mDeathRecipient;
        private final @Type int mType;
        private final int mDisplayId;
        private final String mPhys;
        // Monotonically increasing number; devices with lower numbers were created earlier.
        private final long mCreationOrderNumber;

        InputDeviceDescriptor(int fd, IBinder.DeathRecipient deathRecipient,
                @Type int type, int displayId) {
        InputDeviceDescriptor(int fd, IBinder.DeathRecipient deathRecipient, @Type int type,
                int displayId, String phys) {
            mFd = fd;
            mDeathRecipient = deathRecipient;
            mType = type;
            mDisplayId = displayId;
            mPhys = phys;
            mCreationOrderNumber = sNextCreationOrderNumber.getAndIncrement();
        }

@@ -445,6 +477,10 @@ class InputController {
        public long getCreationOrderNumber() {
            return mCreationOrderNumber;
        }

        public String getPhys() {
            return mPhys;
        }
    }

    private final class BinderDeathRecipient implements IBinder.DeathRecipient {
+13 −16
Original line number Diff line number Diff line
@@ -2285,14 +2285,8 @@ public class InputManagerService extends IInputManager.Stub
        nativeNotifyPortAssociationsChanged(mPtr);
    }

    /**
     * Add a runtime association between the input device name and the display unique id.
     * @param inputDeviceName The name of the input device.
     * @param displayUniqueId The unique id of the associated display.
     */
    @Override // Binder call
    public void addUniqueIdAssociation(@NonNull String inputDeviceName,
            @NonNull String displayUniqueId) {
    public void addUniqueIdAssociation(@NonNull String inputPort, @NonNull String displayUniqueId) {
        if (!checkCallingPermission(
                android.Manifest.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY,
                "addNameAssociation()")) {
@@ -2300,20 +2294,16 @@ public class InputManagerService extends IInputManager.Stub
                    "Requires ASSOCIATE_INPUT_DEVICE_TO_DISPLAY permission");
        }

        Objects.requireNonNull(inputDeviceName);
        Objects.requireNonNull(inputPort);
        Objects.requireNonNull(displayUniqueId);
        synchronized (mAssociationsLock) {
            mUniqueIdAssociations.put(inputDeviceName, displayUniqueId);
            mUniqueIdAssociations.put(inputPort, displayUniqueId);
        }
        nativeChangeUniqueIdAssociation(mPtr);
    }

    /**
     * Remove the runtime association between the input device and the display.
     * @param inputDeviceName The port of the input device to be cleared.
     */
    @Override // Binder call
    public void removeUniqueIdAssociation(@NonNull String inputDeviceName) {
    public void removeUniqueIdAssociation(@NonNull String inputPort) {
        if (!checkCallingPermission(
                android.Manifest.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY,
                "removeUniqueIdAssociation()")) {
@@ -2321,9 +2311,9 @@ public class InputManagerService extends IInputManager.Stub
                    "Requires ASSOCIATE_INPUT_DEVICE_TO_DISPLAY permission");
        }

        Objects.requireNonNull(inputDeviceName);
        Objects.requireNonNull(inputPort);
        synchronized (mAssociationsLock) {
            mUniqueIdAssociations.remove(inputDeviceName);
            mUniqueIdAssociations.remove(inputPort);
        }
        nativeChangeUniqueIdAssociation(mPtr);
    }
@@ -2594,6 +2584,13 @@ public class InputManagerService extends IInputManager.Stub
                    pw.println("  display: " + v);
                });
            }
            if (!mUniqueIdAssociations.isEmpty()) {
                pw.println("Unique Id Associations:");
                mUniqueIdAssociations.forEach((k, v) -> {
                    pw.print("  port: " + k);
                    pw.println("  uniqueId: " + v);
                });
            }
        }
    }

+21 −15
Original line number Diff line number Diff line
@@ -186,7 +186,7 @@ static std::map<int, int> KEY_CODE_MAPPING = {
};

/** Creates a new uinput device and assigns a file descriptor. */
static int openUinput(const char* readableName, jint vendorId, jint productId,
static int openUinput(const char* readableName, jint vendorId, jint productId, const char* phys,
                      DeviceType deviceType, jint screenHeight, jint screenWidth) {
    android::base::unique_fd fd(TEMP_FAILURE_RETRY(::open("/dev/uinput", O_WRONLY | O_NONBLOCK)));
    if (fd < 0) {
@@ -194,6 +194,8 @@ static int openUinput(const char* readableName, jint vendorId, jint productId,
        return -errno;
    }

    ioctl(fd, UI_SET_PHYS, phys);

    ioctl(fd, UI_SET_EVBIT, EV_KEY);
    ioctl(fd, UI_SET_EVBIT, EV_SYN);
    switch (deviceType) {
@@ -295,28 +297,30 @@ static int openUinput(const char* readableName, jint vendorId, jint productId,
    return fd.release();
}

static int openUinputJni(JNIEnv* env, jstring name, jint vendorId, jint productId,
static int openUinputJni(JNIEnv* env, jstring name, jint vendorId, jint productId, jstring phys,
                         DeviceType deviceType, int screenHeight, int screenWidth) {
    ScopedUtfChars readableName(env, name);
    return openUinput(readableName.c_str(), vendorId, productId, deviceType, screenHeight,
                      screenWidth);
    ScopedUtfChars readablePhys(env, phys);
    return openUinput(readableName.c_str(), vendorId, productId, readablePhys.c_str(), deviceType,
                      screenHeight, screenWidth);
}

static int nativeOpenUinputKeyboard(JNIEnv* env, jobject thiz, jstring name, jint vendorId,
                                    jint productId) {
    return openUinputJni(env, name, vendorId, productId, DeviceType::KEYBOARD, /* screenHeight */ 0,
                         /* screenWidth */ 0);
                                    jint productId, jstring phys) {
    return openUinputJni(env, name, vendorId, productId, phys, DeviceType::KEYBOARD,
                         /* screenHeight */ 0, /* screenWidth */ 0);
}

static int nativeOpenUinputMouse(JNIEnv* env, jobject thiz, jstring name, jint vendorId,
                                 jint productId) {
    return openUinputJni(env, name, vendorId, productId, DeviceType::MOUSE, /* screenHeight */ 0,
                         /* screenWidth */ 0);
                                 jint productId, jstring phys) {
    return openUinputJni(env, name, vendorId, productId, phys, DeviceType::MOUSE,
                         /* screenHeight */ 0, /* screenWidth */ 0);
}

static int nativeOpenUinputTouchscreen(JNIEnv* env, jobject thiz, jstring name, jint vendorId,
                                       jint productId, jint height, jint width) {
    return openUinputJni(env, name, vendorId, productId, DeviceType::TOUCHSCREEN, height, width);
                                       jint productId, jstring phys, jint height, jint width) {
    return openUinputJni(env, name, vendorId, productId, phys, DeviceType::TOUCHSCREEN, height,
                         width);
}

static bool nativeCloseUinput(JNIEnv* env, jobject thiz, jint fd) {
@@ -435,9 +439,11 @@ static bool nativeWriteScrollEvent(JNIEnv* env, jobject thiz, jint fd, jfloat xA
}

static JNINativeMethod methods[] = {
        {"nativeOpenUinputKeyboard", "(Ljava/lang/String;II)I", (void*)nativeOpenUinputKeyboard},
        {"nativeOpenUinputMouse", "(Ljava/lang/String;II)I", (void*)nativeOpenUinputMouse},
        {"nativeOpenUinputTouchscreen", "(Ljava/lang/String;IIII)I",
        {"nativeOpenUinputKeyboard", "(Ljava/lang/String;IILjava/lang/String;)I",
         (void*)nativeOpenUinputKeyboard},
        {"nativeOpenUinputMouse", "(Ljava/lang/String;IILjava/lang/String;)I",
         (void*)nativeOpenUinputMouse},
        {"nativeOpenUinputTouchscreen", "(Ljava/lang/String;IILjava/lang/String;II)I",
         (void*)nativeOpenUinputTouchscreen},
        {"nativeCloseUinput", "(I)Z", (void*)nativeCloseUinput},
        {"nativeWriteKeyEvent", "(III)Z", (void*)nativeWriteKeyEvent},
Loading