android R -- InputChannel创建与注册流程

476 阅读6分钟

image.png

高清图:www.plantuml.com/plantuml/pn…

framework/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;

                .....

                // Schedule the first layout -before- adding to the window
                // manager, to make sure we do the relayout before receiving
                // any other events from the system.
                requestLayout();
                InputChannel inputChannel = null;
                if ((mWindowAttributes.inputFeatures
                        & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
                    // step1 创建inputChannel
                    inputChannel = new InputChannel();
                }
                mForceDecorViewVisibility = (mWindowAttributes.privateFlags
                        & PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY) != 0;

               

                try {
                    // step2 调用WMS addWindow
                    res = mWindowSession.addToDisplayAsUser(mWindow, mWindowAttributes,
                            getHostVisibility(), mDisplay.getDisplayId(), userId,
                            mInsetsController.getRequestedVisibility(), inputChannel, mTempInsets,
                            mTempControls);
                } catch (RemoteException e) {
                    
                } finally {
                    
                }

                .......
                // wms对inputChannel赋值之后,
                if (inputChannel != null) {
                    if (mInputQueueCallback != null) {
                        mInputQueue = new InputQueue();
                        mInputQueueCallback.onInputQueueCreated(mInputQueue);
                    }
                    // step3 创建mInputEventReceiver,用于注册client端的inputChannel,传的是主线程的looper
                    mInputEventReceiver = new WindowInputEventReceiver(inputChannel,
                            Looper.myLooper());

                    
                }

                view.assignParent(this);
               ......
                // step4 创建消息回调的InputStage链
                // 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;
                
            }
        }
    }

该方法是显示View的入口,ViewRootImpl中的inputChannel对象是空对象,要经过WMS赋值才有意义,赋值之后会将client的inputChannel注册到主线程的looper中。

step2

framework/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, InsetsState requestedVisibility,
            InputChannel outInputChannel, InsetsState outInsetsState,
            InsetsSourceControl[] outActiveControls) {
           ......

            final WindowState win = new WindowState(this, session, client, token, parentWindow,
                    appOp[0], attrs, viewVisibility, session.mUid, userId,
                    session.mCanAddInternalSystemWindow);
           

            final boolean openInputChannels = (outInputChannel != null
                    && (attrs.inputFeatures & INPUT_FEATURE_NO_INPUT_CHANNEL) == 0);
            if  (openInputChannels) {
                step5 创建InputChannel
                win.openInputChannel(outInputChannel);
            }

           .......

            win.attach();
            mWindowMap.put(client.asBinder(), win);
            
            boolean focusChanged = false;
            if (win.canReceiveKeys()) {
                focusChanged = updateFocusedWindowLocked(UPDATE_FOCUS_WILL_ASSIGN_LAYERS,
                        false /*updateInputWindows*/);
            }

            step6 调整当前获取焦点的窗口信息
            if (focusChanged) {
                displayContent.getInputMonitor().setInputFocusLw(displayContent.mCurrentFocus,
                        false /*updateInputWindows*/);
            }
            displayContent.getInputMonitor().updateInputWindowsLw(false /*force*/);
            ......
        }

        return res;
    }

该函数创建ViewRootImpl对应的WindowState,加入到mWindowMap,WindowState执行了openInputChannel(outInputChannel);方法来创建InputChannel,看下这个方法。

step5

framework/base/services/core/java/com/android/server/wm/WindowState.java

   void openInputChannel(InputChannel outInputChannel) {
        
        String name = getName();
        // step7 InputManager创建inputChannel
        mInputChannel = mWmService.mInputManager.createInputChannel(name);
        mInputChannelToken = mInputChannel.getToken();
        // 保存mInputChannelToken到mInputWindowHandle
        mInputWindowHandle.setToken(mInputChannelToken);
        mWmService.mInputToWindowMap.put(mInputChannelToken, this);
        if (outInputChannel != null) {
           // 给client的inputchannel赋值
            mInputChannel.copyTo(outInputChannel);
        } else {
            
        }
    }

该方法就调用IMS来真正创建InputChannel

下面来分析一下IMS的逻辑 framework/base/services/core/java/com/android/server/input/InputManagerService.java

    /**
     * Creates an input channel to be used as an input event target.
     *
     * @param name The name of this input channel
     */
    public InputChannel createInputChannel(String name) {
        return nativeCreateInputChannel(mPtr, name);
    }

framework/base/services/core/jni/com_android_server_input_InputManagerService.cpp

static jobject nativeCreateInputChannel(JNIEnv* env, jclass /* clazz */, jlong ptr,
                                        jstring nameObj) {
    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);

    ScopedUtfChars nameChars(env, nameObj);
    std::string name = nameChars.c_str();
    // step8 调用ims#createInputChannel
    base::Result<std::unique_ptr<InputChannel>> inputChannel = im->createInputChannel(env, name);

    // step9 根据native的inputChannel 创建java层的inputChannel对象,
    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(
        JNIEnv* /* env */, const std::string& name) {
    ATRACE_CALL();
    return mInputManager->getDispatcher()->createInputChannel(name);
}

调用了InputDispatcher创建createInputChannel

framework/native/services/inputflinger/dispatcher/InputDispatcher.cpp

Result<std::unique_ptr<InputChannel>> InputDispatcher::createInputChannel(const std::string& name) {


    std::unique_ptr<InputChannel> serverChannel;
    std::unique_ptr<InputChannel> clientChannel;
    // step10 创建socketpair,对serverChannel、clientChannel赋值
    status_t result = InputChannel::openInputChannelPair(name, serverChannel, clientChannel);

   
    { // acquire lock
        std::scoped_lock _l(mLock);
        const sp<IBinder>& token = serverChannel->getConnectionToken();
        // 拿到serverChannel的fd
        int fd = serverChannel->getFd();
        //将serverChannel包装成Connection
        sp<Connection> connection =
                new Connection(std::move(serverChannel), false /*monitor*/, mIdGenerator);
        // 保存到mConnectionsByToken
        mConnectionsByToken.emplace(token, connection);

        std::function<int(int events)> callback = std::bind(&InputDispatcher::handleReceiveCallback,
                                                            this, std::placeholders::_1, token);
        // step11 将serverChannel注册到inputDispatcher的mLooper
        mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, new LooperEventCallback(callback), nullptr);
    } // release lock

    // Wake the looper because some connections have changed.
    // 唤醒dispatcher的looper
    mLooper->wake();
    //返回clientChannel
    return clientChannel;
}


static status_t openInputChannelPair(const std::string& name,
                                     std::shared_ptr<InputChannel>& serverChannel,
                                     std::unique_ptr<InputChannel>& clientChannel) {
    std::unique_ptr<InputChannel> uniqueServerChannel;
    status_t result = InputChannel::openInputChannelPair(name, uniqueServerChannel, clientChannel);

    serverChannel = std::move(uniqueServerChannel);
    return result;
}

framework/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];
    // linux的socketpair 全双工socket通信
    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;
    //设置socket参数,读写缓冲区的上限
    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 = new BBinder();
    // serverChannelName以(server)结尾
    std::string serverChannelName = name + " (server)";
    android::base::unique_fd serverFd(sockets[0]);
    outServerChannel = InputChannel::create(serverChannelName, std::move(serverFd), token);
    // clientChannelName以(client)结尾
    std::string clientChannelName = name + " (client)";
    android::base::unique_fd clientFd(sockets[1]);
    outClientChannel = InputChannel::create(clientChannelName, std::move(clientFd), token);
    return OK;
}

std::unique_ptr<InputChannel> InputChannel::create(const std::string& name,
                                                   android::base::unique_fd fd, sp<IBinder> token) {
    const int result = fcntl(fd, F_SETFL, O_NONBLOCK);
    if (result != 0) {
        LOG_ALWAYS_FATAL("channel '%s' ~ Could not make socket non-blocking: %s", name.c_str(),
                         strerror(errno));
        return nullptr;
    }
    // using 'new' to access a non-public constructor
    // 直接new InputChannel
    return std::unique_ptr<InputChannel>(new InputChannel(name, std::move(fd), token));
}

创建socketpair,并且把server端的fd注册到InputDispatcher的looper中。 创建InputChannel传入了channelname,各自的fd 和相同的token,到这里两个inputChannel就创建好了,继续回到step8,继续往下执行,将native的inputchannel返回给java层。

frameworks/base/core/jni/android_view_InputChannel.cpp

jobject android_view_InputChannel_createJavaObject(JNIEnv* env,
                                                   std::unique_ptr<InputChannel> inputChannel) {
    std::string name = inputChannel->getName();
    jlong ptr = android_view_InputChannel_createInputChannel(env, std::move(inputChannel));
    jobject javaInputChannel =
            env->NewObject(gInputChannelClassInfo.clazz, gInputChannelClassInfo.mCtor);
  ......
    // 调用java层的SetNativeInputChannel方法,设置mptr属性值
    env->CallVoidMethod(javaInputChannel, gInputChannelClassInfo.mSetNativeInputChannel, ptr);
    if (env->ExceptionOccurred()) {
        ALOGE("Failed to set native ptr to the Java InputChannel for channel %s.",
              inputChannel->getName().c_str());
        return nullptr;
    }
    return javaInputChannel;
}

static jlong android_view_InputChannel_createInputChannel(
        JNIEnv* env, std::unique_ptr<InputChannel> inputChannel) {
    std::unique_ptr<NativeInputChannel> nativeInputChannel =
            std::make_unique<NativeInputChannel>(std::move(inputChannel));

    return reinterpret_cast<jlong>(nativeInputChannel.release());
}

创建了NativeInputChannel,持有inputchannel的指针,然后调用java层InputChannel对象的构造函数gInputChannelClassInfo保存了java层InputChannel的类信息。

int register_android_view_InputChannel(JNIEnv* env) {
    int res = RegisterMethodsOrDie(env, "android/view/InputChannel", gInputChannelMethods,
                                   NELEM(gInputChannelMethods));

    jclass clazz = FindClassOrDie(env, "android/view/InputChannel");
    gInputChannelClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);

    gInputChannelClassInfo.mCtor =
            GetMethodIDOrDie(env, gInputChannelClassInfo.clazz, "<init>", "()V");
    gInputChannelClassInfo.mSetNativeInputChannel =
            GetMethodIDOrDie(env, gInputChannelClassInfo.clazz, "setNativeInputChannel", "(J)V");

    gInputChannelClassInfo.mPtr = GetFieldIDOrDie(env, gInputChannelClassInfo.clazz, "mPtr", "J");

    return res;
}

所以返回给java层的是NativeInputChannel对象的地址。

native执行完了,返回到WindowState的openInputChannel方法,我们继续看这个方法

framework/base/services/core/java/com/android/server/wm/WindowState.java

   void openInputChannel(InputChannel outInputChannel) {
        
        String name = getName();
        // InputManager创建inputChannel
        mInputChannel = mWmService.mInputManager.createInputChannel(name);
        // 从这边继续执行
        mInputChannelToken = mInputChannel.getToken();
        // 保存mInputChannelToken到mInputWindowHandle
        mInputWindowHandle.setToken(mInputChannelToken);
        mWmService.mInputToWindowMap.put(mInputChannelToken, this);
        if (outInputChannel != null) {
           // 给client的inputchannel赋值
            mInputChannel.copyTo(outInputChannel);
        } else {
            
        }
    }

拿到inputChannel的token,这个token是server和client公用的,保存到属性mInputWindowHandle,并且把token和windowState的对应关系保存到wms的mInputToWindowMap,最后给outInputChannel赋值

frameworks/base/core/java/android/view/InputChannel.java

    /**
     * Creates a copy of this instance to the outParameter. This is used to pass an input channel
     * as an out parameter in a binder call.
     * @param other The other input channel instance.
     */
    public void copyTo(InputChannel outParameter) {
        if (outParameter == null) {
            throw new IllegalArgumentException("outParameter must not be null");
        }
        if (outParameter.mPtr != 0) {
            throw new IllegalArgumentException("Other object already has a native input channel.");
        }
        // 就是把native层的NativeInputChannel的地址保存到mptr
        outParameter.setNativeInputChannel(nativeDup(mPtr));
    }

WMS创建好了inputchannel之后返回到ViewRootImpl的setView方法的step3 创建mInputEventReceiver,来注册client端的InputChannel到主线程的looper。我们继续分析ViewRootImpl的setView

public void setView() {
  // step3 创建mInputEventReceiver,
  mInputEventReceiver = new WindowInputEventReceiver(inputChannel,
                            Looper.myLooper());
}

frameworks/base/core/java/android/view/ViewRootImpl.java

final class WindowInputEventReceiver extends InputEventReceiver {
        public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {
            super(inputChannel, looper);
        }
}

frameworks/base/core/java/android/view/InputEventReceiver.java

public InputEventReceiver(InputChannel inputChannel, Looper looper) {
       ......

        mInputChannel = inputChannel;
        mMessageQueue = looper.getQueue();
        mReceiverPtr = nativeInit(new WeakReference<InputEventReceiver>(this),
                inputChannel, mMessageQueue);

    }

frameworks/base/core/jni/android_view_InputEventReceiver.cpp

static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,
        jobject inputChannelObj, jobject messageQueueObj) {
    std::shared_ptr<InputChannel> inputChannel =
            android_view_InputChannel_getInputChannel(env, inputChannelObj);
    ......
    // 主线程的messageQueue
    sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
    ......
    // 创建NativeInputEventReceiver
    sp<NativeInputEventReceiver> receiver = new NativeInputEventReceiver(env,
            receiverWeak, inputChannel, messageQueue);
    status_t status = receiver->initialize();
    ......

    receiver->incStrong(gInputEventReceiverClassInfo.clazz); // retain a reference for the object
    return reinterpret_cast<jlong>(receiver.get());
}


status_t NativeInputEventReceiver::initialize() {
    setFdEvents(ALOOPER_EVENT_INPUT);
    return OK;
}

void NativeInputEventReceiver::setFdEvents(int events) {
    if (mFdEvents != events) {
        mFdEvents = events;
        // client端的inputchannel的fd
        int fd = mInputConsumer.getChannel()->getFd();
        if (events) {
            // client端的inputChannel注册到主线程的looper
            mMessageQueue->getLooper()->addFd(fd, 0, events, this, nullptr);
        } else {
            mMessageQueue->getLooper()->removeFd(fd);
        }
    }
}


// 事件回调
int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data) {

    if (events & ALOOPER_EVENT_INPUT) {
        JNIEnv* env = AndroidRuntime::getJNIEnv();
        status_t status = consumeEvents(env, false /*consumeBatches*/, -1, nullptr);
        mMessageQueue->raiseAndClearException(env, "handleReceiveCallback");
        return status == OK || status == NO_MEMORY ? KEEP_CALLBACK : REMOVE_CALLBACK;
    }
}

到这里可以看到client端的inputChannel注册到了主线程的looper 到此,两端的inputChannel就分别注册好了。总结一下:server端的注册到inputDispatcher的looper,client端的InputChannel是注册到主线程的looper。inputChannel实质是socketpair,fd注册到looper之后,当socket通道有数据时,唤醒epoll,执行回调函数处理事件数据.