从input tap来看事件注入的调用流程

来源:互联网 发布:手机上怎么看淘宝分销 编辑:程序博客网 时间:2024/05/28 23:12
在应用中进行 input tap 300 600这样的调用,不能在其他应用的窗口上进行事件注入,这里我们通过查看log来了解其原因

log

01-01 07:16:40.877 6841-6909/com.example.test2 I/MyService: input called 0
01-01 07:16:40.877 6841-6909/com.example.test2 I/MyService: execShellCmd start 000

01-01 07:16:41.970 6910-6910/? D/AndroidRuntime: Calling main entry com.android.commands.input.Input
01-01 07:16:41.980 6910-6910/? I/Input: injectMotionEvent: MotionEvent { action=ACTION_DOWN, actionButton=0, id[0]=0, x[0]=300.0, y[0]=600.0, toolType[0]=TOOL_TYPE_UNKNOWN, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=1124143, downTime=1124143, deviceId=1, source=0x1002 }
01-01 07:16:41.980 1223-1648/? D/InputManager-JNI: -====== nativeInjectInputEvent called, injectorUid=10099
01-01 07:16:41.980 1223-1648/? D/InputManager-JNI: -====== gMotionEventClassInfo.clazz
01-01 07:16:41.980 1223-1648/? W/InputDispatcher: -====== InputDispatcher::injectInputEvent
01-01 07:16:41.980 1223-1648/? W/InputDispatcher: -====== hasInjectionPermission, injectorUid=10099
01-01 07:16:41.980 1223-1648/? D/InputManager-JNI: -====== JNI, checkInjectEventsPermissionNonReentrant called
01-01 07:16:41.980 1223-1648/? D/JavaInject: -====== checkInjectEventsPermission, injectorUid=10099
01-01 07:16:41.981 1223-1648/? D/PackageManager: checkUidPermission called, uid=10099, userId=0, permName=android.permission.INJECT_EVENTS
01-01 07:16:41.981 1223-1648/? W/PackageManager: checkUidPermission(): android.permission.INJECT_EVENTS of 10099 is denied.
01-01 07:16:41.981 1223-1648/? I/PerfService: PerfServiceNative_boostEnableAsync:6
01-01 07:16:41.981 1223-1284/? W/InputDispatcher: -====== hasInjectionPermission, injectorUid=10099
01-01 07:16:41.981 1223-1329/? I/libPerfService: 6: set freq: 819000
01-01 07:16:41.981 1223-1284/? D/InputManager-JNI: -====== JNI, checkInjectEventsPermissionNonReentrant called
01-01 07:16:41.982 1223-1284/? D/JavaInject: -====== checkInjectEventsPermission, injectorUid=10099
01-01 07:16:41.982 1223-1329/? I/libPerfService: 6: set: 3
01-01 07:16:41.982 1223-1284/? D/PackageManager: checkUidPermission called, uid=10099, userId=0, permName=android.permission.INJECT_EVENTS
01-01 07:16:41.982 1223-1284/? W/PackageManager: checkUidPermission(): android.permission.INJECT_EVENTS of 10099 is denied.
01-01 07:16:41.982 1223-1284/? W/InputDispatcher: Permission denied: injecting event from pid 6910 uid 10099 to window Window{2a2dd8d u0 StatusBar} owned by uid 10027
01-01 07:16:41.982 1223-1648/? W/InputManager: Input event injection from pid 6910 permission denied.
01-01 07:16:41.983 1223-1648/? W/System.err: java.lang.SecurityException: Injecting to another application requires INJECT_EVENTS permission
01-01 07:16:41.983 1223-1648/? W/System.err:     at com.android.server.input.InputManagerService.injectInputEventInternal(InputManagerService.java:612)
01-01 07:16:41.983 1223-1648/? W/System.err:     at com.android.server.input.InputManagerService.injectInputEvent(InputManagerService.java:586)
01-01 07:16:41.983 1223-1648/? W/System.err:     at android.hardware.input.IInputManager$Stub.onTransact(IInputManager.java:114)
01-01 07:16:41.983 1223-1648/? W/System.err:     at android.os.Binder.execTransact(Binder.java:577)
01-01 07:16:41.984 6910-6910/? D/AndroidRuntime: Shutting down VM


                                                 --------- beginning of crash
01-01 07:16:41.986 6910-6910/? E/AndroidRuntime: *** FATAL EXCEPTION IN SYSTEM PROCESS: main
                                                 java.lang.SecurityException: Injecting to another application requires INJECT_EVENTS permission
                                                     at android.os.Parcel.readException(Parcel.java:1691)
                                                     at android.os.Parcel.readException(Parcel.java:1644)
                                                     at android.hardware.input.IInputManager$Stub$Proxy.injectInputEvent(IInputManager.java:537)
                                                     at android.hardware.input.InputManager.injectInputEvent(InputManager.java:870)
                                                     at com.android.commands.input.Input.injectMotionEvent(Input.java:270)
                                                     at com.android.commands.input.Input.sendTap(Input.java:197)
                                                     at com.android.commands.input.Input.run(Input.java:104)
                                                     at com.android.commands.input.Input.main(Input.java:59)
                                                     at com.android.internal.os.RuntimeInit.nativeFinishInit(Native Method)
                                                     at com.android.internal.os.RuntimeInit.main(RuntimeInit.java:294)




搜索Input event injection from得到InputManagerService.java

 

private boolean injectInputEventInternal(InputEvent event, int displayId, int mode) {

        if (event == null) {

            throw new IllegalArgumentException("event must not be null");

        }

        if (mode != InputManager.INJECT_INPUT_EVENT_MODE_ASYNC

                && mode != InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH

                && mode != InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_RESULT) {

            throw new IllegalArgumentException("mode is invalid");

        }

 

        final int pid = Binder.getCallingPid();

        final int uid = Binder.getCallingUid();

        final long ident = Binder.clearCallingIdentity();

        final int result;

        try {

            result = nativeInjectInputEvent(mPtr, event, displayId, pid, uid, mode,

                    INJECTION_TIMEOUT_MILLIS, WindowManagerPolicy.FLAG_DISABLE_KEY_REPEAT);

        } finally {

            Binder.restoreCallingIdentity(ident);

        }

        switch (result) {

            case INPUT_EVENT_INJECTION_PERMISSION_DENIED:

                Slog.w(TAG, "Input event injection from pid " + pid + " permission denied.");

                throw new SecurityException(

                        "Injecting to another application requires INJECT_EVENTS permission");

            case INPUT_EVENT_INJECTION_SUCCEEDED:

                return true;

            case INPUT_EVENT_INJECTION_TIMED_OUT:

                Slog.w(TAG, "Input event injection from pid " + pid + " timed out.");

                return false;

            case INPUT_EVENT_INJECTION_FAILED:

            default:

                Slog.w(TAG, "Input event injection from pid " + pid + " failed.");

                return false;

        }

    }        

 

 

搜索nativeInjectInputEvent

$ find . -name *.c*|xargs grep 'nativeInjectInputEvent'

Binary file ./out/target/common/obj/JAVA_LIBRARIES/services.core_intermediates/classes/com/android/server/input/InputManagerService.class matches

./frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp:static jint nativeInjectInputEvent(JNIEnv* env, jclass /* clazz */,

./frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp:    { "nativeInjectInputEvent", "(JLandroid/view/InputEvent;IIIIII)I",

./frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp:            (void*) nativeInjectInputEvent },

 

 

vi ./frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp

static jint nativeInjectInputEvent(JNIEnv* env, jclass /* clazz */,

        jlong ptr, jobject inputEventObj, jint displayId, jint injectorPid, jint injectorUid,

        jint syncMode, jint timeoutMillis, jint policyFlags) {

    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);

 

    if (env->IsInstanceOf(inputEventObj, gKeyEventClassInfo.clazz)) {

        KeyEvent keyEvent;

        status_t status = android_view_KeyEvent_toNative(env, inputEventObj, & keyEvent);

        if (status) {

            jniThrowRuntimeException(env, "Could not read contents of KeyEvent object.");

            return INPUT_EVENT_INJECTION_FAILED;

        }

 

        return (jint) im->getInputManager()->getDispatcher()->injectInputEvent(

                & keyEvent, displayId, injectorPid, injectorUid, syncMode, timeoutMillis,

                uint32_t(policyFlags));

    } else if (env->IsInstanceOf(inputEventObj, gMotionEventClassInfo.clazz)) {

        const MotionEvent* motionEvent = android_view_MotionEvent_getNativePtr(env, inputEventObj);

        if (!motionEvent) {

            jniThrowRuntimeException(env, "Could not read contents of MotionEvent object.");

            return INPUT_EVENT_INJECTION_FAILED;

        }

 

        return (jint) im->getInputManager()->getDispatcher()->injectInputEvent(

                motionEvent, displayId, injectorPid, injectorUid, syncMode, timeoutMillis,

                uint32_t(policyFlags));

    } else {

        jniThrowRuntimeException(env, "Invalid input event type.");

        return INPUT_EVENT_INJECTION_FAILED;

    }

}

 

 

frameworks/native/services/inputflinger/InputDispatcher.cpp

一个比较暴力的方法是,屏蔽掉权限检查的code

int32_t InputDispatcher::injectInputEvent(const InputEvent* event, int32_t displayId,

        int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis,

        uint32_t policyFlags) {

 

ALOGD("=====<<<<<>>>>>5-4 policyFlags |= POLICY_FLAG_TRUSTED");

    if (hasInjectionPermission(injectorPid, injectorUid)) {

        policyFlags |= POLICY_FLAG_TRUSTED;

    }

 

 

bool InputDispatcher::hasInjectionPermission(int32_t injectorPid, int32_t injectorUid) {


ALOGD("hasInjectionPermission called");


    return injectorUid == 0

            || mPolicy->checkInjectEventsPermissionNonReentrant(injectorPid, injectorUid);

}

 

这样就可以进行跨进程,跨页面进行点击了

调到了frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp中的

bool NativeInputManager::checkInjectEventsPermissionNonReentrant(

        int32_t injectorPid, int32_t injectorUid) {

ALOGD("-====== JNI, checkInjectEventsPermissionNonReentrant called");

    JNIEnv* env = jniEnv();

    jboolean result = env->CallBooleanMethod(mServiceObj,

            gServiceClassInfo.checkInjectEventsPermission, injectorPid, injectorUid);

    if (checkAndClearExceptionFromCallback(env, "checkInjectEventsPermission")) {

        result = false;

    }

    return result;

}

 

里面又回调到InputManagerService.java中的

    // Native callback.

    private boolean checkInjectEventsPermission(int injectorPid, int injectorUid) {

        return mContext.checkPermission(android.Manifest.permission.INJECT_EVENTS,

                injectorPid, injectorUid) == PackageManager.PERMISSION_GRANTED;

    }

 

检查INJECT_EVENTS权限


只有系统级ap才可以有INJECT_EVENTS permission,这样设计的目的是为了系统安全

 


原创粉丝点击