RIL

来源:互联网 发布:网络禁书txt下载 编辑:程序博客网 时间:2024/05/17 03:14

对于熟悉Android O之前RIL的开发者来说,Android O上RIL最大的改变就是将socket通信换成了binder通信,只不过是/dev/hwbinder,而不是/dev/binder。Binder IPC的开发模式是注册service, 获取service,然后调用相关API。Server端RILD不再是socket监听,而是注册service; RILJ也不再是连接socket,而是获取service,持有引用。通信方式的改变导致RILD和RILJ都发生了改变,但是这个变化并不算大,以前的轮廓还在。

下面根据Android O 源码,从下面两个方面来简单介绍下RIL:
1.RILD daemon部分
2.RIL java 部分

RIL daemon

先从RIL daemon部分开始,因为这样思路比较顺畅。这部分相关代码路径是”/hardware/ril/rild/”,根据Android.mk文件,这个部分code会编译生成可以执行文件,init进程会根据rild.rc来加载运行该文件。
下面是rild.rc中的内容, “/vendor/bin/hw/rild”是binary在手机中的路径:

service ril-daemon /vendor/bin/hw/rild    class main    user radio    group radio cache inet misc audio log readproc wakelock    capabilities BLOCK_SUSPEND NET_ADMIN NET_RAW

rild被加载执行的时候ril.c的main函数会被执行, 该函数主要完成了下面的工作:
1.加载vendor需要的lib, 获取lib的handle。
2.获取Ril_Init函数; 调用Ril_Init函数获取RIL_RadioFunctions类型的返回值。RIL_RadioFunctions是一个结构体,成员全是函数指针,可以通过这些函数指针调用lib内的函数。
3.调用RIL_register函数,注册service,并保存Ril_Init返回的函数指针。

注册service

RIL_register函数的定义在Ril.cpp文件内。这个函数只是做了一些参数检查工作,然后直接调用了Ril_service.cpp内的registerService函数。

void radio::registerService(RIL_RadioFunctions *callbacks, CommandInfo *commands) {    using namespace android::hardware;    int simCount = 1;    const char *serviceNames[] = {//根据SIM的数量来确定service的名称。            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 */);    for (int i = 0; i < simCount; i++) {        pthread_rwlock_t *radioServiceRwlockPtr = getRadioServiceRwlock(i);        int ret = pthread_rwlock_wrlock(radioServiceRwlockPtr);        assert(ret == 0);        radioService[i] = new RadioImpl;//service对象        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]);//注册service        ret = pthread_rwlock_unlock(radioServiceRwlockPtr);        assert(ret == 0);    }    s_vendorFunctions = callbacks;//将callbacks存进全局变量, 用于处理request    s_commands = commands;//}

第一个参数是Ril_Init函数返回的由函数指针组成的结构体变量; 第二个参数是CommandInfo类型的s_commands变量,该变量是用ril_commands.h初始化的,这个头文件里定义了每个request对应的response函数,下面是ril_commands.h的一部分:

  ......  {RIL_REQUEST_DIAL, radio::dialResponse},  {RIL_REQUEST_GET_IMSI, radio::getIMSIForAppResponse},  {RIL_REQUEST_HANGUP, radio::hangupConnectionResponse},  {RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND, radio::hangupWaitingOrBackgroundResponse},  ......

在registerService函数中每个service都是新创建的RadioImpl对象。

struct RadioImpl : public IRadio {}

RadioImpl是个结构体,继承了IRadio。IRadio也是一个结构体,相关.h和C++文件会在编译”hardware/interfaces/radio/1.0/”路径下的.hal文件时生成(可以参考Android.bp)。编译生成的.h和C++文件在”out/soong/intermediates/hardware/interfaces/”路径下。
我们可以在RadioAll.cpp文件中找到registerAsService的定义:

::android::status_t IRadio::registerAsService(const std::string &serviceName) {    ::android::hardware::details::onRegistration("android.hardware.radio@1.0", "IRadio", serviceName);    const ::android::sp<::android::hidl::manager::V1_0::IServiceManager> sm            = ::android::hardware::defaultServiceManager();    if (sm == nullptr) {        return ::android::INVALID_OPERATION;    }    ::android::hardware::Return<bool> ret = sm->add(serviceName.c_str(), this);    return ret.isOk() && ret ? ::android::OK : ::android::UNKNOWN_ERROR;}

到这里知道通信使用的是/dev/hwbinder就可以了。再往下追就到libhwbinder里面了,有些跑题,就此打住。

Ril java部分

先画一个简单的类图,然后进一步分析。
这里写图片描述

Ril.java这个类还是继承了BaseCommands类,实现了CommandInterface接口。不过RILRequest,RILSender和RILReceiver这几个类都没有了; 取而代之的是RadioIndication和RadioResponse。
从这两个类的名字就可以看出RadioIndication用于处理modem主动上报的消息,而RadioResponse用于处理modem对AP侧request的response。

public class RadioResponse extends IRadioResponse.Stub {......}public class RadioResponse extends IRadioResponse.Stub {......}

根据上面的类定义RadioResponse和RadioIndication这两个类都继承了Stub,这明显是为了用于进程间通信。

Ril.java对象是在开机时PhoneApp应用启动的过程中创建的,Ril.java的构造函数完成了初始化工作,包括RadioResponse,RadioIndication对象的创建以及HIDL service的获取。

private IRadio getRadioProxy(Message result) {        ......        try {            mRadioProxy = IRadio.getService(HIDL_SERVICE_NAME[mPhoneId == null ? 0 : mPhoneId]);//获取Rild注册servcie的proxy,            if (mRadioProxy != null) {                mRadioProxy.linkToDeath(mRadioProxyDeathRecipient,                        mRadioProxyCookie.incrementAndGet());                mRadioProxy.setResponseFunctions(mRadioResponse, mRadioIndication);//将RadioResponse和RadioIndication对象传递给service。            } else {                riljLoge("getRadioProxy: mRadioProxy == null");            }        } catch (RemoteException | RuntimeException e) {            mRadioProxy = null;            riljLoge("RadioProxy getService/setResponseFunctions: " + e);        }        ......        return mRadioProxy;    }

getRadioProxy方法获取了HIDL service,并将将RadioResponse和RadioIndication对象传递给service。经过binder传递后,这个两个对象的引用将分别被保存在RadioImpl::mRadioResponse和RadioImpl::mRadioIndication中, 后续用于modem给AP侧上报消息。
这里写图片描述

下面对于AP侧请求和Modem主动上报分别举一个例子:
AP 侧主动请求,以dial拨号为例.
首先看Ril.dial方法

    @Override    public void dial(String address, int clirMode, UUSInfo uusInfo, Message result) {        IRadio radioProxy = getRadioProxy(result);//获取service proxy        if (radioProxy != null) {            //构造request 消息   Start            RILRequest rr = obtainRequest(RIL_REQUEST_DIAL, result,                    mRILDefaultWorkSource);            Dial dialInfo = new Dial();            dialInfo.address = convertNullToEmptyString(address);            dialInfo.clir = clirMode;            if (uusInfo != null) {                UusInfo info = new UusInfo();                info.uusType = uusInfo.getType();                info.uusDcs = uusInfo.getDcs();                info.uusData = new String(uusInfo.getUserData());                dialInfo.uusInfo.add(info);            }            //构造request消息  End            if (RILJ_LOGD) {                // Do not log function arg for privacy                riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));            }            try {                radioProxy.dial(rr.mSerial, dialInfo);//调用dial方法            } catch (RemoteException | RuntimeException e) {                handleRadioProxyExceptionForRR(rr, "dial", e);            }        }    }

下面来看RadioImpl::dial函数:

Return<void> RadioImpl::dial(int32_t serial, const Dial& dialInfo) {#if VDBG    RLOGD("dial: serial %d", serial);#endif    RequestInfo *pRI = android::addRequestToList(serial, mSlotId, RIL_REQUEST_DIAL);//为RequestInfo类型分配了一块内存,并将地址给pRI, 这个是response时用的。    if (pRI == NULL) {        return Void();    }    /**解析参数,并保存在RIL_Dial类型的变量内  Start */    RIL_Dial dial = {};    RIL_UUS_Info uusInfo = {};    int32_t sizeOfDial = sizeof(dial);    if (!copyHidlStringToRil(&dial.address, dialInfo.address, pRI)) {        return Void();    }    dial.clir = (int) dialInfo.clir;    if (dialInfo.uusInfo.size() != 0) {        uusInfo.uusType = (RIL_UUS_Type) dialInfo.uusInfo[0].uusType;        uusInfo.uusDcs = (RIL_UUS_DCS) dialInfo.uusInfo[0].uusDcs;        if (dialInfo.uusInfo[0].uusData.size() == 0) {            uusInfo.uusData = NULL;            uusInfo.uusLength = 0;        } else {            if (!copyHidlStringToRil(&uusInfo.uusData, dialInfo.uusInfo[0].uusData, pRI)) {                memsetAndFreeStrings(1, dial.address);                return Void();            }            uusInfo.uusLength = dialInfo.uusInfo[0].uusData.size();        }        dial.uusInfo = &uusInfo;    }    /**解析参数,并保存在RIL_Dial类型的变量内  End */    CALL_ONREQUEST(RIL_REQUEST_DIAL, &dial, sizeOfDial, pRI, mSlotId);    memsetAndFreeStrings(2, dial.address, uusInfo.uusData);    return Void();}

CALL_ONREQUEST是一个宏定义:

#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

s_vendorFunctions是vendor lib返回的函数指针,所以到这里也就调用了lib里面的相应函数。
当lib处理完之后会调用RIL_onRequestComplete,dialResponse函数会被调用。

int radio::dialResponse(int slotId,                       int responseType, int serial, RIL_Errno e, void *response,                       size_t responseLen) {#if VDBG    RLOGD("dialResponse: serial %d", serial);#endif    if (radioService[slotId]->mRadioResponse != NULL) {        RadioResponseInfo responseInfo = {};        populateResponseInfo(responseInfo, serial, responseType, e);        Return<void> retStatus = radioService[slotId]->mRadioResponse->dialResponse(responseInfo);        radioService[slotId]->checkReturnStatus(retStatus);    } else {        RLOGE("dialResponse: radioService[%d]->mRadioResponse == NULL", slotId);    }    return 0;}

radioService[slotId]中的mRadioResponse 是RILJ在启动时放的回调,在RILJ对应的类是RadioResponse。

Modem主动上报:
在RILD daemon启动时在rild.c的main函数里调用了Ril_init函数,这给前边已经提到过了。

    ...    funcs = rilInit(&s_rilEnv, argc, rilArgv);    ...

调用是传递的参数s_rilEnv是rild.c的全局变量,该变量初始化情况如下:

static struct RIL_Env s_rilEnv = {    RIL_onRequestComplete,    RIL_onUnsolicitedResponse,    RIL_requestTimedCallback,    RIL_onRequestAck};

将s_rilEnv的地址传进Ril_Init函数便是为了给modem上报消息提供调用接口。当modem有消息上报时,RIL_onUnsolicitedResponse函数会被调用。
下面的code为了突出上报功能将wakelock等部分省略了:

#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;    int ret;    bool shouldScheduleTimeout = false;    RIL_SOCKET_ID soc_id = RIL_SOCKET_1;#if defined(ANDROID_MULTI_SIM)    soc_id = socket_id;#endif    if (s_registerCalled == 0) {        // Ignore RIL_onUnsolicitedResponse before RIL_register        RLOGW("RIL_onUnsolicitedResponse called before RIL_register");        return;    }    unsolResponseIndex = unsolResponse - RIL_UNSOL_RESPONSE_BASE;    if ((unsolResponseIndex < 0)        || (unsolResponseIndex >= (int32_t)NUM_ELEMS(s_unsolResponses))) {        RLOGE("unsupported unsolicited response code %d", unsolResponse);        return;    }    ...    ret = s_unsolResponses[unsolResponseIndex].responseFunction(            (int) soc_id, responseType, 0, RIL_E_SUCCESS, const_cast<void*>(data),            datalen);    ...}

s_unsolResponses是ril.cpp的全局变量,使用头文件ril_unsol_commands.h初始化。该文件定义了每个unsolicited 消息对应的函数;RIL_onUnsolicitedResponse通过s_unsolResponses找到对应的函数,并调用。
ril_unsol_commands.h:

    {RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED, radio::radioStateChangedInd, WAKE_PARTIAL},    {RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED, radio::callStateChangedInd, WAKE_PARTIAL},

以RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED为例,RIL_onUnsolicitedResponse会调用callStateChangedInd函数:

int radio::callStateChangedInd(int slotId,                               int indicationType, int token, RIL_Errno e, void *response,                               size_t responseLen) {    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {#if VDBG        RLOGD("callStateChangedInd");#endif        Return<void> retStatus = radioService[slotId]->mRadioIndication->callStateChanged(                convertIntToRadioIndicationType(indicationType));        radioService[slotId]->checkReturnStatus(retStatus);    } else {        RLOGE("callStateChangedInd: radioService[%d]->mRadioIndication == NULL", slotId);    }    return 0;}

callStateChangedInd通过radioService[slotId]的mRadioIndication将消息传到java层,java层对应的类是RadioIndication.java。RadioIndication.callStateChanged会调用ril.java将消息进一步上传。

    public void callStateChanged(int indicationType) {        mRil.processIndication(indicationType);        if (RIL.RILJ_LOGD) mRil.unsljLog(RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED);        mRil.mCallStateRegistrants.notifyRegistrants();    }

到此结束!