我们可以在手机adb shell中,使用input来模拟按键,和之前的sm类似,input也是一个进程,在framework/base/cmds目录下。

一、Input源码

下面我们先看下input的源码:

[cpp] view plain copy
  1. private void run(String[] args) {  
  2.        if (args.length < 1) {  
  3.            showUsage();  
  4.            return;  
  5.        }  
  6.   
  7.        int index = 0;  
  8.        String command = args[index];  
  9.        int inputSource = InputDevice.SOURCE_UNKNOWN;  
  10.        if (SOURCES.containsKey(command)) {  
  11.            inputSource = SOURCES.get(command);  
  12.            index++;  
  13.            command = args[index];  
  14.        }  
  15.        final int length = args.length - index;  
  16.   
  17.        try {  
  18.            if (command.equals("text")) {  
  19.                if (length == 2) {  
  20.                    inputSource = getSource(inputSource, InputDevice.SOURCE_KEYBOARD);  
  21.                    sendText(inputSource, args[index+1]);  
  22.                    return;  
  23.                }  
  24.            } else if (command.equals("keyevent")) {  
  25.                if (length >= 2) {  
  26.                    final boolean longpress = "--longpress".equals(args[index + 1]);  
  27.                    final int start = longpress ? index + 2 : index + 1;  
  28.                    inputSource = getSource(inputSource, InputDevice.SOURCE_KEYBOARD);  
  29.                    if (length > start) {  
  30.                        for (int i = start; i < length; i++) {  
  31.                            int keyCode = KeyEvent.keyCodeFromString(args[i]);  
  32.                            if (keyCode == KeyEvent.KEYCODE_UNKNOWN) {  
  33.                                keyCode = KeyEvent.keyCodeFromString("KEYCODE_" + args[i]);  
  34.                            }  
  35.                            sendKeyEvent(inputSource, keyCode, longpress);  
  36.                        }  
  37.                        return;  
  38.                    }  
  39.                }  
  40.            }.............  

我们再来看看sendKeyEvent函数

[cpp] view plain copy
  1. private void sendKeyEvent(int inputSource, int keyCode, boolean longpress) {  
  2.     long now = SystemClock.uptimeMillis();  
  3.     injectKeyEvent(new KeyEvent(now, now, KeyEvent.ACTION_DOWN, keyCode, 0, 0,  
  4.             KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, inputSource));  
  5.     if (longpress) {  
  6.         injectKeyEvent(new KeyEvent(now, now, KeyEvent.ACTION_DOWN, keyCode, 1, 0,  
  7.                 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_LONG_PRESS,  
  8.                 inputSource));  
  9.     }  
  10.     injectKeyEvent(new KeyEvent(now, now, KeyEvent.ACTION_UP, keyCode, 0, 0,  
  11.             KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, inputSource));  
  12. }  

最后再来看看injectKeyEvent函数,其主要还是调用了,InputManager中的injectInputEvent函数。

[cpp] view plain copy
  1. private void injectKeyEvent(KeyEvent event) {  
  2.     Log.i(TAG, "injectKeyEvent: " + event);  
  3.     InputManager.getInstance().injectInputEvent(event,  
  4.             InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH);  
  5. }  


二、InputManager相关代码

我们再来看看InputManager的injectInputEvent函数,最后还是调用了InputManagerService的injectInputEvent函数。

[cpp] view plain copy
  1. public boolean injectInputEvent(InputEvent event, int mode) {  
  2.     if (event == null) {  
  3.         throw new IllegalArgumentException("event must not be null");  
  4.     }  
  5.     if (mode != INJECT_INPUT_EVENT_MODE_ASYNC  
  6.             && mode != INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH  
  7.             && mode != INJECT_INPUT_EVENT_MODE_WAIT_FOR_RESULT) {  
  8.         throw new IllegalArgumentException("mode is invalid");  
  9.     }  
  10.   
  11.     try {  
  12.         return mIm.injectInputEvent(event, mode);//调用了InputManagerService的injectInputEvent函数  
  13.     } catch (RemoteException ex) {  
  14.         return false;  
  15.     }  
  16. }  

我们再来看看InputManagerService的injectInputEvent函数

[cpp] view plain copy
  1. @Override // Binder call  
  2. public boolean injectInputEvent(InputEvent event, int mode) {  
  3.     return injectInputEventInternal(event, Display.DEFAULT_DISPLAY, mode);  
  4. }  

我们再来看injectInputEventInternal函数

[cpp] view plain copy
  1. private boolean injectInputEventInternal(InputEvent event, int displayId, int mode) {  
  2.     if (event == null) {  
  3.         throw new IllegalArgumentException("event must not be null");  
  4.     }  
  5.     if (mode != InputManager.INJECT_INPUT_EVENT_MODE_ASYNC  
  6.             && mode != InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH  
  7.             && mode != InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_RESULT) {  
  8.         throw new IllegalArgumentException("mode is invalid");  
  9.     }  
  10.   
  11.     final int pid = Binder.getCallingPid();  
  12.     final int uid = Binder.getCallingUid();  
  13.     final long ident = Binder.clearCallingIdentity();  
  14.     final int result;  
  15.     try {  
  16.         result = nativeInjectInputEvent(mPtr, event, displayId, pid, uid, mode,//主要看这个jni函数  
  17.                 INJECTION_TIMEOUT_MILLIS, WindowManagerPolicy.FLAG_DISABLE_KEY_REPEAT);  
  18.     } finally {  
  19.         Binder.restoreCallingIdentity(ident);  
  20.     }  
  21.     switch (result) {  
  22.         case INPUT_EVENT_INJECTION_PERMISSION_DENIED:  
  23.             Slog.w(TAG, "Input event injection from pid " + pid + " permission denied.");  
  24.             throw new SecurityException(  
  25.                     "Injecting to another application requires INJECT_EVENTS permission");  
  26.         case INPUT_EVENT_INJECTION_SUCCEEDED:  
  27.             return true;  
  28.         case INPUT_EVENT_INJECTION_TIMED_OUT:  
  29.             Slog.w(TAG, "Input event injection from pid " + pid + " timed out.");  
  30.             return false;  
  31.         case INPUT_EVENT_INJECTION_FAILED:  
  32.         default:  
  33.             Slog.w(TAG, "Input event injection from pid " + pid + " failed.");  
  34.             return false;  
  35.     }  
  36. }  


三、native层代码

上面这个函数主要调用了nativeInjectInputEvent这个native函数。

[cpp] view plain copy
  1. static jint nativeInjectInputEvent(JNIEnv* env, jclass /* clazz */,  
  2.         jlong ptr, jobject inputEventObj, jint displayId, jint injectorPid, jint injectorUid,  
  3.         jint syncMode, jint timeoutMillis, jint policyFlags) {  
  4.     NativeInputManager* im = reinterpret_cast(ptr);  
  5.   
  6.     if (env->IsInstanceOf(inputEventObj, gKeyEventClassInfo.clazz)) {  
  7.         KeyEvent keyEvent;  
  8.         status_t status = android_view_KeyEvent_toNative(env, inputEventObj, & keyEvent);  
  9.         if (status) {  
  10.             jniThrowRuntimeException(env, "Could not read contents of KeyEvent object.");  
  11.             return INPUT_EVENT_INJECTION_FAILED;  
  12.         }  
  13.   
  14.         return (jint) im->getInputManager()->getDispatcher()->injectInputEvent(  
  15.                 & keyEvent, displayId, injectorPid, injectorUid, syncMode, timeoutMillis,  
  16.                 uint32_t(policyFlags));  
  17.     } else if (env->IsInstanceOf(inputEventObj, gMotionEventClassInfo.clazz)) {  
  18.         const MotionEvent* motionEvent = android_view_MotionEvent_getNativePtr(env, inputEventObj);  
  19.         if (!motionEvent) {  
  20.             jniThrowRuntimeException(env, "Could not read contents of MotionEvent object.");  
  21.             return INPUT_EVENT_INJECTION_FAILED;  
  22.         }  
  23.   
  24.         return (jint) im->getInputManager()->getDispatcher()->injectInputEvent(  
  25.                 motionEvent, displayId, injectorPid, injectorUid, syncMode, timeoutMillis,  
  26.                 uint32_t(policyFlags));  
  27.     } else {  
  28.         jniThrowRuntimeException(env, "Invalid input event type.");  
  29.         return INPUT_EVENT_INJECTION_FAILED;  
  30.     }  
  31. }  

这个函数先根据event的种类,有KeyEvent,MoveEvent来调用相关函数。我们再来看看InputDispatcher::injectInputEvent函数

[cpp] view plain copy
  1. int32_t InputDispatcher::injectInputEvent(const InputEvent* event, int32_t displayId,  
  2.         int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis,  
  3.         uint32_t policyFlags) {  
  4.   
  5.     nsecs_t endTime = now() + milliseconds_to_nanoseconds(timeoutMillis);  
  6.   
  7.     policyFlags |= POLICY_FLAG_INJECTED;  
  8.     if (hasInjectionPermission(injectorPid, injectorUid)) {  
  9.         policyFlags |= POLICY_FLAG_TRUSTED;  
  10.     }  
  11.   
  12.     EventEntry* firstInjectedEntry;  
  13.     EventEntry* lastInjectedEntry;  
  14.     switch (event->getType()) {  
  15.     case AINPUT_EVENT_TYPE_KEY: {  
  16.         const KeyEvent* keyEvent = static_cast<const KeyEvent*>(event);  
  17.         int32_t action = keyEvent->getAction();  
  18.         if (! validateKeyEvent(action)) {  
  19.             return INPUT_EVENT_INJECTION_FAILED;  
  20.         }  
  21.   
  22.         int32_t flags = keyEvent->getFlags();  
  23.         if (flags & AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY) {  
  24.             policyFlags |= POLICY_FLAG_VIRTUAL;  
  25.         }  
  26.   
  27.         if (!(policyFlags & POLICY_FLAG_FILTERED)) {  
  28.             mPolicy->interceptKeyBeforeQueueing(keyEvent, /*byref*/ policyFlags);  
  29.         }  
  30.   
  31.         mLock.lock();  
  32.         firstInjectedEntry = new KeyEntry(keyEvent->getEventTime(),  
  33.                 keyEvent->getDeviceId(), keyEvent->getSource(),  
  34.                 policyFlags, action, flags,  
  35.                 keyEvent->getKeyCode(), keyEvent->getScanCode(), keyEvent->getMetaState(),  
  36.                 keyEvent->getRepeatCount(), keyEvent->getDownTime());  
  37.         lastInjectedEntry = firstInjectedEntry;  
  38.         break;  
  39.      ......  
  40.     }  
  41.   
  42.     InjectionState* injectionState = new InjectionState(injectorPid, injectorUid);  
  43.     if (syncMode == INPUT_EVENT_INJECTION_SYNC_NONE) {  
  44.         injectionState->injectionIsAsync = true;  
  45.     }  
  46.   
  47.     injectionState->refCount += 1;  
  48.     lastInjectedEntry->injectionState = injectionState;  
  49.   
  50.     bool needWake = false;  
  51.     for (EventEntry* entry = firstInjectedEntry; entry != NULL; ) {  
  52.         EventEntry* nextEntry = entry->next;  
  53.         needWake |= enqueueInboundEventLocked(entry);  
  54.         entry = nextEntry;  
  55.     }  
  56. ......  

这个函数和notifyKey函数很像,notifyKey函数是正常走按键流程在dispatchReader中调用的函数。这里也会想notifyKey一样,先调用PhoneWindowManager的interceptKeyBeforeQueueing函数,然后根据不同类型的Event,然后创建EventEntry,最后调用了enqueueInboundEventLocked函数,这个函数之前在按键流程中分析过了。最后也会调用mLooper->wake函数,把InputDispatcherThread线程唤醒,然后执行dispatchOnce函数:

[cpp] view plain copy
  1. bool InputDispatcherThread::threadLoop() {  
  2.     mDispatcher->dispatchOnce();  
  3.     return true;  
  4. }  
dispatchOnce函数会调用dispatchOnceInnerLocked函数,最终发送按键消息到应用。当执行到mLooper->pollOnce函数时,会阻塞。这个在之前的消息机制中介绍过。
[cpp] view plain copy
  1. void InputDispatcher::dispatchOnce() {  
  2.     nsecs_t nextWakeupTime = LONG_LONG_MAX;  
  3.     { // acquire lock  
  4.         AutoMutex _l(mLock);  
  5.         mDispatcherIsAliveCondition.broadcast();  
  6.   
  7.         // Run a dispatch loop if there are no pending commands.  
  8.         // The dispatch loop might enqueue commands to run afterwards.  
  9.         if (!haveCommandsLocked()) {  
  10.             dispatchOnceInnerLocked(&nextWakeupTime);  
  11.         }  
  12.   
  13.         // Run all pending commands if there are any.  
  14.         // If any commands were run then force the next poll to wake up immediately.  
  15.         if (runCommandsLockedInterruptible()) {  
  16.             nextWakeupTime = LONG_LONG_MIN;  
  17.         }  
  18.     } // release lock  
  19.   
  20.     // Wait for callback or timeout or wake.  (make sure we round up, not down)  
  21.     nsecs_t currentTime = now();  
  22.     int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime);  
  23.     mLooper->pollOnce(timeoutMillis);  
  24. }  

这样整个adb input命令模拟按键的过程就比较清楚了。

更多相关文章

  1. Android中JNI调用
  2. 使用Android(安卓)AsyncTask异步线程
  3. android启动Activity的两种方法
  4. Android(安卓)MediaRecorder录制音频的方法
  5. 在Android(安卓)8.0之后版本上添加Hidl Service
  6. Android:startActivityForResult 和 onActivityResult 问题
  7. android notepad详解
  8. 关于Handler的拦截
  9. Android(安卓)网络管理

随机推荐

  1. Robotium学习笔记一
  2. Android: 设置wifi设备名
  3. android音频采集,MediaCodec实时PCM转AAC
  4. Android(安卓)NDK学习 简介
  5. Ubuntu Qt安装安卓android编译器
  6. 准备一个rubymotion for android的实际项
  7. android 内存泄漏的分析
  8. Android(安卓)Studio第三十八期 - HIOS跳
  9. Android中拍照、图片、录音、视频和音频
  10. Android:Property Animation