(笔记)InputChannel跨进程传输机制深度分析

概述

InputChannel是Android输入系统中负责跨进程事件传输的核心组件,它建立了InputDispatcher(SystemServer进程)与应用程序(App进程)之间的高效通信通道。本文深入分析InputChannel的实现机制,包括socket pair通信、事件传输协议、以及应用层接收机制。
AOSP源码 基于Android 7.0

InputChannel整体架构

┌─────────────────────────────────────────────────────────────┐
│                  SystemServer 进程                          │
│  ┌─────────────────────────────────────────────────────┐   │
│  │              InputDispatcher                        │   │
│  │  ┌─────────────────────────────────────────────┐   │   │
│  │  │           InputPublisher                    │   │   │
│  │  │  ┌─────────────────────────────────────┐   │   │   │
│  │  │  │    Server Socket (写端)              │   │   │   │
│  │  │  └─────────────────────────────────────┘   │   │   │
│  │  └─────────────────────────────────────────────┘   │   │
│  └─────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────┘││ Unix Domain Socket Pair│ (SOCK_SEQPACKET)│
┌─────────────────────────────────────────────────────────────┐
│                   Application 进程                          │
│  ┌─────────────────────────────────────────────────────┐   │
│  │                ViewRootImpl                         │   │
│  │  ┌─────────────────────────────────────────────┐   │   │
│  │  │         InputEventReceiver                  │   │   │
│  │  │  ┌─────────────────────────────────────┐   │   │   │
│  │  │  │       InputConsumer                 │   │   │   │
│  │  │  │  ┌─────────────────────────────┐   │   │   │   │
│  │  │  │  │   Client Socket (读端)       │   │   │   │   │
│  │  │  │  └─────────────────────────────┘   │   │   │   │
│  │  │  └─────────────────────────────────────┘   │   │   │
│  │  └─────────────────────────────────────────────┘   │   │
│  └─────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────┘

1. InputChannel的创建和注册

1.1 创建流程

InputChannel的创建是在应用窗口添加到WindowManager时完成的:

应用启动/窗口创建│▼
Activity.setContentView()│▼
ViewRootImpl.setView()│▼
WindowManagerService.addWindow()│▼
InputChannel.openInputChannelPair()│▼
创建Socket Pair
├─ Server Socket → InputDispatcher
└─ Client Socket → Application

1.2 Socket Pair创建代码

文件路径: frameworks/native/libs/input/InputTransport.cpp

status_t InputChannel::openInputChannelPair(const String8& name,sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) {int sockets[2];// 创建Unix域套接字对,使用SOCK_SEQPACKET确保消息边界if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) {status_t result = -errno;ALOGE("channel '%s' ~ Could not create socket pair. errno=%d",name.string(), errno);outServerChannel.clear();outClientChannel.clear();return result;}// 设置socket缓冲区大小为32KB,足够存储多个大型触摸事件int bufferSize = SOCKET_BUFFER_SIZE;  // 32 * 1024setsockopt(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));// 创建服务端通道(InputDispatcher使用)String8 serverChannelName = name;serverChannelName.append(" (server)");outServerChannel = new InputChannel(serverChannelName, sockets[0]);// 创建客户端通道(应用程序使用)String8 clientChannelName = name;clientChannelName.append(" (client)");outClientChannel = new InputChannel(clientChannelName, sockets[1]);return OK;
}

1.3 InputChannel构造函数

InputChannel::InputChannel(const String8& name, int fd) :mName(name), mFd(fd) {// 设置为非阻塞模式,防止发送/接收操作阻塞线程int result = fcntl(mFd, F_SETFL, O_NONBLOCK);LOG_ALWAYS_FATAL_IF(result != 0, "channel '%s' ~ Could not make socket ""non-blocking. errno=%d", mName.string(), errno);
}

1.4 通道注册到InputDispatcher

// frameworks/native/services/inputflinger/InputDispatcher.cpp
status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel,const sp<InputWindowHandle>& inputWindowHandle, bool monitor) {{ // acquire lockAutoMutex _l(mLock);// 检查通道是否已经注册if (getConnectionIndexLocked(inputChannel) >= 0) {ALOGW("Attempted to register already registered input channel '%s'",inputChannel->getName().string());return BAD_VALUE;}// 创建Connection对象,管理与应用的连接sp<Connection> connection = new Connection(inputChannel, inputWindowHandle, monitor);int fd = inputChannel->getFd();mConnectionsByFd.add(fd, connection);// 将文件描述符添加到Looper中监听mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);} // release lock// 唤醒Looper以便立即开始监听新连接mLooper->wake();return OK;
}

2. 事件传输协议

2.1 InputMessage结构

InputChannel使用统一的InputMessage结构来传输不同类型的事件:

字段类型说明
Headerstruct消息头,包含类型和填充
Bodyunion消息体,根据类型包含不同事件数据

2.2 消息类型

// frameworks/native/include/input/InputTransport.h
struct InputMessage {enum {TYPE_KEY = 1,        // 按键事件TYPE_MOTION = 2,     // 运动事件(触摸、鼠标等)TYPE_FINISHED = 3,   // 事件处理完成确认};struct Header {uint32_t type;       // 消息类型uint32_t padding;    // 对齐填充} header;// 消息体必须8字节对齐union Body {struct Key {uint32_t seq;                                // 序列号nsecs_t eventTime __attribute__((aligned(8))); // 事件时间int32_t deviceId;                            // 设备IDint32_t source;                              // 事件源int32_t action;                              // 动作int32_t flags;                               // 标志int32_t keyCode;                             // 键码int32_t scanCode;                            // 扫描码int32_t metaState;                           // 修饰键状态int32_t repeatCount;                         // 重复次数nsecs_t downTime __attribute__((aligned(8))); // 按下时间} key;struct Motion {uint32_t seq;                                // 序列号nsecs_t eventTime __attribute__((aligned(8))); // 事件时间int32_t deviceId;                            // 设备IDint32_t source;                              // 事件源int32_t action;                              // 动作int32_t actionButton;                        // 按键int32_t flags;                               // 标志int32_t metaState;                           // 修饰键状态int32_t buttonState;                         // 按键状态int32_t edgeFlags;                           // 边缘标志nsecs_t downTime __attribute__((aligned(8))); // 按下时间float xOffset;                               // X偏移float yOffset;                               // Y偏移float xPrecision;                            // X精度float yPrecision;                            // Y精度uint32_t pointerCount;                       // 触点数量struct Pointer {PointerProperties properties;            // 触点属性PointerCoords coords;                    // 触点坐标} pointers[MAX_POINTERS];                    // 触点数组} motion;struct Finished {uint32_t seq;                                // 序列号bool handled;                                // 是否已处理} finished;} __attribute__((aligned(8))) body;
};

2.3 消息大小计算

size_t InputMessage::size() const {switch (header.type) {case TYPE_KEY:return sizeof(Header) + body.key.size();case TYPE_MOTION:return sizeof(Header) + body.motion.size();case TYPE_FINISHED:return sizeof(Header) + body.finished.size();}return sizeof(Header);
}// Motion消息的动态大小计算
inline size_t Motion::size() const {return sizeof(Motion) - sizeof(Pointer) * MAX_POINTERS+ sizeof(Pointer) * pointerCount;
}

3. 事件发送:InputPublisher

3.1 InputPublisher架构

InputPublisher负责将InputDispatcher的事件通过InputChannel发送给应用:

InputDispatcher::startDispatchCycleLocked()│▼
Connection::inputPublisher.publishKeyEvent()│▼ 构造InputMessage
填充消息头和消息体│▼ InputChannel::sendMessage()
通过socket发送消息│▼
应用端InputChannel接收

3.2 按键事件发布

// frameworks/native/libs/input/InputTransport.cpp
status_t InputPublisher::publishKeyEvent(uint32_t seq,int32_t deviceId,int32_t source,int32_t action,int32_t flags,int32_t keyCode,int32_t scanCode,int32_t metaState,int32_t repeatCount,nsecs_t downTime,nsecs_t eventTime) {// 构造按键事件消息InputMessage msg;msg.header.type = InputMessage::TYPE_KEY;msg.body.key.seq = seq;msg.body.key.eventTime = eventTime;msg.body.key.deviceId = deviceId;msg.body.key.source = source;msg.body.key.action = action;msg.body.key.flags = flags;msg.body.key.keyCode = keyCode;msg.body.key.scanCode = scanCode;msg.body.key.metaState = metaState;msg.body.key.repeatCount = repeatCount;msg.body.key.downTime = downTime;// 通过InputChannel发送消息return mChannel->sendMessage(&msg);
}

3.3 运动事件发布

status_t InputPublisher::publishMotionEvent(uint32_t seq,int32_t deviceId,int32_t source,int32_t action,int32_t actionButton,int32_t flags,int32_t edgeFlags,int32_t metaState,int32_t buttonState,float xOffset,float yOffset,float xPrecision,float yPrecision,nsecs_t downTime,nsecs_t eventTime,uint32_t pointerCount,const PointerProperties* pointerProperties,const PointerCoords* pointerCoords) {// 检查参数有效性if (pointerCount > MAX_POINTERS || pointerCount < 1) {return BAD_VALUE;}// 构造运动事件消息InputMessage msg;msg.header.type = InputMessage::TYPE_MOTION;msg.body.motion.seq = seq;msg.body.motion.eventTime = eventTime;msg.body.motion.deviceId = deviceId;msg.body.motion.source = source;msg.body.motion.action = action;msg.body.motion.actionButton = actionButton;msg.body.motion.flags = flags;msg.body.motion.metaState = metaState;msg.body.motion.buttonState = buttonState;msg.body.motion.edgeFlags = edgeFlags;msg.body.motion.downTime = downTime;msg.body.motion.xOffset = xOffset;msg.body.motion.yOffset = yOffset;msg.body.motion.xPrecision = xPrecision;msg.body.motion.yPrecision = yPrecision;msg.body.motion.pointerCount = pointerCount;// 复制触点数据for (uint32_t i = 0; i < pointerCount; i++) {msg.body.motion.pointers[i].properties.copyFrom(pointerProperties[i]);msg.body.motion.pointers[i].coords.copyFrom(pointerCoords[i]);}// 通过InputChannel发送消息return mChannel->sendMessage(&msg);
}

3.4 底层Socket发送

status_t InputChannel::sendMessage(const InputMessage* msg) {size_t msgLength = msg->size();ssize_t nWrite;// 使用MSG_DONTWAIT确保非阻塞发送,MSG_NOSIGNAL避免SIGPIPE信号do {nWrite = ::send(mFd, msg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL);} while (nWrite == -1 && errno == EINTR);if (nWrite < 0) {int error = errno;if (error == EAGAIN || error == EWOULDBLOCK) {return WOULD_BLOCK;}if (error == EPIPE || error == ENOTCONN || error == ECONNREFUSED || error == ECONNRESET) {return DEAD_OBJECT;}return -error;}if (size_t(nWrite) != msgLength) {return DEAD_OBJECT;}return OK;
}

4. 事件接收:InputConsumer

4.1 应用层接收架构

应用端通过InputEventReceiver接收事件:

Socket数据到达│▼ Looper监听fd可读
Native InputConsumer回调│▼ 解析InputMessage
创建Java InputEvent对象│▼ 调用Java回调
InputEventReceiver.onInputEvent()│▼ 事件分发
ViewRootImpl处理事件

4.2 InputEventReceiver创建

文件路径: frameworks/base/core/java/android/view/InputEventReceiver.java

public abstract class InputEventReceiver {// 指向native接收器对象的指针private long mReceiverPtr;// 保持对输入通道和消息队列的引用,防止被垃圾回收private InputChannel mInputChannel;private MessageQueue mMessageQueue;// 序列号映射表:从InputEvent序列号到调度器序列号private final SparseIntArray mSeqMap = new SparseIntArray();/*** 创建绑定到指定输入通道的事件接收器*/public InputEventReceiver(InputChannel inputChannel, Looper looper) {if (inputChannel == null) {throw new IllegalArgumentException("inputChannel must not be null");}if (looper == null) {throw new IllegalArgumentException("looper must not be null");}mInputChannel = inputChannel;mMessageQueue = looper.getQueue();// 初始化native接收器,传入弱引用避免内存泄漏mReceiverPtr = nativeInit(new WeakReference<InputEventReceiver>(this),inputChannel, mMessageQueue);mCloseGuard.open("dispose");}
}

4.3 Native层InputConsumer

// frameworks/native/libs/input/InputTransport.cpp
status_t InputConsumer::consume(InputEventFactoryInterface* factory,bool consumeBatches, nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent) {*outEvent = NULL;*outSeq = 0;while (!*outEvent) {if (mMsgDeferred) {// 处理延迟的消息mMsgDeferred = false;} else {// 接收新消息status_t result = mChannel->receiveMessage(&mMsg);if (result) {// 如果没有消息可读,则返回if (result == WOULD_BLOCK) {if (!consumeBatches) {result = OK;}}return result;}}switch (mMsg.header.type) {case InputMessage::TYPE_KEY: {KeyEvent* keyEvent = factory->createKeyEvent();if (!keyEvent) return NO_MEMORY;// 初始化按键事件initializeKeyEvent(keyEvent, &mMsg);*outSeq = mMsg.body.key.seq;*outEvent = keyEvent;break;}case InputMessage::TYPE_MOTION: {ssize_t batchIndex = findBatch(mMsg.body.motion.deviceId, mMsg.body.motion.source);if (batchIndex >= 0) {// 添加到现有批次Batch& batch = mBatches.editItemAt(batchIndex);if (canAddSample(batch, &mMsg)) {batch.samples.push();addSample(batch, &mMsg);break;}}// 开始新批次或立即传递事件MotionEvent* motionEvent = factory->createMotionEvent();if (!motionEvent) return NO_MEMORY;updateTouchState(&mMsg);initializeMotionEvent(motionEvent, &mMsg);*outSeq = mMsg.body.motion.seq;*outEvent = motionEvent;if (batchIndex < 0) {// 创建新批次用于后续事件mBatches.push();Batch& batch = mBatches.editTop();batch.samples.push();addSample(batch, &mMsg);}break;}default:ALOGE("channel received unknown message type %d", mMsg.header.type);return UNKNOWN_ERROR;}}return OK;
}

4.4 底层Socket接收

status_t InputChannel::receiveMessage(InputMessage* msg) {ssize_t nRead;// 非阻塞接收消息do {nRead = ::recv(mFd, msg, sizeof(InputMessage), MSG_DONTWAIT);} while (nRead == -1 && errno == EINTR);if (nRead < 0) {int error = errno;if (error == EAGAIN || error == EWOULDBLOCK) {return WOULD_BLOCK;}if (error == EPIPE || error == ENOTCONN || error == ECONNREFUSED) {return DEAD_OBJECT;}return -error;}if (nRead == 0) { // EOF检查return DEAD_OBJECT;}if (!msg->isValid(nRead)) {return BAD_VALUE;}return OK;
}

5. 事件处理完成确认机制

5.1 确认流程

为了实现ANR检测和流量控制,InputChannel使用确认机制:

应用处理完事件│▼ InputEventReceiver.finishInputEvent()
发送TYPE_FINISHED消息│▼ InputChannel传输
InputDispatcher接收确认│▼ Connection.waitQueue
移除已完成的事件

5.2 应用层发送确认

// frameworks/base/core/java/android/view/InputEventReceiver.java
public final void finishInputEvent(InputEvent event, boolean handled) {if (event == null) {throw new IllegalArgumentException("event must not be null");}if (mReceiverPtr == 0) {Log.w(TAG, "Attempted to finish an input event but the input event "+ "receiver has already been disposed.");} else {// 从序列号映射表中查找调度器序列号int index = mSeqMap.indexOfKey(event.getSequenceNumber());if (index < 0) {Log.w(TAG, "Attempted to finish an input event that is not in progress.");} else {int seq = mSeqMap.valueAt(index);mSeqMap.removeAt(index);// 调用native方法发送确认nativeFinishInputEvent(mReceiverPtr, seq, handled);}}// 回收事件对象event.recycleIfNeededAfterDispatch();
}

5.3 Native层发送确认

status_t InputConsumer::sendFinishedSignal(uint32_t seq, bool handled) {InputMessage msg;msg.header.type = InputMessage::TYPE_FINISHED;msg.body.finished.seq = seq;msg.body.finished.handled = handled;return mChannel->sendMessage(&msg);
}

5.4 InputDispatcher处理确认

void InputDispatcher::handleReceiveCallback(int fd, int events, void* data) {InputDispatcher* d = static_cast<InputDispatcher*>(data);{ // acquire lockAutoMutex _l(d->mLock);ssize_t connectionIndex = d->mConnectionsByFd.indexOfKey(fd);if (connectionIndex < 0) {return; // 连接已移除}sp<Connection> connection = d->mConnectionsByFd.valueAt(connectionIndex);if (events & ALOOPER_EVENT_INPUT) {nsecs_t currentTime = now();bool gotOne = false;status_t status;for (;;) {InputMessage msg;status = connection->inputChannel->receiveMessage(&msg);if (status) {break;}if (msg.header.type == InputMessage::TYPE_FINISHED) {d->finishDispatchCycleLocked(currentTime, connection, msg.body.finished.seq, msg.body.finished.handled);gotOne = true;}}if (gotOne) {d->runCommandsLockedInterruptible();}}} // release lock
}

6. 批量处理和性能优化

6.1 事件批量处理

为了优化性能,InputChannel支持触摸事件的批量处理:

优化技术实现方式性能收益
事件批量多个MOVE事件合并减少跨进程调用次数
延迟传递批量事件延迟到帧边界与UI渲染同步
预测采样根据历史数据预测触点位置减少感知延迟

6.2 触摸重采样

// frameworks/native/libs/input/InputTransport.cpp
// 重采样常量
static const nsecs_t RESAMPLE_LATENCY = 5 * NANOS_PER_MS;      // 5ms延迟
static const nsecs_t RESAMPLE_MIN_DELTA = 2 * NANOS_PER_MS;    // 最小间隔2ms
static const nsecs_t RESAMPLE_MAX_DELTA = 20 * NANOS_PER_MS;   // 最大间隔20ms
static const nsecs_t RESAMPLE_MAX_PREDICTION = 8 * NANOS_PER_MS; // 最大预测8msbool InputConsumer::shouldResampleTool(int32_t toolType) {return toolType == AMOTION_EVENT_TOOL_TYPE_FINGER|| toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN;
}void InputConsumer::resampleTouchState(nsecs_t frameTime, MotionEvent* event,const InputMessage* next) {if (!mResampleTouch || !(event->getSource() & AINPUT_SOURCE_CLASS_POINTER)|| event->getAction() != AMOTION_EVENT_ACTION_MOVE) {return;}// 计算重采样时间nsecs_t sampleTime = frameTime - RESAMPLE_LATENCY;// 执行线性插值重采样uint32_t pointerCount = event->getPointerCount();for (uint32_t i = 0; i < pointerCount; i++) {uint32_t id = event->getPointerId(i);// 获取历史样本数据nsecs_t prevTime = event->getHistoricalEventTime(event->getHistorySize() - 1);nsecs_t nextTime = next->body.motion.eventTime;if (sampleTime > prevTime && sampleTime < nextTime) {// 计算插值因子float alpha = float(sampleTime - prevTime) / float(nextTime - prevTime);// 插值计算新坐标float prevX = event->getHistoricalX(i, event->getHistorySize() - 1);float prevY = event->getHistoricalY(i, event->getHistorySize() - 1);float nextX = next->body.motion.pointers[i].coords.getX();float nextY = next->body.motion.pointers[i].coords.getY();float newX = lerp(prevX, nextX, alpha);float newY = lerp(prevY, nextY, alpha);// 更新事件坐标event->setXOffset(event->getXOffset() + newX - prevX);event->setYOffset(event->getYOffset() + newY - prevY);}}
}

6.3 内存管理优化

class InputConsumer {
private:// 批量事件管理struct Batch {Vector<InputMessage> samples;  // 样本缓存};Vector<Batch> mBatches;           // 批量缓存// 对象池化static const size_t MAX_RECYCLED_EVENTS = 4;KeyEvent* mRecycledKeyEvents[MAX_RECYCLED_EVENTS];MotionEvent* mRecycledMotionEvents[MAX_RECYCLED_EVENTS];// 统计信息TouchState mTouchState;           // 触摸状态跟踪InputMessage mMsg;                // 消息缓冲区bool mMsgDeferred;               // 延迟标志
};

7. 错误处理和连接管理

7.1 连接状态管理

状态说明处理方式
NORMAL正常连接正常收发消息
BROKEN连接断开停止发送,清理资源
ZOMBIE僵尸状态等待应用退出

7.2 错误处理机制

void InputDispatcher::abortBrokenDispatchCycleLocked(nsecs_t currentTime,const sp<Connection>& connection, bool notify) {// 标记连接为断开状态connection->status = Connection::STATUS_BROKEN;// 清理待发送队列drainDispatchQueueLocked(&connection->outboundQueue);drainDispatchQueueLocked(&connection->waitQueue);// 生成取消事件通知其他窗口if (notify) {synthesizeCancelationEventsForConnectionLocked(connection,CancelationOptions(CancelationOptions::CANCEL_ALL_EVENTS,"broken input channel"));}// 从连接映射中移除unregisterInputChannelLocked(connection->inputChannel, notify);
}

7.3 超时检测

String8 InputDispatcher::checkWindowReadyForMoreInputLocked(nsecs_t currentTime,const sp<InputWindowHandle>& windowHandle, const EventEntry* eventEntry,const char* targetType) {// 检查连接状态ssize_t connectionIndex = getConnectionIndexLocked(windowHandle->getInputChannel());if (connectionIndex < 0) {return String8::format("Window is not registered");}sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);if (connection->status != Connection::STATUS_NORMAL) {return String8::format("Window connection is broken");}// 检查等待队列长度和时间if (!connection->waitQueue.isEmpty()) {const DispatchEntry* head = connection->waitQueue.head;nsecs_t waitDuration = currentTime - head->deliveryTime;if (waitDuration > STREAM_AHEAD_EVENT_TIMEOUT) {return String8::format("Waiting too long to send non-key event");}}return String8::empty();
}

8. 调试和监控

8.1 调试开关

// frameworks/native/libs/input/InputTransport.cpp
#define DEBUG_CHANNEL_MESSAGES 0        // 通道消息调试
#define DEBUG_CHANNEL_LIFECYCLE 0       // 通道生命周期调试
#define DEBUG_TRANSPORT_ACTIONS 0       // 传输动作调试
#define DEBUG_RESAMPLING 0              // 重采样调试

8.2 性能监控

监控指标获取方式用途
消息发送延迟sendMessage耗时性能分析
批量事件数量batch.samples.size()优化效果评估
连接状态Connection::status健康检查
重采样统计resample计数器渲染性能分析

8.3 常用调试命令

# 查看InputChannel连接状态
adb shell dumpsys input# 监控socket使用情况
adb shell cat /proc/net/unix | grep input# 查看应用Input事件处理
adb shell dumpsys activity | grep -A5 -B5 Input# 监控触摸重采样
adb shell setprop debug.choreographer.skipwarning 0

9. 与其他组件的协作

9.1 WindowManager集成

// frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
public int addWindow(Session session, IWindow client, int seq,WindowManager.LayoutParams attrs, int viewVisibility, int displayId,Rect outContentInsets, Rect outStableInsets, Rect outOutsets,InputChannel outInputChannel) {// 创建InputChannel对final String name = win.makeInputChannelName();InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);win.setInputChannel(inputChannels[0]);// 注册到InputDispatchermInputManager.registerInputChannel(inputChannels[0], win.mInputWindowHandle);// 返回客户端InputChannelif (outInputChannel != null) {inputChannels[1].transferTo(outInputChannel);inputChannels[1].dispose();}
}

9.2 ViewRootImpl集成

// frameworks/base/core/java/android/view/ViewRootImpl.java
final class WindowInputEventReceiver extends InputEventReceiver {public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {super(inputChannel, looper);}@Overridepublic void onInputEvent(InputEvent event) {enqueueInputEvent(event, this, 0, true);}@Overridepublic void onBatchedInputEventPending() {if (mUnbufferedInputDispatch) {super.onBatchedInputEventPending();} else {scheduleConsumeBatchedInput();}}
}public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {if (mInputChannel != null) {if (mInputQueueCallback != null) {mInputQueue = new InputQueue();mInputQueueCallback.onInputQueueCreated(mInputQueue);}mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,Looper.myLooper());}
}

10. 总结

10.1 InputChannel核心价值

  1. 高效通信: 基于Unix域socket的低延迟跨进程通信
  2. 消息协议: 统一的InputMessage结构支持多种事件类型
  3. 流量控制: 通过确认机制实现ANR检测和流量控制
  4. 性能优化: 批量处理、重采样等技术提升用户体验
  5. 可靠性: 完善的错误处理和连接管理机制

10.2 技术特点

  • 零拷贝传输: 使用SOCK_SEQPACKET确保消息边界
  • 非阻塞IO: 所有socket操作都是非阻塞的
  • 内存对齐: 消息结构针对64位系统优化对齐
  • 批量优化: 触摸事件的智能批量处理
  • 预测性重采样: 减少触摸延迟的关键技术

10.3 系统架构意义

InputChannel作为Android输入系统的通信基础设施:

  • 解耦设计: 分离了系统服务和应用程序的输入处理
  • 性能保障: 确保输入事件的低延迟传输
  • 扩展性: 支持多种输入设备和事件类型
  • 可维护性: 清晰的接口和错误处理机制

相关文件路径

核心实现文件

  • frameworks/native/libs/input/InputTransport.cpp - InputChannel核心实现
  • frameworks/native/include/input/InputTransport.h - InputChannel头文件
  • frameworks/base/core/java/android/view/InputChannel.java - Java层InputChannel
  • frameworks/base/core/java/android/view/InputEventReceiver.java - 事件接收器

JNI层文件

  • frameworks/base/core/jni/android_view_InputChannel.cpp - InputChannel JNI
  • frameworks/base/core/jni/android_view_InputEventReceiver.cpp - InputEventReceiver JNI

测试文件

  • frameworks/native/libs/input/tests/InputChannel_test.cpp - InputChannel单元测试
  • frameworks/base/core/tests/coretests/src/android/view/InputChannelTest.java - Java层测试

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/94845.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/94845.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

AI实时故障诊断系统(实时采集信号)

1.摘要 本文设计了一套“基于Labview的旋转机械信号分析与故障诊断系统&#xff08;可部署AI模型和实时监测设备运行状态&#xff09;”。首先&#xff0c;LabVIEW 端构建了信号采集与设备状态实时监测模块和本地数据故障诊断模块。该系统实现了“数据采集、数据处理、时频域特…

【51单片机】【protues仿真】基于51单片机篮球计时计分器数码管系统

目录 一、主要功能 二、使用步骤 三、硬件资源 四、软件设计 五、实验现象 一、主要功能 1、数码管显示 1、比赛时间为15&#xff1a;00&#xff0c;甲乙队比分默认000&#xff0c;通过按键修改 3、比赛运行的状态下&#xff0c;按开始暂停键&#xff0c;比赛暂停&#…

[读论文]Hunyuan 3D 系列

1.0&#xff1a; &#xff08;adaptive clasisfier guidance&#xff0c;input 输入一个没cam的branch&#xff1b;提高triplane分辨率&#xff09; 总结&#xff1a; 大规模再train zero123&#xff0c;但角度设置不同&#xff1b;adaptive clasisfier guidance&#xff08;f…

深入理解文本向量嵌入(Vector Embeddings):原理、实践与应用场景

深入理解文本向量嵌入&#xff08;Vector Embeddings&#xff09;&#xff1a;原理、实践与应用场景 1. 什么是向量嵌入&#xff1f; 文本向量嵌入&#xff08;Vector Embedding&#xff09;是一种将文本转化为数值向量的技术&#xff0c;使得字符串之间的关联性可以通过数值…

微论-神经网络中记忆的演变

从微突触到宏认知&#xff1a;论神经网络中记忆的生成、固化与演化人脑的智能&#xff0c;并非源于单个神经元的孤立活动&#xff0c;而是诞生于由万亿突触连接所构成的庞大而复杂的网络动态之中。在这个网络中&#xff0c;连接权重的强度分布——即强的约束与弱的变数——共同…

机器视觉学习-day07-图像镜像旋转

图像的镜像旋转分为三种&#xff0c;分别使用filpcode的参数表示&#xff1a;flipcode0&#xff0c;垂直翻转&#xff08;x轴为中线&#xff09; 垂直翻转可以把src沿着x轴翻转&#xff0c;坐标从&#xff08;x,y&#xff09;翻转为(x,-y)。flipcode>0&#xff0c;水平翻转&…

Python备份实战专栏第2/6篇:30分钟搭建企业级API认证系统,安全性吊打90%的方案

30分钟搭建企业级API认证系统&#xff0c;安全性吊打90%的方案 专栏导语&#xff1a;《从零到一&#xff1a;构建企业级Python Web自动化备份系统实战指南》第2篇 作者简介&#xff1a;madechango架构师&#xff0c;负责设计零安全事故的API认证系统&#xff0c;拦截100%非法请…

第6篇:链路追踪系统 - 分布式环境下的请求跟踪

项目地址&#xff1a;https://github.com/nemoob/atlas-log 开箱即用。前言 在微服务架构中&#xff0c;一个用户请求往往会经过多个服务的协作处理。本章将实现一个轻量级的链路追踪系统&#xff0c;让日志具备分布式追踪能力。 分布式链路追踪基础概念 链路追踪的核心价值 #m…

ubuntu25.04编译最新版本qgroundcontrol

编译系统版本: 编译器版本: 编译成功效果

如何在 Docker 和AKS上使用 IIS

前言 在我们的一个客户项目中,我们有一个混合 Swarm 集群,其中包含 Linux 和 Windows 节点。在 Windows 节点上,我们运行了许多 IIS 容器,这些容器运行着多个 Web 应用程序。在这篇博文中,我想向您展示在 Docker 容器中将网站部署到 IIS 上是多么简单。 Internet 信息服…

uniapp 页面favicon.ico文件不存在提示404问题解决

1. uniapp 页面favicon.ico文件不存在提示404问题解决 1.1. 场景 在uniapp中经常出现的&#xff0c;因为找不到 favicon.ico 而报404错误的问题。 GET http://localhost:5174/favicon.ico 404 (Not Found)1.2. 问题原因 在document.ejs中使用link标签相对路径引入文件。 <…

Magicodes.IE.Pdf 生成导出PDF文件 bytes Stream FileStreamResult 下载

1、ExporterAttribute&#xff1a;导出特性 Name&#xff1a;名称 HeaderFontSize&#xff1a;头部字体大小 FontSize&#xff1a;正文字体大小 MaxRowNumberOnASheet&#xff1a;一个Sheet最大允许的行数&#xff0c;设置了之后将输出多个Sheet AutoFitAllColumn&#xff1a;自…

Python LangChain RAG从入门到项目实战10.:质量评价指标体系

好的&#xff0c;RAG (Retrieval-Augmented Generation) 系统的评估是一个多维度的问题&#xff0c;需要同时对检索器 (Retriever) 和生成器 (Generator) 的性能进行衡量。 评估指标主要分为三大类&#xff1a;检索质量、生成质量 和 整体系统质量。下图清晰地展示了这些核心指…

【记录】Copilot|Github Copilot重新学生认证通过方法(2025年7月,包括2FA和认证材料、Why are you not on campus)

文章目录前言步骤最重要的一步前言 事实上&#xff0c;Github Copilot马上就要开源了&#xff0c;我原本的认证过期了。但是在我体验了众多的代码补全工具实在是太难用了之后&#xff0c;我觉得一天也等不了了&#xff0c;就去再一次认证了学生认证。 这次严格了很多&#xff…

【C语言16天强化训练】从基础入门到进阶:Day 13

&#x1f525;个人主页&#xff1a;艾莉丝努力练剑 ❄专栏传送门&#xff1a;《C语言》、《数据结构与算法》、C语言刷题12天IO强训、LeetCode代码强化刷题、洛谷刷题、C/C基础知识知识强化补充、C/C干货分享&学习过程记录 &#x1f349;学习方向&#xff1a;C/C方向学习者…

单元测试到底是什么?该怎么做?

&#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快一、什么是单元测试&#xff1f;单元测试&#xff08;unit testing&#xff09;&#xff0c;是指对软件中的最小可测试单元进行检查和验证。至于“单元”的大小或范…

PostgreSQL【应用 04】加解密扩展 pgcrypto 使用实例(加密、导出、导入、解密流程说明)

加解密扩展 pgcrypto 使用实例1.需求说明2.工具说明2.1 环境说明2.2 插件添加3.实例分析3.1 测试数据3.2 进行加密3.3 数据导出3.3.1 Navicat 导出3.3.2 copy 命令导出3.4 数据解密3.4.1 Navicat 导入3.4.2 copy 导入3.5 坑1.需求说明 从内网导出敏感数据的时候&#xff0c;对…

SDK、JDK、JRE、JVM的区别

SDK、JDK、JRE、JVM的区别一、SDK二、JDK三、JRE四、JVM五、JDK、JRE、JVM三者关系图一、SDK SDK&#xff08;Software Development Kit&#xff0c;程序软件开发工具包&#xff09;&#xff0c;可以认为jdk只是sdk的一种&#xff08;子集&#xff09;&#xff0c;而当提及jav…

如何启动一个分支网络改造试点?三步走

在多云化、全球化的今天&#xff0c;企业的分支网络早已不仅仅是“能连”的问题。视频会议卡顿、ERP 响应延迟、跨境访问不稳、合规风险增大……这些都让 CIO 和 IT 负责人越来越清楚&#xff1a;分支网络改造是数字化的必修课。但是&#xff0c;面对几百甚至上千个分支机构&am…

四,设计模式-原型模式

目的原型模式的产生是为了解决一个问题&#xff0c;即复制对象时对被复制对象所属类的依赖。当需要复制一个对象时&#xff0c;需要遍历对象中的所有成员并进行复制&#xff0c;但存在一些问题&#xff1a;某些成员对象可能是私有的无法访问。同时要复制某个对象&#xff0c;那…