本文主要對android4.4 RIL的telephony與modem的命令互動流程進行分析,當然本文不是重點介紹telephony,
telephony涉及具體業務邏輯內容比較多,包括sim、dail、sms、network等等,以后會針對這些內容學習分析,
RIL在Android體系中的位置:

(A) 應用層發起訪問modem的請求
(B) RILD行程
(A) 應用層發起訪問modem的請求
frameworks/opt/telephony/src/java/com/android/internal/telephony/RIL.java中的類RIL,提供了一系
列的介面給上層應用呼叫,以訪問modem,當然這些介面并不是直接給APP使用,而是由framework中sim、dail、
sms、network等相關服務呼叫,
如: 以查詢SIM卡狀態getIccCardStatus()為例,該API為UiccController模塊所呼叫:
完整的SIM卡請求log:
10-11 12:21:43.630 D/RILJ ( 1833): [3653]> GET_SIM_STATUS
10-11 12:21:43.630 D/RILC ( 1286): [0005]> GET_SIM_STATUS
10-11 12:21:43.630 D/RILC ( 1286): onRequest: GET_SIM_STATUS
10-11 12:21:43.630 D/ATC ( 1286): AT> AT+CPIN?
10-11 12:21:43.640 D/ATC ( 1286): AT< +CPIN: READY
10-11 12:21:43.640 D/ATC ( 1286): AT< OK
10-11 12:21:43.640 D/RILC ( 1286): [0005]< GET_SIM_STATUS {[app_type=1,app_state=5,perso_substate=2,aid_ptr=(null),app_label_ptr=(null),pin1_replaced=0,pin1=0,pin2=0],}
10-11 12:21:43.640 D/RILJ ( 1833): [3653]< GET_SIM_STATUS IccCardState {CARDSTATE_PRESENT,PINSTATE_UNKNOWN,num_apps=1,gsm_id=0{APPTYPE_SIM,APPSTATE_READY},cdma_id=8,ims_id=8}
發起請求:
frameworks/opt/telephony/src/java/com/android/internal/telephony/RIL.java
@Override public void getIccCardStatus(Message result) { //Note: This RIL request has not been renamed to ICC, // but this request is also valid for SIM and RUIM RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_SIM_STATUS, result); /* 獲取一個RILRequest */ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); /* 參考log:[3653]> GET_SIM_STATUS */ send(rr); /* 發送請求 */ }
RILRequest.obtain是從記憶體池獲取一個RILRequest實體,并初始化:
frameworks/opt/telephony/src/java/com/android/internal/telephony/RIL.java
class RILRequest { static final String LOG_TAG = "RilRequest"; ... ... static RILRequest obtain(int request, Message result) { RILRequest rr = null; synchronized(sPoolSync) { /* 從記憶體池中取出一個RILRequest物件*/ if (sPool != null) { rr = sPool; sPool = rr.mNext; rr.mNext = null; sPoolSize--; } } if (rr == null) { /* 如果記憶體池中沒有,則實體化一個 */ rr = new RILRequest(); } rr.mSerial = sNextSerial.getAndIncrement(); /* 獲取串號,并且+1 */ rr.mRequest = request; /* 對應RIL_REQUEST_*請求 */ rr.mResult = result; rr.mParcel = Parcel.obtain(); /* 初始化一個Parcel,用于封包以發送給底層RILD */ if (result != null && result.getTarget() == null) { throw new NullPointerException("Message target must not be null"); } // first elements in any RIL Parcel rr.mParcel.writeInt(request); /* 每個RIL Parcel最開始也最基本的兩個元素 */ rr.mParcel.writeInt(rr.mSerial); return rr; /* 回傳這個從記憶體池中獲取的實體 */ } ... ... String serialString() { //Cheesy way to do %04d StringBuilder sb = new StringBuilder(8); /* 創建一個StringBuilder實體用于操作字串 */ String sn; long adjustedSerial = (((long)mSerial) - Integer.MIN_VALUE)%10000; sn = Long.toString(adjustedSerial); /* 把數值轉換成字串 */ //sb.append("J["); sb.append('['); for (int i = 0, s = sn.length() ; i < 4 - s; i++) { sb.append('0'); } sb.append(sn); sb.append(']'); return sb.toString(); /* 轉換出來的字串格式: [xxxx] */ } ... ... }
send(rr)發送請求到服務端:
frameworks/opt/telephony/src/java/com/android/internal/telephony/RIL.java
private void send(RILRequest rr) { Message msg; ... ... msg = mSender.obtainMessage(EVENT_SEND, rr); /* 發送EVENT_SEND時間,時間引數為RILRequest */ acquireWakeLock(); /* 獲取wakelock,禁止進入休眠 */ msg.sendToTarget(); /* message從handler類獲取,從而可以直接向該handler物件發送訊息,target就是創建message的handler */ }
實際上telephony無法直接與modem通訊,由于每個廠商的modem都不一樣,modem存在于系統中的方式
也不一樣,如:有的CPU芯片廠商的modem是以一個CP核的方式集成在基帶上(高通、展訊等),有的CPU芯
片(Exynos 4412等)需要通過串口/USB外接modem模塊,如:BC72 LTE模塊等,
send(rr)向RILD發送請求,這里涉及一個行程間通信問題,而且Java側與C++側的行程通訊,當然這里并沒
有用Android開發的朋友都熟悉的Bind,而是socket,
telephony/Java側RIL命令互動的處理,暫且稱為RILJ,
RILJ作為socket的客戶端,RILD(rild行程)作為服務端,后面會分析rild行程,
socket客戶端的創建:
frameworks/opt/telephony/src/java/com/android/internal/telephony/RIL.java
public RIL(Context context, int preferredNetworkType, int cdmaSubscription) { ... ... mSenderThread = new HandlerThread("RILSender"); /* 創建RILSender執行緒 */ mSenderThread.start(); Looper looper = mSenderThread.getLooper(); mSender = new RILSender(looper); ConnectivityManager cm = (ConnectivityManager)context.getSystemService( Context.CONNECTIVITY_SERVICE); if (cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE) == false) { riljLog("Not starting RILReceiver: wifi-only"); } else { riljLog("Starting RILReceiver"); mReceiver = new RILReceiver(); mReceiverThread = new Thread(mReceiver, "RILReceiver"); /* 創建RILReceiver執行緒 */ mReceiverThread.start(); ... ... } ... ... } class RILReceiver implements Runnable { byte[] buffer; RILReceiver() { /* 構造時,分配一個陣列 */ buffer = new byte[RIL_MAX_COMMAND_BYTES]; } @Override public void run() { /* 回圈讀取從RILD回傳或主動上報的資料 */ int retryCount = 0; try {for (;;) { LocalSocket s = null; LocalSocketAddress l; try { s = new LocalSocket(); /* 創建一個socket客戶端 */ l = new LocalSocketAddress(SOCKET_NAME_RIL, LocalSocketAddress.Namespace.RESERVED); s.connect(l); /* 連接服務器 */ } ... ... } ... ... try { InputStream is = mSocket.getInputStream(); /* 回圈讀取socket的資料 */ for (;;) { Parcel p; length = readRilMessage(is, buffer); /* 決議socket資料 */ if (length < 0) { // End-of-stream reached break; } p = Parcel.obtain(); /* 獲取一個Parcel */ p.unmarshall(buffer, 0, length); /* 讀取出來的就是之前序列化的byte陣列,所以要進行一個反序列化操作 */ p.setDataPosition(0); /* 從buffer轉換到Parcel之后,需要將指標手動指向到最初的位置 */ //Rlog.v(RILJ_LOG_TAG, "Read packet: " + length + " bytes"); processResponse(p); p.recycle(); /* 資料處理完后,需要回收Parcel的記憶體 */ } } ... ... }
RILReceiver執行緒創建socket客戶端,連接服務端,然后進入等待服務端的processResponse訊息處理回圈,RILJ
接收到RILD回復的response回傳RIL請求的發起者,以getIccCardStatus(Message result)為例,processResponse(p)
會把DRILD的response回傳給UiccController
frameworks/opt/telephony/src/java/com/android/internal/telephony/RIL.java
private static int readRilMessage(InputStream is, byte[] buffer) throws IOException { int countRead; int offset; int remaining; int messageLength; // First, read in the length of the message offset = 0; remaining = 4; do { countRead = is.read(buffer, offset, remaining); /* 讀出訊息的4位元組長度 */ if (countRead < 0 ) { Rlog.e(RILJ_LOG_TAG, "Hit EOS reading message length"); return -1; } offset += countRead; remaining -= countRead; } while (remaining > 0); messageLength = ((buffer[0] & 0xff) << 24) /* 獲取長度 */ | ((buffer[1] & 0xff) << 16) | ((buffer[2] & 0xff) << 8) | (buffer[3] & 0xff); // Then, re-use the buffer and read in the message itself offset = 0; remaining = messageLength; do { countRead = is.read(buffer, offset, remaining); /* 讀取剩余的資料 */ if (countRead < 0 ) { Rlog.e(RILJ_LOG_TAG, "Hit EOS reading message. messageLength=" + messageLength + " remaining=" + remaining); return -1; } offset += countRead; remaining -= countRead; } while (remaining > 0); return messageLength; } private void processResponse (Parcel p) { int type; type = p.readInt(); /* 從RILD回傳的資料第一個位元組,表示請求的回傳型別:RESPONSE_UNSOLICITED/RESPONSE_SOLICITED */ if (type == RESPONSE_UNSOLICITED) { processUnsolicited (p); /* 主動上報 */ } else if (type == RESPONSE_SOLICITED) { RILRequest rr = processSolicited (p); /* 普通請求對應的同步上報 */ if (rr != null) { rr.release(); /* 釋放對應的RILRequest記憶體和wakelock */ decrementWakeLock(); } } }
RILD的response一般有兩種,一種是RILJ普通請求,RILD對RILJ請求的response (RESPONSE_SOLICITED),另一種是RILD主動上報的
response (RESPONSE_UNSOLICITED), processResponse (Parcel p)分別對這兩種情況的response進行處理,
frameworks/opt/telephony/src/java/com/android/internal/telephony/RIL.java
private RILRequest processSolicited (Parcel p) { int serial, error; boolean found = false; serial = p.readInt(); /* 串號,也就是token */ error = p.readInt(); /* 錯誤碼 */ RILRequest rr; rr = findAndRemoveRequestFromList(serial); /* 根據taken取出對應的RILRequest */ ... ... */ case RIL_REQUEST_GET_SIM_STATUS: ret = responseIccCardStatus(p); break; ... ... if (rr.mResult != null) { AsyncResult.forMessage(rr.mResult, ret, null); /* 把rr.mResult存到AsyncResult.userObj,并把rr.mResult.obj轉換為AsyncResult */ rr.mResult.sendToTarget(); /* msg發送到對應的target(Handler) */ } ... ... } private Object responseIccCardStatus(Parcel p) { IccCardApplicationStatus appStatus; ... ... appStatus = new IccCardApplicationStatus(); ... ... return cardStatus; }
回到剛才send(rr),send(rr)并不是直接發送到socket服務端RILD,而是通過一個Message發送到RILSender執行緒,
在handleMessage中,把請求發到socket服務端RILD,
frameworks/opt/telephony/src/java/com/android/internal/telephony/RIL.java
class RILSender extends Handler implements Runnable { /* 繼承Handler,實作Runnable */ public RILSender(Looper looper) { super(looper); } ... ... //***** Handler implementation @Override public void handleMessage(Message msg) { /* 繼承Handler的handleMessage */ RILRequest rr = (RILRequest)(msg.obj); /* Maessage中攜帶的RILRequest物件 */ RILRequest req = null; switch (msg.what) { case EVENT_SEND: /* 發送RIL請求事件 */ try { LocalSocket s; s = mSocket; /* RILReceiver中創建的用于與RILD通訊的socket */ ... ... synchronized (mRequestList) { /* 多執行緒保護操作mRequestList */ mRequestList.append(rr.mSerial, rr); /* 把接受到的RILRequest和對應的串號,存到mRequestList資料 */ } byte[] data; data = rr.mParcel.marshall(); /* 把Parcel中的資料轉換為byte資料 */ rr.mParcel.recycle(); /* Parcel的記憶體回收 */ rr.mParcel = null; ... ... // parcel length in big endian dataLength[0] = dataLength[1] = 0; /* RIL請求包的大小為4個位元組 */ dataLength[2] = (byte)((data.length >> 8) & 0xff); dataLength[3] = (byte)((data.length) & 0xff); //Rlog.v(RILJ_LOG_TAG, "writing packet: " + data.length + " bytes"); s.getOutputStream().write(dataLength); /* 把包大小和包資料發送出去 */ s.getOutputStream().write(data); } catch (IOException ex) { Rlog.e(RILJ_LOG_TAG, "IOException", ex); req = findAndRemoveRequestFromList(rr.mSerial); /* 如果出現例外,則把串號對應的RILRequest從mRequestList中洗掉 */ // make sure this request has not already been handled, // eg, if RILReceiver cleared the list. if (req != null) { rr.onError(RADIO_NOT_AVAILABLE, null); rr.release(); decrementWakeLock(); } } ... ... } } }
(B) RILD行程
RILD作為一個獨立的行程,telephony與modem之間的通訊通道,抽象出一些介面以適配不同的modem廠商,無需關心具體的
硬體操作,或者以哪種形式存存在于系統(modem作為CP集成于CPU或CPU通過串口/USB連接,如: BC72 LTE模塊),因為這些介面
由廠商去實作具體的硬體操作細節,這些介面都在libreference-ril中,在Android中使用BC72 LTE模塊,只要移植
libreference-ril就行,
1. RILD的啟動
RILD有init行程直接啟動,啟動后就監聽RILJ客戶端,等待RILJ連接請求,
device/samsung/smdk4x12/conf/init.smdk4x12.rc
service ril-daemon /system/bin/rild -l /system/lib/libreference-ril.so class main socket rild stream 660 root radio socket rild-debug stream 660 radio system user root
hardware/ril/rild/rild.c為RILD行程入口:
hardware/ril/rild/rild.c
int main(int argc, char **argv) { ... ... dlHandle = dlopen(rilLibPath, RTLD_NOW); /* 打開/system/lib/libreference-ril.so */ if (dlHandle == NULL) { RLOGE("dlopen failed: %s", dlerror()); exit(-1); } RIL_startEventLoop(); /* 創建eventLoop執行緒, 在ril_event_loop()中監聽多路IO的事件,如主動喚醒事件(pipe)、RILJ的請求等 */ /* 獲取/system/lib/libreference-ril.so中RIL_Init函式指標 */ rilInit = (const RIL_RadioFunctions *(*)(const struct RIL_Env *, int, char **))dlsym(dlHandle, "RIL_Init"); if (rilInit == NULL) { RLOGE("RIL_Init not defined or exported in %s\n", rilLibPath); exit(-1); } if (hasLibArgs) { rilArgv = argv + i - 1; argc = argc -i + 1; } else { static char * newArgv[MAX_LIB_ARGS]; static char args[PROPERTY_VALUE_MAX]; rilArgv = newArgv; property_get(LIB_ARGS_PROPERTY, args, ""); argc = make_argv(args, rilArgv); } // Make sure there's a reasonable argv[0] rilArgv[0] = argv[0]; funcs = rilInit(&s_rilEnv, argc, rilArgv); /* 初始化Vender RIL */ RIL_register(funcs); /* 注冊RIL */ ... ... }
hardware/ril/libril/ril.cpp
extern "C" void RIL_startEventLoop(void) { ... ... ret = pthread_create(&s_tid_dispatch, &attr, eventLoop, NULL); /* 創建eventLoop執行緒 */ ... ... } static void * eventLoop(void *param) { int ret; int filedes[2]; ril_event_init(); /* 初始化事件鏈表,timer_list,pending_list, watch_table */ pthread_mutex_lock(&s_startupMutex); s_started = 1; pthread_cond_broadcast(&s_startupCond); pthread_mutex_unlock(&s_startupMutex); ret = pipe(filedes); /* 創建一個pipe,用于每次添加一個新事件時,喚醒selet()回傳,更新fd_set使select監聽新的事件 */ if (ret < 0) { RLOGE("Error in pipe() errno:%d", errno); return NULL; } s_fdWakeupRead = filedes[0]; /* filedes[0]用于讀pipe, filedes[1]用于寫pipe */ s_fdWakeupWrite = filedes[1]; fcntl(s_fdWakeupRead, F_SETFL, O_NONBLOCK); /* 以非阻塞的方式讀pipe */ ril_event_set (&s_wakeupfd_event, s_fdWakeupRead, true, /* 讀pipe描述符系結到s_wakeupfd_event事件,指定回呼processWakeupCallback */ processWakeupCallback, NULL); rilEventAddWakeup (&s_wakeupfd_event); /* 添加s_wakeupfd_event事件到watch_table,更新readFds集合,使select監聽該事件,并觸發該事件 */ // Only returns on error ril_event_loop(); /* 進入多路IO事件監聽回圈 */ RLOGE ("error in event_loop_base errno:%d", errno); // kill self to restart on error kill(0, SIGKILL); return NULL; }
main函式主要啟動eventLoop執行緒,在ril_event_loop()中監聽多路IO的事件,如主動喚醒事件(pipe)、RILJ的請求等,
注冊vendor RIL介面(libreference-ril)
注意這里pipe的主要作用是喚醒select回傳,因為每次動態的添加一個事件,都要更新readFds集合,方便select監聽
集合中新的IO,
rilEventAddWakeup()添加新事件后,都會觸發select回傳
hardware/ril/libril/ril.cpp
static void rilEventAddWakeup(struct ril_event *ev) { ril_event_add(ev); /* 添加事件 */ triggerEvLoop(); /* 觸發事件, 每添加一個事件,都通過寫pipe喚醒select,以更新多路IO集合,使能夠監聽該事件 */ }
hardware/ril/libril/ril_event.cpp
void ril_event_add(struct ril_event * ev) { dlog("~~~~ +ril_event_add ~~~~"); MUTEX_ACQUIRE(); for (int i = 0; i < MAX_FD_EVENTS; i++) { if (watch_table[i] == NULL) { watch_table[i] = ev; /* 將新事件添加到watch_table */ ev->index = i; dlog("~~~~ added at %d ~~~~", i); dump_event(ev); FD_SET(ev->fd, &readFds); /* 更新readFds集合 */ if (ev->fd >= nfds) nfds = ev->fd+1; /* 更新nfds */ dlog("~~~~ nfds = %d ~~~~", nfds); break; } } MUTEX_RELEASE(); dlog("~~~~ -ril_event_add ~~~~"); }
hardware/ril/libril/ril.cpp
static void triggerEvLoop() { int ret; if (!pthread_equal(pthread_self(), s_tid_dispatch)) { /* trigger event loop to wakeup. No reason to do this, * if we're in the event loop thread */ do { ret = write (s_fdWakeupWrite, " ", 1); /* 向pipe寫入一個" ",以喚醒select */ } while (ret < 0 && errno == EINTR); } }
在ril_event_loop()接收到事件或socket客戶端RILJ發過來的請求后,firePending()根據事件請求,呼叫相應的處理函式
hardware/ril/libril/ril_event.cpp
void ril_event_loop() { int n; fd_set rfds; struct timeval tv; struct timeval * ptv; for (;;) { // make local copy of read fd_set memcpy(&rfds, &readFds, sizeof(fd_set)); if (-1 == calcNextTimeout(&tv)) { /* 計算timer_list鏈表中每個事件對應的超時時間 */ // no pending timers; block indefinitely dlog("~~~~ no timers; blocking indefinitely ~~~~"); ptv = NULL; } else { dlog("~~~~ blocking for %ds + %dus ~~~~", (int)tv.tv_sec, (int)tv.tv_usec); ptv = &tv; } printReadies(&rfds); n = select(nfds, &rfds, NULL, NULL, ptv); /* 等待readFds集合中的事件喚醒 */ printReadies(&rfds); dlog("~~~~ %d events fired ~~~~", n); if (n < 0) { if (errno == EINTR) continue; RLOGE("ril_event: select error (%d)", errno); // bail? return; } // Check for timeouts processTimeouts(); /* 檢查timer_list鏈表中是否有事件已經超時 */ // Check for read-ready processReadReadies(&rfds, n); /* 從watch_table中取出監聽到的事件, 并添加到pending_list鏈表 */ // Fire away firePending(); /* 從pending_list依次取出事件,并執行該事件的回呼 */ } } static void processTimeouts() { dlog("~~~~ +processTimeouts ~~~~"); MUTEX_ACQUIRE(); struct timeval now; struct ril_event * tev = timer_list.next; struct ril_event * next; getNow(&now); // walk list, see if now >= ev->timeout for any events /* 檢查timer_list鏈表中是否有事件已經超時 */ dlog("~~~~ Looking for timers <= %ds + %dus ~~~~", (int)now.tv_sec, (int)now.tv_usec); while ((tev != &timer_list) && (timercmp(&now, &tev->timeout, >))) { // Timer expired dlog("~~~~ firing timer ~~~~"); next = tev->next; removeFromList(tev); /* 將該超時移出鏈表 */ addToList(tev, &pending_list); /* 并且將該超時添加到pending鏈表 */ tev = next; /* 指標指向下一個超時 */ } MUTEX_RELEASE(); dlog("~~~~ -processTimeouts ~~~~"); } static void processReadReadies(fd_set * rfds, int n) { dlog("~~~~ +processReadReadies (%d) ~~~~", n); MUTEX_ACQUIRE(); for (int i = 0; (i < MAX_FD_EVENTS) && (n > 0); i++) { struct ril_event * rev = watch_table[i]; if (rev != NULL && FD_ISSET(rev->fd, rfds)) { /* 從watch_table中取出監聽到的事件 */ addToList(rev, &pending_list); /* 并把該事件加入pending_list鏈表 */ if (rev->persist == false) { /* 如果該事件不需要處理,則移出removeWatch */ removeWatch(rev, i); } n--; } } MUTEX_RELEASE(); dlog("~~~~ -processReadReadies (%d) ~~~~", n); } static void firePending() { dlog("~~~~ +firePending ~~~~"); struct ril_event * ev = pending_list.next; while (ev != &pending_list) { /* 從pending_list依次取出事件 */ struct ril_event * next = ev->next; removeFromList(ev); ev->func(ev->fd, 0, ev->param); /* 并執行該事件的回呼 */ ev = next; } dlog("~~~~ -firePending ~~~~"); }
上面分析了RIL_startEventLoop()的事件流程,簡單總結就是根據事件呼叫該事件的處理函式,
到這里還沒說到怎樣創建socket服務端的,回到mian(),funcs = rilInit(&s_rilEnv, argc, rilArgv);
初始化了libreference-ril,RIL_register(funcs);注冊了廠商須實作的相關介面,創建socket服務端的,
并監聽客戶端連接,一旦連接,則開始等待讀取客戶端發過來的請求,
hardware/ril/libril/ril.cpp
extern "C" void RIL_register (const RIL_RadioFunctions *callbacks) { ... ... s_fdListen = android_get_control_socket(SOCKET_NAME_RIL); /* 創建socket服務端,用于與RILJ通信 */ if (s_fdListen < 0) { RLOGE("Failed to get socket '" SOCKET_NAME_RIL "'"); exit(-1); } ret = listen(s_fdListen, 4); /* 監聽RILJ */ if (ret < 0) { RLOGE("Failed to listen on control socket '%d': %s", s_fdListen, strerror(errno)); exit(-1); } /* note: non-persistent so we can accept only one connection at a time */ ril_event_set (&s_listen_event, s_fdListen, false, /* 設定一個監聽事件s_listen_event,一旦與RILJ建立連 */ listenCallback, NULL); /* 則進入listenCallback,等待讀取RILJ發送資料 */ rilEventAddWakeup (&s_listen_event); /* 添加s_listen_event到watch_table, 喚醒select */ ... ... } static void listenCallback (int fd, short flags, void *param) { ... ... s_fdCommand = accept(s_fdListen, (sockaddr *) &peeraddr, &socklen); /* 接受RILJ客戶端的連接 */ ... ... err = getsockopt(s_fdCommand, SOL_SOCKET, SO_PEERCRED, &creds, &szCreds); ret = fcntl(s_fdCommand, F_SETFL, O_NONBLOCK); /* 非阻塞方式讀寫socket */ if (ret < 0) { RLOGE ("Error setting O_NONBLOCK errno:%d", errno); } RLOGI("libril: new connection"); p_rs = record_stream_new(s_fdCommand, MAX_COMMAND_BYTES); /* 創建一個stream用于快取讀socket的資料 */ ril_event_set (&s_commands_event, s_fdCommand, 1, /* 設定s_commands_event,processCommandsCallback回圈讀取socket的資料 */ processCommandsCallback, p_rs); rilEventAddWakeup (&s_commands_event); /* 添加s_commands_event事件,喚醒select */ onNewCommandConnect(); /* 通知RILJ已建立連接 */ } static void processCommandsCallback(int fd, short flags, void *param) { ... ... for (;;) { /* loop until EAGAIN/EINTR, end of stream, or other error */ ret = record_stream_get_next(p_rs, &p_record, &recordlen); /* 回圈從資料流中讀取socket資料 */ if (ret == 0 && p_record == NULL) { /* end-of-stream */ break; } else if (ret < 0) { break; } else if (ret == 0) { /* && p_record != NULL */ processCommandBuffer(p_record, recordlen); /* 對接受到的資料進行組包,下發給vender ril,即libreference-ril.so */ } } }
processCommandBuffer(p_record, recordlen)對接收到的資料進行組包,下發給vender ril,即libreference-ril.so,
然后就脫離了RILD的控制了,libreference-ril.so主要是廠商對RILD控制modem介面的實作,
hardware/ril/libril/ril.cpp
static int processCommandBuffer(void *buffer, size_t buflen) { ... ... p.setData((uint8_t *) buffer, buflen); /* 把接受到的資料填裝到parcel */ // status checked at end status = p.readInt32(&request); /* 決議request */ status = p.readInt32 (&token); /* 決議token,RILJ中的serial */ ... ... pRI = (RequestInfo *)calloc(1, sizeof(RequestInfo)); /* 分配一個RequestInfo,用于發送請求給vendor ril */ pRI->token = token; /* 設定token */ pRI->pCI = &(s_commands[request]); /* 設定請求 */ ret = pthread_mutex_lock(&s_pendingRequestsMutex); assert (ret == 0); pRI->p_next = s_pendingRequests; /* 添加到s_pendingRequests請求鏈表中 */ s_pendingRequests = pRI; ret = pthread_mutex_unlock(&s_pendingRequestsMutex); assert (ret == 0); /* sLastDispatchedToken = token; */ pRI->pCI->dispatchFunction(p, pRI); /* 執行事件回呼,到這里開始進入vender ril了 */ return 0; }
我們仍然以獲取SIM卡狀態為例,pRI->pCI->dispatchFunction(p, pRI)對應呼叫了dispatchVoid()
hardware/ril/libril/ril.cpp
static void dispatchVoid (Parcel& p, RequestInfo *pRI) { clearPrintBuf; printRequest(pRI->token, pRI->pCI->requestNumber); s_callbacks.onRequest(pRI->pCI->requestNumber, NULL, 0, pRI); }
s_callbacks.onRequest(pRI->pCI->requestNumber, NULL, 0, pRI); 呼叫的就是libreference-ril.c中的onRequest()函式,
以上分析了RILD對RILJ下發的請求處理流程,下面接著分析RILD回傳response給RILJ的流程,分兩種情況,一種對請求的回應,
另一種是主動上報,
libreference-ril對請求處理完畢后,呼叫RIL_onRequestComplete回復RILJ該請求的處理結果,
hardware/ril/libril/ril.cpp
RIL_onRequestComplete(RIL_Token t, RIL_Errno e, void *response, size_t responselen) { ... ... p.writeInt32 (RESPONSE_SOLICITED); p.writeInt32 (pRI->token); errorOffset = p.dataPosition(); p.writeInt32 (e); if (response != NULL) { // there is a response payload, no matter success or not. ret = pRI->pCI->responseFunction(p, response, responselen); ... ... } ... ... sendResponse(p); ... ... } static int sendResponse (Parcel &p) { printResponse; return sendResponseRaw(p.data(), p.dataSize()); } static int sendResponseRaw (const void *data, size_t dataSize) { ... ... ret = blockingWrite(fd, (void *)&header, sizeof(header)); /* 先寫4位元組資料長度 */ if (ret < 0) { pthread_mutex_unlock(&s_writeMutex); return ret; } ret = blockingWrite(fd, data, dataSize); /* 再寫資料 */ ... ... }
最終是通過sendResponseRaw()直接通過寫socket回復RILJ,對于主動上報的處理是類似的,也是通過sendResponseRaw()
上報給RILJ,可以參考RIL_onUnsolicitedResponse()函式,
到此,RILJ與RILD之間的通信流程已經分析完,后續分析libreference-ril,libreference-ril中先關介面的實作方式,每個modem廠商都不一樣,
BC72是通過串口/USB發送AT的方式控制,實作通話、短信、上網等功能,
謝謝!
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/55658.html
標籤:Android
上一篇:Android9.0 MTK 平板橫屏方案修改(強制app橫屏 + 開機logo/影片+關機充電橫屏 + RecoveryUI 橫屏)
