主頁 > 移動端開發 > Android4.4 RIL軟體框架

Android4.4 RIL軟體框架

2020-09-16 08:50:56 移動端開發

    文主要對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 橫屏)

下一篇:通過谷歌瀏覽器從官網下載Android Studio

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【從零開始擼一個App】Dagger2

    Dagger2是一個IOC框架,一般用于Android平臺,第一次接觸的朋友,一定會被搞得暈頭轉向。它延續了Java平臺Spring框架代碼碎片化,注解滿天飛的傳統。嘗試將各處代碼片段串聯起來,理清思緒,真不是件容易的事。更不用說還有各版本細微的差別。 與Spring不同的是,Spring是通過反射 ......

    uj5u.com 2020-09-10 06:57:59 more
  • Flutter Weekly Issue 66

    新聞 Flutter 季度調研結果分享 教程 Flutter+FaaS一體化任務編排的思考與設計 詳解Dart中如何通過注解生成代碼 GitHub 用對了嗎?Flutter 團隊分享如何管理大型開源專案 插件 flutter-bubble-tab-indicator A Flutter librar ......

    uj5u.com 2020-09-10 06:58:52 more
  • Proguard 常用規則

    介紹 Proguard 入口,如何查看輸出,如何使用 keep 設定入口以及使用實體,如何配置壓縮,混淆,校驗等規則。

    ......

    uj5u.com 2020-09-10 06:59:00 more
  • Android 開發技術周報 Issue#292

    新聞 Android即將獲得類AirDrop功能:可向附近設備快速分享檔案 谷歌為安卓檔案管理應用引入可安全隱藏資料的Safe Folder功能 Android TV新主界面將顯示電影、電視節目和應用推薦內容 泄露的Android檔案暗示了傳說中的谷歌Pixel 5a與折疊屏新機 谷歌發布Andro ......

    uj5u.com 2020-09-10 07:00:37 more
  • AutoFitTextureView Error inflating class

    報錯: Binary XML file line #0: Binary XML file line #0: Error inflating class xxx.AutoFitTextureView 解決: <com.example.testy2.AutoFitTextureView android: ......

    uj5u.com 2020-09-10 07:00:41 more
  • 根據Uri,Cursor沒有獲取到對應的屬性

    Android: 背景:呼叫攝像頭,拍攝視頻,指定保存的地址,但是回傳的Cursor檔案,只有名稱和大小的屬性,沒有其他諸如時長,連ID屬性都沒有 使用 cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATIO ......

    uj5u.com 2020-09-10 07:00:44 more
  • Android連載29-持久化技術

    一、持久化技術 我們平時所使用的APP產生的資料,在記憶體中都是瞬時的,會隨著斷電、關機等丟失資料,因此android系統采用了持久化技術,用于存盤這些“瞬時”資料 持久化技術包括:檔案存盤、SharedPreference存盤以及資料庫存盤,還有更復雜的SD卡記憶體儲。 二、檔案存盤 最基本存盤方式, ......

    uj5u.com 2020-09-10 07:00:47 more
  • Android Camera2Video整合到自己專案里

    背景: Android專案里呼叫攝像頭拍攝視頻,原本使用的 MediaStore.ACTION_VIDEO_CAPTURE, 后來因專案需要,改成了camera2 1.Camera2Video 官方demo有點問題,下載后,不能直接整合到專案 問題1.多次拍攝視頻崩潰 問題2.雙擊record按鈕, ......

    uj5u.com 2020-09-10 07:00:50 more
  • Android 開發技術周報 Issue#293

    新聞 谷歌為Android TV開發者提供多種新功能 Android 11將自動填表功能整合到鍵盤輸入建議中 谷歌宣布Android Auto即將支持更多的導航和數字停車應用 谷歌Pixel 5只有XL版本 搭載驍龍765G且將比Pixel 4更便宜 [圖]Wear OS將迎來重磅更新:應用啟動時間 ......

    uj5u.com 2020-09-10 07:01:38 more
  • 海豚星空掃碼投屏 Android 接收端 SDK 集成 六步驟

    掃碼投屏,開放網路,獨占設備,不需要額外下載軟體,微信掃碼,發現設備。支持標準DLNA協議,支持倍速播放。視頻,音頻,圖片投屏。好點意思。還支持自定義基于 DLNA 擴展的操作動作。好像要收費,沒體驗。 這里簡單記錄一下集成程序。 一 跟目錄的build.gradle添加私有mevan倉庫 mave ......

    uj5u.com 2020-09-10 07:01:43 more
最新发布
  • 歡迎頁輪播影片

    如圖,引導開始,球從上落下,同時淡入文字,然后文字開始輪播,最后一頁時停止,點擊進入首頁。 在來看看效果圖。 重力球先不講,主要歡迎輪播簡單實作 首先新建一個類 TextTranslationXGuideView,用于影片展示 文本是類似的,最后會有個圖片箭頭影片,布局很簡單,就是一個 TextVi ......

    uj5u.com 2023-04-20 08:40:31 more
  • 【FAQ】關于華為推送服務因營銷訊息頻次管控導致服務通訊類訊息

    一. 問題描述 使用華為推送服務下發IM訊息時,下發訊息請求成功且code碼為80000000,但是手機總是收不到訊息; 在華為推送自助分析(Beta)平臺查看發現,訊息發送觸發了頻控。 二. 問題原因及背景 2023年1月05日起,華為推送服務對咨詢營銷類訊息做了單個設備每日推送數量上限管理,具體 ......

    uj5u.com 2023-04-20 08:40:11 more
  • 歡迎頁輪播影片

    如圖,引導開始,球從上落下,同時淡入文字,然后文字開始輪播,最后一頁時停止,點擊進入首頁。 在來看看效果圖。 重力球先不講,主要歡迎輪播簡單實作 首先新建一個類 TextTranslationXGuideView,用于影片展示 文本是類似的,最后會有個圖片箭頭影片,布局很簡單,就是一個 TextVi ......

    uj5u.com 2023-04-20 08:39:36 more
  • 【FAQ】關于華為推送服務因營銷訊息頻次管控導致服務通訊類訊息

    一. 問題描述 使用華為推送服務下發IM訊息時,下發訊息請求成功且code碼為80000000,但是手機總是收不到訊息; 在華為推送自助分析(Beta)平臺查看發現,訊息發送觸發了頻控。 二. 問題原因及背景 2023年1月05日起,華為推送服務對咨詢營銷類訊息做了單個設備每日推送數量上限管理,具體 ......

    uj5u.com 2023-04-20 08:39:13 more
  • iOS從UI記憶體地址到讀取成員變數(oc/swift)

    開發除錯時,我們發現bug時常首先是從UI顯示發現例外,下一步才會去定位UI相關連的資料的。XCode有給我們提供一系列debug工具,但是很多人可能還沒有形成一套穩定的除錯流程,因此本文嘗試解決這個問題,順便提出一個暴論:UI顯示例外問題只需要兩個步驟就能完成定位作業的80%: 定位例外 UI 組 ......

    uj5u.com 2023-04-19 09:16:23 more
  • FIDE重磅更新!性能飛躍!體驗有禮!

    FIDE 開發者工具重構升級啦!實作500%性能提升,誠邀體驗! 一直以來不少開發者朋友在社區反饋,在使用 FIDE 工具的程序中,時常會遇到諸如加載不及時、代碼預覽/渲染性能不如意的情況,十分影響開發體驗。 作為技術團隊,我們深知一件趁手的開發工具對開發者的重要性,因此,在2023年開年,FinC ......

    uj5u.com 2023-04-19 09:16:15 more
  • 游戲內嵌社區服務開放,助力開發者提升玩家互動與留存

    華為 HMS Core 游戲內嵌社區服務提供快速訪問華為游戲中心論壇能力,支持玩家直接在游戲內瀏覽帖子和交流互動,助力開發者擴展內容生產和觸達的場景。 一、為什么要游戲內嵌社區? 二、游戲內嵌社區的典型使用場景 1、游戲內打開論壇 您可以在游戲內繪制論壇入口,為玩家提供沉浸式發帖、瀏覽、點贊、回帖、 ......

    uj5u.com 2023-04-19 09:15:46 more
  • iOS從UI記憶體地址到讀取成員變數(oc/swift)

    開發除錯時,我們發現bug時常首先是從UI顯示發現例外,下一步才會去定位UI相關連的資料的。XCode有給我們提供一系列debug工具,但是很多人可能還沒有形成一套穩定的除錯流程,因此本文嘗試解決這個問題,順便提出一個暴論:UI顯示例外問題只需要兩個步驟就能完成定位作業的80%: 定位例外 UI 組 ......

    uj5u.com 2023-04-19 09:14:53 more
  • FIDE重磅更新!性能飛躍!體驗有禮!

    FIDE 開發者工具重構升級啦!實作500%性能提升,誠邀體驗! 一直以來不少開發者朋友在社區反饋,在使用 FIDE 工具的程序中,時常會遇到諸如加載不及時、代碼預覽/渲染性能不如意的情況,十分影響開發體驗。 作為技術團隊,我們深知一件趁手的開發工具對開發者的重要性,因此,在2023年開年,FinC ......

    uj5u.com 2023-04-19 09:14:08 more
  • 游戲內嵌社區服務開放,助力開發者提升玩家互動與留存

    華為 HMS Core 游戲內嵌社區服務提供快速訪問華為游戲中心論壇能力,支持玩家直接在游戲內瀏覽帖子和交流互動,助力開發者擴展內容生產和觸達的場景。 一、為什么要游戲內嵌社區? 二、游戲內嵌社區的典型使用場景 1、游戲內打開論壇 您可以在游戲內繪制論壇入口,為玩家提供沉浸式發帖、瀏覽、點贊、回帖、 ......

    uj5u.com 2023-04-19 09:08:34 more