电话是一种开放的通信渠道,任何人都可以随时向任何电话号码致电或者发送短信,因此 Android 用户需要能够轻松屏蔽骚扰电话和短信。在 Android N 推出之前,Android 用户只能依靠下载的应用来限制来自骚扰电话号码的来电和短信。但是,由于没有适当的 API 来屏蔽来电和短信,这些应用大部分要么达不到预期效果,要么用户体验不佳。

一些制造商可能会提供他们自己的开箱即用型屏蔽解决方案,但是如果用户更换设备,由于缺乏互用性,他们的屏蔽列表可能会完全丢失。最后,即便用户采用了提供此类功能的拨号应用和短信客户端,他们可能仍需在每个应用中执行屏蔽操作,才能有效屏蔽来电和短信。Android 7.0 版本引入了 BlockedNumberProvider 内容提供程序,该程序可以存储用户指定的无法通过电话通讯(通话、短信、彩信)与他们联系的电话号码列表。系统会参考屏蔽列表中的号码,限制来自这些号码的来电和短信。Android 7.0 不仅会显示屏蔽号码列表,还可让用户添加和删除号码。

1. 启动Rild后台进程

hardware\ril\rild\rild.c

int main(int argc, char **argv) {    // vendor ril lib path either passed in as -l parameter, or read from rild.libpath property    const char *rilLibPath = NULL;    // ril arguments either passed in as -- parameter, or read from rild.libargs property    char **rilArgv;    //厂商ril库句柄    void *dlHandle;    //厂商ril库回调    const RIL_RadioFunctions *(*rilInit)(const struct RIL_Env *, int, char **);    // Pointer to sap init function in vendor ril    RIL_RadioFunctions *(*rilUimInit)(const struct RIL_Env *, int, char **);    const char *err_str = NULL;    // functions returned by ril init function in vendor ril    const RIL_RadioFunctions *funcs;    ......     //打开厂商库    dlHandle = dlopen(rilLibPath, RTLD_NOW);    //启动事件循环    RIL_startEventLoop();    //调用系统库    rilInit =(const RIL_RadioFunctions *(*)(const struct RIL_Env *, int, char **))dlsym(dlHandle, "RIL_Init");    rilUimInit =(RIL_RadioFunctions *(*)(const struct RIL_Env *, int, char **))dlsym(dlHandle, "RIL_SAP_Init");    //初始化rilInit    funcs = rilInit(&s_rilEnv, argc, rilArgv);    //注册回调函数    RIL_register(funcs);    //注册套接    if (rilUimInit) {        RIL_register_socket(rilUimInit, RIL_SAP_SOCKET, argc, rilArgv);    }done:    .....    rilc_thread_pool();    .....}

2. 启动事件循环

hardware\ril\libril\ril.cpp

extern "C" voidRIL_startEventLoop(void) {    ......    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);    //启动线程,运行 eventLoop    int result = pthread_create(&s_tid_dispatch, &attr, eventLoop, NULL);    while (s_started == 0) {        pthread_cond_wait(&s_startupCond, &s_startupMutex);    }    ......

hardware\ril\libril\ril.cpp

static void *eventLoop(void *param) {    int ret;    int filedes[2];    //初始化事件链表    ril_event_init();    //创建管道    ret = pipe(filedes);    //读写唤醒描述符    s_fdWakeupRead = filedes[0];    s_fdWakeupWrite = filedes[1];    //执行    fcntl(s_fdWakeupRead, F_SETFL, O_NONBLOCK);    //设置事件描述符和事件处理函数    ril_event_set (&s_wakeupfd_event, s_fdWakeupRead, true,                processWakeupCallback, NULL);    rilEventAddWakeup (&s_wakeupfd_event);    //开始ril事件循环    ril_event_loop();    ......    return NULL;}

hardware\ril\libril\ril_event.cpp

void ril_event_init(){    MUTEX_INIT();    FD_ZERO(&readFds);    init_list(&timer_list); //初始化事件链表    init_list(&pending_list);    memset(watch_table, 0, sizeof(watch_table));}static void init_list(struct ril_event * list){    memset(list, 0, sizeof(struct ril_event));    list->next = list;    list->prev = list;    list->fd = -1; //存储文件描述符}

hardware\ril\libril\ril_event.cpp

void ril_event_loop(){    int n;    fd_set rfds;    struct timeval tv;    struct timeval * ptv;    for (;;) {        ......        n = select(nfds, &rfds, NULL, NULL, ptv); //开始select        ......        // Check for timeouts        processTimeouts();        // Check for read-ready        processReadReadies(&rfds, n);        // Fire away        firePending();    }}static void processReadReadies(fd_set * rfds, int n){    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)) {            addToList(rev, &pending_list); //添加到挂起列表            if (rev->persist == false) {                removeWatch(rev, i); //从描述符观察表中移除            }            n--;        }    }}static void firePending(){    struct ril_event * ev = pending_list.next;    while (ev != &pending_list) {        struct ril_event * next = ev->next;        removeFromList(ev);        ev->func(ev->fd, 0, ev->param); //执行函数 processWakeupCallback        ev = next;    }}

hardware\ril\libril\ril.cpp

static void processWakeupCallback(int fd, short flags, void *param) {    char buff[16];    int ret;    //循环从套接端读取    do {        ret = read(s_fdWakeupRead, &buff, sizeof(buff));    } while (ret > 0 || (ret < 0 && errno == EINTR));}

hardware\ril\libril\ril.cpp

static void rilEventAddWakeup(struct ril_event *ev) {    ril_event_add(ev);    triggerEvLoop();}

hardware\ril\libril\ril_event.cpp

void ril_event_add(struct ril_event * ev){    for (int i = 0; i < MAX_FD_EVENTS; i++) {        if (watch_table[i] == NULL) {            watch_table[i] = ev; //加入事件观察表中            ev->index = i; //加索引            FD_SET(ev->fd, &readFds);            if (ev->fd >= nfds) nfds = ev->fd+1;            break;        }    }}

hardware\ril\libril\ril.cpp

static void triggerEvLoop() {    int ret;    if (!pthread_equal(pthread_self(), s_tid_dispatch)) {          //循环触发唤醒事件循环         do {            ret = write (s_fdWakeupWrite, " ", 1);         } while (ret < 0 && errno == EINTR);    }}

3. 启动RIL库

hardware\ril\reference-ril\reference-ril.c

const RIL_RadioFunctions *RIL_Init(const struct RIL_Env *env, int argc, char **argv){    ......    //启动线程,开始主循环    ret = pthread_create(&s_tid_mainloop, &attr, mainLoop, NULL);     ......    return &s_callbacks; //返回操作结构体}//函数回调结构表static const RIL_RadioFunctions s_callbacks = {    RIL_VERSION,    onRequest,    currentState,    onSupports,    onCancel,    getVersion};

hardware\ril\reference-ril\reference-ril.c
开始打开BP(基带处理器)

static void *mainLoop(void *param __unused){    int fd;    int ret;    at_set_on_reader_closed(onATReaderClosed);    at_set_on_timeout(onATTimeout);    for (;;) {        fd = -1;        while  (fd < 0) {            if (isInEmulator()) {                fd = qemu_pipe_open("pipe:qemud:gsm"); //模拟            } else if (s_port > 0) {                fd = socket_network_client("localhost", s_port, SOCK_STREAM); //网络            } else if (s_device_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); //打开基带处理器                if ( fd >= 0 && !memcmp( s_device_path, "/dev/ttyS", 9 ) ) {                    /* disable echo on serial ports */                    struct termios  ios;                    tcgetattr( fd, &ios );                    ios.c_lflag = 0;  /* disable ECHO, ICANON, etc... */                    tcsetattr( fd, TCSANOW, &ios );                }            }            ......        }        s_closed = 0;        ret = at_open(fd, onUnsolicited); // 开始基带处理通讯,出入文件描述符,回调处理函数        RIL_requestTimedCallback(initializeCallback, NULL, &TIMEVAL_0);        ......    }}

4. 未经请求的AT通讯

hardware\ril\reference-ril\atchannel.c

int at_open(int fd, ATUnsolHandler h){    int ret;    pthread_t tid;    pthread_attr_t attr;    s_fd = fd;    s_unsolHandler = h; //回调处理句柄    s_readerClosed = 0;    //开线程循环读取    ret = pthread_create(&s_tid_reader, &attr, readerLoop, &attr);    ......    return 0;}

hardware\ril\reference-ril\atchannel.c
循环读取基带处理器的AT指令

static void *readerLoop(void *arg __unused){    for (;;) {        const char * line;        line = readline(); //读取AT命令        if (line == NULL) {            break;        }        if(isSMSUnsolicited(line)) { //是未经请求的回复            char *line1;            const char *line2;            // 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) {                free(line1);                break;            }            if (s_unsolHandler != NULL) {                s_unsolHandler (line1, line2); //回调            }            free(line1);        } else {            processLine(line); //处理        }    }    onReaderClosed();    return NULL;}

hardware\ril\reference-ril\atchannel.c
读取AT命令行

static const char *readline(){    ssize_t count;    char *p_read = NULL;    char *p_eol = NULL;    char *ret;    /* 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)) {            RLOGE("ERROR: Input line exceeded buffer\n");            /* ditch buffer and start over again */            s_ATBufferCur = s_ATBuffer;            *s_ATBufferCur = '\0';            p_read = s_ATBuffer;        }        do {            //循环读取AT指令数据            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 );            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) {                RLOGD("atchannel: EOF reached");            } else {                RLOGD("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 */    RLOGD("AT< %s\n", ret);    return ret;}

hardware\ril\reference-ril\atchannel.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);    } 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);            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 */            RLOGE("Unsupported AT command type %d\n", s_type);            handleUnsolicited(line);        break;    }    pthread_mutex_unlock(&s_commandmutex);}

hardware\ril\reference-ril\atchannel.c
回调处理

static void handleUnsolicited(const char *line){    if (s_unsolHandler != NULL) {        s_unsolHandler(line, NULL);    }}

hardware\ril\reference-ril\reference-ril.c
处理来自基带处理器的AT指令

static void onUnsolicited (const char *s, const char *sms_pdu){    char *line = NULL, *p;    int err;    /* Ignore unsolicited responses until we're initialized.     * This is OK because the RIL library will poll for initial state     */    if (sState == RADIO_STATE_UNAVAILABLE) {        return;    }    if (strStartsWith(s, "%CTZV:")) {        /* TI specific -- NITZ time */        char *response;        line = p = strdup(s);        at_tok_start(&p);        err = at_tok_nextstr(&p, &response);        if (err != 0) {            RLOGE("invalid NITZ line %s\n", s);        } else {            RIL_onUnsolicitedResponse (                RIL_UNSOL_NITZ_TIME_RECEIVED,                response, strlen(response));        }        free(line);    } else if (strStartsWith(s,"+CRING:")                || strStartsWith(s,"RING")                || strStartsWith(s,"NO CARRIER")                || strStartsWith(s,"+CCWA")    ) {        RIL_onUnsolicitedResponse (            RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED,            NULL, 0);#ifdef WORKAROUND_FAKE_CGEV        RIL_requestTimedCallback (onDataCallListChanged, NULL, NULL); //TODO use new function#endif /* WORKAROUND_FAKE_CGEV */    } else if (strStartsWith(s,"+CREG:")                || strStartsWith(s,"+CGREG:")    ) {        RIL_onUnsolicitedResponse (            RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED,            NULL, 0);#ifdef WORKAROUND_FAKE_CGEV        RIL_requestTimedCallback (onDataCallListChanged, NULL, NULL);#endif /* WORKAROUND_FAKE_CGEV */    } else if (strStartsWith(s, "+CMT:")) {        RIL_onUnsolicitedResponse (            RIL_UNSOL_RESPONSE_NEW_SMS,            sms_pdu, strlen(sms_pdu));    } else if (strStartsWith(s, "+CDS:")) {        RIL_onUnsolicitedResponse (            RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT,            sms_pdu, strlen(sms_pdu));    } else if (strStartsWith(s, "+CGEV:")) {        /* Really, we can ignore NW CLASS and ME CLASS events here,         * but right now we don't since extranous         * RIL_UNSOL_DATA_CALL_LIST_CHANGED calls are tolerated         */        /* can't issue AT commands here -- call on main thread */        RIL_requestTimedCallback (onDataCallListChanged, NULL, NULL);#ifdef WORKAROUND_FAKE_CGEV    } else if (strStartsWith(s, "+CME ERROR: 150")) {        RIL_requestTimedCallback (onDataCallListChanged, NULL, NULL);#endif /* WORKAROUND_FAKE_CGEV */    } else if (strStartsWith(s, "+CTEC: ")) {        int tech, mask;        switch (parse_technology_response(s, &tech, NULL))        {            case -1: // no argument could be parsed.                RLOGE("invalid CTEC line %s\n", s);                break;            case 1: // current mode correctly parsed            case 0: // preferred mode correctly parsed                mask = 1 << tech;                if (mask != MDM_GSM && mask != MDM_CDMA &&                     mask != MDM_WCDMA && mask != MDM_LTE) {                    RLOGE("Unknown technology %d\n", tech);                } else {                    setRadioTechnology(sMdmInfo, tech);                }                break;        }    } else if (strStartsWith(s, "+CCSS: ")) {        int source = 0;        line = p = strdup(s);        if (!line) {            RLOGE("+CCSS: Unable to allocate memory");            return;        }        if (at_tok_start(&p) < 0) {            free(line);            return;        }        if (at_tok_nextint(&p, &source) < 0) {            RLOGE("invalid +CCSS response: %s", line);            free(line);            return;        }        SSOURCE(sMdmInfo) = source;        RIL_onUnsolicitedResponse(RIL_UNSOL_CDMA_SUBSCRIPTION_SOURCE_CHANGED,                                  &source, sizeof(source));    }     ......}

hardware\ril\libril\ril.cpp
响应请求

#if defined(ANDROID_MULTI_SIM)extern "C"void RIL_onUnsolicitedResponse(int unsolResponse, const void *data,                                size_t datalen, RIL_SOCKET_ID socket_id)#elseextern "C"void RIL_onUnsolicitedResponse(int unsolResponse, const void *data,                                size_t datalen)#endif{    int unsolResponseIndex;       unsolResponseIndex = unsolResponse - RIL_UNSOL_RESPONSE_BASE;       // Grab a wake lock if needed for this reponse,    // as we exit we'll either release it immediately    // or set a timer to release it later.    switch (s_unsolResponses[unsolResponseIndex].wakeType) {        case WAKE_PARTIAL:            grabPartialWakeLock();            shouldScheduleTimeout = true;        break;        case DONT_WAKE:        default:            // No wake lock is grabed so don't set timeout            shouldScheduleTimeout = false;            break;    }    appendPrintBuf("[UNSL]< %s", requestToString(unsolResponse));    int responseType;    if (s_callbacks.version >= 13                && s_unsolResponses[unsolResponseIndex].wakeType == WAKE_PARTIAL) {        responseType = RESPONSE_UNSOLICITED_ACK_EXP;    } else {        responseType = RESPONSE_UNSOLICITED;    }    pthread_rwlock_t *radioServiceRwlockPtr = radio::getRadioServiceRwlock((int) soc_id);    int rwlockRet = pthread_rwlock_rdlock(radioServiceRwlockPtr);    assert(rwlockRet == 0);    //执行响应函数    ret = s_unsolResponses[unsolResponseIndex].responseFunction(            (int) soc_id, responseType, 0, RIL_E_SUCCESS, const_cast<void*>(data),            datalen);    ......}

hardware\ril\libril\ril.cpp

static UnsolResponseInfo s_unsolResponses[] = {#include "ril_unsol_commands.h"};

hardware\ril\libril\ril_unsol_commands.h
函数表,由responseFunction查表调用

 {RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED, radio::radioStateChangedInd, WAKE_PARTIAL}, {RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED, radio::callStateChangedInd, WAKE_PARTIAL}, {RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED, radio::networkStateChangedInd, WAKE_PARTIAL}, {RIL_UNSOL_RESPONSE_NEW_SMS, radio::newSmsInd, WAKE_PARTIAL}, ......

5. 经请求的AT通讯

hardware\ril\libril\ril.cpp
注册回调函数

extern "C" voidRIL_register (const RIL_RadioFunctions *callbacks) {    int ret;    int flags;    //内存分配    memcpy(&s_callbacks, callbacks, sizeof (RIL_RadioFunctions));    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);    }    //注册    radio::registerService(&s_callbacks, s_commands);}

hardware\ril\libril\ril_service.cpp
回调函数和函数路由表

void radio::registerService(RIL_RadioFunctions *callbacks, CommandInfo *commands) {    using namespace android::hardware;    int simCount = 1;    const char *serviceNames[] = {            android::RIL_getServiceName()            #if (SIM_COUNT >= 2)            , RIL2_SERVICE_NAME            #if (SIM_COUNT >= 3)            , RIL3_SERVICE_NAME            #if (SIM_COUNT >= 4)            , RIL4_SERVICE_NAME            #endif            #endif            #endif            };    #if (SIM_COUNT >= 2)    simCount = SIM_COUNT;    #endif    configureRpcThreadpool(1, true /* callerWillJoin */); //RPC线程池    for (int i = 0; i < simCount; i++) { //一张sim卡对应一项服务        pthread_rwlock_t *radioServiceRwlockPtr = getRadioServiceRwlock(i);        int ret = pthread_rwlock_wrlock(radioServiceRwlockPtr);        assert(ret == 0);        radioService[i] = new RadioImpl;        radioService[i]->mSlotId = i;        oemHookService[i] = new OemHookImpl;        oemHookService[i]->mSlotId = i;        RLOGD("registerService: starting IRadio %s", serviceNames[i]);        android::status_t status = radioService[i]->registerAsService(serviceNames[i]);        status = oemHookService[i]->registerAsService(serviceNames[i]);        ret = pthread_rwlock_unlock(radioServiceRwlockPtr);        assert(ret == 0);    }    s_vendorFunctions = callbacks;    s_commands = commands;}

hardware\ril\libril\ril_service.cpp
s_vendorFunctions为上述RIL_RadioFunctions

#if defined(ANDROID_MULTI_SIM)#define CALL_ONREQUEST(a, b, c, d, e) \        s_vendorFunctions->onRequest((a), (b), (c), (d), ((RIL_SOCKET_ID)(e)))#define CALL_ONSTATEREQUEST(a) s_vendorFunctions->onStateRequest((RIL_SOCKET_ID)(a))#else#define CALL_ONREQUEST(a, b, c, d, e) s_vendorFunctions->onRequest((a), (b), (c), (d))#define CALL_ONSTATEREQUEST(a) s_vendorFunctions->onStateRequest()#endif

hardware\ril\libril\ril_service.cpp

bool dispatchVoid(int serial, int slotId, int request) {    RequestInfo *pRI = android::addRequestToList(serial, slotId, request);    if (pRI == NULL) {        return false;    }    CALL_ONREQUEST(request, NULL, 0, pRI, slotId);    return true;}

hardware\ril\reference-ril\reference-ril.c
宏调用

static voidonRequest (int request, void *data, size_t datalen, RIL_Token t){    ATResponse *p_response;    int err;    ......    switch (request) {        ......        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); //发送AT指令        default:            RLOGD("Request not supported. Tech: %d",TECH(sMdmInfo));            RIL_onRequestComplete(t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0); //处理请求            break;    }}

hardware\ril\libril\ril.cpp
同上未经请求的回复,对应一张函数表,AT命令的请求相应均由函数跳转表路由到hardware\ril\libril\ril_service.cpp 去执行

static CommandInfo s_commands[] = {#include "ril_commands.h"};

6. RIL抽象服务

hardware\ril\libril\ril_service.cpp

Return<void> RadioImpl::getModemActivityInfo(int32_t serial) { //查询活跃信息#if VDBG    RLOGD("getModemActivityInfo: serial %d", serial);#endif    dispatchVoid(serial, mSlotId, RIL_REQUEST_GET_ACTIVITY_INFO); //上述请求派发函数    return Void();}

hardware\ril\libril\ril_service.cpp

struct RadioImpl : public IRadio {    int32_t mSlotId;    sp<IRadioResponse> mRadioResponse;    sp<IRadioIndication> mRadioIndication;    Return<void> setResponseFunctions(            const ::android::sp<IRadioResponse>& radioResponse,            const ::android::sp<IRadioIndication>& radioIndication);}

intermediates\hardware\interfaces\radio\1.0\[email protected]_genc++_headers\gen\android\hardware\radio\1.0\IRadio.h
一项HAL的Binder服务接口;在hardware\interfaces\radio\1.0\vts\functional提供了一些接口和测试案例

struct IRadio : public ::android::hidl::base::V1_0::IBase {    virtual bool isRemote() const override { return false; }    ......    }

暂且分析到这,以后在扩展到上层系统框架。

更多相关文章

  1. android LOG机制
  2. android的wake_lock介绍
  3. android 编译系统阅读与分析(1)-envsetup.sh (editing....)
  4. Android中 Js 扩展及交互
  5. Android(安卓)M App 永久隐藏导航栏的Solution
  6. Android(安卓)SurfaceFlinger VSync流程分析
  7. SEAndroid安全机制对Android属性访问的保护分析
  8. Android(安卓)GPIO LED 驱动与HAL分析
  9. Rexsee API介绍:Android传感器系列之 - 磁场传感器Magnetic Field

随机推荐

  1. listview背景选择
  2. [置顶] Android(安卓)CardView简单使用方
  3. Android ButterKnife注解框架使用
  4. 01 Android应用的构成
  5. Android(安卓)获取闹钟引发的血案
  6. Android摇一摇功能的实现
  7. Android(安卓)ScrollView截图和图片保存
  8. Android Style与Theme .
  9. 对AndroidManifest.xml的一点理解
  10. Android获取手机经纬度