[Input] socket連接的創(chuàng)建

前一篇文章文虏,我們講了Input ANR是怎么產(chǎn)生的[ANR]Input ANR是怎樣產(chǎn)生的,著重講的Input ANR的觸發(fā)和判定原理紧武。主要分析了system_server進(jìn)程中的InputDispatcher線程的運(yùn)行流程敏储。這個線程主要負(fù)責(zé)事件的分發(fā),通過socket將事件發(fā)送給App端進(jìn)行處理妥箕。

system_server進(jìn)程的InputDispatcher線程更舞,與App端的主線程進(jìn)行通信,需要先建立socket連接宇葱。這篇文章刊头,我們講講socket連接的建立過程。

socketpair使用

socketpair方法印颤,主要用于創(chuàng)建一對無名的穿肄、相互連接的套接字际看。

#include <sys/types.h> 
#include <sys/socket.h>

int socketpair(int domain, int type, int protocol, int sv[2]);

參數(shù):

  • domain:協(xié)議家族
    • AF_LOCAL
    • AF_UNIX
  • type:套接字類型
    • SOCKET_STREAM:基于TCP
    • SOCKET_DGRAM:基于UDP
    • SOCKET_SEQPACKET:序列化包矢否,提供一個序列化的兴喂、可靠的、雙向的基本連接的數(shù)據(jù)傳輸通道衣迷,數(shù)據(jù)長度定長。
  • protocol:協(xié)議類型云矫,只能是0
  • sv:返回的套接字對

返回值:

  • 0:成功
  • 1:失敗

read方法

ssize_t read(int fd, void * buf, size_t count);

作用:將fd所指的文件傳送count個字節(jié)到buf指針?biāo)傅膬?nèi)存中
返回值:

  • 返回實(shí)際讀到的字節(jié)數(shù)
  • 0:表示讀到文件尾让禀,無刻度數(shù)據(jù)
  • 小于0:讀取出錯陨界,需要看具體的errno

write方法

ssize_t write (int fd, const void * buf, size_t count); 

作用:將buf所指的內(nèi)存寫入count個字節(jié)到參數(shù)fd所指的文件中。
返回值:

  • 返回實(shí)際寫入的字節(jié)數(shù)
  • -1:發(fā)生錯誤菌瘪,需要看具體的errno俏扩。

這里先簡單介紹一下read和write方法,之后再出文章詳細(xì)介紹UNIX域套接字录淡。

App跨進(jìn)程調(diào)用WMS

主線程創(chuàng)建Activity的時候嫉戚,會調(diào)用setContentView,最后會調(diào)用到ViewRootImplsetView方法崔拥。

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(); //創(chuàng)建InputChannel對象
      }
      //通過Binder調(diào)用凤覆,進(jìn)入system進(jìn)程的Session
      res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                  getHostVisibility(), mDisplay.getDisplayId(),
                  mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                  mAttachInfo.mOutsets, mInputChannel);
      ...
      if (mInputChannel != null) {
          if (mInputQueueCallback != null) {
              mInputQueue = new InputQueue();
              mInputQueueCallback.onInputQueueCreated(mInputQueue);
          }
          //創(chuàng)建WindowInputEventReceiver對象拆魏,并且傳入剛剛創(chuàng)建好的mInputChannel
          mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,  Looper.myLooper());
      }
    }
}

這個方法,主要是一個跨進(jìn)程的Binder調(diào)用拥峦,最后調(diào)用的WMS中的addWinow方法。

WMS生成兩個InputChannel

public int addWindow(Session session, IWindow client, int seq, WindowManager.LayoutParams attrs, int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets, Rect outOutsets, InputChannel outInputChannel) {
        //創(chuàng)建一對InputChannel
        InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
        //將socket服務(wù)端保存到WindowState的mInputChannel
        win.setInputChannel(inputChannels[0]);
        //socket客戶端傳遞給outInputChannel刑峡,最后會作為跨進(jìn)程調(diào)用的返回值突梦,傳遞給App端
        inputChannels[1].transferTo(outInputChannel);
        //利用socket服務(wù)端作為參數(shù)羽利,注冊到system_server的IMS中
        mInputManager.registerInputChannel(win.mInputChannel, win.mInputWindowHandle);
    }
    //設(shè)置當(dāng)前聚焦窗口
    mInputMonitor.updateInputWindowsLw(false /*force*/);
}

這個方法,主要調(diào)用了InputChannelopenInputChannePair娃闲,生成一對InputChannel匾浪。

  • InputChannel[0] 保存到WindowStatemInputChannel
  • InputChannel[1]傳遞給客戶端,即ViewRootImpl中的mInputChannel玲献,最后會和WindowInputEventReceiver關(guān)聯(lián)梯浪。InputChannel可以跨進(jìn)程通信。
status_t InputChannel::openInputChannelPair(const String8& name,
        sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) {
    int sockets[2];
    //真正創(chuàng)建socket對的地方【核心】
    if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) {
        ...
        return result;
    }

    int bufferSize = SOCKET_BUFFER_SIZE; //32k
    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));

    String8 serverChannelName = name;
    serverChannelName.append(" (server)");
    //創(chuàng)建InputChannel對象
    outServerChannel = new InputChannel(serverChannelName, sockets[0]);

    String8 clientChannelName = name;
    clientChannelName.append(" (client)");
    //創(chuàng)建InputChannel對象
    outClientChannel = new InputChannel(clientChannelName, sockets[1]);
    return OK;
}

在這個方法里礼预,主要做了以下事情:

  • 創(chuàng)建了一個socket pair虏劲,生成一對無名的柒巫,相互連接的套接字
  • 設(shè)兩個套接口的緩沖區(qū)大小為32kb
  • 分別創(chuàng)建服務(wù)端和客戶端的InputChannel對象
    • socket[0]對應(yīng)的是server
    • socket[1]對應(yīng)的是client

到這里,socket的創(chuàng)建就完成了堡掏。

總結(jié)

Android輸入系統(tǒng),system_server和app之間socket的創(chuàng)建流程:

  • 首先App端在初始化view的時候,會通過跨進(jìn)程Binder調(diào)用WMS的addWindow方法
  • WMS在addWindow中會創(chuàng)建socket連接鹅龄,生成兩個inputChannel對象扮休,一個設(shè)置給IMS,一個通過Binder傳回給App玷坠。

拓展閱讀

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末八堡,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子不同,更是在濱河造成了極大的恐慌溶耘,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,284評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件百新,死亡現(xiàn)場離奇詭異庐扫,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)铅辞,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評論 3 395
  • 文/潘曉璐 我一進(jìn)店門萨醒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人囤踩,你說我怎么就攤上這事晓褪。” “怎么了勤庐?”我有些...
    開封第一講書人閱讀 164,614評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長涝涤。 經(jīng)常有香客問我岛杀,道長崭孤,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,671評論 1 293
  • 正文 為了忘掉前任遗锣,我火速辦了婚禮嗤形,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘笔咽。我一直安慰自己霹期,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,699評論 6 392
  • 文/花漫 我一把揭開白布甩十。 她就那樣靜靜地躺著侣监,像睡著了一般臣淤。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上荒典,一...
    開封第一講書人閱讀 51,562評論 1 305
  • 那天寺董,我揣著相機(jī)與錄音,去河邊找鬼遮咖。 笑死,一個胖子當(dāng)著我的面吹牛麦箍,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播享钞,決...
    沈念sama閱讀 40,309評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼栗竖,長吁一口氣:“原來是場噩夢啊……” “哼渠啤!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起沥曹,我...
    開封第一講書人閱讀 39,223評論 0 276
  • 序言:老撾萬榮一對情侶失蹤妓美,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后想邦,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體委刘,經(jīng)...
    沈念sama閱讀 45,668評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,859評論 3 336
  • 正文 我和宋清朗相戀三年呕童,在試婚紗的時候發(fā)現(xiàn)自己被綠了夺饲。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片施符。...
    茶點(diǎn)故事閱讀 39,981評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖戳吝,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情慢洋,我是刑警寧澤,帶...
    沈念sama閱讀 35,705評論 5 347
  • 正文 年R本政府宣布败明,位于F島的核電站太防,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏盈包。R本人自食惡果不足惜醇王,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,310評論 3 330
  • 文/蒙蒙 一崭添、第九天 我趴在偏房一處隱蔽的房頂上張望呼渣。 院中可真熱鬧棘伴,春花似錦屁置、人聲如沸焊夸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽阱穗。三九已至,卻和暖如春使鹅,著一層夾襖步出監(jiān)牢的瞬間揪阶,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評論 1 270
  • 我被黑心中介騙來泰國打工患朱, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留鲁僚,地道東北人。 一個月前我還...
    沈念sama閱讀 48,146評論 3 370
  • 正文 我出身青樓裁厅,卻偏偏與公主長得像冰沙,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子执虹,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,933評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 原創(chuàng)內(nèi)容,轉(zhuǎn)載請注明出處声畏,多謝配合撞叽。 上節(jié)講到InputDispatcher通過publishKeyEvent把i...
    Stan_Z閱讀 10,189評論 5 23
  • http://www.reibang.com/p/2bff4ecd86c9本篇博客主要是過一下Android I...
    wbo4958閱讀 7,801評論 4 19
  • 最近在準(zhǔn)備android面試姻成,整理了下相關(guān)的面試題,分為如下三個部分:android部分愿棋、Java部分科展、算法面試題...
    JasmineBen閱讀 7,098評論 10 137
  • Android Input架構(gòu) Linux Input子系統(tǒng)簡介 Android 是基于Linux 內(nèi)核,Linu...
    Nothing_655f閱讀 2,027評論 0 1
  • 一糠雨、引言 本文作為Android系統(tǒng)架構(gòu)的開篇才睹,起到提綱挈領(lǐng)的作用,從系統(tǒng)整體架構(gòu)角度概要講解Android系統(tǒng)的...
    迷途小碼農(nóng)h閱讀 2,045評論 2 25