




已閱讀5頁,還剩13頁未讀, 繼續(xù)免費閱讀
版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
Framework中的Ril源碼分析目錄(?)- 一概述 二RILRequest 三發(fā)送子線程 如何把數(shù)據(jù)發(fā)送到mSenderThread mSenderThread子線程把請求發(fā)送給RILC 四接收子線程 接收數(shù)據(jù)的過程 數(shù)據(jù)的處理流程 URC消息處理流程 非URC消息處理流程 為了區(qū)別RIL層中的RIL.cpp,我們約定framework中的RIL.java文件描述為RILJ,而hardware中的RIL.cpp描述為RILC。一、概述 所有上層對RIL層的請求,最終都需要在RILJ中轉(zhuǎn)換為RIL層可識別的命令,然后通過Socket通道傳輸下去;同時,RIL層數(shù)據(jù)的上報,也要通過 RILJ進(jìn)行解碼,還原為上層容易識別的格式。因此,RILJ是framework與RIL層交互的通道。 RILJ有兩個主要特點: 1、開啟了兩個獨立線程分別負(fù)責(zé)發(fā)送數(shù)據(jù)和接收數(shù)據(jù) 2、數(shù)據(jù)的發(fā)送和接收是異步的 第一個特點很容易理解,而對于第二個特點有衍生出來了另一個問題:既然是異步的消息機制,也就是說發(fā)送者在發(fā)送完數(shù)據(jù)后就可以返回,那么當(dāng)?shù)玫交貞?yīng)后,就要有一種方法去找到當(dāng)初的請求者,并把結(jié)果返回給他。那么這個方法是什么呢? 這個方法就是令牌系統(tǒng),我們將在第二節(jié)介紹。 有了以上簡要的認(rèn)識,我們從RILJ的入口開始展開我們的分析,也就是RILJ的構(gòu)造函數(shù): javaview plaincopy RIL.java public RIL(Context context, int preferredNetworkType, int cdmaSubscription) super(context); /發(fā)送子線程 mSenderThread = new HandlerThread(RILSender); mSenderThread.start(); Looper looper = mSenderThread.getLooper(); /mSender是發(fā)送子線程的Handler,通過他可以發(fā)送數(shù)據(jù) mSender = new RILSender(looper); /接收子線程 mReceiver = new RILReceiver(); mReceiverThread = new Thread(mReceiver, RILReceiver); mReceiverThread.start(); 可以看到,在構(gòu)造函數(shù)中開啟了兩個獨立的子線程:mSenderThread用于給RILC發(fā)送數(shù)據(jù),而mReceiverThread用于接收RILC上報的數(shù)據(jù)。 下面我們分析兩個子線程的處理流程。而在介紹他們之前,我們先來介紹以下在RIL層中傳遞的消息的格式:RILRequest。二、RILRequest 我們單獨拿出一小節(jié)來介紹RILRequest對象,是因為里面包含了我們在文章開始地方介紹的“消息異步傳輸”的秘密。 首先來看他的屬性:class RILRequest ,說明這是一個獨立的類,沒有繼承任何的父類或接口。他也在RIL.java中,同時也是RIL.java中除了RIL外唯一的類。 我們再來看一下RILRequest的構(gòu)成: javaview plaincopy class RILRequest /令牌 int mSerial; int mRequest; Message mResult; Parcel mp; RILRequest mNext; /生成一個RILRequest的消息對象 static RILRequest obtain(int request, Message result) /釋放資源 void release() /構(gòu)造函數(shù),內(nèi)容為空 private RILRequest() /重置令牌 static void resetSerial() sNextSerial.set(sRandom.nextInt(); /用于調(diào)試 String serialString() /異常處理 void onError(int error, Object ret) 這個類并不復(fù)雜,主要的包括一些成員變量和兩個重要的成員函數(shù):用于生成消息對象的obtain方法和用于釋放對象的release方法。我們先來介紹他的成員變量: mSerial:這個變量就是一個令牌,每生成(obtain)一個新的請求,都將產(chǎn)生一個遞增的、唯一的mSerial,當(dāng)從RILC得到一個數(shù)據(jù)后, 我們將通過mSerial找到當(dāng)初發(fā)送這個請求的對象。這也就是異步通信最關(guān)鍵的聯(lián)系點。我們在RIL層談到的令牌(token)就是這個東西。 mRequest:請求碼,需要和RIL層中的ril_commands.h文件內(nèi)定義的請求碼一致。 mResult:生成當(dāng)前請求的請求者。從RILC中得到數(shù)據(jù)后,需要把數(shù)據(jù)處理后返回給mResult指向的對象。 mp:附加數(shù)據(jù)。 mNext:鏈表結(jié)構(gòu),代表下一個RILRequest。 然后我們介紹RILRequest中主要的方法,先來看看obtain: javaview plaincopy static RILRequest obtain(int request, Message result) RILRequest rr = null; synchronized(sPoolSync) /釋放的RILRequest可以循環(huán)利用 if (sPool != null) rr = sPool; sPool = rr.mNext; rr.mNext = null; sPoolSize-; if (rr = null) rr = new RILRequest(); rr.mSerial = sNextSerial.getAndIncrement(); rr.mRequest = request; rr.mResult = result; rr.mp = Parcel.obtain(); rr.mp.writeInt(request); rr.mp.writeInt(rr.mSerial); return rr; 在obtain過程中,涉及到了sPool的用法,這個對象代表了一個RILRequest對象的鏈表,作用就是對RILRequest的循環(huán)利用, 具體原理就是:當(dāng)一個RILRequest被銷毀(release)的時候,可以把當(dāng)前的RILRequest保存在sPool中,等下次需要申請 RILRequest時就去sPool中取出用即可,而無需重復(fù)的申請(new)RILRequest。同時sPool的最大個數(shù)為 4(MAX_POOL_SIZE)。 然后在obtain中對RILRequest對象的mSerial進(jìn)行初始化,前面說過,這個值是當(dāng)前請求的令牌,是唯一的。他是通過 getAndIncrement的方式生成的。這里補充以下AtomicInteger的知識:AtomicInteger是一個提供原子操作的 Integer的類。在Java語言中,+i和i+操作并不是線程安全的,在使用的時候,不可避免的會用到synchronized關(guān)鍵字。而 AtomicInteger則通過一種線程安全的加減操作接口??梢院唵蔚睦斫鉃?,getAndIncrement的方法可以得到一個絕對遞增的整數(shù)。 接下來就是mResult的初始化,他的初始化過程很簡單,就是簡單的賦值。 然后是mp,他的初始化過程中把上面的request和mSerial都寫了進(jìn)去。 這就是生成RILRequest的過程。 接下來看看release方法: javaview plaincopy void release() synchronized (sPoolSync) if (sPoolSize 8) & 0xff); dataLength3 = (byte)(data.length) & 0xff); /通過Socket通道發(fā)送數(shù)據(jù) s.getOutputStream().write(dataLength); s.getOutputStream().write(data); catch (IOException ex) catch (RuntimeException exc) break; case EVENT_WAKE_LOCK_TIMEOUT: break; 發(fā)送的過程比較直觀,就是通過Socket通道把數(shù)據(jù)長度(dataLength)和數(shù)據(jù)(data)發(fā)送出去。四、接收子線程 接收子線程要完成的就是對接收數(shù)據(jù)的處理操作。我們還分為兩步去分析:1、如何接收的消息;2、消息的處理流程。4.1、接收數(shù)據(jù)的過程 我們直接來看接收子線程的run方法: javaview plaincopy public void run() for (;) /開啟Socket通道 s = new LocalSocket(); l = new LocalSocketAddress(SOCKET_NAME_RIL, LocalSocketAddress.Namespace.RESERVED); s.connect(l); mSocket = s; InputStream is = mSocket.getInputStream(); /接收數(shù)據(jù)過程 for (;) Parcel p; /從通道讀取數(shù)據(jù) length = readRilMessage(is, buffer); if (length 0) break; p = Parcel.obtain(); p.unmarshall(buffer, 0, length); p.setDataPosition(0); /處理數(shù)據(jù) processResponse(p); p.recycle(); /關(guān)閉Socket,然后重新打開 mSocket.close(); mSocket = null; /清除令牌 RILRequest.resetSerial(); /清除所有請求 clearRequestList(RADIO_NOT_AVAILABLE, false); /通知ril連接狀態(tài)改變 notifyRegistrantsRilConnectionChanged(-1); 從上面的過程中我們看到,我們是在接收的子線程中打開了Socket的通道,并且在通道內(nèi)通過for死循環(huán)不斷檢測(readRilMessage)數(shù)據(jù),然后通過processResponse去處理。如果讀取的過程出現(xiàn)異常,將會關(guān)閉Socket通道,并且清除令牌和請求列表,重新打開Socket。 我們現(xiàn)在看一下readRilMessage的過程,至于處理的流程放到下一節(jié)介紹。javaview plaincopy private static int readRilMessage(InputStream is, byte buffer) throws IOException /先讀取數(shù)據(jù)的長度 do /從InputStream中讀取數(shù)據(jù) countRead = is.read(buffer, offset, remaining); if (countRead 0); /計算數(shù)據(jù)長度 messageLength = (buffer0 & 0xff) 24) | (buffer1 & 0xff) 16) | (buffer2 & 0xff) 8) | (buffer3 & 0xff); remaining = messageLength; /再讀取有效數(shù)據(jù) do countRead = is.read(buffer, offset, remaining); if (countRead 0); return messageLength; 可以看出,返回的數(shù)據(jù)分為兩部分,數(shù)據(jù)長度+數(shù)據(jù)內(nèi)容,我們通過對InputStream的連續(xù)讀取得到了完整的數(shù)據(jù),并把數(shù)據(jù)的長度返回出來,而數(shù)據(jù)的內(nèi)容通過buffer帶出來。 下面介紹數(shù)據(jù)的處理流程(processResponse)。4.2、數(shù)據(jù)的處理流程 在RIL層源碼分析文檔中我們介紹過,RIL層收到的消息分為兩部分: 一部分是Modem主動上報的消息,比如新短信的提醒、Modem狀態(tài)的改變等,這類消息稱為URC消息; 另一部分是由終端發(fā)送給Modem后,Modem給出的回應(yīng),屬于非URC消息; 對于URC消息來說,只需要調(diào)用相應(yīng)的通知機制即可;而對于非URC消息,我們還需要把相應(yīng)的數(shù)據(jù)返回給當(dāng)初發(fā)送請求的單位。 既然RIL層對消息的處理方式不同,那么對應(yīng)的在RILJ中也要分開處理: javaview plaincopy private void processResponse (Parcel p) int type; /得到數(shù)據(jù)的類型,是URC消息還是非URC消息 type = p.readInt(); if (type = RESPONSE_UNSOLICITED) /URC消息的處理 processUnsolicited (p); else if (type = RESPONSE_SOLICITED) /非URC消息的處理 RILRequest rr = processSolicited (p); if (rr != null) rr.release(); decrementWakeLock(); 上面看到,URC消息是通過processUnsolicited處理的,而非URC消息是由processSolicited處理的,我們分別介紹兩種處理流程。4.2.1、URC消息處理流程 URC消息是由processUnsolicited處理的: javaview plaincopy private void processUnsolicited (Parcel p) int response; Object ret; /讀取當(dāng)前消息的消息碼 response = p.readInt(); /先處理 switch(response) case RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED: ret = responseVoid(p); break; case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED: ret = responseVoid(p); break; case RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED: ret = responseVoid(p); break; case RIL_UNSOL_RESPONSE_NEW_SMS: ret = responseString(p); break; . /再次處理 switch(response) case RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED: /Radio狀態(tài)改變 switchToRadioState(newState); break; case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED: /通知call狀態(tài)改變 mCallStateRegistrants.notifyRegistrants(new AsyncResult(null, null, null); break; case RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED: /通知網(wǎng)絡(luò)狀態(tài)改變 mVoiceNetworkStateRegistrants.notifyRegistrants(new AsyncResult(null, null, null); break; case RIL_UNSOL_RESPONSE_NEW_SMS: /新短信 SmsMessage sms; sms = SmsMessage.newFromCMT(a); if (mGsmSmsRegistrant != null) /發(fā)送短信通知 mGsmSmsRegistrant.notifyRegistrant(new AsyncResult(null, sms, null); break; case RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT: /短信報告 mSmsStatusRegistrant.notifyRegistrant( new AsyncResult(null, ret, null); break; 上面代碼只挑出部分消息的處理代碼,從中可以看到,URC消息的處理要經(jīng)過兩個switch語句的處理: A、第一個switch: 根據(jù)不同的消息碼對數(shù)據(jù)進(jìn)行初步解析,得到上報的有效數(shù)據(jù)。 responseVoid:當(dāng)前消息的附帶數(shù)據(jù)為空。 responseString:當(dāng)前消息的附帶數(shù)據(jù)為String型,需要得到String。 responseInts:當(dāng)前消息的附帶數(shù)據(jù)為int型的數(shù)組,需要得到這個數(shù)組。 B、第二個switch 在這個switch語句中針對不同的消息碼用剛剛得到的有效數(shù)據(jù)進(jìn)行不同的處理,主要就是調(diào)用相應(yīng)的管理者去做相應(yīng)的通知。4.2.2、非URC消息處理流程 非URC消息是在processSolicited中處理的: javaview plaincopy private RILRequest processSolicited (Parcel p) RILRequest rr; /得到當(dāng)前的RILRequest對象,然后從mRequestList中將其刪除 rr = findAndRemoveRequestFromList(serial); /得到RIL上報的數(shù)據(jù) switch (rr.mRequest) case RIL_REQUEST_GET_SIM_STATUS: ret = responseIccCardStatus(p); break; case RIL_REQUEST_ENTER_SIM_PIN: ret = responseInts(p); break; case RIL_REQUEST_ENTER_SIM_PUK: ret = responseInts(p); break; case RIL_REQUEST_ENTER_SIM_PIN2: ret = responseInts(p); break; case RIL_REQUEST_ENTER_SIM_PUK2: ret = responseInts(p); break; case RIL_REQUEST_CHANGE_SIM_PIN: ret = responseInts(p); break; case RIL_REQUEST_CHANGE_SIM_PIN2: ret = responseInts(p); break; case RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION: ret = responseInts(p); break; case RIL_REQUEST_G
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 市場投訴處理管理制度
- 制造行業(yè)設(shè)備管理制度
- DB62T 4461-2021 小麥品種 隴紫麥2號
- 蟲災(zāi)治理方案(3篇)
- 宗祠修繕募資方案(3篇)
- 政協(xié)2022工作報告
- 物業(yè)資產(chǎn)利用方案(3篇)
- 智能社區(qū)標(biāo)準(zhǔn)商品房租賃服務(wù)協(xié)議
- 成都離婚協(xié)議書模板與婚后財產(chǎn)分割監(jiān)督合同
- 草莓苗綠色種植技術(shù)引進(jìn)與推廣合同
- 第六章+平面向量及其應(yīng)用+小結(jié) 高一下學(xué)期數(shù)學(xué)人教A版(2019)必修第二冊
- 2024年山東省聊城市冠縣中考一模英語試題(原卷版)
- 山東省青島市平度市2024屆中考二模語文試題含解析
- 國開可編程控制器應(yīng)用形考實訓(xùn)任務(wù)六
- 周志華-機器學(xué)習(xí)-Chap01緒論-課件
- 電力儲能用鋰離子電池
- 華為MPR+LTC項目項目總體方案+P183
- 自然資源調(diào)查監(jiān)測技能競賽理論考試題庫大全-中(多選題)
- 水質(zhì)監(jiān)測服務(wù)水質(zhì)自動監(jiān)測系統(tǒng)運行維護(hù)方案
- 小學(xué)生創(chuàng)新大賽創(chuàng)新設(shè)計案例
- MOOC 斷層影像解剖學(xué)-山東大學(xué) 中國大學(xué)慕課答案
評論
0/150
提交評論