Instrumentation中的sendKeyDownUpSync的调用过程

1、使用方法
Instrumentation inst = new Instrumentation();
inst.sendKeyDownUpSync(keyCode);//其中keyCode是要发送的键值比如,确认按键,在KeyEvent.java定义为23,keyCode 就是23
2、/frameworks/base/core/java/android/app/Instrumentation.java

public void sendKeyDownUpSync(int keyCode) {
     sendKeySync(new KeyEvent(KeyEvent.ACTION_DOWN, keyCode));//根据keyCode new了一个KeyEvent
     sendKeySync(new KeyEvent(KeyEvent.ACTION_UP, keyCode));
}

之后会调用sendKeySync接口发送按键

public void sendKeySync(KeyEvent event) {
     validateNotAppThread();  
     long downTime = event.getDownTime();
     long eventTime = event.getEventTime();
     int source = event.getSource();
     if (source == InputDevice.SOURCE_UNKNOWN) {
          source = InputDevice.SOURCE_KEYBOARD;
     }
     if (eventTime == 0) {
          eventTime = SystemClock.uptimeMillis();
     }
     if (downTime == 0) {
          downTime = eventTime;
     }
     KeyEvent newEvent = new KeyEvent(event);
     newEvent.setTime(downTime, eventTime);
     newEvent.setSource(source);
     newEvent.setFlags(event.getFlags() | KeyEvent.FLAG_FROM_SYSTEM);
     setDisplayIfNeeded(newEvent);
     InputManagerGlobal.getInstance().injectInputEvent(newEvent,
          InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH);
}
 

前面在都会event进行设置,最后调用injectInputEvent进行下一步转发
调用到/frameworks/base/core/java/android/hardware/input/InputManagerGlobal.java 里的

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);
           //其中,mIm是IInputManager的对象,InputManagerService实现了IInputManager接口,所以这里调用到InputManagerService.java的injectInputEventToTarget接口
    } catch (RemoteException ex) {
           throw ex.rethrowFromSystemServer();
    }
 }
  

之后到 /frameworks/base/services/core/java/com/android/server/input/InputManagerService.java
会用到

result = mNative.injectInputEvent(event, injectIntoUid,
                    targetUid, mode, INJECTION_TIMEOUT_MILLIS,
                    WindowManagerPolicy.FLAG_DISABLE_KEY_REPEAT);
 //其中mNative是NativeInputManagerService的对象,injectInputEvent的实现在/frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp

com_android_server_input_InputManagerService.cpp

 {"injectInputEvent", "(Landroid/view/InputEvent;ZIIII)I", (void*)nativeInjectInputEvent},


static jint nativeInjectInputEvent(JNIEnv* env, jobject nativeImplObj, jobject inputEventObj,
                                     jboolean injectIntoUid, jint uid, jint syncMode,
                                     jint timeoutMillis, jint policyFlags) {
    NativeInputManager* im = getNativeInputManager(env, nativeImplObj);
    const std::optional<int32_t> targetUid = injectIntoUid ? std::make_optional(uid):                                      
                                                                   std::nullopt;
    // static_cast is safe because the value was already checked at the Java layer
    //if判断该event是Motion的还是keyEvent,我们发送的是keyevent 
    InputEventInjectionSync mode = static_cast<InputEventInjectionSync>(syncMode);
    if (env->IsInstanceOf(inputEventObj, gKeyEventClassInfo.clazz)) {
          const KeyEvent keyEvent = android_view_KeyEvent_toNative(env, inputEventObj);
          const InputEventInjectionResult result =
                  im->getInputManager()->getDispatcher().injectInputEvent(&keyEvent,                                                
                  targetUid,   
                  mode,std::chrono::milliseconds(timeoutMillis),uint32_t(policyFlags));
          return static_cast<jint>(result);
     } int>(InputEventInjectionResult::FAILED);
    }
    .....................................
}

下一步到/frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp里的injectInputEvent,代码很多,主要最后会调用到

mPolicy.interceptKeyBeforeQueueing(keyEvent, /*byref*/ policyFlags);

其中,InputDispatcherPolicyInterface& mPolicy
而NativeInputManager继承InputDispatcherPolicyInterface,所以我们查看/frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp 里的
NativeInputManager的接口实现

void NativeInputManager::interceptKeyBeforeQueueing(const KeyEvent& keyEvent,
                                                     uint32_t& policyFlags) {
     .........
     jint wmActions = env->CallIntMethod(mServiceObj,     
                                          gServiceClassInfo.interceptKeyBeforeQueueing,
                                          eyEventObj.get(), policyFlags);
     //这里调用到了mServiceObj对象中的interceptKeyBeforeQueueing方法,即InputManagerService.java
     //里的interceptKeyBeforeQueueing方法
}
@SuppressWarnings("unused")
private int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
     synchronized (mFocusEventDebugViewLock) {
         if (mFocusEventDebugView != null) {
             mFocusEventDebugView.reportEvent(event);
          }
     }
     return mWindowManagerCallbacks.interceptKeyBeforeQueueing(event, policyFlags);
}

之后到/frameworks/base/services/core/java/com/android/server/wm/InputManagerCallback.java

public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
     return mService.mPolicy.interceptKeyBeforeQueueing(event, policyFlags);
}

又到/frameworks/base/services/core/java/com/android/server/policy/WindowManagerPolicy.java

 public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags);

而/frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java 中的class PhoneWindowManager implements WindowManagerPolicy,所以到这里就到了我们一般修改的按键拦截类PhoneWindowManager

 public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
     final int keyCode = event.getKeyCode();
     final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
     boolean isWakeKey = (policyFlags & WindowManagerPolicy.FLAG_WAKE) != 0 || 
                             event.isWakeKey();
    ..............................
    //在这个类中可以做自定义的按键拦截
}
安装Docker安装插件,可以按照以下步骤进行操作: 1. 首先,安装Docker。可以按照官方文档提供的步骤进行安装,或者使用适合您操作系统的包管理器进行安装。 2. 安装Docker Compose插件。可以使用以下方法安装: 2.1 下载指定版本的docker-compose文件: curl -L https://github.com/docker/compose/releases/download/1.21.2/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose 2.2 赋予docker-compose文件执行权限: chmod +x /usr/local/bin/docker-compose 2.3 验证安装是否成功: docker-compose --version 3. 在安装插件之前,可以测试端口是否已被占用,以避免编排过程中出错。可以使用以下命令安装netstat并查看端口号是否被占用: yum -y install net-tools netstat -npl | grep 3306 现在,您已经安装Docker安装Docker Compose插件,可以继续进行其他操作,例如上传docker-compose.yml文件到服务器,并在服务器上安装MySQL容器。可以参考Docker的官方文档或其他资源来了解如何使用DockerDocker Compose进行容器的安装和配置。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [Docker安装docker-compose插件](https://blog.youkuaiyun.com/qq_50661854/article/details/124453329)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *3* [Docker安装MySQL docker安装mysql 完整详细教程](https://blog.youkuaiyun.com/qq_40739917/article/details/130891879)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值