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(); }
到此结束!
- RIL
- RIL
- RIL
- ril
- RIL
- RIL
- RIL
- RIL
- RIL
- android ril
- RIL SMS
- ril - 1
- ril - 2
- ril - 3
- RIL 驱动
- RIL 函数
- Android RIL
- RIL 架构
- Golang实现词频统计
- 使用nvm管理不同版本的node与npm
- 蓝桥杯第七届-生日蜡烛
- Android 平台上方便实用的 Shell 终端模拟工具
- GitHub下载项目中某个文件夹或文件
- RIL
- webview的使用大全
- Python函数Map()和reduce()的区别和第二天学习Python的心得体会
- 从小白到大数据架构师的学习历程
- mt6735 [Audio APP]收音机 APP添加耳机 hook键,以实现播放、暂停的功能
- 《深度探索C++对象模型》读书笔记——第一章
- FIFO 位宽转换
- 关于MPLS
- 剪绳子算法--动态规划法