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

Commit fefc2640 authored by Linnan Li's avatar Linnan Li Committed by Siarhei Vishniakou
Browse files

Move key remapping to InputReader thread(2/n)



Currently, the key remapping operation occurs on a non-Reader thread,
which leads to concurrent operations on the KCM object by this thread
and the Reader, causing unpredictable concurrency issues.

Here, we move this operation to the Reader thread, aligning it with
most configuration refresh methods, which can resolve the
aforementioned issues.

Additionally, we are removing the device traversal method on the Java
side because we actually intend for the key remapping operation to
apply to all full-keyboard devices. This can be fully achieved during
the InputReader refresh, so we are also removing the deviceId parameter
from the remapping interface.

There should be no behavioral changes.

Bug: 358042225
Test: atest CtsInputTestCases
Test: atest InputTests
Test: atest inputflinger_tests
Flag: EXEMPT refactor

Change-Id: I4b5737a9cd5406d5d93ae72db1c880c9b0b2a6b4
Signed-off-by: default avatarLinnan Li <lilinnan@xiaomi.corp-partner.google.com>
parent 19b22824
Loading
Loading
Loading
Loading
+19 −47
Original line number Diff line number Diff line
@@ -17,27 +17,24 @@
package com.android.server.input;

import android.content.Context;
import android.hardware.input.InputManager;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.ArrayMap;
import android.util.FeatureFlagUtils;
import android.view.InputDevice;

import com.android.internal.annotations.GuardedBy;

import java.util.Map;
import java.util.Objects;

/**
 * A component of {@link InputManagerService} responsible for managing key remappings.
 *
 * @hide
 */
final class KeyRemapper implements InputManager.InputDeviceListener {
final class KeyRemapper {

    private static final int MSG_UPDATE_EXISTING_DEVICES = 1;
    private static final int MSG_UPDATE_EXISTING_KEY_REMAPPING = 1;
    private static final int MSG_REMAP_KEY = 2;
    private static final int MSG_CLEAR_ALL_REMAPPING = 3;

@@ -57,13 +54,7 @@ final class KeyRemapper implements InputManager.InputDeviceListener {
    }

    public void systemRunning() {
        InputManager inputManager = Objects.requireNonNull(
                mContext.getSystemService(InputManager.class));
        inputManager.registerInputDeviceListener(this, mHandler);

        Message msg = Message.obtain(mHandler, MSG_UPDATE_EXISTING_DEVICES,
                inputManager.getInputDeviceIds());
        mHandler.sendMessage(msg);
        Message.obtain(mHandler, MSG_UPDATE_EXISTING_KEY_REMAPPING).sendToTarget();
    }

    public void remapKey(int fromKey, int toKey) {
@@ -91,19 +82,19 @@ final class KeyRemapper implements InputManager.InputDeviceListener {
        }
    }

    private void addKeyRemapping(int fromKey, int toKey) {
        InputManager inputManager = Objects.requireNonNull(
                mContext.getSystemService(InputManager.class));
        for (int deviceId : inputManager.getInputDeviceIds()) {
            InputDevice inputDevice = inputManager.getInputDevice(deviceId);
            if (inputDevice != null && !inputDevice.isVirtual() && inputDevice.isFullKeyboard()) {
                mNative.addKeyRemapping(deviceId, fromKey, toKey);
            }
    private void setKeyRemapping(Map<Integer, Integer> keyRemapping) {
        int index = 0;
        int[] fromKeycodesArr = new int[keyRemapping.size()];
        int[] toKeycodesArr = new int[keyRemapping.size()];
        for (Map.Entry<Integer, Integer> entry : keyRemapping.entrySet()) {
            fromKeycodesArr[index] = entry.getKey();
            toKeycodesArr[index] = entry.getValue();
            index++;
        }
        mNative.setKeyRemapping(fromKeycodesArr, toKeycodesArr);
    }

    private void remapKeyInternal(int fromKey, int toKey) {
        addKeyRemapping(fromKey, toKey);
        synchronized (mDataStore) {
            try {
                if (fromKey == toKey) {
@@ -114,6 +105,7 @@ final class KeyRemapper implements InputManager.InputDeviceListener {
            } finally {
                mDataStore.saveIfNeeded();
            }
            setKeyRemapping(mDataStore.getKeyRemapping());
        }
    }

@@ -123,45 +115,25 @@ final class KeyRemapper implements InputManager.InputDeviceListener {
                Map<Integer, Integer> keyRemapping = mDataStore.getKeyRemapping();
                for (int fromKey : keyRemapping.keySet()) {
                    mDataStore.clearMappedKey(fromKey);

                    // Remapping to itself will clear the remapping on native side
                    addKeyRemapping(fromKey, fromKey);
                }
            } finally {
                mDataStore.saveIfNeeded();
            }
            setKeyRemapping(mDataStore.getKeyRemapping());
        }
    }

    @Override
    public void onInputDeviceAdded(int deviceId) {
    public void updateExistingKeyMapping() {
        if (!supportRemapping()) {
            return;
        }
        InputManager inputManager = Objects.requireNonNull(
                mContext.getSystemService(InputManager.class));
        InputDevice inputDevice = inputManager.getInputDevice(deviceId);
        if (inputDevice != null && !inputDevice.isVirtual() && inputDevice.isFullKeyboard()) {
            Map<Integer, Integer> remapping = getKeyRemapping();
            remapping.forEach(
                    (fromKey, toKey) -> mNative.addKeyRemapping(deviceId, fromKey, toKey));
        }
    }

    @Override
    public void onInputDeviceRemoved(int deviceId) {
    }

    @Override
    public void onInputDeviceChanged(int deviceId) {
        setKeyRemapping(getKeyRemapping());
    }

    private boolean handleMessage(Message msg) {
        switch (msg.what) {
            case MSG_UPDATE_EXISTING_DEVICES:
                for (int deviceId : (int[]) msg.obj) {
                    onInputDeviceAdded(deviceId);
                }
            case MSG_UPDATE_EXISTING_KEY_REMAPPING:
                updateExistingKeyMapping();
                return true;
            case MSG_REMAP_KEY:
                remapKeyInternal(msg.arg1, msg.arg2);
+2 −2
Original line number Diff line number Diff line
@@ -48,7 +48,7 @@ interface NativeInputManagerService {

    int getSwitchState(int deviceId, int sourceMask, int sw);

    void addKeyRemapping(int deviceId, int fromKeyCode, int toKeyCode);
    void setKeyRemapping(int[] fromKeyCodes, int[] toKeyCodes);

    boolean hasKeys(int deviceId, int sourceMask, int[] keyCodes, boolean[] keyExists);

@@ -311,7 +311,7 @@ interface NativeInputManagerService {
        public native int getSwitchState(int deviceId, int sourceMask, int sw);

        @Override
        public native void addKeyRemapping(int deviceId, int fromKeyCode, int toKeyCode);
        public native void setKeyRemapping(int[] fromKeyCodes, int[] toKeyCodes);

        @Override
        public native boolean hasKeys(int deviceId, int sourceMask, int[] keyCodes,
+30 −5
Original line number Diff line number Diff line
@@ -357,6 +357,7 @@ public:
    FloatPoint getMouseCursorPosition(ui::LogicalDisplayId displayId);
    void setStylusPointerIconEnabled(bool enabled);
    void setInputMethodConnectionIsActive(bool isActive);
    void setKeyRemapping(const std::map<int32_t, int32_t>& keyRemapping);

    /* --- InputReaderPolicyInterface implementation --- */

@@ -504,6 +505,9 @@ private:

        // True if there is an active input method connection.
        bool isInputMethodConnectionActive{false};

        // Keycodes to be remapped.
        std::map<int32_t /* fromKeyCode */, int32_t /* toKeyCode */> keyRemapping{};
    } mLocked GUARDED_BY(mLock);

    std::atomic<bool> mInteractive;
@@ -761,6 +765,8 @@ void NativeInputManager::getReaderConfiguration(InputReaderConfiguration* outCon
        outConfig->stylusButtonMotionEventsEnabled = mLocked.stylusButtonMotionEventsEnabled;

        outConfig->stylusPointerIconEnabled = mLocked.stylusPointerIconEnabled;

        outConfig->keyRemapping = mLocked.keyRemapping;
    } // release lock
}

@@ -1910,6 +1916,16 @@ void NativeInputManager::setInputMethodConnectionIsActive(bool isActive) {
    mInputManager->getDispatcher().setInputMethodConnectionIsActive(isActive);
}

void NativeInputManager::setKeyRemapping(const std::map<int32_t, int32_t>& keyRemapping) {
    { // acquire lock
        std::scoped_lock _l(mLock);
        mLocked.keyRemapping = keyRemapping;
    } // release lock

    mInputManager->getReader().requestRefreshConfiguration(
            InputReaderConfiguration::Change::KEY_REMAPPING);
}

// ----------------------------------------------------------------------------

static NativeInputManager* getNativeInputManager(JNIEnv* env, jobject clazz) {
@@ -1983,10 +1999,19 @@ static std::vector<int32_t> getIntArray(JNIEnv* env, jintArray arr) {
    return vec;
}

static void nativeAddKeyRemapping(JNIEnv* env, jobject nativeImplObj, jint deviceId,
                                  jint fromKeyCode, jint toKeyCode) {
static void nativeSetKeyRemapping(JNIEnv* env, jobject nativeImplObj, jintArray fromKeyCodesArr,
                                  jintArray toKeyCodesArr) {
    const std::vector<int32_t> fromKeycodes = getIntArray(env, fromKeyCodesArr);
    const std::vector<int32_t> toKeycodes = getIntArray(env, toKeyCodesArr);
    if (fromKeycodes.size() != toKeycodes.size()) {
        jniThrowRuntimeException(env, "FromKeycodes and toKeycodes cannot match.");
    }
    NativeInputManager* im = getNativeInputManager(env, nativeImplObj);
    im->getInputManager()->getReader().addKeyRemapping(deviceId, fromKeyCode, toKeyCode);
    std::map<int32_t, int32_t> keyRemapping;
    for (int i = 0; i < fromKeycodes.size(); i++) {
        keyRemapping.insert_or_assign(fromKeycodes[i], toKeycodes[i]);
    }
    im->setKeyRemapping(keyRemapping);
}

static jboolean nativeHasKeys(JNIEnv* env, jobject nativeImplObj, jint deviceId, jint sourceMask,
@@ -2491,7 +2516,7 @@ static jobject nativeGetLights(JNIEnv* env, jobject nativeImplObj, jint deviceId
            jTypeId = env->GetStaticIntField(gLightClassInfo.clazz,
                                             gLightClassInfo.lightTypeKeyboardMicMute);
        } else {
            ALOGW("Unknown light type %d", lightInfo.type);
            ALOGW("Unknown light type %s", ftl::enum_string(lightInfo.type).c_str());
            continue;
        }

@@ -2955,7 +2980,7 @@ static const JNINativeMethod gInputManagerMethods[] = {
        {"getScanCodeState", "(III)I", (void*)nativeGetScanCodeState},
        {"getKeyCodeState", "(III)I", (void*)nativeGetKeyCodeState},
        {"getSwitchState", "(III)I", (void*)nativeGetSwitchState},
        {"addKeyRemapping", "(III)V", (void*)nativeAddKeyRemapping},
        {"setKeyRemapping", "([I[I)V", (void*)nativeSetKeyRemapping},
        {"hasKeys", "(II[I[Z)Z", (void*)nativeHasKeys},
        {"getKeyCodeForKeyLocation", "(II)I", (void*)nativeGetKeyCodeForKeyLocation},
        {"createInputChannel", "(Ljava/lang/String;)Landroid/view/InputChannel;",