四--RIL层代码分析--整个电话来访过程

2024-04-22 17:38

本文主要是介绍四--RIL层代码分析--整个电话来访过程,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

        最近公司开发一个几百万的项目,要求重写系统RIL层,看了几个招聘信息,只要你会RIL层开发的,工资上w每个月不是梦,这是几天研究的成果,希望对大家有所帮助,兄弟们加油吧! 

先来一个总的流程图:

流程图.jpg

 

拨出电话流程:

在系统源码这个路径下/packages/apps/Phone/src/com/android/phone/DialtactsActivity.java

contactsandroidmanifest.xmlandroid:process="android.process.acore"说明此应用程序运行在acore进程中。DialtactsActivityintent-filteraction属性设置为maincatelog属性设置为launcher,所以此activity能出现首先启动的就是这个activity在主菜单中,并且是点击此应用程序的第一个界面。dialtactsactivity包含四个tab,分别由TwelveKeyDialerRecentCallsListActivity,两个activity-aliasDialtactsContactsEntryActivityDialtactsFavoritesEntryActivity分别表示联系人和收藏tab,但是正真的联系人列表和收藏是由ContactsListActivity负责。

2

进入TwelveKeyDialer OnClick方法,按住的按钮id为:R.id.digits,执行

placecall()

Intent intent = newIntent(Intent.ACTION_CALL_PRIVILEGED,

           Uri.fromParts("tel", number, null));

intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

startActivity(intent);

3

intert.ACTION_CALL_PRIVILEGED实际字符串为android.intent.action.CALL_PRIVILEGED,通过查找知道了packegs/phone下面的androidmanifest.xmlPrivilegedOutgoingCallBroadcasteractivity-alias设置了intent-filter,所以需要找到其targetactivityOutgoingCallBroadcaster。所以进入OutgoingCallBroadcaster


onCreate()

//如果为紧急号码马上启动intent.setClass(this,InCallScreen.class); startActivity(intent);


Intent broadcastIntent = new Intent(Intent.ACTION_NEW_OUTGOING_CALL);


       if (number != null) broadcastIntent.putExtra(Intent.EXTRA_PHONE_NUMBER,number);


       broadcastIntent.putExtra(EXTRA_ALREADY_CALLED, callNow);


       broadcastIntent.putExtra(EXTRA_ORIGINAL_URI,intent.getData().toString());


       if (LOGV) Log.v(TAG, "Broadcasting intent " + broadcastIntent+ ".");


       sendOrderedBroadcast(broadcastIntent, PERMISSION, null, null,


                            Activity.RESULT_OK, number, null);


4Intent.ACTION_NEW_OUTGOING_CALL实际字符串为android.intent.action.NEW_OUTGOING_CALL,通过查找知道了packegs/phone


下面的androidmanifest.xmlOutgoingCallReceiver Receiver接收此intent消息。找到OutgoingCallReceiver,执行


onReceive()函数


Intent newIntent = new Intent(Intent.ACTION_CALL, uri);


       newIntent.putExtra(Intent.EXTRA_PHONE_NUMBER, number);


       newIntent.setClass(context, InCallScreen.class);


       newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

5、请求拨号的java部分流程


onCreate(第一次)/onNewIntent(非第一次)


internalResolveIntent


   placeCall(intent);


     PhoneUtils.placeCall(mPhone, number, intent.getData());


       phone.dial(number);


         mCT.dial(newDialString);


           dial(dialString, CommandsInterface.CLIR_DEFAULT);


              cm.dial(pendingMO.address,clirMode,obtainCompleteMessage());//obtainCompleteMessage(EVENT_OPERATION_COMPLETE);


                send(rr);


                  msg =mSender.obtainMessage(EVENT_SEND, rr);


                  acquireWakeLock();


                  msg.sendToTarget();


                RILSender.handleMessage()


                  case EVENT_SEND:


                    ...


                   s.getOutputStream().write(dataLength);                  


                    s.getOutputStream().write(data);//从这里流程跑到下面ril.cpp中监听部份


---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

上面步骤:为APP就是java层传下的信息(就是执行的动作:按键打电话),已经做完,下面讲RIL层如何来接受上层来的信息

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

第一、《创建轮询机制》

 

6.请求拨号的c/c++部分流程

/*初始化事件循环,启动串口监听,注册socket监听*/

6.1在til/rild/rild.c为入口函数

RIL_startEventLoop()

6.2在libril/ril.cpp

第一、建立事件循环线程

ret = pthread_create(&s_tid_dispatch, &attr, eventLoop, NULL);

RIL_startEventLoop(void){

    ..........

ret = pthread_create(&s_tid_dispatch, &attr, eventLoop, NULL);//创建线程,为入口函数,去实现它的功能

}

--------------------------------------------------------------------

eventLoop入口函数->跳到/ril/libril/ril.cpp 实现

----------------------------------------------------------------------

eventLoop(void *param)

{
ril_event_init();/*初始化*/

void ril_event_init()
{
    MUTEX_INIT();
LOGD("-2.2-Ril_evnet.cpp-ril_event_init-shi-xian-han-shu-");
    FD_ZERO(&readFds);
    init_list(&timer_list);
    init_list(&pending_list);
    memset(watch_table, 0, sizeof(watch_table));
}
ret = pipe(filedes);
s_fdWakeupRead = filedes[0];/
* 消息循环中侦听*/
s_fdWakeupWrite = filedes[1];/* 用于通知消息循环定义消息已发送*/

第二、注册进程唤醒事件回调
ril_event_set(&s_wakeupfd_event, s_fdWakeupRead, true, processWakeupCallback, NULL);/*注册进程唤醒事件回调*/

static void processWakeupCallback(int fd, short flags, void *param) {
    char buff[16];
    int ret;
LOGD("--2.5-ril_event_set--processWakeupCallback- read(s_fdWakeupRead, &buff, sizeof(buff));---");
    LOGV("processWakeupCallback");

    /* empty our wakeup socket out */
    do {
       
ret = read(s_fdWakeupRead, &buff, sizeof(buff));
    } while (ret > 0 || (ret < 0 && errno == EINTR));
}


              
rilEventAddWakeup (&s_wakeupfd_event);
->static void rilEventAddWakeup(struct ril_event *ev)
                           {
                                  ril_event_add(ev);
                                  triggerEvLoop();
                           }
// Add event to watch list
void ril_event_add(struct ril_event * ev)
{
LOGD("---RIL_evnent.cpp--shi--xian--void ril_event_add(struct ril_event * ev)----");
    dlog("~~~~ +ril_event_add ~~~~");
    MUTEX_ACQUIRE();
    for (int i = 0; i < MAX_FD_EVLL) {
 //1:
            watch_table[i] = ev;//把上面ril_event_add函数添加的事件_wakeupfd_event结构体添加到这个数组来
            ev->index = i;
            dlog("~~~~ added at %d ~~~~", i);
            dump_event(ev);
 //2:
            FD_SET(ev->fd, &readFds);
            if (ev->fd >= nfds) nfds = ev->fd+1;
            dlog("~~~~ nfds = %d ~~~~", nfds);
            break;ENTS; i++) {
        if (watch_table[i] == NU
        }
    }
    MUTEX_RELEASE();
    dlog("~~~~ -ril_event_add ~~~~");
}


static void triggerEvLoop(){
    int ret;
 LOGD("--- ret = write (s_fdWakeupWrite, " ", 1);---");
    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);
         } while (ret < 0 && errno == EINTR);
    }
}

第三、建立事件循环
ril_event_loop();/
*建立事件循环*/

}
4.
当调用ril_event_loop()时,就去跳到->reference-ril/reference-ril.c去实现

/* 我们知道对于Linux 设备来讲,我们可以使用select 函数等待在FDS 上,只要FDS 中记录的设备有数据到来,
select 就会设置相应的标志位并返回。readFDS 记录了所有的事件相关设备句柄。readFDS 中句柄是在在AddEvent
加入的。所有的事件侦听都是建立在linux 的select readFDS 基础上。

ril_event_loop 利用select 等待在readFDS  (fd_set)上,当select 设备有数据时,ril_event_loop 会从select 返回,
在watch_list 中相应的Event 放置到pend_list,如果Event 是持久性的则不从watch_list 中删除。然后ril_event_loop
遍历pengding_list 处理Event 事件,发起事件回调函数。
*/

void ril_event_loop()
{
    int n;
    fd_set rfds;
    struct timeval tv;
    struct timeval * ptv

   for (;;) {

         ...}

         n =select(nfds, &rfds,NULL, NULL, ptv);//等待唤醒fd

         // Check for timeouts

         processTimeouts();// 处理定时消息 ,处理ril_event_init ->pending_list

         // Check for read-ready

         processReadReadies(&rfds, n);// 处理侦听消息 ,处理ril_event_init ->watch_list

         // Fire away

         firePending(); // 处理挂起消息

       }

 ######################################################################################################################

多路复用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: 无名管道,用于队列主动唤醒(前面提到的队列刷新,就用它来实现,请参考使用它的相关地方)

 ######################################################################################################################

一上电,就开始执行上面程序,不断的轮询是否有事件(主要是通过pipe作用,再通select机制来处理三态信息:监听,超时,挂起)

当有事件来了,就执行下面函数,对它初始化,和线程mainloop->readloop读取信息和->readline()响应,而

 RIL_requestTimedCallback(initializeCallback, NULL, &TIMEVAL_0);中的initializeCallback发送AT> ATE0Q0V1命令

######################################################################################################################

第二、读取并判断modem发的信息(URC,还是响应)

6.3reference-ril/reference-ril.c->RIL_init()

/*初始化Vendor RIL 并进行注册*/

 1.入口:funcs =rilInit(&s_rilEnv, argc, rilArgv);//实际是通过动态加载动态库的方式执行reference-ril.c中的RIL_Init


const RIL_RadioFunctions *RIL_Init(const struct RIL_Env *env, int argc, char **argv)
{
   
    while ( -1 != (opt = getopt(argc, argv, "p:d:s:"))) {
        switch (opt) {
      //获取dev/ttyUSB,只是打开而已,是否获取,由线程mainLoop执行完才知道
            case 'd':
                s_device_path = optarg;
                LOGI("Opening tty device %s\n", s_device_path);
            break;

            case 's':
                s_device_path   = optarg;
                s_device_socket = 1;
                LOGI("Opening socket %s\n", s

_device_path);
            break;

        return NULL;
    }

    第四、单独启动一个线程读取串口数据
    ret = pthread_create(&s_tid_mainloop, &attr,mainLoop, NULL);//
创建一个线程mainLoop

    return &s_callbacks;//返回一个ril_init,给 RIL_register(&s_callbacks);回调,进行初始化
}

6.4实现mainloop()函数
static void *
mainLoop(void *param)
{
    at_set_on_reader_closed(onATReaderClosed);
    at_set_on_timeout(onATTimeout);

    for (;;) {
        fd = -1;
        while  (fd < 0) {
            if (s_port > 0) {
                fd = socket_loopback_client(s_port, SOCK_STREAM);
            } else if (s_device_socket) {
                if (!strcmp(s_device_path, "/dev/socket/qemud")) {
                    /* Qemu-specific control socket */
                  fd = socket_local_client( "qemud", ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM );
                    if (fd >= 0 ) {
                        char  answer[2];

                        if ( write(fd, "gsm", 3) != 3 ||
                             read(fd, answer, 2) != 2 ||
                             memcmp(answer, "OK", 2) != 0)
                        {
                            close(fd);
                            fd = -1;
                        }
                   }
                }
                else
              /*  获取rild socket*/

fd = socket_local_client( s_device_path, ANDROID_SOCKET_NAMESPACE_FILESYSTEM,SOCK_STREAM );
            } else if (s_device_path != NULL) {
                fd = open (s_device_path, O_RDWR);

        }

        ret = at_open(fd, onUnsolicited);

附:在atchannel.c

int at_open(int fd, ATUnsolHandler h)
{
#ifdef HUAWEI_EM770W /*新增的modulse*/

 {        fd2 = open ("/dev/ttyUSB2", O_RDWR);

    ret = pthread_create(&s_tid_reader_urc, &attr, urc_readerLoop, &attr);

       }

    ret = pthread_create(&s_tid_reader, &attr, readerLoop, &attr);

#endif

    return 0;
}

第五、通过readloop()函数判断为AT:等待回应还是URC请求

/*下面read的阻塞式的读取modoem(是initializeCallback()函数发送的AT命令,)发来信息,还判断是URC还是AT回应请求,并等待回应是否OK,*/

static void *readerLoop(void *arg)
{
    for (;;) {
        const char * line;

        line =readline();

        if (line == NULL) {
            break;
        }

        if(isSMSUnsolicited(line)) {
            char *line1;
            const char *line2;
            line1 = strdup(line);
            line2 = readline();

            if (line2 == NULL) {
                break;
            }

            if (s_unsolHandler != NULL) {
                s_unsolHandler (line1, line2);
            }
            free(line1);
        } else {
            processLine(line);/*对上面读取信息进行解析判断*/
        }

#ifdef HAVE_ANDROID_OS
        if (s_ackPowerIoctl > 0) {          

            ioctl(s_fd, OMAP_CSMI_TTY_ACK, &s_readCount);
            s_readCount = 0;
        }
#endif /*HAVE_ANDROID_OS*/
    }

    onReaderClosed();

    return NULL;
}

/*AT的response有两种,一种是unsolicited。另一种是普通response,也就是命令的响应。
response信息的获取在readerLoop()中。由readline()函数读取上来。
读取到的line将被传入processLine()函数进行解析,processLine()函数首先会判断当前的响应是主动响应还是普通响应,
如果是主动响应,将调用handleUnsolicited()函数,如果为普通响应,那么将调用handleFinalResponse()函数进行处理
对响应串的主要的解析过程,由at_tok.c中的各种解析函数完成,提供字符串分析解析功能。
*/
static void processLine(const char *line)
{
    pthread_mutex_lock(&s_commandmutex);

    if (sp_response == NULL) {
        /* no command pending */
        handleUnsolicited(line);
    } else if (isFinalResponseSuccess(line)) {
        sp_response->success = 1;
        handleFinalResponse(line);
    } else if (isFinalResponseError(line)) {
        sp_response->success = 0;
        handleFinalResponse(line);//1.用来处理UCR请求,上报RIL.java层
    } else if (s_smsPDU != NULL && 0 == strcmp(line, "> ")) {
        // See eg. TS 27.005 4.3
        // Commands like AT+CMGS have a "> " prompt
        writeCtrlZ(s_smsPDU);
        s_smsPDU = NULL;
    } else switch (s_type) {
        case NO_RESULT:
            handleUnsolicited(line);//2.用来处理send_at_command()发过的回应
            break;
        case NUMERIC:
            if (sp_response->p_intermediates == NULL
                && isdigit(line[0])
            ) {
                addIntermediate(line);
            } else {
                /* either we already have an intermediate response or
                   the line doesn't begin with a digit */
                handleUnsolicited(line);
            }
            break;
        case SINGLELINE:
            if (sp_response->p_intermediates == NULL
                && strStartsWith (line, s_responsePrefix)
            ) {
                addIntermediate(line);
            } else {
                /* we already have an intermediate response */
                handleUnsolicited(line);
            }
            break;
        case MULTILINE:
            if (strStartsWith (line, s_responsePrefix)) {
                addIntermediate(line);
            } else {
                handleUnsolicited(line);
            }
        break;

        default: /* this should never be reached */
            LOGE("Unsupported AT command type %d\n", s_type);
            handleUnsolicited(line);
        break;
    }

    pthread_mutex_unlock(&s_commandmutex);
}


static const char *readline()
{
//在这打印Modem回应的OK/err信息,还有是否是URC还是AT命令请求信???
    LOGD("AT< %s\n", ret);
    return ret;//返回,读取好的上面信息
}

 RIL_requestTimedCallback(initializeCallback, NULL, &TIMEVAL_0);//打印AT> ATE0Q0V1

/*发生AT命令*/

static void initializeCallback(void *param)
{    

    at_handshake

at_send_command("ATE0Q0V1", NULL);//同步机制,send_at_command  是同步的,命令发送后,send_at_command 将等待在s_commandcond ,直到有 sp_response->finalResponse。

        setRadioState (RADIO_STATE_SIM_NOT_READY);
    }
}

       }
}

######################################################################################################################

上面函数执行完了,说明在ril_evnet_loop()轮询中有事件,再去把信息向下层的模块发生AT命令,等知道,模块的生效

接下来就要去注册到reference-ril.so动态库去,等待dlopen调用

######################################################################################################################

第三、处理两个socket

6.5libril/ril.cpp-

/*注册rild socket端口事件监听到事件循环中和bedug socket*/

第六、注册rild socket端口事件监听到事件循环中
RIL_register(funcs);


RIL_register (const RIL_RadioFunctions *callbacks){//说明已经初始化完了 ,才回调
    if (callbacks == NULL|| ! (callbacks->version == RIL_VERSION || callbacks->version == 1)) {
        LOGE("RIL_register: RIL_RadioFunctions * null or invalid version"," (expected %d)", RIL_VERSION);
        return;
    }

    if (s_registerCalled > 0) {
      LOGE("RIL_register has been called more than once. ""Subsequent call ignored");
      LOGD("RIL_register has been called more than once. ""Subsequent call ignored");
        return;
    }
//1:换个马甲
    memcpy(&s_callbacks, callbacks, sizeof (RIL_RadioFunctions));

    s_registerCalled = 1;

    for (int i = 0; i < (int)NUM_ELEMS(s_commands); i++) {
        assert(i == s_commands[i].requestNumber);
    }

    for (int i = 0; i < (int)NUM_ELEMS(s_unsolResponses); i++) {
        assert(i + RIL_UNSOL_RESPONSE_BASE
                == s_unsolResponses[i].requestNumber);
    }

       if (s_started == 0) {
        RIL_startEventLoop();
    }

    // start listen socket  开始侦听套接字

#if 0
    ret = socket_local_server (SOCKET_NAME_RIL,ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);

          s_fdListen = ret;

#else

2:获取init.rc定义的rild socket
    s_fdListen= android_get_control_socket(SOCKET_NAME_RIL);
    ret = listen(s_fdListen, 4);

#endif
/*如果ril socket 端口一有数据,就去执行listencallback函数
   这个函数就建立起与客户端的监听话柄
   s_fdLiten继续监听其他客户端的链接*/

第六、将此端口加入事件select队列
    ril_event_set (&s_listen_event, s_fdListen, false,listenCallback, NULL);

    rilEventAddWakeup (&s_listen_event);

#if 1
3.获取debug socket

    s_fdDebug= android_get_control_socket(SOCKET_NAME_RIL_DEBUG);

     ret = listen(s_fdDebug, 4);

//将此处端口加入到select队列去
    ril_event_set (&s_debug_event, s_fdDebug, true,debugCallback, NULL);

    rilEventAddWakeup (&s_debug_event);
#endif

}

  

第七、 如果rild socket端口有数据来了将执行listencallback函数

 ril_event_set (&s_listen_event, s_fdListen, false,listenCallback, NULL);
static void listenCallback(int fd, short flags, void *param) {
    int ret;
    int err;
    int is_phone_socket;
    RecordStream *p_rs;

    struct sockaddr_un peeraddr;
    socklen_t socklen = sizeof (peeraddr);

    struct ucred creds;
    socklen_t szCreds = sizeof(creds);

    struct passwd *pwd = NULL;

    assert (s_fdCommand < 0);
    assert (fd == s_fdListen);
//连接JAVA层来的sockcet
    s_fdCommand = accept(s_fdListen, (sockaddr *) &peeraddr, &socklen);

    if (s_fdCommand < 0 ) {
        LOGE("Error on accept() errno:%d", errno);
        rilEventAddWakeup(&s_listen_event);
       return;
    }

    errno = 0;
    is_phone_socket = 0;

    err = getsockopt(s_fdCommand, SOL_SOCKET, SO_PEERCRED, &creds, &szCreds);

    if (err == 0 && szCreds > 0) {
        errno = 0;
        pwd = getpwuid(creds.uid);
        if (pwd != NULL) {if (strcmp(pwd->pw_name, PHONE_PROCESS) == 0) {  is_phone_socket = 1;}

          else {
                LOGE("RILD can't accept socket from process %s", pwd->pw_name);
            }
        } else { LOGE("Error on getpwuid() errno: %d", errno); }
    } else {
        LOGD("Error on getsockopt() errno: %d", errno);
    }

    if ( !is_phone_socket ) {
      LOGE("RILD must accept socket from %s", PHONE_PROCESS);

      close(s_fdCommand);
      s_fdCommand = -1;

      onCommandsSocketClosed();

      /* start listening for new connections again */
      rilEventAddWakeup(&s_listen_event);

      return;
    }

    ret = fcntl(s_fdCommand, F_SETFL, O_NONBLOCK);

    if (ret < 0) {
        LOGE ("Error setting O_NONBLOCK errno:%d", errno);
    }

    LOGI("libril: new connection");
//有数据来的时候,把s_fdCommand绑定到record_stream_new 。目的就是保证数据的完整性
    p_rs = record_stream_new(s_fdCommand, MAX_COMMAND_BYTES);
//当有数据来的时候,函数就去执行processCommandsCallback()函数,把数据读到p_record中
    ril_event_set (&s_commands_event, s_fdCommand, 1, processCommandsCallback, p_rs);

static void processCommandsCallback(int fd, short flags, void *param) {
    RecordStream *p_rs;
    void *p_record;
    size_t recordlen;
    int ret;

    assert(fd == s_fdCommand);

    p_rs = (RecordStream *)param;
LOGD("--SHI-XIAN--ril_regieter-----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);

        if (ret == 0 && p_record == NULL) {
            /* end-of-stream */
            break;
        } else if (ret < 0) {
            break;
        } else if (ret == 0) { /* && p_record != NULL */
        //阻塞方式获取数据 到p_record 利用RecordStream机制保证数据完整
            processCommandBuffer(p_record, recordlen);
        }
    }

    if (ret == 0 || !(errno == EAGAIN || errno == EINTR)) {
        /* fatal error or end-of-stream */
        if (ret != 0) {
            LOGE("error on reading command socket errno:%d\n", errno);
        } else {
            LOGW("EOS.  Closing command socket.");
        }

        close(s_fdCommand);
        s_fdCommand = -1;

        ril_event_del(&s_commands_event);

        record_stream_free(p_rs);

        /* start listening for new connections again 开始监听新的连接*/
        rilEventAddWakeup(&s_listen_event);

        onCommandsSocketClosed();
    }
}

把accpet接受到rild socket 来的信息先绑定,后读到p_record,说明向下动作全部结束,等待onRequest发请求

 第八,状态结束,等待onRequest发请求


static int
processCommandBuffer(void *buffer, size_t buflen) {
    Parcel p;
    status_t status;
    int32_t request;
    int32_t token;
    RequestInfo *pRI;
    int ret;
LOGD("---shixian -processCommandBuffer---");
    p.setData((uint8_t *) buffer, buflen);

上面实现状态检查全部结束结束,下面为java来的请求,响应onRequest()方法

    // status checked at end 

    status = p.readInt32(&request);
    status = p.readInt32 (&token);//请求队列的序列号

    if (status != NO_ERROR) {
        LOGE("invalid request block");
        return 0;
    }

    if (request < 1 || request >= (int32_t)NUM_ELEMS(s_commands)) {
        LOGE("unsupported request code %d token %d", request, token);
        // FIXME this should perhaps return a response
        return 0;
    }


    pRI = (RequestInfo *)calloc(1, sizeof(RequestInfo));

    pRI->token = token;
    pRI->pCI = &(s_commands[request]);

    ret = pthread_mutex_lock(&s_pendingRequestsMutex);
    assert (ret == 0);

    pRI->p_next = s_pendingRequests;
    s_pendingRequests = pRI;

    ret = pthread_mutex_unlock(&s_pendingRequestsMutex);
    assert (ret == 0);

/*    sLastDispatchedToken = token; */

    pRI->pCI->dispatchFunction(p, pRI);

  //假设是接收了dial指令,pRI->PCI->dispatchFunction(p,pRI),调用dispatchDial(p,pRI)

    return 0;
}

   s_callbacks.onRequest(pRI->pCI->requestNumber, &dial,sizeof(dial), pRI);
       in reference-ril.c onRequest()

 

/*** Callback methods from the RIL library to us ***/

/**
 * Call from RIL to us to make a RIL_REQUEST
 *
 * Must be completed with a call to RIL_onRequestComplete()
 *
 * RIL_onRequestComplete() may be called from any thread, before or after
 * this function returns.
 *
 * Will always be called from the same thread, so returning here implies
 * that the radio is ready to process another command (whether or not
 * the previous command has completed).
 */
static void
onRequest (int request, void *data, size_t datalen, RIL_Token t)
{
    ATResponse *p_response;
    int err;

    LOGD("onRequest: %s", requestToString(request));

    /* Ignore all requests except RIL_REQUEST_GET_SIM_STATUS
     * when RADIO_STATE_UNAVAILABLE.
     */
    if (sState == RADIO_STATE_UNAVAILABLE
        && request != RIL_REQUEST_GET_SIM_STATUS
    ) {
        RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
        return;
    }

    /* Ignore all non-power requests when RADIO_STATE_OFF
     * (except RIL_REQUEST_GET_SIM_STATUS)
     */
    if (sState == RADIO_STATE_OFF
        && !(request == RIL_REQUEST_RADIO_POWER
            || request == RIL_REQUEST_GET_SIM_STATUS)
    ) {
        RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
        return;
    }

    switch (request) {
        case RIL_REQUEST_GET_SIM_STATUS: {
            RIL_CardStatus *p_card_status;
            char *p_buffer;
            int buffer_size;

            int result = getCardStatus(&p_card_status);
            if (result == RIL_E_SUCCESS) {
                p_buffer = (char *)p_card_status;
                buffer_size = sizeof(*p_card_status);
            } else {
                p_buffer = NULL;
                buffer_size = 0;
            }
            RIL_onRequestComplete(t, result, p_buffer, buffer_size);
            freeCardStatus(p_card_status);
            break;
        }
        case RIL_REQUEST_GET_CURRENT_CALLS:
            requestGetCurrentCalls(data, datalen, t);
            break;
        case RIL_REQUEST_DIAL:
            requestDial(data, datalen, t);
            break;
        case RIL_REQUEST_HANGUP:
            requestHangup(data, datalen, t);
            break;
        case RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND:
            // 3GPP 22.030 6.5.5
            // "Releases all held calls or sets User Determined User Busy
            //  (UDUB) for a waiting call."
            at_send_command("AT+CHLD=0", NULL);

            /* success or failure is ignored by the upper layer here.
               it will call GET_CURRENT_CALLS and determine success that way */
            RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
            break;
        case RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND:
            // 3GPP 22.030 6.5.5
            // "Releases all active calls (if any exist) and accepts
            //  the other (held or waiting) call."
            at_send_command("AT+CHLD=1", NULL);

            /* success or failure is ignored by the upper layer here.
               it will call GET_CURRENT_CALLS and determine success that way */
            RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
            break;
        case RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE:
            // 3GPP 22.030 6.5.5
            // "Places all active calls (if any exist) on hold and accepts
            //  the other (held or waiting) call."
            at_send_command("AT+CHLD=2", NULL);

#ifdef WORKAROUND_ERRONEOUS_ANSWER
            s_expectAnswer = 1;
#endif /* WORKAROUND_ERRONEOUS_ANSWER */

            /* success or failure is ignored by the upper layer here.
               it will call GET_CURRENT_CALLS and determine success that way */
            RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
            break;
        case RIL_REQUEST_ANSWER:
            at_send_command("ATA", NULL);

#ifdef WORKAROUND_ERRONEOUS_ANSWER
            s_expectAnswer = 1;
#endif /* WORKAROUND_ERRONEOUS_ANSWER */

            /* success or failure is ignored by the upper layer here.
               it will call GET_CURRENT_CALLS and determine success that way */
            RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
            break;
        case RIL_REQUEST_CONFERENCE:
            // 3GPP 22.030 6.5.5
            // "Adds a held call to the conversation"
            at_send_command("AT+CHLD=3", NULL);

            /* success or failure is ignored by the upper layer here.
               it will call GET_CURRENT_CALLS and determine success that way */
            RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
            break;
        case RIL_REQUEST_UDUB:
            /* user determined user busy */
            /* sometimes used: ATH */
            at_send_command("ATH", NULL);

            /* success or failure is ignored by the upper layer here.
               it will call GET_CURRENT_CALLS and determine success that way */
            RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
            break;

        case RIL_REQUEST_SEPARATE_CONNECTION:
            {
                char  cmd[12];
                int   party = ((int*)data)[0];

                // Make sure that party is in a valid range.
                // (Note: The Telephony middle layer imposes a range of 1 to 7.
                // It's sufficient for us to just make sure it's single digit.)
                if (party > 0 && party < 10) {
                    sprintf(cmd, "AT+CHLD=2%d", party);
                    at_send_command(cmd, NULL);
                    RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
                } else {
                    RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
                }
            }
            break;

        case RIL_REQUEST_SIGNAL_STRENGTH:
            requestSignalStrength(data, datalen, t);
            break;
        case RIL_REQUEST_REGISTRATION_STATE:
        case RIL_REQUEST_GPRS_REGISTRATION_STATE:
            requestRegistrationState(request, data, datalen, t);
            break;
        case RIL_REQUEST_OPERATOR:
            requestOperator(data, datalen, t);
            break;
        case RIL_REQUEST_RADIO_POWER:
            requestRadioPower(data, datalen, t);
            break;
        case RIL_REQUEST_DTMF: {
            char c = ((char *)data)[0];
            char *cmd;
            asprintf(&cmd, "AT+VTS=%c", (int)c);
            at_send_command(cmd, NULL);
            free(cmd);
            RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
            break;
        }
        case RIL_REQUEST_SEND_SMS:
            requestSendSMS(data, datalen, t);
            break;
        case RIL_REQUEST_SETUP_DATA_CALL:
            requestSetupDataCall(data, datalen, t);
            break;
        case RIL_REQUEST_SMS_ACKNOWLEDGE:
            requestSMSAcknowledge(data, datalen, t);
            break;

        case RIL_REQUEST_GET_IMSI:
            p_response = NULL;
            err = at_send_command_numeric("AT+CIMI", &p_response);

            if (err < 0 || p_response->success == 0) {
                RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
            } else {
                RIL_onRequestComplete(t, RIL_E_SUCCESS,
                    p_response->p_intermediates->line, sizeof(char *));
            }
            at_response_free(p_response);
            break;

        case RIL_REQUEST_GET_IMEI:
            p_response = NULL;
            err = at_send_command_numeric("AT+CGSN", &p_response);

            if (err < 0 || p_response->success == 0) {
                RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
            } else {
                RIL_onRequestComplete(t, RIL_E_SUCCESS,
                    p_response->p_intermediates->line, sizeof(char *));
            }
            at_response_free(p_response);
            break;

        case RIL_REQUEST_SIM_IO:
            requestSIM_IO(data,datalen,t);
            break;

        case RIL_REQUEST_SEND_USSD:
            requestSendUSSD(data, datalen, t);
            break;

        case RIL_REQUEST_CANCEL_USSD:
            p_response = NULL;
            err = at_send_command_numeric("AT+CUSD=2", &p_response);

            if (err < 0 || p_response->success == 0) {
                RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
            } else {
                RIL_onRequestComplete(t, RIL_E_SUCCESS,
                    p_response->p_intermediates->line, sizeof(char *));
            }
            at_response_free(p_response);
            break;

        case RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC:
            at_send_command("AT+COPS=0", NULL);
            break;

        case RIL_REQUEST_DATA_CALL_LIST:
            requestDataCallList(data, datalen, t);
            break;

        case RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE:
            requestQueryNetworkSelectionMode(data, datalen, t);
            break;

        case RIL_REQUEST_OEM_HOOK_RAW:
            // echo back data
            RIL_onRequestComplete(t, RIL_E_SUCCESS, data, datalen);
            break;


        case RIL_REQUEST_OEM_HOOK_STRINGS: {
            int i;
            const char ** cur;

            LOGD("got OEM_HOOK_STRINGS: 0x%8p %lu", data, (long)datalen);


            for (i = (datalen / sizeof (char *)), cur = (const char **)data ;
                    i > 0 ; cur++, i --) {
                LOGD("> '%s'", *cur);
            }

            // echo back strings
            RIL_onRequestComplete(t, RIL_E_SUCCESS, data, datalen);
            break;
        }

        case RIL_REQUEST_WRITE_SMS_TO_SIM:
            requestWriteSmsToSim(data, datalen, t);
            break;

        case RIL_REQUEST_DELETE_SMS_ON_SIM: {
            char * cmd;
            p_response = NULL;
            asprintf(&cmd, "AT+CMGD=%d", ((int *)data)[0]);
            err = at_send_command(cmd, &p_response);
            free(cmd);
            if (err < 0 || p_response->success == 0) {
                RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
            } else {
                RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
            }
            at_response_free(p_response);
            break;
        }

        case RIL_REQUEST_ENTER_SIM_PIN:
        case RIL_REQUEST_ENTER_SIM_PUK:
        case RIL_REQUEST_ENTER_SIM_PIN2:
        case RIL_REQUEST_ENTER_SIM_PUK2:
        case RIL_REQUEST_CHANGE_SIM_PIN:
        case RIL_REQUEST_CHANGE_SIM_PIN2:
            requestEnterSimPin(data, datalen, t);
            break;

        default:
            RIL_onRequestComplete(t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0);
            break;
    }
}

 

    rilEventAddWakeup(&s_commands_event);

    onNewCommandConnect();
}

 

 最后,就进入

 frameworks/base/telephony/java/com/android/internal/telephony/gsm/RIL.java

 

6.4、串口监听收到atd命令的应答"OK"或"nocarrier"等
readerLoop()
line = readline();
processLine(line);
   handleFinalResponse(line);
     pthread_cond_signal(&s_commandcond);//至此,前面的等待结束,接着执行RIL_onRequestComplete函数
6.5、java层收到应答后的处理,以dial为例子.
ril.java->RILReceiver.run()
   for(;;)
    {
     ...
     length = readRilMessage(is, buffer);
     p = Parcel.obtain();
    p.unmarshall(buffer, 0, length);
     p.setDataPosition(0);
    processResponse(p);
       type = p.readInt();
       if (type == RESPONSE_SOLICITED) {
         processSolicited (p);
           serial = p.readInt();
           rr = findAndRemoveRequestFromList(serial);
          rr.mResult.sendToTarget();
......
    }
CallTracker.java->handleMessage (Message msg)
   switch (msg.what) {
     case EVENT_OPERATION_COMPLETE:
       ar = (AsyncResult)msg.obj;
       operationComplete();
         cm.getCurrentCalls(lastRelevantPoll);
第二部分:unsolicited 消息从modem上报到java的流程。
  c++部份
readerLoop()
line = readline();
processLine(line);
   handleUnsolicited(line);
     if (s_unsolHandler != NULL) {
       s_unsolHandler (line1, line2);//实际执行的是voidonUnsolicited (const char *s, const char *sms_pdu)
         if (strStartsWith(s,"+CRING:")
                ||strStartsWith(s,"RING")
                || strStartsWith(s,"NOCARRIER")
                ||strStartsWith(s,"+CCWA")
         )
           RIL_onUnsolicitedResponse (RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED, NULL,0);
              p.writeInt32(RESPONSE_UNSOLICITED);
              p.writeInt32 (unsolResponse);
             ret =s_unsolResponses[unsolResponseIndex].responseFunction(p, data, datalen);
              ret = sendResponse(p);
                sendResponseRaw(p.data(),p.dataSize());
                  ret = blockingWrite(fd, (void*)&header, sizeof(header));
                  blockingWrite(fd, data,dataSize);
java部份
ril.java->RILReceiver.run()
   for(;;)

    {
     ...
     length = readRilMessage(is, buffer);
     p = Parcel.obtain();
     p.unmarshall(buffer, 0, length);
     p.setDataPosition(0);
     processResponse(p);
       processUnsolicited (p);
         response = p.readInt();
         switch(response) {
        ...
         case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED: ret =  responseVoid(p); break;
         ...
         }
         switch(response) {
              caseRIL_UNSOL_RESPONSE_CALL_STATE_CHANGED:

                if (RILJ_LOGD)unsljLog(response);
                mCallStateRegistrants
                    .notifyRegistrants(newAsyncResult(null, null, null));
              ...
         }



这篇关于四--RIL层代码分析--整个电话来访过程的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/926427

相关文章

浅析Spring Security认证过程

类图 为了方便理解Spring Security认证流程,特意画了如下的类图,包含相关的核心认证类 概述 核心验证器 AuthenticationManager 该对象提供了认证方法的入口,接收一个Authentiaton对象作为参数; public interface AuthenticationManager {Authentication authenticate(Authenti

作业提交过程之HDFSMapReduce

作业提交全过程详解 (1)作业提交 第1步:Client调用job.waitForCompletion方法,向整个集群提交MapReduce作业。 第2步:Client向RM申请一个作业id。 第3步:RM给Client返回该job资源的提交路径和作业id。 第4步:Client提交jar包、切片信息和配置文件到指定的资源提交路径。 第5步:Client提交完资源后,向RM申请运行MrAp

性能分析之MySQL索引实战案例

文章目录 一、前言二、准备三、MySQL索引优化四、MySQL 索引知识回顾五、总结 一、前言 在上一讲性能工具之 JProfiler 简单登录案例分析实战中已经发现SQL没有建立索引问题,本文将一起从代码层去分析为什么没有建立索引? 开源ERP项目地址:https://gitee.com/jishenghua/JSH_ERP 二、准备 打开IDEA找到登录请求资源路径位置

活用c4d官方开发文档查询代码

当你问AI助手比如豆包,如何用python禁止掉xpresso标签时候,它会提示到 这时候要用到两个东西。https://developers.maxon.net/论坛搜索和开发文档 比如这里我就在官方找到正确的id描述 然后我就把参数标签换过来

poj 1258 Agri-Net(最小生成树模板代码)

感觉用这题来当模板更适合。 题意就是给你邻接矩阵求最小生成树啦。~ prim代码:效率很高。172k...0ms。 #include<stdio.h>#include<algorithm>using namespace std;const int MaxN = 101;const int INF = 0x3f3f3f3f;int g[MaxN][MaxN];int n

【机器学习】高斯过程的基本概念和应用领域以及在python中的实例

引言 高斯过程(Gaussian Process,简称GP)是一种概率模型,用于描述一组随机变量的联合概率分布,其中任何一个有限维度的子集都具有高斯分布 文章目录 引言一、高斯过程1.1 基本定义1.1.1 随机过程1.1.2 高斯分布 1.2 高斯过程的特性1.2.1 联合高斯性1.2.2 均值函数1.2.3 协方差函数(或核函数) 1.3 核函数1.4 高斯过程回归(Gauss

计算机毕业设计 大学志愿填报系统 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试

🍊作者:计算机编程-吉哥 🍊简介:专业从事JavaWeb程序开发,微信小程序开发,定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事,生活就是快乐的。 🍊心愿:点赞 👍 收藏 ⭐评论 📝 🍅 文末获取源码联系 👇🏻 精彩专栏推荐订阅 👇🏻 不然下次找不到哟~Java毕业设计项目~热门选题推荐《1000套》 目录 1.技术选型 2.开发工具 3.功能

SWAP作物生长模型安装教程、数据制备、敏感性分析、气候变化影响、R模型敏感性分析与贝叶斯优化、Fortran源代码分析、气候数据降尺度与变化影响分析

查看原文>>>全流程SWAP农业模型数据制备、敏感性分析及气候变化影响实践技术应用 SWAP模型是由荷兰瓦赫宁根大学开发的先进农作物模型,它综合考虑了土壤-水分-大气以及植被间的相互作用;是一种描述作物生长过程的一种机理性作物生长模型。它不但运用Richard方程,使其能够精确的模拟土壤中水分的运动,而且耦合了WOFOST作物模型使作物的生长描述更为科学。 本文让更多的科研人员和农业工作者

MOLE 2.5 分析分子通道和孔隙

软件介绍 生物大分子通道和孔隙在生物学中发挥着重要作用,例如在分子识别和酶底物特异性方面。 我们介绍了一种名为 MOLE 2.5 的高级软件工具,该工具旨在分析分子通道和孔隙。 与其他可用软件工具的基准测试表明,MOLE 2.5 相比更快、更强大、功能更丰富。作为一项新功能,MOLE 2.5 可以估算已识别通道的物理化学性质。 软件下载 https://pan.quark.cn/s/57

代码随想录冲冲冲 Day39 动态规划Part7

198. 打家劫舍 dp数组的意义是在第i位的时候偷的最大钱数是多少 如果nums的size为0 总价值当然就是0 如果nums的size为1 总价值是nums[0] 遍历顺序就是从小到大遍历 之后是递推公式 对于dp[i]的最大价值来说有两种可能 1.偷第i个 那么最大价值就是dp[i-2]+nums[i] 2.不偷第i个 那么价值就是dp[i-1] 之后取这两个的最大值就是d