日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > Android >内容正文

Android

【Android 事件分发】事件分发源码分析 ( 驱动层通过中断传递事件 | WindowManagerService 向 View 层传递事件 )

發(fā)布時(shí)間:2025/6/17 Android 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【Android 事件分发】事件分发源码分析 ( 驱动层通过中断传递事件 | WindowManagerService 向 View 层传递事件 ) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

Android 事件分發(fā) 系列文章目錄

【Android 事件分發(fā)】事件分發(fā)源碼分析 ( 驅(qū)動(dòng)層通過中斷傳遞事件 | WindowManagerService 向 View 層傳遞事件 )


文章目錄

  • Android 事件分發(fā) 系列文章目錄
  • 一、事件分發(fā)脈絡(luò)
  • 二、驅(qū)動(dòng)層通過中斷傳遞事件
  • 三、WindowManagerService 向 View 傳遞事件





一、事件分發(fā)脈絡(luò)



事件分發(fā)分析流程 :

① 驅(qū)動(dòng)層 -> Framework 層 : 用戶觸摸 , 或按鍵 后 , 事件在硬件中產(chǎn)生 , 從 硬件驅(qū)動(dòng)層 , 傳遞到 Framework 層 ;

② WMS -> View 層 : WindowManagerService ( 簡(jiǎn)稱 WMS ) 將事件傳遞到 View 層 ;

③ View 層內(nèi)部 : 事件在 View 的容器及下層容器 / 組件 之間傳遞 ;





二、驅(qū)動(dòng)層通過中斷傳遞事件



硬件產(chǎn)生事件后 , 驅(qū)動(dòng)層通過中斷傳遞事件 ;

中斷在嵌入式 Linux 中經(jīng)常使用 , 分為 外部中斷 和 內(nèi)部中斷 ;

  • 外部中斷 : 由外部事件產(chǎn)生的中斷 , 如這里的由硬件觸摸 / 按鍵 產(chǎn)生的事件產(chǎn)生的中斷 ;
  • 內(nèi)部中斷 : 程序運(yùn)行出現(xiàn)崩潰 , 異常 等情況 ;

中斷是指在 CPU 正常執(zhí)行指令時(shí) , 內(nèi)部或外部事件 / 事先設(shè)置好的中斷操作 , 會(huì)引起 CPU 中斷當(dāng)前正在執(zhí)行的指令 , 轉(zhuǎn)而運(yùn)行當(dāng)前中斷對(duì)應(yīng)的相關(guān)指令 , 中斷程序執(zhí)行完畢后 , 繼續(xù)執(zhí)行后續(xù)中斷前未執(zhí)行完畢的代碼 ;


中斷有兩種方式 : 一種是輪詢的 , CPU 不斷讀取硬件的狀態(tài) ; 另一種是硬件產(chǎn)生事件會(huì)后 , 發(fā)送信息給 CPU , 讓 CPU 暫停當(dāng)前工作 , 執(zhí)行中斷任務(wù) ;





三、WindowManagerService 向 View 傳遞事件



在 【Android 應(yīng)用開發(fā)】UI繪制流程 ( 生命周期機(jī)制 | 布局加載機(jī)制 | UI 繪制流程 | 布局測(cè)量 | 布局?jǐn)[放 | 組件繪制 | 瀑布流布局案例 ) 博客中 , 分析了 UI 布局繪制流程 , 從 ActivityThread 開始 , 逐步調(diào)用 , 繪制 UI 界面 , 調(diào)用鏈如下 :

ActivityThread | handleResumeActivity -> WindowManager | addView -> ViewRootImpl | setView ;
最后在 ViewRootImpl 的 performTraversals 方法中 , 完成 測(cè)量 , 布局 , 繪畫 操作 ;

在 WindowManagerGlobal 中的 addView 方法的主要作用是添加 DecorView ;


各個(gè)窗口的層級(jí)如下 : 事件傳遞從 Activity 逐層向下傳遞的 View 組件上 ;


這里開始從 ViewRootImpl 的 setView 方法進(jìn)行分析 ;

通過 new InputChannel() 直接創(chuàng)建輸入通道 ;

還調(diào)用了 WindowSession 的 addToDisplay 方法 , mWindowSession 成員是 IWindowSession 類型 , 通過 mWindowSession = WindowManagerGlobal.getWindowSession() 獲得 ;
WindowManagerGlobal 的 getWindowSession 方法中 , 最終 WindowSession 又調(diào)用回了 WMS 的 openSession , 創(chuàng)建了一個(gè) WindowSession 對(duì)象 ;

在 ViewRootImpl 的 setView 方法中 , 注冊(cè)了 mInputEventReceiver , 傳入 InputChannel 和 Looper 參數(shù) , InputChannel 就是事件傳入的通道 , Looper 用于輪詢事件是否發(fā)生 ;

ViewRootImpl 參考源碼 :

public final class ViewRootImpl implements ViewParent,View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks {public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {requestLayout();if ((mWindowAttributes.inputFeatures& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {mInputChannel = new InputChannel();}...res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,getHostVisibility(), mDisplay.getDisplayId(), mWinFrame,mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel);...if (mInputChannel != null) {if (mInputQueueCallback != null) {mInputQueue = new InputQueue();mInputQueueCallback.onInputQueueCreated(mInputQueue);}mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,Looper.myLooper());}} }

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


WindowManagerService 獲取 WindowSession 方法 : 通過調(diào)用 WindowManagerGlobal 的 getWindowSession 獲取 , 最終還是調(diào)用了 WindowManagerService 的 openSession 方法 ;

WindowManagerGlobal 參考源碼 :

public final class WindowManagerGlobal {public static IWindowSession getWindowSession() {synchronized (WindowManagerGlobal.class) {if (sWindowSession == null) {try {InputMethodManager imm = InputMethodManager.getInstance();IWindowManager windowManager = getWindowManagerService();sWindowSession = windowManager.openSession(new IWindowSessionCallback.Stub() {@Overridepublic void onAnimatorScaleChanged(float scale) {ValueAnimator.setDurationScale(scale);}},imm.getClient(), imm.getInputContext());} catch (RemoteException e) {throw e.rethrowFromSystemServer();}}return sWindowSession;}} }

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


在 WindowManagerService 的 addWindow 方法中 ,

  • 初始化了 窗口的狀態(tài) WindowState ,
  • 通過調(diào)用 WindowState 的 openInputChannel 方法 , 設(shè)置了 InputChannel , 就是將 ViewRootImpl 中 setView 方法中 new InputChannel() 創(chuàng)建的 InputChannel 傳遞進(jìn)來 ;

WindowManagerService 參考源碼 :

/** {@hide} */ public class WindowManagerService extends IWindowManager.Stubimplements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {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) {// 初始化窗口狀態(tài) final WindowState win = new WindowState(this, session, client, token, parentWindow,appOp[0], seq, attrs, viewVisibility, session.mUid,session.mCanAddInternalSystemWindow);if (openInputChannels) {win.openInputChannel(outInputChannel);}}@Overridepublic IWindowSession openSession(IWindowSessionCallback callback, IInputMethodClient client,IInputContext inputContext) {if (client == null) throw new IllegalArgumentException("null client");if (inputContext == null) throw new IllegalArgumentException("null inputContext");Session session = new Session(this, callback, client, inputContext);return session;} }

/frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java


WindowState 的 openInputChannel 方法 , 其中調(diào)用了 InputChannel.openInputChannelPair(name) 靜態(tài)方法 , 這是開啟了 222 個(gè) InputChannel , inputChannels[0] 放在服務(wù)端 , inputChannels[1] 放在了客戶端 ;

服務(wù)端 與 客戶端 需要進(jìn)行通信 , 二者通過 Looper 進(jìn)行通信 , 通信前需要進(jìn)行注冊(cè) , 在 InputDispatcher.cpp 中進(jìn)行的注冊(cè) ;

WindowState 參考源碼 :

/** A window in the window manager. */ class WindowState extends WindowContainer<WindowState> implements WindowManagerPolicy.WindowState {void openInputChannel(InputChannel outInputChannel) {if (mInputChannel != null) {throw new IllegalStateException("Window already has an input channel.");}String name = getName();InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);// 服務(wù)端mInputChannel = inputChannels[0];// 客戶端 mClientChannel = inputChannels[1];mInputWindowHandle.inputChannel = inputChannels[0];if (outInputChannel != null) {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);}mService.mInputManager.registerInputChannel(mInputChannel, mInputWindowHandle);} }

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


下面分析在 InputDispatcher 中 , 注冊(cè) 服務(wù)端 與 客戶端 InputChannel 的過程 ;

在 registerInputChannel 方法中 , 創(chuàng)建了 Connection 連接 , 這就是兩個(gè) 服務(wù)端 與 客戶端 InputChannel 溝通的通道 , 每個(gè) InputChannel 都有一個(gè) fd , 通過 int fd = inputChannel->getFd() 獲取 fd , 調(diào)用 mConnectionsByFd.add(fd, connection) 將 fd 與 Connection 對(duì)應(yīng)起來 ;
最后將 fd 注冊(cè)在 Looper 中 , mLooper->addFd ;

只要有任何事件輸入 , 該 Looper 就會(huì)被喚醒 , 通過 InputChannel 傳遞到 Activity , 進(jìn)而傳遞給各個(gè)層級(jí)的 View 組件 ;

status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel,const sp<InputWindowHandle>& inputWindowHandle, bool monitor) { #if DEBUG_REGISTRATIONALOGD("channel '%s' ~ registerInputChannel - monitor=%s", inputChannel->getName().c_str(),toString(monitor)); #endif{ // acquire lockAutoMutex _l(mLock);if (getConnectionIndexLocked(inputChannel) >= 0) {ALOGW("Attempted to register already registered input channel '%s'",inputChannel->getName().c_str());return BAD_VALUE;}sp<Connection> connection = new Connection(inputChannel, inputWindowHandle, monitor);int fd = inputChannel->getFd();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; }

/frameworks/native/services/inputflinger/InputDispatcher.cpp

總結(jié)

以上是生活随笔為你收集整理的【Android 事件分发】事件分发源码分析 ( 驱动层通过中断传递事件 | WindowManagerService 向 View 层传递事件 )的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。