日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

ril.java_RIL.java里request流程

發布時間:2025/3/15 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 ril.java_RIL.java里request流程 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Android GSM驅動模塊(rild)詳細分析(二)request流程

熊貓哥哥 發表于IT168和Opendroid 轉載請注明

1. 多路復用I/O機制的運轉

上文說到request是接收,是通過ril_event_loop中的多路復用I/O,也對初始化做了分析.現在我們來仔細看看這個機制如何運轉.

ril_event_set負責配置一個event,主要有兩種event:

ril_event_add添加使用多路I/O的event,它負責將其掛到隊列,同時將event的通道句柄fd加入到watch_table,然后通過select等待.

ril_timer_add添加timer event,它將其掛在隊列,同時重新計算最短超時時間.

無論哪種add,最后都會調用triggerEvLoop來刷新隊列,更新超時值或等待對象.

刷新之后, ril_event_loop從阻塞的位置,select返回,只有兩種可能,一是超時,二是等待到了某I/O操作.

超時的處理在processTimeouts中,摘下超時的event,加入pending_list.

檢查有I/O操作的通道的處理在processReadReadies中,將超時的event加入pending_list.

最后在firePending中,檢索pending_list的event并依次執行event->func.

這些操作完之后,計算新超時時間,并重新select阻塞于多路I/O.

前面的初始化流程已分析得知,初始化完成以后,隊列上掛了3個event對象,分別是:

s_listen_event: 名為rild的socket,主要requeset & response通道

s_debug_event: 名為rild-debug的socket,調試用requeset & response通道(流程與s_listen_event基本相同,后面僅分析s_listen_event)

s_wakeupfd_event: 無名管道,用于隊列主動喚醒(前面提到的隊列刷新,就用它來實現,請參考使用它的相關地方)

2. request的傳入和dispatch

明白了event隊列的基本運行流程,我們可以來看看request是怎么傳入和dispatch的了.

層的部分,核心代碼在frameworks/base/telephony/java/com/android/internal/telephony

/gsm/RIL.java,這是android

java框架處理radio(gsm)的核心組件.本文因為主要關注rild,也就是驅動部分,所以這里只作簡單介紹.

我們看一個具體的例子,RIL.java中的dial函數:

public void

dial (String address, int clirMode, Message result)

{

RILRequest rr = RILRequest.obtain(RIL_REQUEST_DIAL, result);

rr.mp.writeString(address);

rr.mp.writeInt(clirMode);

if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));

send(rr);

}

rr是以RIL_REQUEST_DIAL為request號而申請的一個RILRequest對象.這個request號在java框架和rild庫中共享(參考RILConstants.java中這些值的由來:))

RILRequest初始化的時候,會連接名為rild的socket(也就是rild中s_listen_event綁定的socket),初始化數據傳輸的通道.

rr.mp

是Parcel對象,Parcel是一套簡單的序列化協議,用于將對象(或對象的成員)序列化成字節流,以供傳遞參數之用.這里可以看到String

address和int

clirMode都是將依次序列化的成員.在這之前,rr初始化的時候,request號跟request的序列號(自動生成的遞增數),已經成為頭兩個

將被序列化的成員.這為后面的request解析打下了基礎.

接下來是send到handleMessage的流程,send將rr直接傳遞給另一個線程的handleMessage,handleMessage執行data = rr.mp.marshall()執行序列化操作, 并將data字節流寫入到rild socket.

接下來回到我們的rild,select發現rild socket有了請求鏈接的信號,導致s_listen_event被掛入pending_list,執行event->func,即

static void listenCallback (int fd, short flags, void *param);

接下來,s_fdCommand = accept(s_fdListen, (sockaddr *) &peeraddr, &socklen),獲取傳入的socket描述符,也就是上層的java RIL傳入的連接.

后,通過record_stream_new建立起一個record_stream, 將其與s_fdCommand綁定,

這里我們不關注record_stream 的具體流程, 我們來關注command event的回調,

processCommandsCallback函數, 從前面的event機制分析, 一旦s_fdCommand上有數據,

此回調函數就會被調用. (略過onNewCommandConnect的分析)

processCommandsCallback通過

record_stream_get_next阻塞讀取s_fdCommand上發來的 數據,

直到收到一完整的request(request包的完整性由record_stream的機制保證),

然后將其送達processCommandBuffer.

進入processCommandBuffer以后,我們就正式進入了命令的解析部分. 每個命令將以RequestInfo的形式存在.

typedef struct RequestInfo {

int32_t token; //this is not RIL_Token

CommandInfo *pCI;

struct RequestInfo *p_next;

char cancelled;

char local; // responses to local commands do not go back to command process

} RequestInfo;

里的pRI就是一個RequestInfo結構指針, 從socket過來的數據流, 前面提到是Parcel處理過的序列化字節流,

這里會通過反序列化的方法提取出來. 最前面的是request號, 以及token域(request的遞增序列號).

我們更關注這個request號, 前面提到, 上層和rild之間, 這個號是統一的. 它的定義是一個包含ril_commands.h的枚舉,

在ril.cpp中

static CommandInfo s_commands[] = {

#include "ril_commands.h"

};

pRI直接訪問這個數組, 來獲取自己的pCI.

這是一個CommandInfo結構:

typedef struct {

int requestNumber;

void (*dispatchFunction) (Parcel &p, struct RequestInfo *pRI);

int(*responseFunction) (Parcel &p, void *response, size_t responselen);

} CommandInfo;

基本解析到這里就完成了, 接下來, pRI被掛入pending的request隊列, 執行具體的pCI->dispatchFunction, 進行詳細解析.

3. request的詳細解析

對dial而言, CommandInfo結構是這樣初始化的:

{RIL_REQUEST_DIAL, dispatchDial, responseVoid},

里執行dispatchFunction, 也就是dispatchDial這一函數.我們可以看到其實有很多種類的dispatch

function, 比如dispatchVoid, dispatchStrings, dispatchSIM_IO等等, 這些函數的區別,

在于Parcel傳入的參數形式,Void就是不帶參數的,Strings是以string[]做參數,又如Dial等,有自己的參數解析方式,以此類

推.

request號和參數現在都有了,那么可以進行具體的request函數調用了.

s_callbacks.onRequest(pRI->pCI->requestNumber, xxx, len, pRI)完成這一操作.

s_callbacks 是上篇文章中提到的獲取自libreference-ril的RIL_RadioFunctions結構指針,request請求在這里轉入底層的 libreference-ril處理,handler是reference-ril.c中的onRequest.

onRequest進行一個簡單的switch分發,我們依然來看RIL_REQUEST_DIAL

流程是 onRequest-->requestDial-->at_send_command-->at_send_command_full-->at_send_command_full_nolock-->writeline

requestDial中將命令和參數轉換成對應的AT命令,調用公共send command接口at_send_command.

了這個接口之外,還有

at_send_command_singleline,at_send_command_sms,at_send_command_multiline

等,這是根據at返回值,以及發命令流程的類型來區別的.比如at+csq這類,需要at_send_command_singleline,而發送短

信,因為有prompt提示符">",傳裸數據,結束符等一系列操作,需要專門用at_send_command_sms來實現.

然后執行at_send_command_full,前面幾個接口都會最終到這里,再通過一個互斥的at_send_command_full_nolock調用,然后完成最終的寫出操作,在writeline中,寫出到初始化時打開的設備中.

writeline返回之后,還有一些操作,如保存type等信息,供response回來時候使用,以及一些超時處理. 不再詳述.

到這里,request的詳細流程,就分析完畢了.

總結

以上是生活随笔為你收集整理的ril.java_RIL.java里request流程的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。