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调起分发流程