android touch事件传递/inputflinger流程分析

本文详细剖析了Android11中Touch数据从Kernel到App的传递流程,包括ViewRootImpl注册InputChannel、InputFlinger从Kernel读取Touch数据、InputFlinger发送Touch数据给View以及ViewRootImpl接收并处理Touch数据等关键环节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

由于项目需要,需要了解下android touch数据的传递流程,看了下代码后把过程记录下来,方便后面查阅。

本文章基于Android11开源源码,所有代码均可以在aosp官方提供的地址去查阅下载,Android11具体流程可能和其他Android版本有点不一致,

如果文中有不对的地方欢迎同学们指出一起讨论交流~

从4条线(4个方向)来分析android 的touch 数据传送机制,沿途主要关注touch数据从kernel出来到app的路线,把这条路打通,不关注细节,以及touch数据是如何决定给到哪个activity(窗口,view)的,

目录

ViewRootImpl 注册 InputChannel

InputFlinger 从kernel读取touch数据

InputFlinger 把touch数据发送给View

ViewRootImpl接收touch数据并给到app


一句话概括,app往wms那边添加窗口的同时,wms创建一对socket pair,用InputChannel封装,一个给app,一个给InputFlinger,之后InputFlinger通过这个unix socket fd把touch数据发给app。

拿button举例子,整体流程大概是,app起来后,会在ViewRootImpl 那边往wms添加window的时候,同时创建一个InputChannel 也一起带过去,wms会作为中介把这个InputChannel 传给InputFlinger, 点击button后,inputflinger读到从kernel出来的数据后,会通过这个InputChannel把数据给到ViewRootImpl, 接着通过ViewPostImeInputStage给到View,再创建一个PerformClick通过View.post()去执行,回调button的onClick()接口。(怎么知道给到哪个activity哪个window哪个View就是接下来分析过程中理清的)

ViewRootImpl 注册 InputChannel

app activity 起来后,创建了PhoneWindow 后往wms 添加window时,在ViewRootImpl创建了InputChannel作为出参一起传过去,wms通过socket pair 创建了2个InputChannel,一个作为client 一个作为server,client把fd给ViewRootImpl传过来的那个InputChannel, server给 传给InputFlinger, InputFlinger 创建Connection 保存下来,之后用它来回传touch数据给app。

看下图:

看下代码:

//frameworks/base/core/java/android/view/ViewRootImpl.java
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView,
           int userId) {
       //......
      
      //创建 InputChannel 
      inputChannel = new InputChannel();
      
      //在添加窗口的时候通过binder ipc一起给到wms
      //note1
      res = mWindowSession.addToDisplayAsUser(mWindow, mSeq, mWindowAttributes,
      getHostVisibility(), mDisplay.getDisplayId(), userId, mTmpFrame,
      mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
      mAttachInfo.mDisplayCutout, inputChannel,
      mTempInsets, mTempControls);
      
      //同时创建WindowInputEventReceiver用来接收touch数据(其实不只touch,
      //应该是包括按键,键盘啥的,我们目前先就只关注touch)
      //note2
      mInputEventReceiver = new WindowInputEventReceiver(inputChannel,
        Looper.myLooper());

      //......
      //创建用于处理input数据的InputStage,
      //note19
     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;     
      
}

//frameworks/base/core/java/android/view/IWindowSession.aidl
int addToDisplayAsUser(IWindow window, int seq, in WindowManager.LayoutParams attrs,
            in int viewVisibility, in int layerStackId, in int userId,
            out Rect outFrame, out Rect outContentInsets, out Rect outStableInsets,
            out DisplayCutout.ParcelableWrapper displayCutout, out InputChannel outInputChannel,
            out InsetsState insetsState, out InsetsSourceControl[] activeControls);
//注意这边inputChannel是作为出参传进去的,后面在WindowState那边创建了socket pair后
//会重新给他赋值使其作为接收数据的客户端拥有可以接收touch数据的fd。
//当然这边是跨进程的然后中间是有binder做了处理简化了流程。

跟下mWindowSession.addToDisplayAsUser(),

其中这边mWindowSession 实例为 Session对象, 是在WindowManagerGlobal 那边从wms拿到的,之后在创建ViewRootImpl的时候再传过来,可以简单看下~

//在这边赋值的
//frameworks/base/core/java/android/view/ViewRootImpl.java
public ViewRootImpl(Context context, Display display, IWindowSession session,
        boolean useSfChoreographer) {
//.......
    mWindowSession = session;
//.......       
}

//这边传过来的
public ViewRootImpl(Context context, Display display) {
        this(context, display, WindowManagerGlobal.getWindowSession(),
                false /* useSfChoreographer */);
}

//frameworks/base/core/java/android/view/WindowManagerGlobal.java
public void addView(View view, ViewGroup.LayoutParams params,
        Display display, Window parentWindow, int userId) {
 //......
 
     //创建ViewRootImpl
     root = new ViewRootImpl(view.getContext(), display);
 
 //.......       
 }
 
//这边通过binder ipc从wms那边去获取的,再接着看下wms实现
//frameworks/base/core/java/android/view/WindowManagerGlobal.java
public static IWindowSession getWindowSession() {
    //......
    //从wms那边拿
    sWindowSession = windowManager.openSession(......);
    return sWindowSession;
}

//wms直接new了一个Session对象返回
//frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
public IWindowSession openSession(IWindowSessionCallback callback) {
    return new Session(this, callback);
}


好了,确认mWindowSession 就是Session了,接着回到note1的 mWindowSession.addToDisplayAsUser(),继续看InputChanne的注册,其实就是通过binder ipc到了wms那边

//frameworks/base/services/core/java/com/android/server/wm/Session.java
public int addToDisplayAsUser(IWindow window, int seq, WindowManager.LayoutParams attrs,
        int viewVisibility, int displayId, int userId, Rect outFrame,
        Rect outContentInsets, Rect outStableInsets,
        DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel,
        InsetsState outInsetsState, InsetsSourceControl[] outActiveControls) {
    return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outFrame,
            outContentInsets, outStableInsets, outDisplayCutout, outInputChannel,
            outInsetsState, outActiveControls, userId);

直接调用wms的addWindow()接口



//frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
public int addWindow(Session session, IWindow client, int seq,
        LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame,
        Rect outContentInsets, Rect outStableInsets,
        DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel,
        InsetsState outInsetsState, InsetsSourceControl[] outActiveControls,
        int requestUserId) {
//......        
    //给WindowState了
    win.openInputChannel(outInputChannel);
//......
}

//接着往WindowState看
//frameworks/base/services/core/java/com/android/server/wm/WindowState.java
void openInputChannel(InputChannel outInputChannel) {
//......
    //创建一对InputChannle 
    InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
    //作为server和client
    mInputChannel = inputChannels[0];
    mClientChannel = inputChannels[1];
    //server端InputFlinger那边
    //这边wms、InputManagerService、InputFlinger 共进程,直接调用后,
    //InputManagerService也是直接调用给到InputFlinger
    mWmService.mInputManager.registerInputChannel(mInputChannel);    
    
    //......
    //client 赋值给出参然后返回到ViewRootImpl作为接收touch数据客户端
    mClientChannel.transferTo(outInputChannel);    
//......
}

其实也就是在这创建了2个能进行通信的c++ InputChannel,分别作为通信的client和server,里边分别包含socket pair 创建的2个fd,做为client的InputChannel赋值给ViewRootClient 传过来的java InputChannel,做为server的InputChannel 通过进程内函数(非binder)调用给到InputFlinger那边,分别用来接收和发送touch数据。

接着看 mWmService.mInputManager.registerInputChannel(),

//frameworks/base/services/core/java/com/android/server/input/InputManagerService.java
public void registerInputChannel(InputChannel inputChannel) {
    if (inputChannel == null) {
        throw new IllegalArgumentException("inputChannel must not be null.");
    }
    nativeRegisterInputChannel(mPtr, inputChannel);
    
 }
 

//frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
static void nativeRegisterInputChannel(JNIEnv* env, jclass /* clazz */, jlong ptr,
                                       jobject inputChannelObj) {
//......
 status_t status = im->registerInputChannel(env, inputChannel);
//......
}

status_t NativeInputManager::registerInputChannel(JNIEnv* /* env */,
                                                  const sp<InputChannel>& inputChannel) {
    ATRACE_CALL();
    return mInputManager->getDispatcher()->registerInputChannel(inputChannel);
}

//到InputDispatcher那边了
//frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp
status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel) {
#if DEBUG_REGISTRATION
    ALOGD("channel '%s' ~ registerInputChannel", inputChannel->getName().c_str());
#endif

    { // acquire lock
        std::scoped_lock _l(mLock);
        //查重
        sp<Connection> existingConnection = getConnectionLocked(inputChannel->getConnectionToken());
        if (existingConnection != nullptr) {
            ALOGW("Attempted to regis
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值