InputChannel通道建立-Android12

Posted xhBruce

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了InputChannel通道建立-Android12相关的知识,希望对你有一定的参考价值。

InputChannel通道建立-android12

android12-release

InputDispatcher线程分发事件-Android12 最后通过mChannel->sendMessage(&msg)发送给InputEventReceiver接收端,之间使用Socket实现通信。


frameworks/base/core/java/android/view/InputChannel.java
frameworks/base/core/java/android/view/InputEventReceiver.java
frameworks/native/libs/input/InputTransport.cpp

1. APP界面建立InputChannel

InputReader和InputDispatcher都是运行在system_server进程,通过建立InputChannel socket传递给APP进程

1.1 APP界面添加

App即将显示处理ActivityThread.handleResumeActivity中:

  • performResumeActivity通过Instrumentation.java通知Activity.onResume
  • wm.addView(decor, l)r.activity.makeVisible()实质一样,通过WindowManager(即WindowManagerImpl)调用WindowManagerGlobal.addView()ViewRootImpl.setView()建立InputChannel

frameworks/base/core/java/android/app/ActivityThread.java

public void handleResumeActivity(ActivityClientRecord r, boolean finalStateRequest,
        boolean isForward, String reason) 
    // ... ...
    if (!performResumeActivity(r, finalStateRequest, reason)) 
        return;
    
    // ... ...
    if (r.window == null && !a.mFinished && willBeVisible) 
        r.window = r.activity.getWindow();
        View decor = r.window.getDecorView();
        decor.setVisibility(View.INVISIBLE);
        ViewManager wm = a.getWindowManager();
        // ... ...
        if (a.mVisibleFromClient) 
            if (!a.mWindowAdded) 
                a.mWindowAdded = true;
                wm.addView(decor, l);
             else 
                // ... ...
            
        
        // ... ...
    
    // ... ...
    if (!r.activity.mFinished && willBeVisible && r.activity.mDecor != null && !r.hideForNow) 
        // ... ...
        if (r.activity.mVisibleFromClient) 
            r.activity.makeVisible();
        
    
    // ... ...

1.1.1 Context.WINDOW_SERVICE 实际获取WindowManagerImpl

frameworks/base/core/java/android/app/Activity.java

final void attach(Context context, ActivityThread aThread,
        Instrumentation instr, IBinder token, int ident,
        Application application, Intent intent, ActivityInfo info,
        CharSequence title, Activity parent, String id,
        NonConfigurationInstances lastNonConfigurationInstances,
        Configuration config, String referrer, IVoiceInteractor voiceInteractor,
        Window window, ActivityConfigCallback activityConfigCallback, IBinder assistToken,
        IBinder shareableActivityToken) 
    // ... ...
    mWindow = new PhoneWindow(this, window, activityConfigCallback);
    // ... ...
    mUiThread = Thread.currentThread();
    mMainThread = aThread;
    // ... ...
    mWindow.setWindowManager(
            (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
            mToken, mComponent.flattenToString(),
            (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
    // ... ...

1.2 InputChannel / WindowInputEventReceiver建立联系

  1. 创建Java层的InputChannel对象
  2. mWindowSession.addToDisplayAsUser()向WMS注册InputChannel信息,通过InputChannel::openInputChannelPair创建的socket pair,将其中的客户端赋值给mInputChannel.
  3. WindowInputEventReceiver 接收InputChannel消息
  4. InputStage 事件处理责任链

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

public void addView(View view, ViewGroup.LayoutParams params,
        Display display, Window parentWindow, int userId) 

    synchronized (mLock) 
        // ... ...
        root = new ViewRootImpl(view.getContext(), display);
        // ... ...
        // do this last because it fires off messages to start doing things
        try 
            root.setView(view, wparams, panelParentView, userId);
         catch (RuntimeException e) 
            // BadTokenException or InvalidDisplayException, clean up.
            if (index >= 0) 
                removeViewLocked(index, true);
            
            throw e;
        
    

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) 
            // ... ...
            InputChannel inputChannel = null;
            if ((mWindowAttributes.inputFeatures
                    & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) 
                inputChannel = new InputChannel();
            
            // ... ...
            try 
                // ... ...
                res = mWindowSession.addToDisplayAsUser(mWindow, mWindowAttributes,
                        getHostVisibility(), mDisplay.getDisplayId(), userId,
                        mInsetsController.getRequestedVisibility(), inputChannel, mTempInsets,
                        mTempControls);
                if (mTranslator != null) 
                    mTranslator.translateInsetsStateInScreenToAppWindow(mTempInsets);
                    mTranslator.translateSourceControlsInScreenToAppWindow(mTempControls);
                
             catch (RemoteException e) 
                // ... ...
             finally 
                if (restore) 
                    attrs.restore();
                
            
            // ... ...
            if (inputChannel != null) 
                // ... ...
                mInputEventReceiver = new WindowInputEventReceiver(inputChannel,
                        Looper.myLooper());
                // ... ...
            

            // 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;
            mPendingInputEventQueueLengthCounterName = "aq:pending:" + counterSuffix;
        
    

1.3 InputChannel使用socket通信

  1. 服务端serverChannel、客户端clientChannel;将clientChannel给到java层mInputChannel
  2. setsockopt() socket通信
  3. 创建Connection,并将serverChannel->getFd()添加到Looper监听

mWindowSession.addToDisplayAsUser() --> mService.addWindow() --> win.openInputChannel(outInputChannel) -->mWmService.mInputManager.createInputChannel(name) ==JNI==>最终调用InputDispatcher::createInputChannel
frameworks/base/services/core/java/com/android/server/wm/Session.java
frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
frameworks/base/services/core/java/com/android/server/wm/WindowState.java

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());
#endif

    std::unique_ptr<InputChannel> serverChannel;
    std::unique_ptr<InputChannel> clientChannel;
    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();
        int fd = serverChannel->getFd();
        sp<Connection> connection =
                new Connection(std::move(serverChannel), false /*monitor*/, mIdGenerator);

        if (mConnectionsByToken.find(token) != mConnectionsByToken.end()) 
            ALOGE("Created a new connection, but the token %p is already known", token.get());
        
        mConnectionsByToken.emplace(token, connection);

        std::function<int(int events)> callback = std::bind(&InputDispatcher::handleReceiveCallback,
                                                            this, std::placeholders::_1, token);

        mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, new LooperEventCallback(callback), nullptr);
     // release lock

    // Wake the looper because some connections have changed.
    mLooper->wake();
    return clientChannel;

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 = new BBinder();

    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;

2. 开发者选项中指针位置建立InputChannel

开发者选项中指针位置

  • WMS监听开关POINTER_LOCATION,enablePointerLocation初始化绘制界面PointerLocationView,注册registerPointerEventListener监听
  • 实质就是InputChannel \\ InputEventReceiver,在DisplayContent.java初始化是已经建立,这里注意有其他功能通过该InputChannel监听MotionEvent事件

3. Drag and drop拖放框架 建立InputChannel

Drag and drop拖放框架

View.startDrag/startDragAndDrop --> mAttachInfo.mSession.performDrag() --> mDragDropController.performDrag() --> mCallback.get().registerInputChannel() --> state.register() --> mInputInterceptor = new InputInterceptor(display) --> InputChannel / DragInputEventReceiver

  • APP调用startDrag()启动时建立InputChannel / DragInputEventReceiver

frameworks/base/core/java/android/view/View.java
frameworks/base/services/core/java/com/android/server/wm/Session.java
frameworks/base/services/core/java/com/android/server/wm/DragDropController.java
frameworks/base/services/core/java/com/android/server/wm/WindowManagerInternal.java
frameworks/base/services/core/java/com/android/server/wm/DragState.java

以上是关于InputChannel通道建立-Android12的主要内容,如果未能解决你的问题,请参考以下文章

InputChannel通道建立-Android12

InputChannel发送Input给App-Android12

Android系统源码阅读(12):InputChannel的注册过程

InputManagerService实体按键及组合按键-Android12

InputManagerService实体按键及组合按键-Android12

InputManagerService实体按键及组合按键-Android12