<一>--RIL层代码分析-RIL_RadioFunctions *RIL_Init(funcs =rilInit()->mainloop()

 ril/rild/rild.c->main()为函数入口

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

1.消息队列select为非阻塞的去轮询事件
2.read的阻塞的去读取上层发下来的命令,并响应

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


int main(int argc, char **argv)

{
    const char * rilLibPath = NULL;
    char **rilArgv;
    void *dlHandle;
    const RIL_RadioFunctions *(*rilInit)(const struct RIL_Env *, int, char **);
    const RIL_RadioFunctions *funcs;
    char libPath[PROPERTY_VALUE_MAX];
    unsigned char hasLibArgs = 0;

   ........

OpenLib:
#endif
    switchUser();
/*打开dlopen()函数,就会动态去加载动态库vendor RIL 获取由RIL_register(funcs);注册进来的参数,并解析*/
    dlHandle = dlopen(rilLibPath, RTLD_NOW);

    if (dlHandle == NULL) {
        fprintf(stderr, "dlopen failed: %s\n", dlerror());
        exit(-1);
    }
/*消息队列的入口,添加到select,用阻塞方式去读取那些ril_event_set()的数据##每当看到打印信息,不按顺序打下来说明阻塞##*/
     RIL_startEventLoop();
/*通过dlsym函数得到rilInit函数指针的引用*/
    rilInit = (const RIL_RadioFunctions *(*)(const struct RIL_Env *, int, char **))dlsym(dlHandle, "RIL_Init");

    if (rilInit == NULL) {
        fprintf(stderr, "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];
/*利用得到的rilInit函数指针,调用真正的RIL_Init ,实际是动态加载动态库去链接reference-ril.c ,由dlopen()函数加载*/
    funcs = rilInit(&s_rilEnv, argc, rilArgv);
/*RIL_register作用一:把vendor RIL(即RIL_init) 注册到reference-ril库去等待,dopen()函数加载链接
附:RIL_init通过是onRequest()方法,将上层来的请求进行映射后转换成对应的AT命令发给硬件,rild通过RIL_register注册这一指针。
  RIL_register作用二:创建rild socket主要是等待java层得数据通过,传到下一层,还创建debug socket*/
    RIL_register(funcs);

done:

    while(1) {
        // sleep(UINT32_MAX) seems to return immediately on bionic
        sleep(0x00ffffff);
    }

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

所有文件:

hardware/ril/reference-ril$ ls

Android.mk   atchannel.h  at_tok.h  misc.h     NOTICE    atchannel.c at_tok.c   ril_event.h   reference-ril.c  misc.c    MODULE_LICENSE_APACHE2 

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

在编译时libril被链入rild,它为rild提供了event处理功能,还提供了在rildVendor RIL之间传递请求和响应消息的能力。

libril.so驻留在rild这一守护进程中,主要完成同上层通信的工作,接受ril请求并传递给librefrence_ril.so, 同时把来自librefrence_ril.so的反馈回传给调用进程。

librefrence.so负责直接与modem通信,这包括将来自libril的指令转换为AT指令,并且将AT指令写入modem中。

reference-ril会接收调用者传来的参数,参数内容为与radio的通信方式。如通过串口连接modem,那么参数为这种形式:-d /dev/ttySx

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

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
reference-ril/reference-ril.c  ->RIL_RadioFunctions *RIL_Init()函数
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

const RIL_RadioFunctions *RIL_Init(const struct RIL_Env *env, int argc, char **argv)
{
    int ret;
    int fd = -1;
    int opt;
    pthread_attr_t attr;

    s_rilenv = env;
LOGD("--referencen_ril.c-- RIL_RadioFunctions -shi-xian--*RIL_Init-----");
    while ( -1 != (opt = getopt(argc, argv, "p:d:s:"))) {
        switch (opt) {
            case 'p':
                s_port = atoi(optarg);
                if (s_port == 0) {
                    usage(argv[0]);
                    return NULL;
                }
                LOGI("Opening loopback port %d\n", s_port);
            break;
//获取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;

            default:
                usage(argv[0]);
                return NULL;
        }
    }

    if (s_port < 0 && s_device_path == NULL) {
        usage(argv[0]);
        return NULL;
    }
//上面获取了设备节点和socket
    pthread_attr_init (&attr);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    LOGD("---reference-ril.c --ril_init--ru-kou-   ret = pthread_create(&s_tid_mainloop, &attr, mainLoop, NULL);-")
  //创建一个线程,单独去读取串口数据
    ret = pthread_create(&s_tid_mainloop, &attr,mainLoop, NULL);//创建一个线程mainLoop

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

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

           这个任务的入口是RIL_Init, RIL_Init首先通过参数获取硬件接口的设备文件或模拟硬件接口的socket. 接下来便新开一个线程继续初始化, 即mainLoop。mainLoop的主要任务是建立起与硬件的通信,然后通过read方法阻塞等待硬件的主动上报或响应。
           在注册一些基础回调(timeout,readerclose)后,mainLoop首先打开硬件设备文件,建立起与硬件的通信,s_device_path和s_port是前面获取的设备路径参数,将其打开(两者可以同时打开并拥有各自的reader,这里也很容易添加双卡双待等支持)。接下来通过at_open函数建立起这一设备文件上的reader等待循环,这也是通过新建一个线程完成, ret = pthread_create(&s_tid_reader, &attr, readerLoop, &attr),入口点readerLoop。
           AT命令都是以/r/n或/n/r的换行符来作为分隔符的,所以readerLoop是line驱动的,除非出错,超时等,否则会读到一行完整的响应或主动上报,才会返回。这个循环跑起来以后,我们基本的AT响应机制已经建立了起来。它的具体分析,包括at_open中挂接的ATUnsolHandler, 我们都放到后面分析response的连载文章里去。
有了响应的机制(当然,能与硬件通信也已经可以发请求了),通过RIL_requestTimedCallback(initializeCallback, NULL, &TIMEVAL_0),跑到initializeCallback中,执行一些Modem的初始化命令,主要都是AT命令的方式。发AT命令的流程,我们放到后面分析request的连载文章里。这里可以看到,主要是一些参数配置,以及网络状态的检查等
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

mainloop的作用:主要任务是建立起与硬件的通信,然后通过at_open()->readloop()->line()方法阻塞等待是否又数据过来,并向硬件主动上报或响应(OK)。

                                  发命令的是由initializeCallback()发过来的ATE0Q0V1等

1.打开rild socket(init.rc传过来的)是用于等待read()后java层传来的数据(再去调nitializeCallback发at命令)

2.就是调用RIL_requestTimedCallback(initializeCallback, NULL, &TIMEVAL_0);函数,用来向modem发生AT命令

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

static void *
mainLoop(void *param)
{
LOGD("----shi-xian---mainLoop-----");
LOGI("------------in mainLoop\n");
    int fd;
    int ret;
    static struct timeval TIMEVAL_DELAYINIT = {0,0};//延时函数
    AT_DUMP("== ", "entering mainLoop()", -1 );
    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 */
                      //1:
                LOGD("--1----socket_local_client---after--qian-yi-ge-");
                    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
                //1:
                LOGD("---2---socket_local_client---after--hou-yi-ge-");
                    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);
                if ( fd >= 0 ) {
                    /* disable echo on serial ports */
                    struct termios  ios;
                    tcgetattr( fd, &ios );
                    ios.c_lflag = 0;  /* disable ECHO, ICANON, etc... */
                    tcsetattr( fd, TCSANOW, &ios );
                    LOGI("---open() sucess\n");
                }else{
                LOGI("---open() failed\n");
                }
            }

            if (fd < 0) {
                perror ("opening AT interface. retrying...");
                sleep(10);
                /* never returns */
            }
        }

        s_closed = 0;
        //2:
        LOGD("--jin--ru---at_open---");
        ret = at_open(fd, onUnsolicited);

        if (ret < 0) {
            LOGE ("AT error %d on at_open\n", ret);
            return 0;
        }

  TIMEVAL_DELAYINIT.tv_sec = 15;
  LOGD("going to enter initializeCallback\n");
  LOGD ("Will delay RIL initialization for %d seconds", TIMEVAL_DELAYINIT.tv_sec);
 //3: 
 LOGD("---jin -ru--RIL_requestTimedCallback(initializeCallback, NULL,
 &TIMEVAL_0);---");
        RIL_requestTimedCallback(initializeCallback, NULL, &TIMEVAL_0);//打印AT> ATE0Q0V1

        // Give initializeCallback a chance to dispatched, since
        // we don't presently have a cancellation mechanism
        sleep(1);

        waitForClose();
        LOGI("Re-opening after close");
    }
}
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

at_open()的作用:1.可以添加自己想要的modem

                                  2.函数建立起这一设备文件上的reader等待循环

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
/**
 * Starts AT handler on stream "fd'
 * returns 0 on success, -1 on error
 */
int at_open(int fd, ATUnsolHandler h)
{
    int ret;
    pthread_t tid;
    pthread_attr_t attr;
LOGD("---shi--xian --at_open-----------");
    s_fd = fd;
    s_unsolHandler = h;
    s_readerClosed = 0;

    s_responsePrefix = NULL;
    s_smsPDU = NULL;
    sp_response = NULL;

    /* Android power control ioctl */
#ifdef HAVE_ANDROID_OS
#ifdef OMAP_CSMI_POWER_CONTROL
    ret = ioctl(fd, OMAP_CSMI_TTY_ENABLE_ACK);
    if(ret == 0) {
        int ack_count;
  int read_count;
        int old_flags;
        char sync_buf[256];
        old_flags = fcntl(fd, F_GETFL, 0);
        fcntl(fd, F_SETFL, old_flags | O_NONBLOCK);
        do {
            ioctl(fd, OMAP_CSMI_TTY_READ_UNACKED, &ack_count);
   read_count = 0;
            do {
                ret = read(fd, sync_buf, sizeof(sync_buf));
    if(ret > 0)
     read_count += ret;
            } while(ret > 0 || (ret < 0 && errno == EINTR));
            ioctl(fd, OMAP_CSMI_TTY_ACK, &ack_count);
         } while(ack_count > 0 || read_count > 0);
        fcntl(fd, F_SETFL, old_flags);
        s_readCount = 0;
        s_ackPowerIoctl = 1;
    }
    else
        s_ackPowerIoctl = 0;

#else // OMAP_CSMI_POWER_CONTROL
    s_ackPowerIoctl = 0;

#endif // OMAP_CSMI_POWER_CONTROL
#endif /*HAVE_ANDROID_OS*/

    pthread_attr_init (&attr);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

#ifdef HUAWEI_EM770W //新增的modem,在创建一个线程去实现它的功能

    int fd2 = -1;

    while(fd2 < 0) {

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

        if (fd2 < 0) {

            perror ("opening URC interface. retrying...");

            sleep(10);

        }

    }

    if(fd2 > 0) {

        urc_fd = fd2;

        struct termios ios;

        tcgetattr( fd2, &ios );

        ios.c_lflag = 0;
        tcsetattr( fd2, TCSANOW, &ios );

    }

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

    if (ret < 0) {

        perror ("pthread_create");

        return -1;

    }

#else
LOGD("---at_open----ru-kou--ret = pthread_create(&s_tid_reader, &attr, readerLoop,&attr);------");
    ret = pthread_create(&s_tid_reader, &attr,readerLoop, &attr);

    if (ret < 0) {
        perror ("pthread_create");
        return -1;
    }
#endif

    return 0;
}
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

readerLoop()作用:阻塞地去读取,modem发过来的AT命令,并回应(OK)和上报上层,后再去阻塞的形式读取等待下一个AT命令

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

static void *readerLoop(void *arg)
{
LOGD("---shi-xian --readerLoop--");
    for (;;) {
        const char * line;

        line = readline();

        if (line == NULL) {
            break;
        }

        if((isSMSUnsolicited(line)) {
            char *line1;
            const char *line2;
LOGD("---shi-xian --readerLoop-isSMSUnsolicited(line)---");
            // The scope of string returned by 'readline()' is valid only
            // till next call to 'readline()' hence making a copy of line
            // before calling readline again.
            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) {
            /* acknowledge that bytes have been read and processed */
            ioctl(s_fd, OMAP_CSMI_TTY_ACK, &s_readCount);
            s_readCount = 0;
        }
#endif /*HAVE_ANDROID_OS*/
    }

    onReaderClosed();

    return NULL;
}
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


/**
 * Reads a line from the AT channel, returns NULL on timeout.
 * Assumes it has exclusive read access to the FD
 *
 * This line is valid only until the next call to readline
 *
 * This function exists because as of writing, android libc does not
 * have buffered stdio.
 */

static const char *readline()
{
    ssize_t count;

    char *p_read = NULL;
    char *p_eol = NULL;
    char *ret;
LOGD("----shi--xian---readline-----");
    /* this is a little odd. I use *s_ATBufferCur == 0 to
     * mean "buffer consumed completely". If it points to a character, than
     * the buffer continues until a \0
     */
    if (*s_ATBufferCur == '\0') {
        /* empty buffer */
        s_ATBufferCur = s_ATBuffer;
        *s_ATBufferCur = '\0';
        p_read = s_ATBuffer;
    } else {   /* *s_ATBufferCur != '\0' */
        /* there's data in the buffer from the last read */

        // skip over leading newlines
        while (*s_ATBufferCur == '\r' || *s_ATBufferCur == '\n')
            s_ATBufferCur++;

        p_eol = findNextEOL(s_ATBufferCur);

        if (p_eol == NULL) {
            /* a partial line. move it up and prepare to read more */
            size_t len;

            len = strlen(s_ATBufferCur);

            memmove(s_ATBuffer, s_ATBufferCur, len + 1);
            p_read = s_ATBuffer + len;
            s_ATBufferCur = s_ATBuffer;
        }
        /* Otherwise, (p_eol !- NULL) there is a complete line  */
        /* that will be returned the while () loop below        */
    }

    while (p_eol == NULL) {
        if (0 == MAX_AT_RESPONSE - (p_read - s_ATBuffer)) {
            LOGE("ERROR: Input line exceeded buffer\n");
            /* ditch buffer and start over again */
            s_ATBufferCur = s_ATBuffer;
            *s_ATBufferCur = '\0';
            p_read = s_ATBuffer;
        }

        do {
            count = read(s_fd, p_read,
                            MAX_AT_RESPONSE - (p_read - s_ATBuffer));
        } while (count < 0 && errno == EINTR);

        if (count > 0) {
            AT_DUMP( "<< ", p_read, count );
            s_readCount += count;

            p_read[count] = '\0';

            // skip over leading newlines
            while (*s_ATBufferCur == '\r' || *s_ATBufferCur == '\n')
                s_ATBufferCur++;

            p_eol = findNextEOL(s_ATBufferCur);
            p_read += count;
        } else if (count <= 0) {
            /* read error encountered or EOF reached */
            if(count == 0) {
                LOGD("atchannel: EOF reached");
            } else {
                LOGD("atchannel: read error %s", strerror(errno));
            }
            return NULL;
        }
    }

    /* a full line in the buffer. Place a \0 over the \r and return */

    ret = s_ATBufferCur;
    *p_eol = '\0';
    s_ATBufferCur = p_eol + 1; /* this will always be <= p_read,    */
                                                     /* and there will be a \0 at *p_read */
//在这打印Modem回应的OK信息
    LOGD("AT< %s\n", ret);
    return ret;//返回,读取好的上面信息
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值