Android输入系统IMS(5)--ims分发到java层

1.addWindow函数(InputChannel创建注册):

    通过上一篇的分析,我们发现InputDispatcherThread调用InputChannel的sendMessage函数发送了一条消息,但是我们不知道谁在接收这条输入事件消息。在这里提前告诉大家是APP在接收这些消息。这篇我们将讲解消息到底是怎么发送到app的。

status_t InputChannel::sendMessage(const InputMessage* msg) {
    size_t msgLength = msg->size();
    ssize_t nWrite;
    do {
//最终通过socketpair发送出去,根据之前带代码可以知道是通过wms发给app了。
        nWrite = ::send(mFd, msg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL);
    } while (nWrite == -1 && errno == EINTR);
 
}

   有发送就一定有接收以及初始化函数这样很自然就会关注到:InputChannel::openInputChannelPair函数.通过搜索代码关键字可以得到如下的函数关系图:

   app都是带Activity的,调用startActivity(Intent), 会通过Binder IPC机制, 最终调用到ActivityThread中的handleLaunchActivity方法开始分析,下图的流程显示了启动过程中的函数调用关系:

根据上面的的分析可以从 addWindow()函数入手分析调用过程。

    根据这个时序图可以看出WindowManagerService.java中 给addWindow函数传入了outInputChannel变量对象。使用InputChannel.openInputChannelPair(name);在native层创建的  InputChannel[] inputChannels会调用mInputManager.registerInputChannel函数 -> com_android_server_input_InputManagerService.cpp    中的static void nativeRegisterInputChannel -> InputDispatcher::registerInputChannel注册到native c++层。InputDispatcher要能够发送事件数据,必须的要让其知道对应的window的InputChannel,这个通过注册实现的。同时调用inputChannels[1].transferTo(outInputChannel);把native其中的一个inputChannels[1]转换到java层的outInputChannel,包含socketpair文件句柄。(outInputChannel是在app启动过程中java层NEW出来的后面会分析)

status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel,
        const sp<InputWindowHandle>& inputWindowHandle, bool monitor) {
#if DEBUG_REGISTRATION
    ALOGD("channel '%s' ~ registerInputChannel - monitor=%s", inputChannel->getName().string(),
            toString(monitor));
#endif

    { // acquire lock
        AutoMutex _l(mLock);

        if (getConnectionIndexLocked(inputChannel) >= 0) {
            ALOGW("Attempted to register already registered input channel '%s'",
                    inputChannel->getName().string());
            return BAD_VALUE;
        }
       //这个将inputWindowHandle对应的inputChannel封装为Connection
        sp<Connection> connection = new Connection(inputChannel, inputWindowHandle, monitor);
        //这个就是unix socket文件句柄
        int fd = inputChannel->getFd();
       //将connection保存到映射表中
        mConnectionsByFd.add(fd, connection);

        if (monitor) {
            mMonitoringChannels.push(inputChannel);
        }

        mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
    } // release lock

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

上面这段代码中的fd网络文件句柄和connection是通信发送事件的关键;上一篇我们已经分析分发过程了:其中部分代码:

void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
        const sp<Connection>& connection) {
 
 DispatchEntry* dispatchEntry = connection->outboundQueue.head;
 case EventEntry::TYPE_KEY: {
            KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry);
 
            // Publish the key event.
            status = connection->inputPublisher.publishKeyEvent(dispatchEntry->seq,
                    keyEntry->deviceId, keyEntry->source,
                    dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags,
                    keyEntry->keyCode, keyEntry->scanCode,
                    keyEntry->metaState, keyEntry->repeatCount, keyEntry->downTime,
                    keyEntry->eventTime);
            break;
}

可以看到操作的都是connection对象,可以总结一下:上一篇分析的InputChannel::sendMessage方式输入事件到目前为止是发送到了WindowManagerService.java中使用InputChannel.openInputChannelPair(name);创建的  InputChannel[] inputChannels.其中的inputChannels[1]转换到java层的outInputChannel。

 

2. app启动过程如何触发addWindow函数执行的:

///
final void handleResumeActivity(IBinder token,
        boolean clearHide, boolean isForward, boolean reallyResume) {
			
	        // TODO Push resumeArgs into the activity for consideration
            ActivityClientRecord r = performResumeActivity(token, clearHide);
		
            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();
                WindowManager.LayoutParams l = r.window.getAttributes();
                a.mDecor = decor;
                l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
                l.softInputMode |= forwardBit;
                if (a.mVisibleFromClient) {
                    a.mWindowAdded = true;
                    wm.addView(decor, l);//decor是view类,wm是个ViewManager接口
                }

            // If the window has already been added, but during resume
            // we started another activity, then don't yet make the
            // window visible.
            } else if (!willBeVisible) {
                if (localLOGV) Slog.v(
                    TAG, "Launch " + r + " mStartedActivity set");
                r.hideForNow = true;
            }
	
}		
public interface ViewManager//接口
{
    public void addView(View view, ViewGroup.LayoutParams params);
    public void updateViewLayout(View view, ViewGroup.LayoutParams params);
    public void removeView(View view);
}
public interface WindowManager extends ViewManager {
}

WindowManagerImpl.java
public final class WindowManagerImpl implements WindowManager {

 private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
    private final Display mDisplay;
    private final Window mParentWindow;
	
    @Override
    public void addView(View view, ViewGroup.LayoutParams params) {
        mGlobal.addView(view, params, mDisplay, mParentWindow);
    }

}	
WindowManagerGlobal.java
 public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow) {

			root = new ViewRootImpl(view.getContext(), display);

            view.setLayoutParams(wparams);

            mViews.add(view);
            mRoots.add(root);
            mParams.add(wparams);
			root.setView(view, wparams, panelParentView);//root是ViewRootImpl类
}				
ViewRootImpl.java
public final class ViewRootImpl implements ViewParent,
        View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks {
		final IWindowSession mWindowSession;	
	    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {

			    // 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();
                if ((mWindowAttributes.inputFeatures
                        & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
                    mInputChannel = new InputChannel();//第一次需要创建InputChannel导致native层创建socketpair
                }
				
				res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                            getHostVisibility(), mDisplay.getDisplayId(),
                            mAttachInfo.mContentInsets, mInputChannel);
		
		}
}
//通过AIDL跨进程通信机制最终调用到WindowManagerService的addWindow();
//IWindowSession.aidl
interface IWindowSession {
    int addToDisplay(IWindow window, int seq, in WindowManager.LayoutParams attrs,
            in int viewVisibility, in int layerStackId, out Rect outContentInsets,
            out InputChannel outInputChannel);
}		
	
// ./common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/view/IWindowSession.java

@Override public int addToDisplay(android.view.IWindow window, int seq, android.view.WindowManager.LayoutParams attrs, int viewVisibility, int layerStackId, android.graphics.Rect outContentInsets, android.view.InputChannel outInputChannel) throws android.os.RemoteException
{
mRemote.transact(Stub.TRANSACTION_addToDisplay, _data, _reply, 0);
}	
	
	
// framework/base/services/core/java/com/android/server/wm/Session.java.
final class Session extends IWindowSession.Stub
        implements IBinder.DeathRecipient {
	final WindowManagerService mService;
    @Override
    public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
            int viewVisibility, int displayId, Rect outContentInsets,
            InputChannel outInputChannel) {
        return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
                outContentInsets, outInputChannel);
    }	
}

// WindowManagerService.java
    public int addWindow(Session session, IWindow client, int seq,
            WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
            Rect outContentInsets, InputChannel outInputChannel) {
}

    通过上的关键代码可以看到使用了接口,继承,AIDL跨进程通信机制,handleResumeActivity函数最终是触发了WindowManagerService.java的 public int addWindow函数的调用。

3.APP启动创建的 InputChannel监听器初始化:

ViewRootImpl.java
public final class ViewRootImpl implements ViewParent,
        View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks {
		final IWindowSession mWindowSession;	
	    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
                if (mInputChannel != null) {//mInputChannel 指向native层创建的inputChannels[1]
                    if (mInputQueueCallback != null) {
                        mInputQueue = new InputQueue();
                        mInputQueueCallback.onInputQueueCreated(mInputQueue);
                    }
					//为InputChannel注册监听器
                    mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
                            Looper.myLooper());
                }		
				
    final class WindowInputEventReceiver extends InputEventReceiver {
        public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {
            super(inputChannel, looper);
        }

        @Override
        public void onInputEvent(InputEvent event) {
            enqueueInputEvent(event, this, 0, true);
        }

        @Override
        public void onBatchedInputEventPending() {
            if (mUnbufferedInputDispatch) {
                super.onBatchedInputEventPending();
            } else {
                scheduleConsumeBatchedInput();
            }
        }

        @Override
        public void dispose() {
            unscheduleConsumeBatchedInput();
            super.dispose();
        }
    }
    WindowInputEventReceiver mInputEventReceiver;	
	
InputEventReceiver.java
public abstract class InputEventReceiver {

	    public InputEventReceiver(InputChannel inputChannel, Looper looper) {
			mInputChannel = inputChannel;
			mMessageQueue = looper.getQueue();
			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) {
   //通过inputChannelObj 获取native层的InputChannel
    sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,
            inputChannelObj);
    //获取java层InputEventReceiver对象的native层的消息队列
    sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
    //使用inputChannel和messageQueue创建native对应的InputEventReceiver对象
    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());
}
status_t NativeInputEventReceiver::initialize() {
    setFdEvents(ALOOPER_EVENT_INPUT);
    return OK;
}
void NativeInputEventReceiver::setFdEvents(int events) {
    if (mFdEvents != events) {
        mFdEvents = events;
        int fd = mInputConsumer.getChannel()->getFd();
        if (events) {
			//用looper监听inputChannel对应的socketpair文件句柄
            mMessageQueue->getLooper()->addFd(fd, 0, events, this, NULL);
        } else {
            mMessageQueue->getLooper()->removeFd(fd);
        }
    }
}


int Looper::addFd(int fd, int ident, int events, ALooper_callbackFunc callback, void* data) {
    return addFd(fd, ident, events, callback ? new SimpleLooperCallback(callback) : NULL, data);
}
 
int Looper::addFd(int fd, int ident, int events, const sp<loopercallback>& callback, void* data) {
    { // acquire lock
        AutoMutex _l(mLock);
        Request request;
        request.fd = fd;
        request.ident = ident;
        //这个很重要,当被监听的文件发生变化时就会调用该callback函数
        request.callback = callback;
        request.data = data;
 
        ssize_t requestIndex = mRequests.indexOfKey(fd);
        if (requestIndex < 0) {
            int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, & eventItem);
            mRequests.add(fd, request);
        }
    } // release lock
    return 1;
}

     通过上面的关键代码分析,这段代码完成了epoll对 “WindowManagerService.java中使用InputChannel.openInputChannelPair(name);创建的  InputChannel[] inputChannels.其中的inputChannels[1]转换到java层的outInputChannel"完成了监听初始化动作。下面看看是如何监听有可读 数据接收的。

4.APP端的InputChannel中的事件接收

int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
    int result = 0;
    for (;;) {
        while (mResponseIndex < mResponses.size()) {
            const Response& response = mResponses.itemAt(mResponseIndex++);
            int ident = response.request.ident;
            if (ident >= 0) {
                int fd = response.request.fd;
                int events = response.events;
                void* data = response.request.data;
                if (outFd != NULL) *outFd = fd;
                if (outEvents != NULL) *outEvents = events;
                if (outData != NULL) *outData = data;
                return ident;
            }
        }
        result = pollInner(timeoutMillis);
    }
}
 
int Looper::pollInner(int timeoutMillis) {
    struct epoll_event eventItems[EPOLL_MAX_EVENTS];
    //睡眠等待消息
    int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);
    for (int i = 0; i < eventCount; i++) {
        int fd = eventItems[i].data.fd;
        uint32_t epollEvents = eventItems[i].events;
        if (fd == mWakeReadPipeFd) {
            if (epollEvents & EPOLLIN) {
                awoken();
            }
        } else {
            ssize_t requestIndex = mRequests.indexOfKey(fd);
            if (requestIndex >= 0) {
                int events = 0;
                if (epollEvents & EPOLLIN) events |= ALOOPER_EVENT_INPUT;
                if (epollEvents & EPOLLOUT) events |= ALOOPER_EVENT_OUTPUT;
                if (epollEvents & EPOLLERR) events |= ALOOPER_EVENT_ERROR;
                if (epollEvents & EPOLLHUP) events |= ALOOPER_EVENT_HANGUP;
                //将输入事件push到队列上
                pushResponse(events, mRequests.valueAt(requestIndex));
            }
        }
    }
Done: ;
    //处理response事件
    for (size_t i = 0; i < mResponses.size(); i++) {
        Response& response = mResponses.editItemAt(i);
        if (response.request.ident == ALOOPER_POLL_CALLBACK) {
            int fd = response.request.fd;
            int events = response.events;
            void* data = response.request.data;
            // 下面的callback就是 NativeInputEventRecieverd
            int callbackResult = response.request.callback->handleEvent(fd, events, data);
            if (callbackResult == 0) {
                removeFd(fd);
            }
            response.request.callback.clear();
            result = ALOOPER_POLL_CALLBACK;
        }
    }
    return result;
}
 
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, NULL);
        mMessageQueue->raiseAndClearException(env, "handleReceiveCallback");
        return status == OK || status == NO_MEMORY ? 1 : 0;
}
    return 1;
}
 
status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,
        bool consumeBatches, nsecs_t frameTime, bool* outConsumedBatch) {
    for (;;) {
        uint32_t seq;
        InputEvent* inputEvent;
        //从buffer取出事件
        status_t status = mInputConsumer.consume(&mInputEventFactory,
                consumeBatches, frameTime, &seq, &inputEvent);
        if (!skipCallbacks) {
            jobject inputEventObj;
            switch (inputEvent->getType()) {
            case AINPUT_EVENT_TYPE_KEY:
                //转换为java层的InputEvent
                inputEventObj = android_view_KeyEvent_fromNative(env,
                        static_cast<keyevent*>(inputEvent));
                break;
            }
            if (inputEventObj) {
                //会调用到java层的函数InputEventReceiver->dispatchInputEvent
                env->CallVoidMethod(receiverObj.get(),
                        gInputEventReceiverClassInfo.dispatchInputEvent, seq,
 inputEventObj);
            }
        }
    }
}

    再来看看InputEventReceiver.java文件中的:

    // Called from native code.
    @SuppressWarnings("unused")
    private void dispatchInputEvent(int seq, InputEvent event) {
        mSeqMap.put(event.getSequenceNumber(), seq);
        onInputEvent(event);//处理event
    }
    public void onInputEvent(InputEvent event) {
        finishInputEvent(event, false);
    }
    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);
                nativeFinishInputEvent(mReceiverPtr, seq, handled);
            }
        }
        event.recycleIfNeededAfterDispatch();
    }

    分析到这里,输入事件已经传递到java层了。具体事件怎么分发流动还要看当前app是如何写的,以及是什么按键。输入事件并不是全部被window的view处理了,比如返回键,如果此时系统输入法是显示的处于最上面,back键首先会去关闭输入法,而window的view是接收不到这个键。一般来说对应Global/system按键是systemserver系统进程处理的并且处理完不会发送到app。对于user按键则最终会调用ViewGroup的:

public final boolean dispatch(Callback receiver, DispatcherState state,
        Object target) {
    switch (mAction) {
        case ACTION_DOWN: {
            mFlags &= ~FLAG_START_TRACKING;
            boolean res = receiver.onKeyDown(mKeyCode, this);
            return res;
        }
    }
    return false;
}

 对于按键是系统处理还是app处理可以参考这篇文章:https://blog.csdn.net/qianhaifeng2012/article/details/51737370

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值