调制解调器代码如何与安卓代码交互

43

我希望了解Android Modem代码如何调用/传递消息到Android应用层的高级概念。以SMS为例,如果网络发送SMS并且Modem(例如Qualcomm C代码解析)如何将其传输到Android应用程序层?

是否总是发生JNI调用?作为调制解调器和Android之间的接口?您能否与我们分享相关信息。谢谢。

2个回答

79
在AOSP/CAF/CM源代码(即Android Open Source Project,CodeAurora Forum和Cyanogenmod)的几乎所有Android源代码库中,都有一个名为rild(Radio Interface Layer Daemon)的C代码。这通常在源树的/hardware/ril目录下找到。
此守护程序从Android启动时运行,并创建一个名为/dev/socket/rild和/dev/socket/rild-debug的套接字。会有一款专有库从高通、HTC等厂商那里动态加载,它与无线电固件进行通信。而且,rild的回调钩子就是通过它来建立的。
在rild层面上,通过上述套接字,就是Android层(在源树frameworks/base/telephony/com/android/internal/telephony/RIL.java中找到的)进行通信的方式。
在Java侧,它打开套接字以进行读取/写入,并通过该套接字设置意图和委托来广播/接收事件。
例如,有一个来电,专有库会调用由rild设置的回调钩子。 rild将标准通用AT Hayes调制解调器命令写入套接字,在Java侧进行读取和解释,然后PhoneManager广播CALL_STATE_RINGING,其中Phone应用程序(在源packages/apps/Phone中找到)已注册接收器并启动用户界面,这就是你如何回答电话的过程。另一个例子是,当你在Android上拨打电话时,创建意图(intent),然后将意图发送到PhoneManager(一切的根源,我记不清楚了,但应该在源码树中的frameworks/base/core/java某个位置),PhoneManager接收到意图后,将其转换为一系列AT Hayes调制解调器命令,写入套接字,rild随后调用专有库的回调函数,专有库再委托给无线电固件。
最后一个例子是,从Messaging(位于packages/apps/Mms源树中)应用程序发送短信时,你输入的文本被放入意图中,PhoneManager接收到意图后,将文本转换成使用7位GSM字母编码的GSM编码,将其写入套接字,rild 随后调用专有库的回调函数,专有库再委托给无线电固件,此时文本已经离开手持设备的领域并在空中传播... :)除此之外,还可以在Android中发送广播消息,前提是使用READ_PHONE_STATE权限并在AndroidManifest.xml中指定。
同样,在接收短信时,流程相反,无线电固件接收到一些字节,专有库调用rild的回调函数,从而将字节写入套接字。在Java端,从套接字中读取并解码字节序列,将其转换为我们所知道的文本,触发一条带有消息接收通知的广播。Messaging应用程序已注册该广播的接收器,并向通知栏发送意图,以显示类似于"来自+xxxxxx的新消息"的内容。
意图(intents)可在 frameworks/base/telephony/java/com/android/internal/telephony/TelephonyIntents.java找到。这就是电话系统的工作原理要点,真正美妙之处在于它使用通用的AT Hayes调制解调器命令,因此简化和隐藏了真正的专有机制。
至于类似高通、HTC这样的公司,别想他们会开源所涉及的库,因为无线电电话层嵌入在S-o-C(芯片级系统)电路中!
顺带一提,这也是为什么刷写无线电固件很有风险的原因,一些手机提供了这种功能,但如果刷写了不正确的固件(例如不兼容或不适合手机的固件),可能会让手机变成废物,只能当门挡或纸重了!:)
应该注意到,这里没有涉及任何JNI机制。
根据我对其工作原理的理解,无线电固件加载到某个内存地址中,Linux内核已保留了该地址空间,并且不会触及它。这有点类似旧PC时代DOS启动时由BIOS使用的保留地址,我想这里也是类似的。标记为保留的地址被固件占用,专有的无线电库与其通信。由于库正在由内核拥有的地址空间中运行,具有root权限,因此可以“与其交流”。如果你考虑使用旧的BASIC方言peek和poke,我想你不会太离谱,通过向该地址写入一定字节序列,无线电固件就会采取行动,几乎就像具有中断向量表一样……这只是我猜测它的工作原理而已。 :)

2
@gonzobrains 套接字!请阅读上面的第五和第六段 :) 名为 rild 的套接字是由ril守护进程创建的,Java端打开它进行读/写操作... - t0mm13b
3
理论上,你可以替换或修改rild守护程序以记录Hayes AT&T命令……通过修改代码,可以拦截启动呼叫等命令序列,使java / android侧看不到它……这绝对需要从头开始定制ROM。如果你能理解我的意思,这是一种中间人攻击的方式……这并不容易-可能会破坏rild接收/发出呼叫/短信的核心目的。 - t0mm13b
2
@B770 这由电话芯片组透明处理,Android 在高层处理路由 前提是 条件满足,即如果插入耳机,则重新路由,否则通过麦克风/听筒正常工作,如果激活了蓝牙耳机,则重新路由,否则正常。因此,不,麦克风的输入不会通过 rild/sockets 传输。 - t0mm13b
2
请注意,我在我的答案中所描述的底层内容受到限制和封闭源代码,因此无法确切得知。此外,GSM、CDMA是用于电话的独特频率,它们使用Samsung、Motorola、HTC等供应商特定的库。在Android的这个方面中没有已知的开源电话机制,不存在。 - t0mm13b
2
是的,播放预先录制的文件会很有趣。因此,一种选择是更改从麦克风写入的缓冲区。 - B770
显示剩余14条评论

2

继t0mm13b的解释后,当我们谈论智能手机时,就涉及到短信/通话的3层操作。

RIL(用户级别)<-> AP <-> CP

AP:应用处理器(Android操作系统运行的地方。想象一下游戏、歌曲、视频、相机等在该处理器上运行)

CP:蜂窝处理器(实际处理来/去电/短信的空中接口,与网络塔交互等)

现在假设某些数据在CP端收到(它可以是互联网数据/短信/电话)。现在在AP和CP之间有一些逻辑通道。因此,CP将根据数据类型将接收到的数据推送到相应的通道。这些数据将由AP接收。AP将把这些数据发送回RIL/App。RIL将解码这些数据(特别是通话/短信数据)。基于这个,向用户提供有关短信/电话的通知。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接