1.去电流程三中跟踪到最后的时候可以看到其调用了RIL的dail方法

这里继续以此分析其从RIL到Modem的流程

@Override

public void dial(String address, int clirMode, UUSInfo uusInfo, Message result) {

//获取radio对象

IRadio radioProxy = getRadioProxy(result);

if (radioProxy != null) {

//构建RIL请求消息

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);

}

if (RILJ_LOGD) {

// Do not log function arg for privacy

riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));

}

try {

//调用dial方法

radioProxy.dial(rr.mSerial, dialInfo);

} catch (RemoteException | RuntimeException e) {

handleRadioProxyExceptionForRR(rr, "dial", e);

}

}

}

1.1使用单例模式通过获取Radio对象,可以看到其获取的是HIDL的对象,并且设置的回复方法mRadioResponse,可以参见RIL架构分析。

protected IRadio getRadioProxy(Message result) {

...

try {

//获取HIDL的服务并设置setResponseFunctions

mRadioProxy = IRadio.getService(HIDL_SERVICE_NAME[mPhoneId == null ? 0 : mPhoneId]);

if (mRadioProxy != null) {

mRadioProxy.linkToDeath(mRadioProxyDeathRecipient,

mRadioProxyCookie.incrementAndGet());

//设置mRadioResponse和mRadioIndication

mRadioProxy.setResponseFunctions(mRadioResponse, mRadioIndication);

} else {

riljLoge("getRadioProxy: mRadioProxy == null");

}

} catch (RemoteException | RuntimeException e) {

mRadioProxy = null;

riljLoge("RadioProxy getService/setResponseFunctions: " + e);

}

...

}

可以看到其通过HIDL方式获取到Radio对象后,进一步调用此对象的dial方法

继续查找远端的Radio类

发现RadioImpl继承了IRadio

struct RadioImpl : public V1_1::IRadio

2.在 ril_service 中实现了dial方法,继续跟进此方法

Return RadioImpl::dial(int32_t serial, const Dial& dialInfo) {

#if VDBG

RLOGD("dial: serial %d", serial);

#endif

//构建请求对象,Event侧和reference测协定的统一格式,当从event测发送到reference测时需要标准化为此对象

RequestInfo *pRI = android::addRequestToList(serial, mSlotId, RIL_REQUEST_DIAL);

if (pRI == NULL) {

return Void();

}

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;

}

//

CALL_ONREQUEST(RIL_REQUEST_DIAL, &dial, sizeOfDial, pRI, mSlotId);

memsetAndFreeStrings(2, dial.address, uusInfo.uusData);

return Void();

}

疑问点:为何没有进入EventLoop循环????

在Android7.0上是通过Select获取Socke发送过来的消息,然后通过EventLoop进行处理,最后调用到processCommandsCallback之后进行处理。和同事沟通后HIDL发送消息也会被Select获取到,之后一路调用到ev->func(ev->fd, 0, ev->param); ,但在8.0上没有processCommandsCallback处理,这里笔者也未追溯到其如何进一步处理,后续会进一步进行分析。但从现有源码来看其是调用到了RadioImpl的dial方法进行处理。

3.继续跟踪CALL_ONREQUEST

搜索CALL_ONREQUEST,可以看到其实际调用的是s_vendorFunctions->onRequest

#define CALL_ONREQUEST(a, b, c, d, e) s_vendorFunctions->onRequest((a), (b), (c), (d))

在registerService方法中看到s_vendorFunctions其实是传进来的callbacks实例,即RIL_RadioFunctions对象,这里具体分析可以见Android 8.0RIL框架分析。

在ril.c中继续跟踪OnRequest方法,回到之前rild.c的main中,我们看到其先调用rilInit进行初始化,之后返回了funcs,在传如RIL_register进行注册

跟进到reference-ril.c的 onRequest 方法

/**

* 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.

*

* Because onRequest function could be called from multiple different thread,

* we must ensure that the underlying at_send_command_* function

* is atomic.

*/

static void

onRequest (int request, void *data, size_t datalen, RIL_Token t)

{

ATResponse *p_response;

int err;

RLOGD("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中处理

switch (request) {

...

case RIL_REQUEST_DIAL:

requestDial(data, datalen, t);

break;

...

}

}

4.继续跟进requestDial方法

static void requestDial(void *data, size_t datalen __unused, RIL_Token t)

{

RIL_Dial *p_dial;

char *cmd;

const char *clir;

int ret;

p_dial = (RIL_Dial *)data;

switch (p_dial->clir) {

case 1: clir = "I"; break; /*invocation*/

case 2: clir = "i"; break; /*suppression*/

default:

case 0: clir = ""; break; /*subscription default*/

}

asprintf(&cmd, "ATD%s%s;", p_dial->address, clir);

//发送AT命令

ret = at_send_command(cmd, NULL);

free(cmd);

/* 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);

}

5.继续跟踪at_send_command

int at_send_command (const char *command, ATResponse **pp_outResponse)

{

int err;

err = at_send_command_full (command, NO_RESULT, NULL,

NULL, 0, pp_outResponse);

return err;

}

6.继续跟进at_send_command_full

/** * Internal send_command implementation * * timeoutMsec == 0 means infinite timeout */

static int at_send_command_full (const char *command, ATCommandType type,

const char *responsePrefix, const char *smspdu,

long long timeoutMsec, ATResponse **pp_outResponse)

{

int err;

bool inEmulator;

if (0 != pthread_equal(s_tid_reader, pthread_self())) {

/* cannot be called from reader thread */

return AT_ERROR_INVALID_THREAD;

}

inEmulator = isInEmulator();

if (inEmulator) {

pthread_mutex_lock(&s_writeMutex);

}

pthread_mutex_lock(&s_commandmutex);

//继续发送

err = at_send_command_full_nolock(command, type,

responsePrefix, smspdu,

timeoutMsec, pp_outResponse);

pthread_mutex_unlock(&s_commandmutex);

if (inEmulator) {

pthread_mutex_unlock(&s_writeMutex);

}

if (err == AT_ERROR_TIMEOUT && s_onTimeout != NULL) {

s_onTimeout();

}

return err;

}

7.继续跟进at_send_command_full_nolock

/** * Internal send_command implementation * Doesn't lock or call the timeout callback * * timeoutMsec == 0 means infinite timeout */

static int at_send_command_full_nolock (const char *command, ATCommandType type,

const char *responsePrefix, const char *smspdu,

long long timeoutMsec, ATResponse **pp_outResponse)

{

int err = 0;

struct timespec ts;

if(sp_response != NULL) {

err = AT_ERROR_COMMAND_PENDING;

goto error;

}

//给modem发送AT消息

err = writeline (command);

if (err < 0) {

goto error;

}

s_type = type;

s_responsePrefix = responsePrefix;

s_smsPDU = smspdu;

//创建sp_respose作为回应

sp_response = at_response_new();

if (timeoutMsec != 0) {

setTimespecRelative(&ts, timeoutMsec);

}

//发送完后阻塞线程

while (sp_response->finalResponse == NULL && s_readerClosed == 0) {

if (timeoutMsec != 0) {

//进入阻塞状态,待另一个线程满足s_commandcond后解除

err = pthread_cond_timedwait(&s_commandcond, &s_commandmutex, &ts);

} else {

err = pthread_cond_wait(&s_commandcond, &s_commandmutex);

}

//超时结束

if (err == ETIMEDOUT) {

err = AT_ERROR_TIMEOUT;

goto error;

}

}

if (pp_outResponse == NULL) {

at_response_free(sp_response);

} else {

/* line reader stores intermediate responses in reverse order */

reverseIntermediates(sp_response);

//将回应发给请求的线程

*pp_outResponse = sp_response;

}

sp_response = NULL;

if(s_readerClosed > 0) {

err = AT_ERROR_CHANNEL_CLOSED;

goto error;

}

err = 0;

error:

clearPendingCommand();

return err;

}

可以看到这里做了两个重要的操作:

1.通过writeLine发送数据给modem

2.阻塞当前线程等待modem回应

8.这样数据就发送到了modem了

/** * Sends string s to the radio with a \r appended. * Returns AT_ERROR_* on error, 0 on success * * This function exists because as of writing, android libc does not * have buffered stdio. */

static int writeline (const char *s)

{

size_t cur = 0;

size_t len = strlen(s);

ssize_t written;

if (s_fd < 0 || s_readerClosed > 0) {

return AT_ERROR_CHANNEL_CLOSED;

}

//AT命令的打印

RLOGD("AT> %s\n", s);

AT_DUMP( ">> ", s, strlen(s) );

/* the main string */

while (cur < len) {

do {

s_fd是modem和rilc的串口

written = write (s_fd, s + cur, len - cur);

} while (written < 0 && errno == EINTR);

if (written < 0) {

return AT_ERROR_GENERIC;

}

cur += written;

}

/* the \r */

//以r结尾

do {

written = write (s_fd, "\r" , 1);

} while ((written < 0 && errno == EINTR) || (written == 0));

if (written < 0) {

return AT_ERROR_GENERIC;

}

return 0;

}

android 8.0 ril.java,Android 8.0 RIL源码分析(一)相关推荐

  1. android 代码 drawable,Android Drawable完全解析(一):Drawable源码分析(中)

    呃...我不是故意要凑篇幅写个什么上下篇,实在是因为Drawable源码有点长,一篇写不下啦O(∩_∩)O~ 鉴于源码一般较长,以后所有源码分析的部分,英文注释非必要情况都不再保留! 2:Drawab ...

  2. Android 12 新APP启动画面(SplashScreen API)简介源码分析

    以往的启动画面 默认情况下刚启动APP时会显示一会白色背景 如果把这个启动背景设置为null,则一闪而过的白色会变成黑色 如果把启动Activity设置为背景透明[< item name=&qu ...

  3. Android多媒体框架(3)—— libstagefright中MediaCodec源码分析

    libstagefright中MediaCodec源码分析 和前两篇一样,我们按照MediaCodec的各个状态来分析libstagefright中MediaCodec的源代码. configure ...

  4. Java并发编程之ThreadLocal源码分析

    1 一句话概括ThreadLocal   什么是ThreadLocal?顾名思义:线程本地变量,它为每个使用该对象的线程创建了一个独立的变量副本. 2 ThreadLocal使用场景   用一句话总结 ...

  5. 死磕java并发cas_死磕 java并发包之AtomicInteger源码分析

    问题 (1)什么是原子操作? (2)原子操作和数据库的ACID有啥关系? (3)AtomicInteger是怎么实现原子操作的? (4)AtomicInteger是有什么缺点? 简介 AtomicIn ...

  6. Java集合篇:LinkedList源码分析

    (注:本文内容基于JDK1.6) 一.概述: LinkedList与ArrayList一样实现List接口,只是ArrayList是List接口的大小可变数组的实现,LinkedList是List接口 ...

  7. java多线程系列:ThreadPoolExecutor源码分析

    前言 这篇主要讲述ThreadPoolExecutor的源码分析,贯穿类的创建.任务的添加到线程池的关闭整个流程,让你知其然所以然.希望你可以通过本篇博文知道ThreadPoolExecutor是怎么 ...

  8. java多线程系列:ThreadPoolExecutor源码分析,java基础面试笔试题

    我总结出了很多互联网公司的面试题及答案,并整理成了文档,以及各种学习的进阶学习资料,免费分享给大家. 扫描二维码或搜索下图红色VX号,加VX好友,拉你进[程序员面试学习交流群]免费领取.也欢迎各位一起 ...

  9. Java类集框架 —— HashMap源码分析

    HashMap是基于Map的键值对映射表,底层是通过数组.链表.红黑树(JDK1.8加入)来实现的. HashMap结构 HashMap中存储元素,是将key和value封装成了一个Node,先以一个 ...

  10. Java类集框架 —— LinkedList源码分析

    在JDK1.7之前,LinkedList是采用双向环形链表来实现的,在1.7及之后,Oracle将LinkedList做了优化,将环形链表改成了线性链表.本文对于LinkedList的源码分析基于JD ...

最新文章

  1. 快讯 | 第二届数据标准化及治理大会成功举办,清华力量助推中国数据标准化建设
  2. JavaScript中的数组遍历forEach()与map()方法以及兼容写法
  3. python高阶函数
  4. abb机器人建立工件坐标系_ABB机器人大地坐标系修改案例
  5. C语言学习之输入10个数,输出其中最大的一个数。
  6. 基于PHPEnv的本地环境搭建—PHP第一个项目:HelloWorld(从安装到运行)
  7. VS2010+Opencv249 图像叠加 添加水印
  8. 根据[user]查找所有者为[user]的文件列表
  9. 关于tomcat不能启动的问题(NB:JAVA_HOME should point to a JDK not a JRE)
  10. 发际线对于一个人的颜值影响有多大?
  11. 【渝粤教育】国家开放大学2018年春季 8618-21T燃气行业规范 参考试题
  12. 【项目管理案例】第九期:如何做好项目整合管理
  13. 计算机英语考虑是,计算机英语中单词privilege和permission的区别
  14. Android Studio集成NDK开发环境
  15. 【源码】loess method扩展算法仿真
  16. “万丈高楼平地起,编程学习要趁早”
  17. File类,字节字符输入输出流,缓冲流,标准流,对象序列化流
  18. HDU - 5514 Frogs
  19. 【Day3.4】东台吉尔湖
  20. 网易考试大题知识盲区之B树、B+树、B*树

热门文章

  1. nextSibling 属性与 nextElementSibling 属性的异同
  2. about云成立5周年:中秋国庆【赠送优惠】活动
  3. _beginthreadex 执行失败
  4. 概念:HPC 分布式计算 云计算 异构计算
  5. kettle运行spoon.bat时找不到javaw文件 bug报错
  6. 为国内制造业转型升级而努力,董明珠终将折戟沉沙还是笑傲江湖?
  7. 加拿大计算机学硕,加拿大专业硕士和学术硕士的区别一共就是这些!
  8. Condition 原理解析
  9. matlab 加法器,Matlab GUI编程实例(加法器)
  10. 花10年时间学程序就能做好吗?