1. 程式人生 > >RIL 流程 關鍵傳輸介面分析

RIL 流程 關鍵傳輸介面分析

RIL 分為RILJ 和RILC 部分,而RIL 和modem 通訊通過socket ,傳送的是串列埠 AT command

[其實只要熟悉linux 程式設計,rild 部分確實很好理解]花了4天左右認認真真分析

在初始化 reference-ril 庫的時候,建立 客戶端socket 連線到modem,而通過atchannel 的at_send_command_full_nolock傳送AT command到modem, 也是通過輪詢 readline 讀取返回資訊

hardware/ril/reference-ril/reference-ril.c

const RIL_RadioFunctions *RIL_Init(const struct RIL_Env *env, int argc, char **argv){

    //....
    fd = socket_local_client( s_device_path,ANDROID_SOCKET_NAMESPACE_FILESYSTEM,
                                            SOCK_STREAM );    
}

hardware/ril/reference-ril/atchannel.c


static const char *readline(){
//....
   count = read(s_fd, p_read,MAX_AT_RESPONSE - (p_read - s_ATBuffer));

}
static int at_send_command_full_nolock (const char *command, ATCommandType type,
                    const char *responsePrefix, const char *smspdu,
                    long long timeoutMsec, ATResponse **pp_outResponse)
{
//.....
    err = writeline (command);

    while (sp_response->finalResponse == NULL && s_readerClosed == 0) {
        if (timeoutMsec != 0) {
            err = pthread_cond_timedwait(&s_commandcond, &s_commandmutex, &ts);
        } else {
            err = pthread_cond_wait(&s_commandcond, &s_commandmutex);
        }

    }

    if (pp_outResponse == NULL) {
        at_response_free(sp_response);
    } else {
        /* line reader stores intermediate responses in reverse order */
        reverseIntermediates(sp_response);
        *pp_outResponse = sp_response;
    }

    sp_response = NULL;

    if(s_readerClosed > 0) {
        err = AT_ERROR_CHANNEL_CLOSED;
        goto error;
    }

}

但是RILJ和RILC 通訊的,其實在開機啟動的時候,在init.rc檔案中,會配置socket 管道,RIL.java和rild.c會根據socketname 相互得到socket,並且,RIL.java 端會充當客戶端,rild.c 端充當伺服器端

service rild  /system/bin/rild
    class main
    socket rild0 stream 660 root radio

上面的rild程序 申明建立socket rild0 許可權是660 owner是root 歸屬於radio ,並且在RIL.java中會建立rild0的socket

class RILReceiver implements Runnable {
    static final String[] SOCKET_NAME_RIL = {"rild0", "rild1", "rild2"};

    @Override
    public void run() {
        
        rilSocket = SOCKET_NAME_RIL[0];
        
        s = new LocalSocket();
        l = new LocalSocketAddress(rilSocket,
                LocalSocketAddress.Namespace.RESERVED);
        s.connect(l);
    
    }

}

 重點在RILC端,因為rild守護程序隨開機啟動,所以rild.c開機就啟動,rild的socket 伺服器端如下

hardware/ril/rild/rild.c

int main(int argc, char **argv) {

    if (strncmp(clientId, "0", MAX_CLIENT_ID_LENGTH)) {
        strlcat(rild, clientId, MAX_SOCKET_NAME_LENGTH);
        RIL_setRilSocketName(rild);  //socketname =rild0
    }

 
}

hardware/ril/libril/ril.cpp

static void startListen(RIL_SOCKET_ID socket_id, SocketListenParam* socket_listen_p) {

    switch(socket_id) {
        case RIL_SOCKET_1:
            strncpy(socket_name, RIL_getRilSocketName(), 9);
            break;

    fdListen = android_get_control_socket(socket_name);
    ret = listen(fdListen, 4);

}

在startListen 找到socket 使得RILJ和RILC 通訊,但是如何讀寫資料?

的到了socket ,就可以接收RILJ傳送的請求訊息

hardware/ril/libril/ril.cpp

static void processCommandsCallback(int fd, short flags, void *param) {

     for (;;) {
        /* loop until EAGAIN/EINTR, end of stream, or other error */
        //獲取訊息 存入p_record buffer中
        ret = record_stream_get_next(p_rs, &p_record, &recordlen);
        
        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, p_info->socket_id);
        }
    }

}
int record_stream_get_next (RecordStream *p_rs, void ** p_outRecord,
                                    size_t *p_outRecordLen)
{

    countRead = read (p_rs->fd, p_rs->read_end, p_rs->buffer_end - p_rs->read_end);
    ret = getNextRecord (p_rs, p_outRecordLen);
    *p_outRecord = ret;
}

在processCommandBuffer 過程中將請求訊息,轉化為 AT指令通過dispatchFunction方法,最後通過   at_send_command_full_nolock傳送給modem

最後就是讀取modem 返回的訊息,並且返回給RILJ埠

在輪詢readerLoop,通過 readline獲取返回資料,然後通過

s_unsolHandler (line1, line2)
processLine(line); 

處理讀取的一行資料

modem 上報分為主動上報和主動上報,也就和URC 和非URC

static void processLine(const char *line)
{
    if (sp_response == NULL) {
        /* no command pending */
        handleUnsolicited(line);  //主動上報
    } else if (isFinalResponseSuccess(line)) {
        sp_response->success = 1;
        handleFinalResponse(line);  //非主動上報


}
/** add an intermediate response to sp_response*/
static void addIntermediate(const char *line)
{
    ATLine *p_new;

    p_new = (ATLine  *) malloc(sizeof(ATLine));

    p_new->line = strdup(line);

    /* note: this adds to the head of the list, so the list
       will be in reverse order of lines received. the order is flipped
       again before passing on to the command issuer */
    p_new->p_next = sp_response->p_intermediates;
    sp_response->p_intermediates = p_new;
}
/** assumes s_commandmutex is held */
static void handleFinalResponse(const char *line)
{
    sp_response->finalResponse = strdup(line);

    pthread_cond_signal(&s_commandcond);
}

當處理 handleFinalResponse 時候,說明modem 已經返回資料完畢,但是在讀取中會走addIntermediate ,資料全部儲存在sp_response中,當讀取完成會通過handleFinalResponse 喚醒在阻塞在at_send_command_full_nolock 函式中,通過  pthread_cond_wait 等待handleFinalResponse 釋放s_commandcond,最後將資料儲存在pp_outResponse

如果返回資料成功,會通過 RIL_onRequestComplete返回,直接write寫回 RILJ客戶端

RIL_onRequestComplete(t, RIL_E_SUCCESS, &response, sizeof(int));
sendResponse(p, socket_id);
static int
blockingWrite(int fd, const void *buffer, size_t len) {

    while (writeOffset < len) {
        ssize_t written;
        do {
            written = write (fd, toWrite + writeOffset,
                                len - writeOffset);
        } while (written < 0 && ((errno == EINTR) || (errno == EAGAIN)));
    }

    return 0;
}

當然主動上報直接回調 onUnsolicited 通過 RIL_onUnsolicitedResponse 將資料寫回RILJ

ret = sendResponse(p, soc_id);