adb shell
命令都继承 ShellCommand.java
adb shell input
跳过 inputReader 的过程封装 MotionEvent 到 InputDispatcher
InputShellCommand
frameworks/base/services/core/java/com/android/server/input/InputShellCommand.java
/**
* Builds a MotionEvent and injects it into the event stream.
*
* @param inputSource the InputDevice.SOURCE_* sending the input event
* @param action the MotionEvent.ACTION_* for the event
* @param downTime the value of the ACTION_DOWN event happened
* @param when the value of SystemClock.uptimeMillis() at which the event happened
* @param x x coordinate of event
* @param y y coordinate of event
* @param pressure pressure of event
*/
private void injectMotionEvent(int inputSource, int action, long downTime, long when,
float x, float y, float pressure, int displayId) {
final int pointerCount = 1;
MotionEvent.PointerProperties[] pointerProperties =
new MotionEvent.PointerProperties[pointerCount];
MotionEvent.PointerCoords[] pointerCoords = new MotionEvent.PointerCoords[pointerCount];
for (int i = 0; i < pointerCount; i++) {
pointerProperties[i] = new MotionEvent.PointerProperties();
pointerProperties[i].id = i;
pointerProperties[i].toolType = getToolType(inputSource);
pointerCoords[i] = new MotionEvent.PointerCoords();
pointerCoords[i].x = x;
pointerCoords[i].y = y;
pointerCoords[i].pressure = pressure;
pointerCoords[i].size = DEFAULT_SIZE;
}
if (displayId == INVALID_DISPLAY
&& (inputSource & InputDevice.SOURCE_CLASS_POINTER) != 0) {
displayId = DEFAULT_DISPLAY;
}
MotionEvent event = MotionEvent.obtain(downTime, when, action, pointerCount,
pointerProperties, pointerCoords, DEFAULT_META_STATE, DEFAULT_BUTTON_STATE,
DEFAULT_PRECISION_X, DEFAULT_PRECISION_Y, getInputDeviceId(inputSource),
DEFAULT_EDGE_FLAGS, inputSource, displayId, DEFAULT_FLAGS);
InputManagerGlobal.getInstance().injectInputEvent(event,
InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH);
}
InputManagerGlobal
/**
* Manages communication with the input manager service on behalf of
* an application process. You're probably looking for { @link InputManager}.
*
* @hide
*/
public final class InputManagerGlobal {
...
/**
* @see InputManager#injectInputEvent(InputEvent, int, int)
*/
public boolean injectInputEvent(InputEvent event, int mode, int targetUid) {
Objects.requireNonNull(event , "event must not be null");
if (mode != InputEventInjectionSync.NONE
&& mode != InputEventInjectionSync.WAIT_FOR_FINISHED
&& mode != InputEventInjectionSync.WAIT_FOR_RESULT) {
throw new IllegalArgumentException("mode is invalid");
}
try {
return mIm.injectInputEventToTarget(event, mode, targetUid);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
}
InputManagerService
@Override // Binder call
public boolean injectInputEventToTarget(InputEvent event, int mode, int targetUid) {
if (!checkCallingPermission(android.Manifest.permission.INJECT_EVENTS,
"injectInputEvent()", true /*checkInstrumentationSource*/)) {
throw new SecurityException(
"Injecting input events requires the caller (or the source of the "
+ "instrumentation, if any) to have the INJECT_EVENTS permission.");
}
// We are not checking if targetUid matches the callingUid, since having the permission
// already means you can inject into any window.
Objects.requireNonNull(event, "event must not be null");
if (mode != InputEventInjectionSync.NONE
&& mode != InputEventInjectionSync.WAIT_FOR_FINISHED
&& mode != InputEventInjectionSync.WAIT_FOR_RESULT) {
throw new IllegalArgumentException("mode is invalid");
}
final int pid = Binder.getCallingPid();
final long ident = Binder.clearCallingIdentity();
final boolean injectIntoUid = targetUid != Process.INVALID_UID;
final int result;
try {
result = mNative.injectInputEvent(event, injectIntoUid,
targetUid, mode, INJECTION_TIMEOUT_MILLIS,
WindowManagerPolicy.FLAG_DISABLE_KEY_REPEAT);
} finally {
Binder.restoreCallingIdentity(ident);
}
switch (result) {
case InputEventInjectionResult.SUCCEEDED:
return true;
case InputEventInjectionResult.TARGET_MISMATCH:
if (!injectIntoUid) {
throw new IllegalStateException("Injection should not result in TARGET_MISMATCH"
+ " when it is not targeted into to a specific uid.");
}
throw new IllegalArgumentException(
"Targeted input event injection from pid " + pid
+ " was not directed at a window owned by uid "
+ targetUid + ".");
case InputEventInjectionResult.TIMED_OUT:
Slog.w(TAG, "Input event injection from pid " + pid + " timed out.");
return false;
case InputEventInjectionResult.FAILED:
default:
Slog.w(TAG, "Input event injection from pid " + pid + " failed.");
return false;
}
}
NativeInputManagerService
@Override
public native int injectInputEvent(InputEvent event, boolean injectIntoUid, int uid,
int syncMode, int timeoutMillis, int policyFlags);
InputDispatcher.cpp
总结
通过 injectMotionEvent 方法传递触摸事件都只跳过了 inputReader , 进入 inputDisptecher , 要通过 WindowManagerService 的过滤策略