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 Original line Diff line number Diff line
@@ -17,27 +17,24 @@
package com.android.server.input;
package com.android.server.input;


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


import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.GuardedBy;


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


/**
/**
 * A component of {@link InputManagerService} responsible for managing key remappings.
 * A component of {@link InputManagerService} responsible for managing key remappings.
 *
 *
 * @hide
 * @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_REMAP_KEY = 2;
    private static final int MSG_CLEAR_ALL_REMAPPING = 3;
    private static final int MSG_CLEAR_ALL_REMAPPING = 3;


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


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

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


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


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


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


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

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


    @Override
    public void updateExistingKeyMapping() {
    public void onInputDeviceAdded(int deviceId) {
        if (!supportRemapping()) {
        if (!supportRemapping()) {
            return;
            return;
        }
        }
        InputManager inputManager = Objects.requireNonNull(
        setKeyRemapping(getKeyRemapping());
                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) {
    }
    }


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


    int getSwitchState(int deviceId, int sourceMask, int sw);
    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);
    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);
        public native int getSwitchState(int deviceId, int sourceMask, int sw);


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


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


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


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


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

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


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


        outConfig->stylusPointerIconEnabled = mLocked.stylusPointerIconEnabled;
        outConfig->stylusPointerIconEnabled = mLocked.stylusPointerIconEnabled;

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


@@ -1910,6 +1916,16 @@ void NativeInputManager::setInputMethodConnectionIsActive(bool isActive) {
    mInputManager->getDispatcher().setInputMethodConnectionIsActive(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) {
static NativeInputManager* getNativeInputManager(JNIEnv* env, jobject clazz) {
@@ -1983,10 +1999,19 @@ static std::vector<int32_t> getIntArray(JNIEnv* env, jintArray arr) {
    return vec;
    return vec;
}
}


static void nativeAddKeyRemapping(JNIEnv* env, jobject nativeImplObj, jint deviceId,
static void nativeSetKeyRemapping(JNIEnv* env, jobject nativeImplObj, jintArray fromKeyCodesArr,
                                  jint fromKeyCode, jint toKeyCode) {
                                  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);
    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,
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,
            jTypeId = env->GetStaticIntField(gLightClassInfo.clazz,
                                             gLightClassInfo.lightTypeKeyboardMicMute);
                                             gLightClassInfo.lightTypeKeyboardMicMute);
        } else {
        } else {
            ALOGW("Unknown light type %d", lightInfo.type);
            ALOGW("Unknown light type %s", ftl::enum_string(lightInfo.type).c_str());
            continue;
            continue;
        }
        }


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