Android application 接受按键分发 流程分析

原文链接:https://blog.csdn.net/qq_34211365/article/details/103243723

ViewRootImpl.java


    /**
     * We have one child
     */
    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
        synchronized (this) {
        ......
        if ((mWindowAttributes.inputFeatures
                        & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
                    mInputChannel = new InputChannel();创建channel
               }
               res = mWindowSession.addToDisplay(mWindow, mSeq,mWindowAttributes,getHostVisibility(), mDisplay.getDisplayId(), mTmpFrame,mAttachInfo.mContentInsets,
               mAttachInfo.mStableInsets,mAttachInfo.mOutsets,
               mAttachInfo.mDisplayCutout, mInputChannel,
               mTempInsets);配置channel
         ......
    }

 

WindowManagerService.java

public int addWindow(Session session, IWindow client, int seq,
            LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame,
            Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
            DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel,
            InsetsState outInsetsState) {
           ......
           final WindowState win = new WindowState(this, session, client, token, parentWindow,
                    appOp[0], seq, attrs, viewVisibility, session.mUid,
                    session.mCanAddInternalSystemWindow);
           final boolean openInputChannels = (outInputChannel != null
                    && (attrs.inputFeatures & INPUT_FEATURE_NO_INPUT_CHANNEL) == 0);
            if  (openInputChannels) {
                win.openInputChannel(outInputChannel);
            }
           ......
 }

    void openInputChannel(InputChannel outInputChannel) {
        if (mInputChannel != null) {
            throw new IllegalStateException("Window already has an input channel.");
        }
        String name = getName();
        //创建InputChannelPair
        InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
        //服务端InputChannel
        mInputChannel = inputChannels[0];
        //客户端InputChannel
        mClientChannel = inputChannels[1];
        mInputWindowHandle.token = mClient.asBinder();
        if (outInputChannel != null) {
            //将客户端InputChannel发送回ViewRootImpl
            mClientChannel.transferTo(outInputChannel);
            mClientChannel.dispose();
            mClientChannel = null;
        } else {
            // If the window died visible, we setup a dummy input channel, so that taps
            // can still detected by input monitor channel, and we can relaunch the app.
            // Create dummy event receiver that simply reports all events as handled.
            mDeadWindowEventReceiver = new DeadWindowEventReceiver(mClientChannel);
        }
        //将服务端InputChannel注册到InputDispatcher
        mWmService.mInputManager.registerInputChannel(mInputChannel, mClient.asBinder());
    }

openInputChannelPair

    /**
     * Creates a new input channel pair.  One channel should be provided to the input
     * dispatcher and the other to the application's input queue.
     * @param name The descriptive (non-unique) name of the channel pair.
     * @return A pair of input channels.  The first channel is designated as the
     * server channel and should be used to publish input events.  The second channel
     * is designated as the client channel and should be used to consume input events.
     */
    public static InputChannel[] openInputChannelPair(String name) {
        if (name == null) {
            throw new IllegalArgumentException("name must not be null");
        }

        if (DEBUG) {
            Slog.d(TAG, "Opening input channel pair '" + name + "'");
        }
        return nativeOpenInputChannelPair(name);
    }

android_view_InputChannel.cpp

static jobjectArray android_view_InputChannel_nativeOpenInputChannelPair(JNIEnv* env,
        jclass clazz, jstring nameObj) {
    ScopedUtfChars nameChars(env, nameObj);
    std::string name = nameChars.c_str();

    sp<InputChannel> serverChannel;
    sp<InputChannel> clientChannel;
    //创建Native层serverChannel和clientChannel
    status_t result = InputChannel::openInputChannelPair(name, serverChannel, clientChannel);
    .......
    //创建java层数组,用在后面存放java层InputChannel,并返回
    jobjectArray channelPair = env->NewObjectArray(2, gInputChannelClassInfo.clazz, NULL);
    ......
    //创建java层的server端的InputChannel对象
    jobject serverChannelObj = android_view_InputChannel_createInputChannel(env,
            std::make_unique<NativeInputChannel>(serverChannel));
    ......
    //创建java层的clien端的InputChannel对象
    jobject clientChannelObj = android_view_InputChannel_createInputChannel(env,
            std::make_unique<NativeInputChannel>(clientChannel));
    ......
    env->SetObjectArrayElement(channelPair, 0, serverChannelObj);
    env->SetObjectArrayElement(channelPair, 1, clientChannelObj);
    return channelPair;
}

 InputTransport.cpp

InputChannel::openInputChannelPair 
status_t InputChannel::openInputChannelPair(const std::string& name,
        sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) {
    //一对socket数组
    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;
    //对两个socker分别设置
    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;
    //创建ServerChannel,后缀名+server
    serverChannelName += " (server)";
    //通过setFd将sockets[0]和ServerChannel关联上
    outServerChannel = new InputChannel(serverChannelName, sockets[0]);

    std::string clientChannelName = name;
    //创建ClientChannel,后缀名+client
    clientChannelName += " (client)";
    //通过setFd将sockets[1]和ClientChannel关联上
    outClientChannel = new InputChannel(clientChannelName, sockets[1]);
    return OK;
}
InputChannel::InputChannel(const std::string& name, int fd) :
          mName(name) {
          ......
          setFd(fd);
  }

一对java层InputChannel,并将一对NativeInputChannel赋值给java层InputChannel的mPtr属性,并将server端InputChannel赋值给数组0,将client端InputChannel赋值给数组1,最后将数组返回给java层

WindowState 

    void openInputChannel(InputChannel outInputChannel) {
        if (mInputChannel != null) {
            throw new IllegalStateException("Window already has an input channel.");
        }
        String name = getName();
        //native层返回的InputChannel数组,server端和cilent端
        InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
        //server端InputChannel
        mInputChannel = inputChannels[0];
        //client端InputChannel
        mClientChannel = inputChannels[1];
        mInputWindowHandle.token = mClient.asBinder();
        if (outInputChannel != null) {
            //将client端InputChannel传回到ViewRootImpl
            mClientChannel.transferTo(outInputChannel);
            mClientChannel.dispose();
            mClientChannel = null;
        } else {
            // If the window died visible, we setup a dummy input channel, so that taps
            // can still detected by input monitor channel, and we can relaunch the app.
            // Create dummy event receiver that simply reports all events as handled.
            mDeadWindowEventReceiver = new DeadWindowEventReceiver(mClientChannel);
        }
        //server端InputChannel注册到native层InputDispatcher
        mWmService.mInputManager.registerInputChannel(mInputChannel, mClient.asBinder());
    }

InputChannel.java

    /**
     * Transfers ownership of the internal state of the input channel to another
     * instance and invalidates this instance.  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 transferTo(InputChannel outParameter) {
        if (outParameter == null) {
            throw new IllegalArgumentException("outParameter must not be null");
        }

        nativeTransferTo(outParameter);
    }

android_view_InputChannel.cpp 

/*
mClientChannel.transferTo(outInputChannel);
*/
//注意该方法参数中的otherObj和obj,otherObj代表传递下来的参数outInputChannel,obj代表调用此方法的对象mClientChannel
static void android_view_InputChannel_nativeTransferTo(JNIEnv* env, jobject obj,
        jobject otherObj) {
        //当java层的outInputChannel的mPtr已经指向了一个NativeInputChannel时抛一个异常返回
    if (android_view_InputChannel_getNativeInputChannel(env, otherObj) != NULL) {
        jniThrowException(env, "java/lang/IllegalStateException",
                "Other object already has a native input channel.");
        return;
    }
    //获取java层mClientChannel的mPtr属性,mPtr属性会指向一个NativeInputChannel对象,根据前面分析此时mClientChannel的mPtr指向client端的NativeInputChannel
    NativeInputChannel* nativeInputChannel =
            android_view_InputChannel_getNativeInputChannel(env, obj);
    android_view_InputChannel_setNativeInputChannel(env, otherObj, nativeInputChannel);
    android_view_InputChannel_setNativeInputChannel(env, obj, NULL);
}
static NativeInputChannel* android_view_InputChannel_getNativeInputChannel(JNIEnv* env,
        jobject inputChannelObj) {
    //jni方法,获取inputChannelObj对象的gInputChannelClassInfo.mPtr属性
    jlong longPtr = env->GetLongField(inputChannelObj, gInputChannelClassInfo.mPtr);
    return reinterpret_cast<NativeInputChannel*>(longPtr);
}
static void android_view_InputChannel_setNativeInputChannel(JNIEnv* env, jobject inputChannelObj,
        NativeInputChannel* nativeInputChannel) {
        //jni方法,将inputChannelObj的gInputChannelClassInfo.mPtr属性赋值为nativeInputChannel
    env->SetLongField(inputChannelObj, gInputChannelClassInfo.mPtr,
             reinterpret_cast<jlong>(nativeInputChannel));
}

上面的方法主要作用就是将mClientChannel的mPtr属性赋值给outInputChannel,并将mClientChannel的mPtr赋值为NULL,这样就实现了将mClientChannel与outInputChannel互换,outInputChannel是ViewRootImpl的传递过来的mInputChannel,达到了将mClientChannel传递个应用客户端的目的。

 

InputManagerService.java

    /**
     * Registers an input channel so that it can be used as an input event target.
     * @param inputChannel The input channel to register.
     * @param inputWindowHandle The handle of the input window associated with the
     * input channel, or null if none.
     */
    public void registerInputChannel(InputChannel inputChannel, IBinder token) {
        if (inputChannel == null) {
            throw new IllegalArgumentException("inputChannel must not be null.");
        }
        if (token == null) {
            token = new Binder();
        }
        inputChannel.setToken(token);
        //native方法
        nativeRegisterInputChannel(mPtr, inputChannel, Display.INVALID_DISPLAY);
    }

com_android_server_input_InputManagerService.cpp

static void nativeRegisterInputChannel(JNIEnv* env, jclass /* clazz */,
        jlong ptr, jobject inputChannelObj, jint displayId) {
    //ptr是java层InputManagerService中的mPtr属性,在InputManagerService初始化时指向了NativeInputManager
    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
    //通过java层传下来的inputChannels[0]获取到Native层的server端InputChannel
    sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,
            inputChannelObj);
    if (inputChannel == nullptr) {
        throwInputChannelNotInitialized(env);
        return;
    }
    //注册inputChannel
    status_t status = im->registerInputChannel(env, inputChannel, displayId);
    if (status) {
        std::string message;
        message += StringPrintf("Failed to register input channel.  status=%d", status);
        jniThrowRuntimeException(env, message.c_str());
        return;
    }
    //设置handleInputChannelDisposed回调
    android_view_InputChannel_setDisposeCallback(env, inputChannelObj,
            handleInputChannelDisposed, im);
 }
status_t NativeInputManager::registerInputChannel(JNIEnv* /* env */,
        const sp<InputChannel>& inputChannel, int32_t displayId) {
    ATRACE_CALL();
    return mInputManager->getDispatcher()->registerInputChannel(
            inputChannel, displayId);
}
//InputDispatcher.h
// All registered connections mapped by channel file descriptor.
KeyedVector<int, sp<Connection> > mConnectionsByFd GUARDED_BY(mLock);
status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel,
        int32_t displayId) {
    { // acquire lock
        ......
        //创建Connection对象
        sp<Connection> connection = new Connection(inputChannel, false /*monitor*/);
        //获取之前通过setFd存入的socket[0]
        int fd = inputChannel->getFd();
        //将fd和connection关联,后续InputDispatch通过fd可以获取对应connection,通过connection获取server InputChannel和client InputChannel通信从而将事件分发到对应的应用窗口
        mConnectionsByFd.add(fd, connection);
        mInputChannelsByToken[inputChannel->getToken()] = inputChannel;
        //将fd添加到Looper线程进行监听,在收到对端相应事件之后回调handleReceiveCallback
        mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
    } // release lock
    // Wake the looper because some connections have changed.
    mLooper->wake();
    return OK;
}

从java层传下来的inputChannels[0]就已经注册到了InputDispatcher并且将对应的Fd添加到了InputDispatcher的Loop进行监听,并且传进去了一个回调handleReceiveCallback,应用端窗口处理完输入事件之后回调此方法。

handleReceiveCallback

ViewRootImpl.java

在上面流程addToDisplay方法执行完之后ViewRootImpl中的mInputChannel已经变成了client端的InputChannel即inputChannels[1]

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
      ......
      mInputChannel = new InputChannel();
      res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                            getHostVisibility(), mDisplay.getDisplayId(), mTmpFrame,
                            mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                            mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel,
                            mTempInsets);
                            ......
        if (mInputChannel != null) {
                    if (mInputQueueCallback != null) {
                        mInputQueue = new InputQueue();
                        mInputQueueCallback.onInputQueueCreated(mInputQueue);
                    }
                    mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
                            Looper.myLooper());
                }       
      ......
}

WindowInputEventReceiver

    /**
     * Creates an input event receiver bound to the specified input channel.
     *
     * @param inputChannel The input channel.
     * @param looper The looper to use when invoking callbacks.
     */
    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;
        //UI线程的messagequeue
        mMessageQueue = looper.getQueue();
        //native方法,将自己,client端的InputChannel和UI线程的messagequeue传进去
        mReceiverPtr = nativeInit(new WeakReference<InputEventReceiver>(this),
                inputChannel, mMessageQueue);

        mCloseGuard.open("dispose");
    }

android_view_InputEventReceiver.cpp

static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,
        jobject inputChannelObj, jobject messageQueueObj) {
    //见过很多次了该方法,通过传下来的cilent端的InputChannel获取对应的native层InputChannel
    sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,
            inputChannelObj);
    if (inputChannel == NULL) {
        jniThrowRuntimeException(env, "InputChannel is not initialized.");
        return 0;
    }
    //通过传下来的messagequeue获取对于native层的messagequeue
    sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
    if (messageQueue == NULL) {
        jniThrowRuntimeException(env, "MessageQueue is not initialized.");
        return 0;
    }
    //创建NativeInputEventReceiver
    sp<NativeInputEventReceiver> receiver = new NativeInputEventReceiver(env,
            receiverWeak, inputChannel, messageQueue);
    status_t status = receiver->initialize();
    if (status) {
        String8 message;
        message.appendFormat("Failed to initialize input event receiver.  status=%d", status);
        jniThrowRuntimeException(env, message.string());
        return 0;
    }
    receiver->incStrong(gInputEventReceiverClassInfo.clazz); // retain a reference for the object
    return reinterpret_cast<jlong>(receiver.get());
}

创建NativeInputEventReceiver

//给NativeInputEventReceiver成员变量赋值
NativeInputEventReceiver::NativeInputEventReceiver(JNIEnv* env,
        jobject receiverWeak, const sp<InputChannel>& inputChannel,
        const sp<MessageQueue>& messageQueue) :
        mReceiverWeakGlobal(env->NewGlobalRef(receiverWeak)),
        mInputConsumer(inputChannel), mMessageQueue(messageQueue),
        mBatchedInputEventPending(false), mFdEvents(0) {
    }
}

status_t NativeInputEventReceiver::initialize() {
    setFdEvents(ALOOPER_EVENT_INPUT);
    return OK;
}
void NativeInputEventReceiver::setFdEvents(int events) {
    if (mFdEvents != events) {
        mFdEvents = events;
        //获取client端InputChannel的Fd即socket[1]
        int fd = mInputConsumer.getChannel()->getFd();
        if (events) {
            //将fd添加到UI线程进行监听,回调传的this
            mMessageQueue->getLooper()->addFd(fd, 0, events, this, NULL);
        } else {
            mMessageQueue->getLooper()->removeFd(fd);
        }
    }
}

 到此client端的Fd也已经传递到了UI线程进行监听,InputDispatch与ViewRootImpl的socket连接已经建立。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值