Android系统源码分析Input - InputChannel通信

Input属于SystemServer进程,要想把事件分发给应用,需要和应用跨进程通信,这里看下InputChannel的建立过程。

  1. 在向Window添加View的过程中会创建客户端的InputChannel对象,并在调用addToDisplayAsUser时,将inputChannel传给WindowManagerService。可以看到这里还创建了很多InputStage,InputStage用于应用处理事件,这个后面再分析。
ini 复制代码
// frameworks/base/core/java/android/view/ViewRootImpl.java

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView,
        int userId) {
    synchronized (this) {
        if (mView == null) {
            mView = view;
            
            ...
            InputChannel inputChannel = null;
            if ((mWindowAttributes.inputFeatures
                    & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
                // 创建InputChannel
                inputChannel = new InputChannel();
            }
         
            try {
                ...
                // 将InputChannel传给WindowManagerService
                res = mWindowSession.addToDisplayAsUser(mWindow, mWindowAttributes,
                        getHostVisibility(), mDisplay.getDisplayId(), userId,
                        mInsetsController.getRequestedVisibleTypes(), inputChannel, mTempInsets,
                        mTempControls, attachedFrame, compatScale);
                ...
            } catch (RemoteException | RuntimeException e) {
                ...
            }

            // Set up the input pipeline.
            CharSequence counterSuffix = attrs.getTitle();
            mSyntheticInputStage = new SyntheticInputStage();
            InputStage viewPostImeStage = new ViewPostImeInputStage(mSyntheticInputStage);
            InputStage nativePostImeStage = new NativePostImeInputStage(viewPostImeStage,
                    "aq:native-post-ime:" + counterSuffix);
            InputStage earlyPostImeStage = new EarlyPostImeInputStage(nativePostImeStage);
            InputStage imeStage = new ImeInputStage(earlyPostImeStage,
                    "aq:ime:" + counterSuffix);
            InputStage viewPreImeStage = new ViewPreImeInputStage(imeStage);
            InputStage nativePreImeStage = new NativePreImeInputStage(viewPreImeStage,
                    "aq:native-pre-ime:" + counterSuffix);

            mFirstInputStage = nativePreImeStage;
            mFirstPostImeInputStage = earlyPostImeStage;
    }
}
java 复制代码
// frameworks/base/services/core/java/com/android/server/wm/Session.java

@Override
public int addToDisplayAsUser(IWindow window, WindowManager.LayoutParams attrs,
        int viewVisibility, int displayId, int userId, @InsetsType int requestedVisibleTypes,
        InputChannel outInputChannel, InsetsState outInsetsState,
        InsetsSourceControl.Array outActiveControls, Rect outAttachedFrame,
        float[] outSizeCompatScale) {
    return mService.addWindow(this, window, attrs, viewVisibility, displayId, userId,
            requestedVisibleTypes, outInputChannel, outInsetsState, outActiveControls,
            outAttachedFrame, outSizeCompatScale);
}
  1. 如果没有INPUT_FEATURE_NO_INPUT_CHANNEL就创建InputChannel。
java 复制代码
// frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java

public int addWindow(Session session, IWindow client, LayoutParams attrs, int viewVisibility,
        int displayId, int requestUserId, @InsetsType int requestedVisibleTypes,
        InputChannel outInputChannel, InsetsState outInsetsState,
        InsetsSourceControl.Array outActiveControls, Rect outAttachedFrame,
        float[] outSizeCompatScale) {
    ...
    final boolean openInputChannels = (outInputChannel != null
            && (attrs.inputFeatures & INPUT_FEATURE_NO_INPUT_CHANNEL) == 0);
    if  (openInputChannels) {
        win.openInputChannel(outInputChannel);
    }
    ...
}
  1. 在系统启动过程中,会将inputManagerService传给WindowManagerService。这里调用IMS来创建InputChannel,并将channel的client端传给应用。
ini 复制代码
// frameworks/base/services/core/java/com/android/server/wm/WindowState.java

void openInputChannel(@NonNull InputChannel outInputChannel) {
    if (mInputChannel != null) {
        throw new IllegalStateException("Window already has an input channel.");
    }
    String name = getName();
    mInputChannel = mWmService.mInputManager.createInputChannel(name);
    mInputChannelToken = mInputChannel.getToken();
    mInputWindowHandle.setToken(mInputChannelToken);
    mWmService.mInputToWindowMap.put(mInputChannelToken, this);
    mInputChannel.copyTo(outInputChannel);
}
  1. 调用到Native创建InputChannel。
ruby 复制代码
// frameworks/base/services/core/java/com/android/server/input/InputManagerService.java

public InputChannel createInputChannel(String name) {
    return mNative.createInputChannel(name);
}
  1. 调用到InputDispacher
c 复制代码
// frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp

static jobject nativeCreateInputChannel(JNIEnv* env, jobject nativeImplObj, jstring nameObj) {
    NativeInputManager* im = getNativeInputManager(env, nativeImplObj);

    ScopedUtfChars nameChars(env, nameObj);
    std::string name = nameChars.c_str();

    base::Result<std::unique_ptr<InputChannel>> inputChannel = im->createInputChannel(name);

    if (!inputChannel.ok()) {
        std::string message = inputChannel.error().message();
        message += StringPrintf(" Status=%d", static_cast<int>(inputChannel.error().code()));
        jniThrowRuntimeException(env, message.c_str());
        return nullptr;
    }

    jobject inputChannelObj =
            android_view_InputChannel_createJavaObject(env, std::move(*inputChannel));
    if (!inputChannelObj) {
        return nullptr;
    }

    android_view_InputChannel_setDisposeCallback(env, inputChannelObj,
            handleInputChannelDisposed, im);
    return inputChannelObj;
}
...
base::Result<std::unique_ptr<InputChannel>> NativeInputManager::createInputChannel(
        const std::string& name) {
    ATRACE_CALL();
    return mInputManager->getDispatcher().createInputChannel(name);
}
  1. 创建InputChannel,并把server端封装到Connection中,Connection主要用来管理与InputChannel相关的状态。最后把clientChannel返回给应用,用于给Input发送消息。
c 复制代码
// frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp

Result<std::unique_ptr<InputChannel>> InputDispatcher::createInputChannel(const std::string& name) {
    if (DEBUG_CHANNEL_CREATION) {
        ALOGD("channel '%s' ~ createInputChannel", name.c_str());
    }

    std::unique_ptr<InputChannel> serverChannel;
    std::unique_ptr<InputChannel> clientChannel;
    // 创建Channel
    status_t result = InputChannel::openInputChannelPair(name, serverChannel, clientChannel);

    if (result) {
        return base::Error(result) << "Failed to open input channel pair with name " << name;
    }

    { // acquire lock
        std::scoped_lock _l(mLock);
        const sp<IBinder>& token = serverChannel->getConnectionToken();
        const int fd = serverChannel->getFd();
        std::shared_ptr<Connection> connection =
                std::make_shared<Connection>(std::move(serverChannel), /*monitor=*/false,
                                             mIdGenerator);
        // 将服务端通道的`IBinder token`和对应的`Connection`对象存入映射表,用于后续事件分发。
        auto [_, inserted] = mConnectionsByToken.try_emplace(token, connection);
        if (!inserted) {
            ALOGE("Created a new connection, but the token %p is already known", token.get());
        }

        std::function<int(int events)> callback = std::bind(&InputDispatcher::handleReceiveCallback,
                                                            this, std::placeholders::_1, token);
         // 将服务端通道的Socket文件描述符注册到Looper,监听输入事件(ALOOPER_EVENT_INPUT)。当应用有事件可读时,触发回调handleReceiveCallback、。
        mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, sp<LooperEventCallback>::make(callback),
                       nullptr);
    } // release lock

    // Wake the looper because some connections have changed.
    mLooper->wake();
    return clientChannel;
}
  1. 可以看到InputChannel是用Socket实现的。
c 复制代码
// frameworks/native/libs/input/InputTransport.cpp

status_t InputChannel::openInputChannelPair(const std::string& name,
                                            std::unique_ptr<InputChannel>& outServerChannel,
                                            std::unique_ptr<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=%s(%d)", name.c_str(),
              strerror(errno), errno);
        outServerChannel.reset();
        outClientChannel.reset();
        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));

    sp<IBinder> token = sp<BBinder>::make();

    std::string serverChannelName = name + " (server)";
    android::base::unique_fd serverFd(sockets[0]);
    outServerChannel = InputChannel::create(serverChannelName, std::move(serverFd), token);

    std::string clientChannelName = name + " (client)";
    android::base::unique_fd clientFd(sockets[1]);
    outClientChannel = InputChannel::create(clientChannelName, std::move(clientFd), token);
    return OK;
}
相关推荐
娅娅梨5 小时前
Android- Surface, SurfaceView, TextureView, SurfaceTexture 原理图解
android·surface
2501_915918416 小时前
HTTPS 端口号详解 443 端口作用、iOS 抓包方法、常见 HTTPS 抓包工具与网络调试实践
android·网络·ios·小程序·https·uni-app·iphone
程序员码歌6 小时前
明年35岁了,如何破局?说说心里话
android·前端·后端
非门由也8 小时前
Android studio安装教程——超详细(含安装包安装教程)
android·ide·android studio
平淡风云8 小时前
Android应用添加日历提醒功能
android·日历
骐骥19 小时前
2025-09-08升级问题记录:app提示“此应用专为旧版Android打造..”或“此应用与最新版 Android 不兼容”
android·升级·不兼容·target sdk·专为旧版 android 系统
Zender Han10 小时前
Flutter 视频播放器——flick_video_player 介绍与使用
android·flutter·ios·音视频
尚久龙11 小时前
安卓学习 之 用户登录界面的简单实现
android·运维·服务器·学习·手机·android studio·安卓
Modu_MrLiu11 小时前
Android实战进阶 - 启动页
android·实战进阶·启动页·倒计时场景
出门吃三碗饭12 小时前
编译器构造:从零手写汇编与反汇编程序(一)
android·汇编