android InputChannel;
android FD的概念
1.全局监听是在SystemGesturesPointerEventListener.java中的
在DisplayPolicy的构造方法中,有new方法
mSystemGestures = new SystemGesturesPointerEventListener(mContext, mHandler,
new SystemGesturesPointerEventListener.Callbacks()
这就实现了全局的SystemGesturesPointerEventListener,
displayContent.registerPointerEventListener(mSystemGestures);这句就是监听传到
在DisplayContent构造方法中,new 了 DisplayPolicy对象
mDisplayPolicy = new DisplayPolicy(service, this);
在看看构造方法传入的参数 DisplayContent(Display display, WindowManagerService service,
ActivityDisplay activityDisplay)
在RootWindowContainer中新建的DisplayContent,
display是什么呢,就是显示,双屏或者外显的话 就是不同的display对象
再看DisplayContent中方法
void registerPointerEventListener(@NonNull PointerEventListener listener) {
mPointerEventDispatcher.registerInputEventListener(listener);
}
final InputChannel inputChannel = mWmService.mInputManager.monitorInput(
"PointerEventDispatcher" + mDisplayId, mDisplayId);
mPointerEventDispatcher = new PointerEventDispatcher(inputChannel);
重点来了,点击触摸事件是怎么传递的, 重点就是这个InputChannel ,驱动事件就是通过这个来传递的,实际上,
每个activity/window都是有InputChannel对象的, 那他们怎么通信的呢,这里先思考一下,这是不是属于android跨进程通信, 思考一下有哪些方法可以做到跨进程,这里毫无疑问 用的socket,快速,双工通信
代码分析android.view.InputChannel.java android.view.InputChannel.aidl
android_view_InputChannel.cpp
frameworks\native\libs\input\InputTransport.cpp
status_t InputChannel::openInputChannelPair(const std::string& name,
sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) {
int sockets[2];
if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) {
status_t result = -errno;
ALOGE("channel '%s' ~ Could not create socket pair. errno=%d",
name.c_str(), errno);
outServerChannel.clear();
outClientChannel.clear();
return result;
}
int bufferSize = SOCKET_BUFFER_SIZE;
setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));
setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));
setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));
setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));
std::string serverChannelName = name;
serverChannelName += " (server)";
outServerChannel = new InputChannel(serverChannelName, sockets[0]);
std::string clientChannelName = name;
clientChannelName += " (client)";
outClientChannel = new InputChannel(clientChannelName, sockets[1]);
return OK;
}
InputChannel::InputChannel(const std::string& name, int fd) :
mName(name) {
#if DEBUG_CHANNEL_LIFECYCLE
ALOGD("Input channel constructed: name='%s', fd=%d",
mName.c_str(), fd);
#endif
setFd(fd);
}
了解C++的同学,应该知道这里, 其实就相当于建立了socket通信,这也有一个关键点,文件描述符FD的概念,
做android的要记住一点,android基于linux,我对linux其实也是一知半解,但是linux有一个概念, 一切皆文件,
简单来说,这里有两个FD,通过这两个FD,两个文件之间建立了socket通信,这样就完成了事件的传递
这里就是分析一下点击触摸事件是怎么传递的,修改其实很简单
代码如下(示例):
diff --git a/alps/frameworks/base/services/core/java/com/android/server/wm/DisplayPolicy.java b/alps/frameworks/base/services/core/java/com/android/server/wm/DisplayPolicy.java
index 43ccbcee3f..b5221ac51f 100644
--- a/alps/frameworks/base/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/alps/frameworks/base/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -149,6 +149,7 @@ import android.view.InsetsState;
import android.view.MotionEvent;
import android.view.PointerIcon;
import android.view.Surface;
+import android.view.KeyEvent;
import android.view.View;
import android.view.ViewRootImpl;
import android.view.WindowManager;
@@ -481,6 +482,15 @@ public class DisplayPolicy {
@Override
public void onSwipeFromRight() {
+
+ long now = SystemClock.uptimeMillis();
+ KeyEvent down = new KeyEvent(now, now, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK, 0);
+ InputManager.getInstance().injectInputEvent(down, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
+ KeyEvent up = new KeyEvent(now, now, KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK, 0);
+ InputManager.getInstance().injectInputEvent(up, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
+
+
+
final Region excludedRegion;
synchronized (mLock) {
excludedRegion = mDisplayContent.calculateSystemGestureExclusion();
@@ -496,6 +506,13 @@ public class DisplayPolicy {
@Override
public void onSwipeFromLeft() {
+
+ long now = SystemClock.uptimeMillis();
+ KeyEvent down = new KeyEvent(now, now, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK, 0);
+ InputManager.getInstance().injectInputEvent(down, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
+ KeyEvent up = new KeyEvent(now, now, KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK, 0);
+ InputManager.getInstance().injectInputEvent(up, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
+
final Region excludedRegion;
synchronized (mLock) {
excludedRegion = mDisplayContent.calculateSystemGestureExclusion();
这里其实写返回键的代码,可以参考systemui的KeyButtonView.java中
private void sendEvent(int action, int flags, long when) {
mMetricsLogger.write(new LogMaker(MetricsEvent.ACTION_NAV_BUTTON_EVENT)
.setType(MetricsEvent.TYPE_ACTION)
.setSubtype(mCode)
.addTaggedData(MetricsEvent.FIELD_NAV_ACTION, action)
.addTaggedData(MetricsEvent.FIELD_FLAGS, flags));
// TODO(b/122195391): Added logs to make sure sysui is sending back button events
if (mCode == KeyEvent.KEYCODE_BACK && flags != KeyEvent.FLAG_LONG_PRESS) {
Log.i(TAG, "Back button event: " + KeyEvent.actionToString(action));
if (action == MotionEvent.ACTION_UP) {
mOverviewProxyService.notifyBackAction((flags & KeyEvent.FLAG_CANCELED) == 0,
-1, -1, true /* isButton */, false /* gestureSwipeLeft */);
}
}
final int repeatCount = (flags & KeyEvent.FLAG_LONG_PRESS) != 0 ? 1 : 0;
final KeyEvent ev = new KeyEvent(mDownTime, when, action, mCode, repeatCount,
0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
flags | KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY,
InputDevice.SOURCE_KEYBOARD);
int displayId = INVALID_DISPLAY;
// Make KeyEvent work on multi-display environment
if (getDisplay() != null) {
displayId = getDisplay().getDisplayId();
}
// Bubble controller will give us a valid display id if it should get the back event
BubbleController bubbleController = Dependency.get(BubbleController.class);
int bubbleDisplayId = bubbleController.getExpandedDisplayId(mContext);
if (mCode == KeyEvent.KEYCODE_BACK && bubbleDisplayId != INVALID_DISPLAY) {
displayId = bubbleDisplayId;
}
if (displayId != INVALID_DISPLAY) {
ev.setDisplayId(displayId);
}
mInputManager.injectInputEvent(ev, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
}
中间的一大堆就可以不用看了, 看在哪里调用的sendEvent方法;
onTouchEvent中
sendEvent(KeyEvent.ACTION_DOWN, 0, mDownTime);
sendEvent(KeyEvent.ACTION_UP, KeyEvent.FLAG_CANCELED);
以及最后一句
mInputManager.injectInputEvent(ev, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
这就相当于发送了返回键的键值
adb shell input keyevent 4
第二种方法,runtime发送adb命令 ,这个自己百度