input命令逻辑分析

input命令

adb shell input 命令可以模拟用户点击,比如Power键,如何实现的
首先分析此命令的逻辑实现
input命令代码实现在frameworks/base/cmds/input/src/com/android/commands/input/Input.java

Input继承自BaseCommand,先来分析一下抽象类BaseCommand

base/core/java/com/android/internal/os/BaseCommand.java

    /**
     * Call to run the command.
     */
    public void run(String[] args) {
    
        //没有参数时,展示命令用法,类似-help
        if (args.length < 1) {
            onShowUsage(System.out);
            return;
        }

        //处理参数 mArgs
        mArgs.init(null, null, null, null, args, 0);

        try {
            onRun();
        } catch (IllegalArgumentException e) {
            onShowUsage(System.err);
        } catch (Exception e) {
            System.exit(1);
        }
    }
    /**抽象方法,子类实现
     * Implement the command.
     */
    public abstract void onRun() throws Exception;
    
    /**
     * Print help text for the command.
     */
    public abstract void onShowUsage(PrintStream out);
    
    /**
     * Return the next argument on the command line, whatever it is; if there are
     * no arguments left, return null.
     */
    public String nextArg() {
        return mArgs.getNextArg();
    }
base/cmds/input/src/com/android/commands/input/Input.java

    Input() {//添加不同命令的command对象
        COMMANDS.put("text", new InputText());
        COMMANDS.put("keyevent", new InputKeyEvent());
        COMMANDS.put("tap", new InputTap());
        COMMANDS.put("swipe", new InputSwipe());
        COMMANDS.put("draganddrop", new InputDragAndDrop());
        COMMANDS.put("press", new InputPress());
        COMMANDS.put("roll", new InputRoll());
        COMMANDS.put("motionevent", new InputMotionEvent());
    }

    //命令入口
    public static void main(String[] args) {
        (new Input()).run(args);
    }
    
        @Override
    public void onRun() throws Exception {
        //命令第一个参数
        String arg = nextArgRequired();
        //获取处理InputCmd
        InputCmd cmd = COMMANDS.get(arg);
        //调用InputCmd的run方法
        cmd.run(inputSource, displayId);
    }
    
    class InputKeyEvent implements InputCmd {
        @Override
        public void run(int inputSource, int displayId) {
                //将参数转换成键值,并调用sendKeyEvent
                final int keycode = KeyEvent.keyCodeFromString(arg);
                sendKeyEvent(inputSource, keycode, longpress, displayId);
           
        }

        private void sendKeyEvent(int inputSource, int keyCode, boolean longpress, int displayId) {

            //生成上层的KeyEvent对象
            KeyEvent event = new KeyEvent(now, now, KeyEvent.ACTION_DOWN, keyCode, repeatCount, inputSource);
            //完整的按键事件分包含DOWN和UP
            injectKeyEvent(event);
            injectKeyEvent(KeyEvent.changeAction(event, KeyEvent.ACTION_UP));
        }
        //调用InputManager的injectInputEvent方法
    private static void injectKeyEvent(KeyEvent event) {
        InputManager.getInstance().injectInputEvent(event,
                InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH);
    }
    }
    

根据不同的命令参数分发给不同的InputCmd处理,实际是调用到InputManager单例对象中
base/core/java/android/hardware/input/InputManager.java

    private InputManager(IInputManager im) {
        mIm = im;
    }
    
    public static InputManager getInstance() {
        synchronized (InputManager.class) {
            if (sInstance == null) {
                //单例模式,mIm为IMS对象,binder通信
                    sInstance = new InputManager(IInputManager.Stub
                    .asInterface(ServiceManager.getServiceOrThrow(Context.INPUT_SERVICE)));
            }
            return sInstance;
        }
    }
    
    //调用IMS的injectInputEvent
    public boolean injectInputEvent(InputEvent event, int mode) {
        ...
            return mIm.injectInputEvent(event, mode);
    }
    
    base/services/core/java/com/android/server/input/InputManagerService.java
    private boolean injectInputEventInternal(InputEvent event, int mode) {
        ...
        //调用native层方法
            result = nativeInjectInputEvent(mPtr, event, pid, uid, mode,
                    INJECTION_TIMEOUT_MILLIS, WindowManagerPolicy.FLAG_DISABLE_KEY_REPEAT);
    }

如此就能将相应生成的事件传递到native层中,继续分发处理

base/services/core/jni/com_android_server_input_InputManagerService.cpp
static jint nativeInjectInputEvent(JNIEnv* env, jclass /* clazz */,
        jlong ptr, jobject inputEventObj, jint injectorPid, jint injectorUid,
        jint syncMode, jint timeoutMillis, jint policyFlags) {
    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);

        KeyEvent keyEvent;//转换成Native层的KeyEvent对象,调用InputDispatcher的injectInputEvent方法
        status_t status = android_view_KeyEvent_toNative(env, inputEventObj, & keyEvent);
        const int32_t result =
                im->getInputManager()->getDispatcher()->injectInputEvent(&keyEvent, injectorPid,
                                                                         injectorUid, syncMode,
                                                                         std::chrono::milliseconds(
                                                                                 timeoutMillis),
                                                                         uint32_t(policyFlags));
        return static_cast<jint>(result);
    
}

native/services/inputflinger/dispatcher/InputDispatcher.cpp
int32_t InputDispatcher::injectInputEvent(const InputEvent* event, int32_t injectorPid,
                                          int32_t injectorUid, int32_t syncMode,
                                          std::chrono::milliseconds timeout, uint32_t policyFlags) {

    std::queue<EventEntry*> injectedEntries;
    switch (event->getType()) {
        case AINPUT_EVENT_TYPE_KEY: {//处理Key事件

            KeyEvent keyEvent;//转换上层对象,模拟的Key事件也要走拦截的逻辑
            keyEvent.initialize(incomingKey.getId(), VIRTUAL_KEYBOARD_ID, incomingKey.getSource(),
                                incomingKey.getDisplayId(), INVALID_HMAC, action, flags, keyCode,
                                incomingKey.getScanCode(), metaState, incomingKey.getRepeatCount(),
                                incomingKey.getDownTime(), incomingKey.getEventTime());

            if (!(policyFlags & POLICY_FLAG_FILTERED)) {
                android::base::Timer t;
                mPolicy->interceptKeyBeforeQueueing(&keyEvent, /*byref*/ policyFlags);
            }

            //转换KeyEntry,入队injectedEntries
            KeyEntry* injectedEntry =
                    new KeyEntry(incomingKey.getId(), incomingKey.getEventTime(),
                                 VIRTUAL_KEYBOARD_ID, incomingKey.getSource(),
                                 incomingKey.getDisplayId(), policyFlags, action, flags, keyCode,
                                 incomingKey.getScanCode(), metaState, incomingKey.getRepeatCount(),
                                 incomingKey.getDownTime());
            injectedEntries.push(injectedEntry);
            break;
        }
    bool needWake = false;
    while (!injectedEntries.empty()) {
        //将injectedEntries加入mInboundQueue中,等待InputDispatcher分发
        needWake |= enqueueInboundEventLocked(injectedEntries.front());
        injectedEntries.pop();
}
    
    
bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) {
    ...
    mInboundQueue.push_back(entry);
    ...
}

后续和一般按键事件一样走正常的Input逻辑,待dispatchOnce调起分发流程

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值