【文档说明】Android-Telephony原理解析与开发指南课件.pptx,共(288)页,3.972 MB,由小橙橙上传
转载请保留链接:https://www.ichengzhen.cn/view-6026.html
以下为本文档部分文字说明:
AndroidTelephony原理解析与开发指南第一章初识Android•1.1SmartPhone智能手机的系统结构•1.2Android系统架构–1.2.1应用层(Applications)–1.2.2应用框架层(Frameworks)–1.2.3系统运行库层(UserL
ibraries)–1.2.4核心层(LinuxKernel)•1.3AndroidTelephony框架结构•1.4本章小结1.1SmartPhone智能手机的系统结构BPAP多媒体卡接口CameraLCDKEYBroadAudi
o……ABB/DBBRF串口AudioDriver天线随着手机芯片处理能力的提升、上网能力的扩展和发展(蓝牙、Wi-Fi、4G网络),手机应用得到非常广泛的扩大和发展。在SmartPhone的硬件设计上,采用处理能力比较强大的处理器
作为AP应用处理器,来支持开放手机操作系统及操作系统之上的扩展应用,由此可见智能手机发展的趋势和方向。1.2Android系统架构Android手机操作系统是一个分层的基于LinuxKernel智能手机操作系统,共有分为4层,从上到下分别是:Application
s(应用层)Framework(应用框架层)Libraries(系统运行库层)LinuxKernel(核心层)1.2Android系统架构应用层包括了Android各种应用程序,这些应用程序是使用Java语言开发,并
运行在Dalvik虚拟机上,在Android系统架构中的第一层。在Android源码和SDK中,Google已经捆绑和发布一些核心应用及源代码,如Dialer、MMS、日历、Google地图、浏览器、联系人等应用。1.2.1应用层(Applications)1.
2Android系统架构应用框架层是Google发布的核心应用时所使用的API框架,开发人员可以使用这些框架提供的API来快速开发自己的应用程序,Android中主要的一些组件如下:Views(视图)Resourc
eManager(资源管理器)NotificationManager(通知管理器)ActivityManager(Activity管理器)1.2.2应用框架层(Frameworks)1.2Android系统架构Android系统架构中的第三层为系统
运行库层(UserLibraries),这一层主要包含了手机系统平台必须的C/C++核心库、Dalvik虚拟机运行环境和HAL子层。1.C/C++核心库,如libc(系统C库)、MediaFramework(多媒体库)、OpenGL、SQLit
e、WebKit、SSL2.Dalvik虚拟机运行环境每一个Android应用程序都运行在Dalvik虚拟机之上,且每一个应用程序都有自己独立运行的进程空间;Dalvik虚拟机只执行DEX可执行文件。1.2.3系统运行库层(UserLibrari
es)1.2Android系统架构Android基于LinuxKernel提供核心系统服务,例如文件管理、内存管理、进程管理、网络堆栈、驱动模型等操作系统的基本服务能力。LinuxKernel内核同时也作为硬件和软件之间的抽象层,需要一些与移动设备相关驱动程序支持,主要的驱动有:DisplayDr
iver(显示驱动)、KeyboardDriver(键盘驱动)、AudioDriver(音频驱动)、PowerManagement(电源管理)、BinderIPC驱动、BluetoothDriver(蓝牙驱动)、WIFIDriver(Wi-Fi驱动)、CameraDri
ver(照相机驱动)等1.2.4核心层(LinuxKernel)1.3AndroidTelephony框架结构APSoftWareTelephonyFrameworkRadioInterfaceLayer(UserLibraries/HAL)
UserSpaceAppsLinuxKernelDrivers……BPSoftWareModemStackDriversModemAPIs……1.3AndroidTelephony框架结构1.AndroidTelephony的业务应用跨越
了AP和BP,AP与BP相互通信,符合前面介绍的SmartPhone智能手机硬件基本结构2.Android系统在AP应用处理器上运行,而Telephony运行在LinuxKernel之上的UserSpace空间。3.AndroidTelephony也采用了分层结构
的设计,共跨越了三层Applications、Framework和UserLibraries层,与Android操作系统整体分层结构保持一致;4.AndroidTelephony从上到下工分三层,Telephony应用、Telephon
y框架、RIL(RadioInterfaceLayer,无线通信接口层,主要位于UserLibraries层中的HAL层中,什么是HAL,接下来详细介绍)。5.BPSoftWare在BP基带处理器上运行,主要负责实际的无线通信能力处理,不在本书讨论的范围
。1.3AndroidTelephony框架结构了解AndroidHAL的设计与实现Applications&FrameworkRuntimeLinuxDriverRilStubWifiStub……HAL1.4本章小结1.还记得SmartPhone智能手机基本硬件中的AP和BP主从处理器
结构吗?基于Android平台手机也符合SmartPhone的体系结构,Android是基于LinuxKernel运行在AP上的智能手机操作系统,同时也是一个分层的操作系统平台,从上到下主要分为4层;在AP上运行的T
elephony相关应用与Android整体分层结构是保持一致,每层中的Telephony相关内容都是本书重点讲述的内容。2.Android手机中的基本通信能力跨越了AP和BP,AP和BP的相互协作完成了基本的通信功能,AP上的各种Teleph
ony应用,通过丰富的界面展示了通信相关的各种形式和状态,也可通过界面向BP发起通信能力相关的控制,且BP中负责实施具体的通信能力;3.这里提出一个问题,请读者结合本章内容思考:AndroidTelephony处于在整个Android智能手机平
台什么位置,HAL是什么?通过本章的学习,你清楚了吗?AndroidTelephony原理解析与开发指南第二章搭建Android源代码编译调试环境•2.1UbuntuLinux操作系统及工具安装–2.1.1PC配置建议–2.1.2Ubuntu安装光盘制作&安装过程–2.1.3安装OpenJDK
–2.1.4Ubuntu系统工具包更新升级•2.2Android源代码下载及编译过程–2.2.1源代码下载–2.2.2编译Android源代码–2.2.3编译单个模块第二章搭建Android源代码编译调试
环境•2.3AndroidStudio及SDK–2.3.1下载和配置AndroidStudio–2.3.2AndroidSDK下载及配置和使用–2.3.3使用AndroidSDK启动Android虚拟设备–2.3.4Android调试工具adb的使用方法–2.
3.5相关技巧汇总说明•2.4在Google手机上调试Android源码–2.4.1Google手机对应编译选项–2.4.2Google手机刷入工厂镜像–2.4.3编译本地镜像并刷入Google手机–2.4.4Google手机上调试Android源码•2.5本章小结
2.1UbuntuLinux操作系统及工具安装CPU类型:英特尔酷睿i5处理器或i7处理器内存:8GB或更大容量内存硬盘容量:500GB或1T显卡:集成显卡或其他独立显卡2.1.1PC配置建议2.1UbuntuLinux操作系统及工具安装1.选用64位Ubuntu17
.10桌面版操作系统2.Ubuntu向导式安装过程,其中的关键是磁盘合理分区。目前PC市场上硬盘都较大,2T已成为基本配置,本例中的/根目录挂载分区包括了/home用户数据分区(读者也可以分配独立的/home分区挂载点),在Android编译环境中,源代码的保存和编译都在此空间进行,所
以需要较大空间,因此将除去swap交换分区占用的磁盘空间剩余的磁盘空间都分配到此挂载分区。2.1.2Ubuntu安装光盘制作&安装过程2.1UbuntuLinux操作系统及工具安装注意编译Android源码需要选择不同的JDK。编译AndroidO源码需要
OpenJDK8,Ubuntu17.10系统中安装和验证OpenJDK的命令如下:$sudoapt-getupdate$sudoapt-getinstallopenjdk-8-jdk$java-versiono
penjdkversion"1.8.0_151"OpenJDKRuntimeEnvironment(build1.8.0_151-8u151-b12-0ubuntu0.17.10.2-b12)OpenJDK64-BitServerVM(build25.151-b12,mixedmo
de)2.1.3安装OpenJDK2.1UbuntuLinux操作系统及工具安装编译AndroidO源码还需要更新和安装Ubuntu的系统工具包,其Linux命令为:$sudoapt-getinstallgit-coregnupgflexbisongperfbuild-esse
ntialzipcurl\zlib1g-devgcc-multilibg++-multiliblibc6-dev-i386lib32ncurses5-dev\x11proto-core-devlibx11-devlib32z-d
evccachelibgl1-mesa-devlibxml2-utilsxsltprocunzip因网络异常或其它异常情况下,这些工具包可能不能完全下载和更新,那就需要在执行完此命令以后,再次执行此命令验证工具包
是否完整安装和更新0upgraded,0newlyinstalled,0toremoveand247notupgraded.说明所有的包没有遗漏,都已经安装完成,如每个工具包提示均已完成更新和安装,便可进入下一步操作,否则我们
继续执行此命令更新和安装剩余未完成的Ubuntu系统工具包。2.1.4Ubuntu系统工具包更新升级2.2Android源代码下载及编译过程步骤一:下载并配置repo$sudoapt-getinstallpyt
hon$curlhttps://storage.googleapis.com/git-repo-downloads/repo>repo$chmoda+xrepo注意:在~/用户主目录下新建一个bin目录,并将此目录设置
在PATH目录中;我们将保存常用的一些脚本或二进制可执行程序在此目录下,不必再更新系统环境变量就能在任意目录执行这些脚本或可执行程序。$mkdir~/bin$vi~/.bashrc在文件最后一行增加PATH=~
/bin:$PATH,保存退出$source.bashrc//立即生效配置的PATH目录$mvrepo~/bin/2.2.1下载源码2.2Android源代码下载及编译过程步骤二:配置git个人信息$gitco
nfig--globaluser.nametelephony$gitconfig--globaluser.emailtelephony@android.com查看配置的git信息$cat~/.gitconfig[user]name=telephonyemail=telepho
ny@android.com[color]ui=auto2.2.1下载源码2.2Android源代码下载及编译过程步骤三:获取源码分支并下载$repoinit-uhttps://android.googlesource.com/platform/mani
fest…*[newtag]android-8.0.0_r4->android-8.0.0_r4*[newtag]android-8.0.0_r7->android-8.0.0_r7*[newtag]android-8.0.0_r9->android-8.0.0_r9*[newtag]a
ndroid-8.1.0_r1->android-8.1.0_r1…可根据实际情况,选择最新的Android源码分支下载$repoinit-uhttps://android.googlesource.com/platform/manifest-b
android-8.1.0_r1repohasbeeninitializedin/home/android/Oreo$reposync–j8//开始下载2.2.1下载源码2.2Android源代码下载及编译过程环境变量初始化设置$sourcebuild/envsetup.sh//或者
.build/envsetup.sh加载编译脚本//使用第二种方法需要注意build前有一个空格includingdevice/asus/fugu/vendorsetup.shincludingdevice/generic/car/vendorsetup.shinclud
ingdevice/generic/mini-emulator-arm64/vendorsetup.sh……includingdevice/huawei/angler/vendorsetup.shincludingdevice/lge/bullhead/vendorse
tup.shincludingsdk/bash_completion/adb.bash2.2.2编译Android源码2.2Android源代码下载及编译过程选择编译产品$lunchYou'rebuildingonLinuxLunchmenu...pickacombo:1.
aosp_arm-eng2.aosp_arm64-eng……28.aosp_angler-userdebug29.aosp_bullhead-userdebug30.aosp_bullhead_svelte-userdebugWhichwouldyoulike?[aosp_arm
-eng]aosp_arm64-eng2.2.2编译Android源码2.2Android源代码下载及编译过程编译信息确认并开始编译======================================
======PLATFORM_VERSION_CODENAME=RELPLATFORM_VERSION=8.1.0//AndroidO版本TARGET_PRODUCT=aosp_arm64//lunch选择aosp_arm64-engTARGET_BUILD_VARIANT=eng……BUILD_
ID=OPM1.171019.011//编译号OUT_DIR=outAUX_OS_VARIANT_LIST=============================================$make–j82.2.2编译Android
源码2.2Android源代码下载及编译过程$mmmpackages/service/Telephony///编译TeleService应用$mmmframeworks/base///编译framework.jar$cdpa
ckages/service/Telephony//TeleService应用代码目录$mm//编译TeleService模块$cd$oreo$cdframeworks/base//进入framework代码目录$mm//编译framework$cd$oreo$makeTele
Service//编译TeleService应用$makeframework//编译framework.jar应用2.2.3编译单个模块2.3AndroidStudio及SDKAndroidStudio的下载地址:https://developer.an
droid.com/studio/index.html,Google提供了Windows32/64、Mac和Linux不同的4个平台版本供我们下载和使用。选择Linux版本,下载android-studio-ide-171.44430
03-linux.zip文件到本地。$unzipandroid-studio-ide-171.4443003-linux.zip$cdandroid-studio/bin$./studio.sh//启动AndroidSt
udio2.3.1下载和配置AndroidStudio2.3AndroidStudio及SDK(1)第一次启动AndroidStudio将启动安装向导,将在线更新AndroidSDK、Gradle等工具包,要关闭启动安装向导,可修改bin目录下的ide
a.properties配置文件,增加一行配置信息如下:disable.android.first.run=true(2)每次启动AndroidStudio都需要进入android-studio/bin目录,再运行studio.sh脚本,操作较多,比较省事的办法是增加
一个desktop图标,在UbuntuActivity菜单中方便启动,具体的操作如下:$sudovi/usr/share/applications/androidstudio.desktop//需要root权限增加以下配置信息[DesktopEntry]Name=
androidstudioComment=androidstudioType=ApplicationTerminal=falseIcon=/home/android/tools/android-studio/bin
/studio.pngExec=/home/android/tools/android-studio/bin/studio.sh鼠标左键单击UbuntuActivity,输入androidstudio即可匹配出AndroidStudio应用,鼠标左键单击And
roidStudio图标即可启动它了。2.3.1下载和配置AndroidStudio2.3AndroidStudio及SDKAndroidSDK的下载页面与AndroidStudio在同一个页面:https://developer.android.com/
studio/index.html,Google提供了Windows、Mac和Linux三个平台的版本供我们下载和使用。同样选择Linux版本,下载sdk-tools-linux-3859397.zip到本地(1)此版本的AndroidSDK是基本的And
roid命令行工具,可以使用此工具中包含的sdkmanager工具下载和更新其他的SDK工具包。(2)使用AndroidStudio通过界面的方式管理更加方便的管理AndroidSDK。启动AndroidStudio,在Configure
弹出的菜单中选择SDKManager或者在AndroidStudioFile菜单->Settings界面中,进入AndroidSDK管理界面。(3)SDKManager界面列出了Android已经发布的所有SDK版本,选择安装的AndroidSDK版本越多,下载和安装时间就越长,需要的
磁盘空间就越大;读者可以根据自己的兴趣和需要选择下载。(4)AndroidSDK安装完成后,还请记录SDK中对应工具的PATH路径。2.3.2AndroidSDK下载及配置和使用2.3AndroidStudio及SD
K启动AndroidStudio,Tools菜单->Android选项->AVDManager,打开AVDManager,通过界面向导式的操作创建虚拟设备。2.3.3使用AndroidSDK启动Android虚拟设备2.3And
roidStudio及SDKAndroid模拟设备启动完成后,会默认5554端口连接到计算机,这时可运行adbdevices命令查看连接到本地计算机上的Android设备列表,详情如下:$adbdev
icesListofdevicesattachedemulator-5554device//device状态为正常情况,可查看模拟器运行日志查看虚拟机运行日志:adblogcat查看应用日志,可结合|grep过滤匹配自己想查
看的日志内容。adblogcat–bradio查看RIL日志。2.3.4Android调试工具adb的使用方法2.3AndroidStudio及SDK1adblogcat日志输出脚本我们在开发、调试Android代码过程中使用最多的就是adb命令
,通过它我们可以获取到想要的日志信息,帮助我们分析、定位程序逻辑。查看main日志的命令:adblogcat–vthreadtime查看radio日志的命令:adblogcat-vtime–bradio查看event日志的命令:adblogcat-v
time-bevents2.3.5相关技巧汇总2.3AndroidStudio及SDK2查找代码脚本面对Android浩瀚的代码量,如何能快速的找到一些关键字呢?Android源码中已经给您准备了对应的脚本工具,就在源码主目录下的
build/envsetup.sh文件中。$geditbuild/envsetup.shfunctionjgrep()//查找并匹配java文件文件中对应的关键字{find.-name.repo-pr
une-o-name.git-prune-o-nameout-prune-o-typef-name"*\.java"\-execgrep--color-n"$@"{}+}functioncgrep()//查找并匹配c相关文件文件中对应的关键字{find.
-name.repo-prune-o-name.git-prune-o-nameout-prune-o-typef\(-name'*.c'-o-name'*.cc'-o-name'*.cpp'-o-name'*.h'-o-name'*.hpp'\)\-
execgrep--color-n"$@"{}+}……2.3.5相关技巧汇总2.4在Google手机上调试Android源码2.4.1Google手机对应编译选项终端代码名称编译选项PixelXLmarlinaosp_marlin-userdebugPixelsailfish
aosp_sailfish-userdebugHiKey(开发板)hikeyhikey-userdebugNexus6Pangleraosp_angler-userdebugNexus5Xbullheadaosp_b
ullhead-userdebugNexus6shamuaosp_shamu-userdebug2.4在Google手机上调试Android源码2.4.2Google手机刷入工厂镜像GoogleNexus和Pixel系列手机的工厂
镜像文件的下载地址:https://developers.google.com/android/images,Nexus6P手机对应的FactoryImages是angler8.1.0(OPM1.171019
.011,Dec2017),即Nexus6P手机Android8.1.0工厂刷机镜像。2.4在Google手机上调试Android源码2.4.3编译本地镜像并刷入Google手机1.下载Google手机对应的驱动文件DriverBinarieshttps://devel
opers.google.com/android/drivers,选择Nexus6P("angler")binariesforAndroid8.1.0(OPM1.171019.011)的两个Driver文件Vendorimage和Qualcomm,
对应的文件名分别是:huawei-angler-opm1.171019.011-41db8ed5.tgz和qcom-angler-opm1.171019.011-f7e511bb.tgz,解压后是两个Shell脚本:extract-huawei-angler.sh
和extract-qcom-angler.sh,并将这两个文件拷贝到AndroidO源码的主目录下。2.4在Google手机上调试Android源码2.4.3编译本地镜像并刷入Google手机2.DriverBinaries导入到Android8.1.0源码工程https://de
velopers.google.com/android/drivers,选择Nexus6P("angler")binariesforAndroid8.1.0(OPM1.171019.011)的两个Driver文件Vendorimage和Qualc
omm,对应的文件名分别是:huawei-angler-opm1.171019.011-41db8ed5.tgz和qcom-angler-opm1.171019.011-f7e511bb.tgz,解压后是两个Shell脚本:extrac
t-huawei-angler.sh和extract-qcom-angler.sh,并将这两个文件拷贝到AndroidO源码的主目录下。2.4在Google手机上调试Android源码2.4.3编译本地镜像并
刷入Google手机3.使用angler编译选项重新编译前面的编译Android源码,lunch选项是aosp_arm64-eng,而现在导入了Nexus6P的驱动文件后,编译Nexus6P手机对应的镜像文件,在lunch的时候需要选择aosp_angler-userdebug
,并以全新的方式编译整个代码,最简单的方式就是删除保存编译结果的out目录。2.4在Google手机上调试Android源码2.4.3编译本地镜像并刷入Google手机4.fastboot刷入本地编译出的镜像文件$sudo–s//一定要使用root账号刷机,否则没有
权限,fastboot将刷机失败#fastbootflashbootboot.img#fastbootflashsystemsystem.img#fastbootflashvendorvendor.img#fastbootflashus
erdatauserdata.img#fastbootreboot2.4在Google手机上调试Android源码2.4.4Google手机上调试Android源码选择com.android.phone进程加载的代码入口文件PhoneApp.java,作为修改实例,其相对路
径为:packages/services/Telephony/src/com/android/phone/PhoneApp.java。在AndroidStudio连续快速的两次按下右Shift按键,输入PhoneApp.java将快速匹配出该文件,在代码中的onCreate方
法增加一行打印日志的代码来验证代码修改后是否能成功运行在Google手机上,代码修改和编译详情如下:@OverridepublicvoidonCreate(){android.util.Log.d("Android","MyCode
runontheNexus6P");……}$cd$oreo$mmmpackages/services/Telephony/[100%10/10]Install:out/target/product/angler/sys
tem/priv-app/TeleService/TeleService.apk2.4在Google手机上调试Android源码2.4.4Google手机上调试Android源码TeleService.apk,需要将此文件push到Ne
xus6P手机上运行,再此之前还需要remount手机,只有remount成功以后才能pushapk系统应用、系统jar包、so动态库等文件到手机/system挂载点。具体操作如下:$adbrootrestartingadbdasroot$adb
remountdm_verityisenabledonthesystempartition.Use"adbdisable-verity"todisableverity.Ifyoudonot,remountmaysucceed,however,youw
illstillnotbeabletowritetothesevolumes.remountsucceeded$adbdisable-verityVeritydisabledon/systemNowrebootyourdeviceforsettingstotakeeffe
ct//需要重启手机$adbreboot$adbrootrestartingadbdasroot$adbremount$remountsucceeded2.4在Google手机上调试Android源码2.4.4Google手机上调试Android源码进入out/target/product/ang
ler/system/priv-app/TeleService/目录查证编译后文件更新的情况,除了TeleService.apk文件更新,还有oat目录也同时更新了,该目录下有TeleService.odex和TeleService.vdex,这两
个文件同样需要安装到Nexus6P手机上对应的目录,否则我们的修改不会生效。具体操作如下:$treeout/target/product/angler/system/priv-app/TeleService/oat
out/target/product/angler/system/priv-app/TeleService/oat└──arm64├──TeleService.odex└──TeleService.vdex$adbpushout/target/product/angle
r/system/priv-app/TeleService/TeleService.apk/system/priv-app/TeleService/out/target/product/angler/sys
tem/priv-app/TeleService/TeleService.apk:1filepushed.21.0MB/s(7691558bytesin0.350s)$adbpushout/target/product/angler/system/priv-app/TeleService/oa
t/system/priv-app/TeleService///重点关注push的目录没有oatout/target/product/angler/system/priv-app/TeleService/oat/:2filespush
ed.10.9MB/s(2032058bytesin0.178s)$adbreboot//重启手机或是killcom.android.phone的进程重启AndroidTelephony原理解析与开发指南第三章深入解析通话流程•3.1拨号流程
分析–3.1.1打开Nexus6P手机的拨号盘–3.1.2进入拨号界面DialtactsActivity–3.1.3DialpadFragment拨号盘–3.1.4ITelecomService接收拨号请求服务–3.1.5Ca
llsManager拨号流程处理–3.1.6IInCallService服务的响应过程–3.1.7继续分析CallsManager.placeOutgoingCall–3.1.8Telecom应用拨号流程回顾与总结–3.1.9IConnectionService服务响应过程–3.1.10Tele
comAdapter接收消息回调–3.1.11拨号流程总结第三章深入解析通话流程•3.2来电流程分析–3.2.1分析radio来电日志–3.2.2UNSOL_RESPONSE_CALL_STATE_CHANGED消息处理–3.2.3扩展RegistrantLis
t消息处理机制–3.2.4GsmCdmaCallTracker消息处理–3.2.5ITelecomService处理来电消息–3.2.6来电流程总结–3.3通话总结–3.3.1通话关键代码汇总–3.3.2通话状态更新消息上报流程–3.3
.3控制通话消息下发流程•3.4建立ANDROID通话模型•3.5本章小结3.1拨号流程分析通过数据线将Nexus6P手机连接到计算机,打开Ubuntu命令行,首先使用adbdevices查看和确认手机与计算机连接是否成功,然后使用adblogcat相关命令查看Nex
us6P手机的运行日志)$adblogcat-vtime-beventsI/am_new_intent(797):[0,69578539,51,com.android.dialer/.app.DialtactsActivity,android.inten
t.action.MAIN,NULL,NULL,270532608]点击电话按钮进入拨号界面,ActivityManagerService将启动com.android.dialer包下的DialtactsActivity3.1.1打开Nexus6P手机的拨号
盘3.1拨号流程分析查看DialtactsActivity的onClick方法,发现拨号浮动按钮的响应事件为调用当前类的showDialpadFragment方法,从而可以得知弹出拨号盘对应的代码是Dialp
adFragment.java需要重点关注:packages/apps/Dialer/java/com/android/dialer/app/DialtactsActivity.java和dialtacts_activity.xml代码代码库packages
/apps/Dialer将编译出Dialer.apk应用程序,统一称为Dialer应用3.1.2进入拨号界面DialtactsActivity3.1拨号流程分析Dialer应用中(com.android.dialer进程内)的拨号流程主要完成的任务是:DialpadFragme
nt提供用户拨号的交互界面CallIntentBuilder创建拨号请求的intent对象TelecomManager继续传递拨号请求intent对象3.1.3DialpadFragment拨号盘3.1拨号流程分析3.1.3Dia
lpadFragment拨号盘3.1拨号流程分析ITelecomService的接口服务实现逻辑是TelecomServiceImpl.java,其代码文件的详细路径是:packages/services/Telecomm/src/com
/android/server/telecom/TelecomServiceImpl.java。代码库packages/services/Telecomm,编译Telecom.apk应用程序,统一称为Telecom应用。3.1.4ITelecomService
接收拨号请求服务3.1拨号流程分析packages/services/Telecomm/AndroidManifest.xml文件服务定义的关键信息<serviceandroid:name=".components.TelecomService"android:si
ngleUser="true"android:process="system">//指定运行进程为system_server系统进程<intent-filter><actionandroid:name="android.telecom.ITelecomService"/></intent-fil
ter></service>3.1.4ITelecomService接收拨号请求服务跟进TelecomServiceImpl.java中的placeCall方法中的逻辑,将响应Dialer应用发起的跨进程服务接口
调用,最终调用调用了CallsManager对象startOutgoingCall和placeOutgoingCall两个方法。3.1拨号流程分析3.1.5CallsManager拨号流程处理Telecom应用中完成了第一次的bindServic
e和对应Service的接口调用,对bindToService流程进行回顾和总结3.1拨号流程分析3.1.5CallsManager拨号流程处理总结Telecom应用中的拨号流程3.1拨号流程分析3.1.6IInCallService服务的响应过程InCallService的
onBind流程3.1拨号流程分析3.1.6IInCallService服务的响应过程InCallService的setInCallAdapter流程3.1拨号流程分析3.1.6IInCallService服务的响应过程IInCallSer
vice的addCall流程3.1拨号流程分析3.1.7继续分析CallsManager.placeOutgoingCall拨号流程中Telecom第二次bindService与第一次bindService
的处理过程非常相似,分三步走:bindServiceaddConnectionServiceAdaptercreateConnection第二次bindService的服务对象为:SERVICE_INTERFACE,即“android.telecom.Connec
tionService”3.1拨号流程分析3.1.8Telecom应用拨号流程回顾与总结拨号流程跟踪到这一步,已经涉及到三个应用的消息传递Dialer、Telecom和TeleService,可见流程
复杂和漫长,消息类型又相近,比如,两次服务的bind过程,几个Call对象的创建、转换和传递,各种Listener消息回调等等。Telecom应用CallsManager对象的startOutgoingCall和placeOutgoingCall
方法,两次bind绑定不同的服务,并且过程也非常相似,分三步走,总结如下:bindServicesetInCallAdapter/addConnectionServiceAdapteraddCall/createConnection3.1拨号流程分析3
.1.9IConnectionService服务响应过程TeleService应用中的拨号流程3.1拨号流程分析3.1.10TelecomAdapter接收消息回调3.1拨号流程分析3.1.11拨号流程总结拨号流程,需要把拨号请求发送到RIL层,我们跟
踪到了五个代码库和三个Android系统应用Dialer、Telecom、TeleService,需要我们重点掌握以下几点。拨号入口DialpadFragment第一次跨进程访问Telecom应用第一次bindSer
viceTelecom应用第二次bindServiceAdapter第一次回调Telecom应用中的拨号流程Dialer和TeleService应用中对应服务的响应3.2来电流程分析3.2.1分析radio来电日志I/RILQ(604):(0/604):RIL[0][
event]qcril_qmi_voice_all_call_status_ind_hdlr:callstateINCOMINGforconnid1I/RILQ(604):(0/604):RIL[0][event]qcril_qmi_voice_voip_create_call
_info_entry:Createdcallinfoentry0x7a49883000withcallandroidid1,qmiid1,mediaid7D/RILJ(1109):[UNSL]<UNSOL_RESPONSE_CALL_STATE_CHANGED[SUB0]D/RILJ(1109)
:[4185]>GET_CURRENT_CALLS[SUB0]D/RILJ(1109):[4185]<GET_CURRENT_CALLS{[id=1,INCOMING,toa=129,norm,mt,0,voc,noevp,,cli=1,,1]}[SUB0]D/GsmCdmaC
allTracker(1109):[GsmCdmaCallTracker]pendingMo=null,dc=id=1,INCOMING,toa=129,norm,mt,0,voc,noevp,,cli=1,,1D/GsmCdmaCallTracker(1
109):[GsmCdmaCallTracker]updatephonestate,old=IDLEnew=RINGINGD/Phone(1109):EventEVENT_CALL_RING_CONTINUEReceivedstate=RINGINGD/Phone(1109):Sendingnot
ifyIncomingRing3.2来电流程分析3.2.2UNSOL_RESPONSE_CALL_STATE_CHANGED消息处理Java代码中查找关键字“UNSOL_RESPONSE_CALL_STATE_CHANGED”,发现RadioIndication类的callStateChange
d方法调用。最终发现此方法调用是Native层的Android服务跨进程调用。继续查看mRil.mCallStateRegistrants.notifyRegistrants调用,mRil即RILJava对象,其mCallStateRe
gistrants属性以及相关更新的方法在RIL的父类BaseCommands中定义和实现3.2来电流程分析3.2.3扩展RegistrantList消息处理机制RegistrantList消息处理机制包括两个重要的Java类:Registran
tList.java和Registrant.java。这里有一个重要的关键字就是“registrant”,中文意思为“登记者”。其实这里采用了GoF中非常著名的设计模式——观察者模式3.2来电流程分析3.2.4GsmCdmaCallTracker消息处理3.2来电
流程分析3.2.5ITelecomService处理来电消息ITelecomService处理来电消息有四个核心处理机制:第一次跨进程服务接口调用Telecom应用第一次bindServiceTelecom应用第二次bindSer
viceIncomingCallFilter作为Telecom应用独立的业务3.2来电流程分析3.2.6来电流程总结来电流程,首先是RIL层接收到消息,再分别传递给TeleService、Telecom和Dialer这三个系统应用。来电入
口分析通过radio日志并结合代码的分析,两次RegistrantList消息通知。1.第一次跨进程访问来电流程中第一次跨进程访问,将从TeleService应用访问到Telecom应用中的ITelecomService服务接口addNewIncomingCall,
重点参考framework/base代码库下的TelecomManager.java代码中的处理逻辑。2.Telecom应用第一次bindServiceTelecom应用接收到来电消息,ConnectionService
Wrapper对象的createConnection方法将被调用,与拨号流程中的第二次bandService流程一致。3.Telecom应用第二次bindServiceTeleService应用创建Inco
mingTelephonyConnection后,将通过AdapterBinder对象跨进程的调用ConnectionServiceWrapper的mAdapter对象中的服务接口,通过Telecom中对来电号码
的过滤处理,最终会调用到InCallController的bindToService方法,与拨号流程中与IInCallService服务的交互一致3.3通话总结3.3.1通话关键代码汇总主动拨号和被动来电流程的分析过程中,涉及的代码共有5个代码库,
分别是:packages/apps/Dialerpackages/services/Telecommpackages/services/Telephonyframeworks/base/telecommframeworks/opt/teleph
ony3.3通话总结3.3.2通话状态更新消息上报流程我们拨号成功后,对方接听了此路通话,那么通话界面将更新当前通话为通话中的状态,并开始通话计时,可以理解为Modem->RIL->TeleService
->Telecom->Dialer一层一层上报通话状态为通话中的消息处理和发送过程,重点掌握以下几点:三个应用的Call信息传递RegistrantList消息处理TelephonyConnection对象的Listener注册IConnec
tionServiceAdapter接口汇总IInCallService接口汇总3.3通话总结3.3.3控制通话消息下发流程我们在通话界面,想更改当前通话状态,比如挂断/接听当前接收到来电,挂断或保持通当前通话等操作,我
们可以理解为控制通话消息下发的过程,从Dialer->Telecom->TeleService->RIL->Modem通话控制消息一层一层的下发,最终交给Modem处理具体的通话控制三个应用的控制消息传递IInCallAdapter接口汇总IConnectionServ
ice接口汇总3.4建立Android通话模型Android通话模型3.4建立Android通话模型3.4.1系统的分层Dialer、Telecom和TeleService三大应用可理解为:Dialer应用是普通的AndroidApp应用,其运行进程的用户信息和进程
信息也能说明此问题;Telecom应用运行在system_server进程上,其进程用户名为system系统用户,说明它是在AndroidFramework框架层;TeleService应用运行的进程名是com.android.phone,其进程的用
户名是radio,承载着TelephonyCall协议栈,同样可以认为它运行在AndroidFramework框架层;最后是RIL它运行在HAL硬件抽象层。3.4建立Android通话模型3.4.2交互方式
Dialer、Telecom、TeleService和RIL都是通过服务进行交互的,图3-16中,它们之间有箭头连接的都是通过Service跨进程的接口调用实现的。Dialer与TeleService之间没有直接的消息传递,都是通过Telecom进行消息中转
,Telecom与RIL同样没有直接的消息传递,通过TeleService进行消息中转。通过Service进行跨进程接口调用实现消息,Service接口调用本身就是同步的接口调用,在Service端的实现将转换为异步的方式处理,待消息处理完成后,在使用回调的接口传递消息处理的结果。3.4
建立Android通话模型3.4.3对通话相关流程分解根据消息的传递方向,可分解成两大类:第一类控制通话消息下发流程:应用层通过框架层向RIL层发起通话管理和控制相关RIL请求,RIL层转换成对应的消息发送给Modem执行,其中包括拨号、接听电话、拒接电话、保持、恢复通话等;第二类通话
状态更新消息上报流程:RIL层接收到Modem的Call状态变化通知,通过框架层向应用层发起通话状态变化通知,包括来电、电话接通、进入通话中等通话状态改变。3.5本章小结本章根据通话的主要四个流程结合代码进行了详细的解析和总结:a)主动拨号流程b)被动接收来电流程c)本地主动控制
通话状态流程d)通话状态变更消息上报流程这些通话相关流程之间有什么关系或者规律呢?建立Android通话模型可以回答这个问题,在学习Telephony过程中,一定要掌握和理解这个模型。2.4在Goog
le手机上调试Android源码2.4.4Google手机上调试Android源码日志验证代码修改内容$mlog|grep-i"nexus6p"//mlog-sAndroid02-2600:01:28.07746714671DAndroid:MyCoderunontheNexu
s6P“02-2600:01:28.077”:以手机上时间为准的时间戳“Android”:是打印日志的TAG“MyCoderunontheNexus6P”:是日志打印内容到此,我们已经成功搭建了Android源代码调试环境,从An
droid官网下载Android8.1.0源码、AndroidStudio、AndroidSDK以及Nexus6P手机对应的FactoryImages和DriverBinaries,然后成功编译本地镜像文件,刷入Android8.1.0userdebug版本的a
ngler手机镜像文件,最后修改TeleService模块代码,编译后push到Nexus6P手机上验证我们的代码修改是否生效。2.5本章小结1.本章主要介绍了如何搭建Android源码下载、编译和调试环境以及相关工具的使用及技巧,包括UbuntuLin
ux系统、源代码编译方法、AndroidSDK、AndroidStudio等使用方法,最后是对GoogleNexus6P手机的刷机和调试环境的构建。2.这些内容是我们深入学习Android源码的基础,希望读者能够根据本
章内容搭建起自己的编译调试环境。如果没有Linux的基础,还得多多学习Linux常用命令,可在UbuntuLinux系统中实际动手操作一下。AndroidTelephony原理解析与开发指南第四章详解Telecom•4.1TELECOM应用加载入口–4.1.1TelecomManager核心逻辑
分析–4.1.2Telecom应用代码汇总–4.1.3ITelecomService的onBind过程•4.2TELECOM交互模型–4.2.1汇总frameworks/base/telecomm代码–4.2.2bindIInCallSe
rvice机制–4.2.3bindIConnectionService机制–4.2.4演进Telecom交互模型•4.3核心LISTENER回调消息处理–4.3.1CallsManagerListener–4.3
.2Call.Listener–4.3.3CreateConnectionResponse–4.3.4总结Listener消息•4.4扩展CALLSMANAGER–4.4.1记录通话日志–4.4.2耳机Hook事件–4.4.3通知栏信息同步•4.5本章小结
4.1Telecom应用加载入口对象的创建和获取SystemServiceRegistry类中的构造方法是private的,也就是说没有SystemServiceRegistry对象的存在,在它的static静态代码块中将创建和保存TelecomManager对象;此对象的创建时
机在system_server进程的启动过程中。TelecomManager类中的from方法,将使用Context上下文对象的getSystemService,将获取SystemServiceRegistry中保存的TelecomManager普通Java对象。IT
elecomService系统服务com.android.server.telecom.components.TelecomService类作为Telecom应用的加载入口,在SystemServer系统启动过程
中加载。4.1.1TelecomManager核心逻辑分析4.1Telecom应用加载入口4.1.2Telecom应用代码汇总4.1Telecom应用加载入口4.1.3ITelecomService的onBind过程TelecomService类onBind方法的逻辑比较简单,有两个
非常重要的内容:1.创建TelecomSystem对象,将初始化Telecom应用中的核心对象2.获取Binder对象并返回4.2Telecom交互模型4.2.1汇总frameworks/base/telecomm代码4.2Telecom
交互模型4.2.2bindIInCallService机制bindIInCallService的过程将与Dialer应用中的服务交互,最终展示和更新通话界面,其中关键的三个步骤bindServicesetInCallAdapteraddCall4.2Telecom交互模型
4.2.3bindIConnectionService机制bindIConnectionService,它将与TeleService应用中的服务交互,发出通话控制消息或是接收通话状态更新的消息;其中关键的三个步骤bindServiceaddConnectionServic
eAdaptercreateConnection4.2Telecom交互模型4.2.4演进Telecom交互模型4.2Telecom交互模型4.2.4演进Telecom交互模型4.3核心Listener回调消息处理4.3.1CallsManagerListener4.3核心Listen
er回调消息处理4.3.2Call.Listener4.3核心Listener回调消息处理4.3.3CreateConnectionResponseCreateConnectionResponse接口定义了两个方法:handleCreateConnectionSuccess和handleCr
eateConnectionFailure,它总共有两个子类Call和CreateConnectionProcessor,Call和CreateConnectionProcessor都是CreateConnectionResponse接口对象。reateConnectionProcessor的
mCallResponse属性是Call对象,ConnectionServiceWrapper的mPendingResponses将保存CreateConnectionProcessor对象列表。4.3核心Listener回调消
息处理4.3.4总结Listener消息4.4扩展CallsManager4.4扩展CallsManager4.4.1记录通话日志CallLogManager类负责记录通话日志,它重写了CallsManagerListener父类on
CallStateChanged一个方法,在响应CallsManagerListener消息回调时,通过判断通话的发起方和通话断开的DisconnectCause将通话日志分为呼出、呼入、拒绝和未接四个类型4.4扩展CallsManager4
.4.2耳机Hook事件HeadsetMediaButton类负责监听耳机hook按键的事件,在事件消息回调响应过程中,接收到耳机Hook按键的长按或短按事件,交给CallsManager对象的onMediaButton方法处理,将有接听电话、
拒接电话和通话静音三个操作。4.4扩展CallsManager4.4.3通知栏信息同步IncomingCallNotifier类负责手机状态栏显示或隐藏来电信息,通过onCallAdded、onCallRemoved、onC
allStateChanged方法的消息回调,在updateIncomingCall方法中进行显示或隐藏来电信息StatusBarNotifier类负责通知栏通话静音、扬声器状态的同步显示,仅重写了父类CallsManagerListener的onCallRemoved方法,通话断开的时
候调用notifyMute或notifySpeakerphone取消通知栏通话静音、扬声器的信息显示。4.5本章小结本章详细总结和演进Telecom交互模型以及Listener消息回调机制。1.Telecom消息入口ITelecomService、IInCal
lAdapter和IConnectionServiceAdapter三个Service,作为三种不同类型的消息的入口。2.Telecom消息出口InCallController和ConnectionSe
rviceWrapper两次bindService操作,作为Telecom应用消息的出口。3.下发顺时针上报逆时针消息机制Telecom应用通过消息入口和出口的5个Service,承载两种类型的消息:控制通话下发顺时
针方向消息处理和上报通话状态变化逆时针方法消息处理。4.Listener消息处理机制Call和CallsManager对象作为Listener回调消息的交换中心,掌握图4-12中Listener对象关系。5.Call
sManagerListener12个CallsManagerListener对象接收到CallsManagermListeners消息回调,判断当前Call的属性和状态,将实现通话日志、通知栏信息同步、电源管理、耳机交互等通话扩展的功能点。AndroidTelephony原理解析与
开发指南第五章详解TeleService•5.1加载过程分析–5.1.1应用基本信息–5.1.2PhoneGlobals.onCreate–5.1.3TelephonyGlobals.onCreate•5
.2TELEPHONYPHONE–5.2.1GsmCdmaPhone–5.2.2Composition组合关系–5.2.3FacadePattern–5.2.4Handler消息处理机制•5.3扩展PHONEACCOUNT–
5.3.1PhoneAccount初始化过程–5.3.2PhoneAccount注册响应–5.3.3PhoneAccount在拨号流程中的作用分析–5.3.4小结•5.4TELESERVICE服务–5.4.1phone系统服务–5.4.2isub系统服务–5.4.3ICon
nectionService应用服务•5.5本章小结5.1加载过程分析5.1加载过程分析查看TeleService系统应用AndroidManifest.xml配置文件,定义了此应用加载方式和加载入口,配置信息详情如下:<manifestxmlns:android="http:/
/schemas.android.com/apk/res/android"xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"package="com.android.phon
e"coreApp="true"android:sharedUserId="android.uid.phone"android:sharedUserLabel="@string/phoneAppLabel"><applicationandroid:name="PhoneApp"android:pe
rsistent="true"android:label="@string/phoneAppLabel"……5.1.1应用基本信息5.1加载过程分析TeleService系统应用加载入口的逻辑相对简单,详情如下:publicclassPho
neAppextendsApplication{//继承系统Application类@Override//重写父类的onCreate方法publicvoidonCreate(){//非常关键,除系统调用,其他情况下不进行加载if(UserHandle.myUs
erId()==0){//Wearerunningastheprimaryuser,soshouldbringupthe//globalphonestate.mPhoneGlobals=newPhoneGlobals(this
);mPhoneGlobals.onCreate();mTelephonyGlobals=newTelephonyGlobals(this);mTelephonyGlobals.onCreate();}}}5.1.1应用基本信息5.1加载过程分析PhoneGlobals对象的onCreate方法
中的核心逻辑,总结出以下四个关键点创建Phone对象CallManager的消息注册初始化ITelephony服务其他操作5.1.2PhoneGlobals.onCreate5.1加载过程分析TelephonyGlobals.onCr
eate,其代码逻辑详情如下:publicvoidonCreate(){//MakethisworkwithMulti-SIMdevicesPhone[]phones=PhoneFactory.getPhones();for(Phonephone:
phones){//初始化TTYmTtyManagers.add(newTtyManager(mContext,phone));}TelecomAccountRegistry.getInstance(m
Context).setupOnBoot();//加载PhoneAccount}5.1.3TelephonyGlobals.onCreate5.2TelephonyPhoneTeleService系统应用的加载过
程,可以理解为Telephony业务模型的加载过程,创建以GsmCdmaPhone对象为中心,同步创建GsmCdmaCallTracker、ServiceStateTracker、DcTracker和RILJ等关键业务对象的过程,同时向RILJ对象注
册HandlerMessage回调消息。5.2TelephonyPhone5.2.1GsmCdmaPhone5.2TelephonyPhone5.2.2Composition组合关系5.2TelephonyPhone5.2.3FacadePattern5.2TelephonyPho
ne5.2.4Handler消息处理机制在GsmCdmaPhone类中的Handler消息处理机制,可分成以下三个大类:基本Handler消息注册和响应机制。RegistrantList封装的Handler消息运行机制。创建的Message对象作为RILJ类Callback
的回调对象。5.3扩展PhoneAccount5.3.1PhoneAccount初始化过程TelecomAccountRegistry完成PhoneAccount初始化业务逻辑,可分为两个关键步骤:创建TelecomAccountRegistry对象调
用setupOnBoot方法5.3扩展PhoneAccount5.3.2PhoneAccount注册响应调用TelecomManager的registerPhoneAccount方法注册PhoneAccount,Telecom系统应用中的调用过程:TelecomManager.regist
erPhoneAccount->getTelecomService().registerPhoneAccount->TelecomServiceImpl.mBinderImpl.registerPhoneAc
count->mPhoneAccountRegistrar.registerPhoneAccount->addOrReplacePhoneAccount5.3扩展PhoneAccount5.3.2PhoneAccount注册响应Nexus6P手机中导出记录
PhoneAccount的XML文件,导出的adbpull命令,以及此文件的关键内容信息,详情如下:$adbpull/data/user_de/0/com.android.server.telecom/files/phone-ac
count-registrar-state.xml.<phone_account_registrar_stateversion="9">//版本号9<default_outgoing/><accounts><phone_account><account_handle><phone_account_
handle><component_name>com.android.phone/com.android.services.telephony.TelephonyConnectionService</component_name>//服务信
息<id>8986011785110158XXXX</id>//SIM卡的ICCID<user_serial_number>0</user_serial_number>//0UserHandler,即系统用户</phone_account_handl
e></account_handle><handle>tel:%2B86186XXXXXXXX</handle>//手机号码<subscription_number>tel:%2B86186XXXXXXXX</subscri
ption_number><capabilities>54</capabilities>//GsmCdmaPhone对象的通话能力取值5.3扩展PhoneAccount5.3.3PhoneAccount在拨号流程中的作用分析PhoneAccount对象的使用和传递,从以下四个关键流程
分别进行分析1.startOutgoingCall2.placeOutgoingCall3.createConnection4.IConnectionService5.3扩展PhoneAccount5.3.4小结5.4TeleService服务5.4.1phone系统服务privatePhoneI
nterfaceManager(PhoneGlobalsapp,Phonephone){//私有构造方法mApp=app;mPhone=phone;mCM=PhoneGlobals.getInstance().mCM;......publish();}privatevo
idpublish(){ServiceManager.addService("phone",this);//加入phone名称的系统服务}5.4TeleService服务5.4.2isub系统服务isub系统服务同样
是在TeleService系统应用加载过程创建和发布的,初始化调用过程是:PhoneApp.onCreate->PhoneGlobals.onCreate->PhoneFactory.makeDefaultP
hones->makeDefaultPhone->SubscriptionController.init5.4TeleService服务5.4.3IConnectionService应用服务回顾Telecom交互模型bindIConnec
tionService处理机制,IConnectionService服务接收到createConnection请求,通过ConnectionRequest对象获取相关信息后创建TelephonyConnection对象,并完成通话相关操作后,通过TelephonyConne
ction对象的相关信息,创建ParcelableConnection对象返回给Telecom进程。5.4TeleService服务5.4.3IConnectionService应用服务1.区分ConnectionCon
nectionRequest和ParcelableConnection均实现了Parcelable接口,可跨进程进行传递,在Telecom和TeleService两个系统应用进程间传递2.TelephonyConnection对象创建过程拨号
流程中TelephonyConnection对象的创建过程如下:TelephonyConnectionService.createConnection->onCreateOutgoingConnection->getTelephonyConnection来电流程中TelephonyConnect
ion对象的创建过程如下:TelephonyConnectionService.createConnection->onCreateIncomingConnection5.4TeleService服务5.4.3IConnectionSer
vice应用服务3.setOriginalConnection通话流程中创建TelephonyConnection对象,都会初始化originalConnection属性,这样便与TelephonyVoiceCall语音通话模型建立起了关联关系。4.Telepho
nyConnection消息处理机制拨号流程中TelephonyConnectionService响应Telecom系统应用发起的通话控制请求,首先是通过callId获取Connection对象,然后调用Connection对象的onXXX方法进行通话控制的调用TelephonyC
onnection对象获取对应的callId,再通过mAdapter调用Telecom系统应用中的服务来设置当前通话的最新状态。5.5本章小结本章从TeleService系统应用的加载过程、TelephonyPhone业务模型
、PhoneAcount以及提供的Service服务这四个方面,详细解析了TeleService系统应用的核心业务逻辑。TeleService加载过程TelephonyPhone业务模型PhoneAcountTeleService服务AndroidT
elephony原理解析与开发指南第六章VoiceCall语音通话模型•6.1详解GSMCDMACALLTRACKER–6.1.1代码结构解析–6.1.2Handler消息处理方式–6.1.3与RILJ对象的交互机制•6.2HANDLEPOLLC
ALLS方法–6.2.1准备阶段–6.2.2更新通话相关信息–6.2.3发出通知–6.2.4更新mState•6.3通话管理模型分析–6.3.1GsmCdmaCall–6.3.2GsmCdmaConnection–6.3.3DriverCall、Call、Connection第六章Voi
ceCall语音通话模型•6.4补充通话连接断开处理机制–6.4.1本地主动挂断通话–6.4.2远端断开通话•6.5区分CONNECTION•6.6扩展INCALLUI–6.6.1初始化过程–6.6.2a
ddCall–6.6.3InCallUi通话界面–6.6.4updateCall•6.7验证CALL运行模型–6.7.1TelephonyVoiceCall–6.7.2TelecomCall–6.7.3InCallUiCall•6.8本章小结6.1详解GsmCdmaCal
lTracker6.1.1代码结构解析6.1详解GsmCdmaCallTracker6.1.2Handler消息处理方式GsmCdmaCallTracker类中使用其中的两种运行和处理机制:基本的Handler消息注册和响应处理机制;Handler消息Callback回调处理方式。6
.1详解GsmCdmaCallTracker6.1.3与RILJ对象的交互机制6.1详解GsmCdmaCallTracker6.1.3与RILJ对象的交互机制6.2handlePollCalls方法6.2.1准备阶段ListpolledCalls;//声明CallList对象,它将保存R
ILJ查询出的当前Call对象列表if(ar.exception==null){//mCi.getCurrentCalls执行成功,RILJ无异常polledCalls=(List)ar.result;//强制类型
转换}elseif(isCommandExceptionRadioNotAvailable(ar.exception)){polledCalls=newArrayList();//Radio不可用状态,创建一个空的列表}else{pollCallsAfterDelay();//
调用父类方法,延迟处理,将继续调用pollCallsWhenSafereturn;}ConnectionnewRinging=null;//来电请求创建的通话连接对象booleanhasAnyCallDisconnected=f
alse;//通话连接断开标志booleanneedsPollDelay=false;//延迟查询标志booleanunknownConnectionAppeared=false;//出现未知通话连接的标志……6.2handlePollCalls方法6.2.2更新通话相关信息1.获取co
nn对象和dc对象根据i数组mConnections的下标取值获取GsmCdmaConnection对象,然后通过curDC索引值获取polledCalls列表中的DriverCall对象dc,匹配DriverCall对象是通过dc.
index==i+1关系完成,如果无法匹配到DriverCall对象,则进入下一次循环完成DriverCall对象的匹配2.通话状态的变化根据conn和dc这两个对象基本信息的组合关系,可得出4种通话状态的变化,分别是:A出现新的通话B通话连接断开C通话连接断开并且有新的来电D通话状态发生变化
6.2handlePollCalls方法6.2.2更新通话相关信息条件说明conn==null&&dc!=null出现新的通话,主要有两种情况:主动拨号后第一次查询到此通话连接和接收到来电请求conn!=null&&dc==null通话连接已经断开conn!=null&&dc
!=null&&!conn.compareTo(dc)&&isPhoneTypeGsm()GSM网络下,通话连接断开的同时,接收到新的来电请求conn!=null&&dc!=null通话状态发生了变化6.2handlePollCalls方法6.2.3发出通知完成循环mConn
ections数组更新GsmCdmaCallTracker对象通话相关信息后,根据最新的通话基本信息,发出通话状态变化相关消息通知1.conn与dc对象的匹配关系,dc.index==i+1说明conn对象是通过dc对象创建的。2.conn与dc对象的状态组
合关系,这些组合关键构成了通话状态变化的所有应用场景。3.mConnections数组的下标与其保存的GsmCdmaConnection对象的index的对应关系,通过代码分析,其实它们是一一对应的。即,mConnections[0]引用的Connection对象的mIndex
取值也一定是0。6.2handlePollCalls方法6.2.4更新mState1.通过Call对象获取其mState状态从而更新GsmCdmaCallTracker的mState属性,它们之间的状态是保持同步的。2.发出mState状态变化的消息
通知。6.2handlePollCalls方法6.2.4更新mState6.3通话管理模型分析6.3.1GsmCdmaCall属性类型说明mStateState当前通话的状态mConnectionsArrayLi
st<Connection>通话的连接对象列表mOwnerGsmCdmaCallTracker所有者是GsmCdmaCallTracker6.3通话管理模型分析6.3.2GsmCdmaConnection属性类型说明mIndex
intGsmCdmaCallTracker.connections数组的下标值mOwnerGsmCdmaCallTracker它的所有者是GsmCdmaCallTrackermParentGsmCdmaC
all它的根源是GsmCdmaCall,即GsmCdmaCall对象拥有它mTelecomCallIdString通话连接的一些基本信息在com.android.internal.telephony.Connection父类中实现的,mAddress通话连
接对方的电话号码;mIsIncoming是否来电;mCause通话断开原因编号;mConnectTime通话建立连接始时间等mAddressStringmDialStringStringmPostDialStringStringmIsIncomingbooleanmCauseintmConnect
TimelonguserDataObjectmPartialWakeLockPowerManager.WakeLock电源管理6.3通话管理模型分析6.3.3DriverCall、Call、Connection6.3通话管理模型分析6.3.3DriverCall、Call、Conn
ection6.4补充通话连接断开处理机制6.4.1本地主动挂断通话主动挂断电话的处理机制,可分为三个处理过程,详情如下。1.发起挂断通话连接的请求CallTracker.hangup->mCi.hangupXXX->GsmCdmaCall.onH
angupLocal->GsmCdmaConnection.onHangupLocal2.接收到RIL发出的通话状态变化GsmCdmaCallTracker.handlePollCalls->conn.onDisconnect->mPa
rent.onDisconnect,mParent为GsmCdmaCall对象。3.清理通话连接状态为DISCONNECTED的Connection对象CallTracker.internalClearDisconnected->Call.clearDisconnected6
.4补充通话连接断开处理机制6.4.2远端断开通话端断开通话连接时,GsmCdmaCallTracker对象会向RILJ对象查询通话连接断开的原因。1.handlePollCalls方法handlePoll
Calls方法中,处理完成本地主动挂断通话连接的后,接着会处理是否远端挂断电话的逻辑2.EVENT_GET_LAST_CALL_FAIL_CAUSE消息响应获取causeCode,作为参数调用conn.onRemoteDisconnect方法完成通话连接远端断开相关的处理
。更新mState并发出通话状态变化的消息通知。3.conn.onRemoteDisconnect方法将causeCode通话连接断开原因编号转变成为DisconnectCause的枚举类型,其处理逻辑采用了常用的switchcase方式6.5区分Con
nection6.6扩展InCallUi6.6.1初始化过程InCallUi通话界面的初始化过程,可理解为Telecom系统应用bindIInCallService过程,可分为两个重要逻辑:1.onBind2.setInCallAdapter6.6扩展InCallUi6.6.2addC
allTelecom系统应用处理拨号请求或是接收到来电消息,都会创建对象com.android.server.telecom.Call,转换为ParcelableCall对象,通过调用IInCallService服务的addCall方法,传递Parcelable
Call对象给InCallUi通话界面进行通话信息的展示6.6扩展InCallUi6.6.3InCallUi通话界面1.加载入口showMainInCallFragment方法中通过CallList获取当前通话信息,选择加载
的第一级Fragment,有三个选项:来电界面通话界面视频通话界面这三个InCallActivity的第一级Fragment分别是:AnswerFragment、InCallFragment和VideoCallFra
gment6.6扩展InCallUi6.6.3InCallUi通话界面2.InCallFragmentInCallFragment作为Fragment,加载过程将依次调用重写父类的onAttach、onCreate、o
nCreateView、onViewCreated和onResume方法。frag_incall_voice.xml作为InCallFragment的布局文件。创建contactGridManager、pager和endCallButton等View控件。建立InC
allFragment、CallCardPresenter和InCallPresenter间消息处理框架。6.6扩展InCallUi6.6.3InCallUi通话界面3.InCallButtonGridFragmentInCallButtonGri
dFragment作为Fragment,是InCallFragment子级Fragment。InCallButtonGridFragment创建六个通话控制按钮的View控件。InCallButtonGridFragment与InCallFragment相互引用。建立InCal
lFragment、CallButtonPresenter和InCallPresenter间消息处理框架。6.6扩展InCallUi6.6.3InCallUi通话界面4.Fragment、Presenter总结6.6
扩展InCallUi6.6.3InCallUi通话界面5.通话界面缩略图6.6扩展InCallUi6.6.3InCallUi通话界面7.小结InCallService的addCall响应逻辑,可归纳为两点:a.创建android.t
elecom.Phone和android.telecom.Call对象为中心的Call.Callback消息处理框架。b.加载InCallFragment和InCallButtonGridFragment
界面,同时创建CallCardPresenter、CallButtonPresenter与InCallPresenter的消息处理框架。6.6扩展InCallUi6.6.4updateCallInCallUi无论展示的是来电界
面还是通话中界面,接收到通话信息改变的消息通知,比如:来电界面用户接听后进入到通话中的状态,通话中被对方Hold或本地主动Hold当前通话等,都是Telecom系统应用向IInCallService服务发起updateCall
接口调用6.7验证Call运行模型6.7.1TelephonyVoiceCall1.拨号CallTrackermState:OFFHOOKmRingingCall:GsmCdmaCallinfomState:IDLE,mConnections[]mForegroundCal
l:GsmCdmaCallinfomState:DIALING,mConnections[callId:TC@2_1isExternal:Nincoming:falsestate:DIALINGpostdialstate:N
OT_STARTED]mBackgroundCall:GsmCdmaCallinfomState:IDLE,mConnections[]mConnections[callId:TC@2_1isExternal:Ni
ncoming:falsestate:DIALINGpostdialstate:NOT_STARTED]CallTrackermState:OFFHOOKmRingingCall:GsmCdmaCalli
nfomState:IDLE,mConnections[]mForegroundCall:GsmCdmaCallinfomState:ACTIVE,mConnections[callId:TC@2_1isExternal:Ni
ncoming:falsestate:ACTIVEpostdialstate:COMPLETE]mBackgroundCall:GsmCdmaCallinfomState:IDLE,mConnections[]
mConnections[callId:TC@2_1isExternal:Nincoming:falsestate:ACTIVEpostdialstate:COMPLETE]6.7验证Call运行模型6.7.1TelephonyVoiceCall2.来电CallTrackermSta
te:RINGINGmRingingCall:GsmCdmaCallinfomState:INCOMING,mConnections[callId:nullisExternal:Nincoming:truestate:INC
OMINGpostdialstate:NOT_STARTED]mForegroundCall:GsmCdmaCallinfomState:IDLE,mConnections[]mBackgroundCall:GsmCdmaCa
llinfomState:IDLE,mConnections[]mConnections[callId:nullisExternal:Nincoming:truestate:INCOMINGpostdialstate:NOT_STAR
TED]//接听电话后的信息变化CallTrackermState:OFFHOOKmRingingCall:GsmCdmaCallinfomState:IDLE,mConnections[]mForegroundCall:GsmCdmaCallinfom
State:ACTIVE,mConnections[callId:TC@3_1isExternal:Nincoming:truestate:ACTIVEpostdialstate:NOT_STARTED]mBackgroundCall:GsmCdmaCallinfomState:IDL
E,mConnections[]mConnections[callId:TC@3_1isExternal:Nincoming:truestate:ACTIVEpostdialstate:NOT_STAR
TED]6.7验证Call运行模型6.7.1TelephonyVoiceCall3.两路通话CallTrackermState:RINGINGmRingingCall:GsmCdmaCallinfomState
:WAITING,mConnections[callId:nullisExternal:Nincoming:truestate:WAITINGpostdialstate:NOT_STARTED]mForegro
undCall:GsmCdmaCallinfomState:ACTIVE,mConnections[callId:TC@4_1isExternal:Nincoming:falsestate:ACTIVEpostdialstate:CO
MPLETE]mBackgroundCall:GsmCdmaCallinfomState:IDLE,mConnections[]mConnections[callId:TC@4_1isExternal:Nincoming
:falsestate:ACTIVEpostdialstate:COMPLETEcallId:nullisExternal:Nincoming:truestate:WAITINGpostdialstate:NOT_STARTED]6.
7验证Call运行模型6.7.2TelecomCallCallIdMappermCalls{com.android.server.telecom.Callinfo:mId:TC@6mConnectionId:TC@6_1mState:ACTIVEmCallDirection:1mHan
dle:tel:00000001mIsConference:false,mChildCalls[]com.android.server.telecom.Callinfo:mId:TC@7mConnectionId:TC@7_1mState:RINGINGmCallDire
ction:2mHandle:tel:00000002mIsConference:false,mChildCalls[]}6.7验证Call运行模型6.7.3InCallUiCallInCallUiPhonemCalls{Call[id:TC@3,state:ACTIVE,details:[..
....],ChildCall[]Call[id:TC@4,state:ACTIVE,details:[......],ChildCall[]Call[id:9a26bf64-0741-4927-a463-c2af2e0c2303,state:ACTIVE,d
etails:[......],ChildCall[Call[id:TC@4,state:ACTIVE,details:[......]Call[id:TC@3,state:ACTIVE,details:[......]]Call[id:TC@5,state:HOLDING,details:
[......],ChildCall[]}InCallUi通话界面共有四个Call对象,一个ConferenceCall对象,三个通话连接创建的Call对象,两个状态是ACTIVE通话中状态,归属ConferenceCal
l对象中,一个状态是HOLDING通话保持状态。6.7验证Call运行模型6.7.3InCallUiCallInCallUiPhonemCalls{Call[id:TC@3,state:ACTIVE,details:[......]
,ChildCall[]Call[id:TC@4,state:ACTIVE,details:[......],ChildCall[]Call[id:9a26bf64-0741-4927-a463-c2af2e0c2303,state:AC
TIVE,details:[......],ChildCall[Call[id:TC@4,state:ACTIVE,details:[......]Call[id:TC@3,state:ACTIVE,details:[......]]Call[id:
TC@5,state:HOLDING,details:[......],ChildCall[]}InCallUi通话界面共有四个Call对象,一个ConferenceCall对象,三个通话连接创建的Call对象,两个状态是ACTIVE通话中状态,归属ConferenceCall对象中,
一个状态是HOLDING通话保持状态。6.8本章小结本章以GsmCdmaCallTracker为中心,从Handler消息处理方式、与RILJ的交互机制和handlePollCalls关键业务逻辑这三个方面做
了详细的分析和总结,分析和验证VoiceCall语音通话业务模型,并扩展讲解InCallUi通话界面的核心实现机制,需要重点掌握:1.GsmCdmaCallTracker的Handler消息处理方式2.GsmCdmaCallTracker与RILJ的交互机制3.handlePollCalls方
法中Call、Connection对象的处理机制4.DriverCall、Call、Connection的通话管理模型5.区分State6.区分Connection7.InCallUi通话界面8.验证Call模型AndroidTelephony原理解析与开发指南第七章ServiceSta
te网络服务•7.1ServiceState–7.1.1ServiceState类的本质–7.1.2关键常量信息–7.1.3关键属性–7.1.4关键方法•7.2ServiceStateTracker运行机制详解–7.2.1核心类图–7.2.2代码结构–7
.2.3Handler消息处理机制–7.2.4与RILJ的交互机制•7.3handlePollStateResult方法–7.3.1异常处理–7.3.2handlePollStateResultMessage–7.3.3继续更新mNewSS–7
.3.4pollStateDone方法完成收尾工作第7章ServiceState网络服务•7.4*#*#4636#*#*测试工具–7.4.1网络服务信息–7.4.2扩展ITelephonyRegistry–7.4.3展示
小区信息–7.4.4小区信息更新源头–7.4.5信号强度实时变化•7.5飞行模式–7.5.1飞行模式开启关闭入口逻辑–7.5.2Radio模块开启关闭–7.5.3Wifi模块开启关闭–7.5.4蓝牙模块开启关闭•7.6扩展SIM卡业务–7.6.1SIM卡业务分析–7.6.2驻网过程分
析–7.6.3SoftSim业务实现分析•7.7本章小结7.1ServiceStateServiceState类实现了Parcelable接口,主要有以下两个过程组成。1.writeToParcel序列化
过程,将对象数据写入外部提供的Parcel中。2.createFromParcel反序列化过程,通过外部提供的Parcel获取基本数据来创建ServiceState对象。7.1.1ServiceState类的本质7.1ServiceState7.1.2关
键常量信息分类定义描述网络服务状态STATE_IN_SERVICE服务状态正常STATE_OUT_OF_SERVICE不在服务中STATE_EMERGENCY_ONLY只能呼叫紧急号码STATE_POWER_OFF无线通信模块已经关闭网络注册信息RIL_REG
_STATE_NOT_REG网络未注册RIL_REG_STATE_HOME注册本地网络服务RIL_REG_STATE_DENIED拒绝注册RIL_REG_STATE_ROAMING注册漫游网络服务…总计10个RIL_REG_STA
TE_XXX无线通信网络类型RIL_RADIO_TECHNOLOGY_GPRS2GGSM网络RIL_RADIO_TECHNOLOGY_TD_SCDMA3GTD_SCMA网络RIL_RADIO_TECHNOLOGY_LTE4GLTE网
络…总计19个RIL_RADIO_TECHNOLOGY_XXX,参考rilRadioTechnologyToString方法中匹配网络类型的对应关系7.1ServiceState7.1.3关键属性属性类型描述mVoiceRegSt
ateint网络服务状态(语音)mDataRegStateint移动数据服务状态mVoiceRoamingTypeint语音漫游类型mDataRoamingTypeint移动数据漫游类型mVoiceOperatorAlphaLongmDat
aOperatorAlphaLongString电信运营商名称mVoiceOperatorAlphaShortmDataOperatorAlphaShortString电信运营商名称mVoiceOperatorNumericmDataOp
eratorNumericString电信运营商编号mIsManualNetworkSelectionboolean手动选择电信运营商标志mIsEmergencyOnlyboolean仅紧急呼救状态标志7.1Se
rviceState7.1.4关键方法ServiceState类实现了Parcelable接口,使用Parcel序列化方式,关键方法主要体现在以下三个方面。1.ServiceState类的序列化过程和反序列化2.get/set方法3.rilRadioTechnology
ToString方法获取手机网络类型对应关系4.toString方法7.2ServiceStateTracker运行机制详解7.2.1核心类图7.2ServiceStateTracker运行机制详解7.2.2
代码结构_关键方法分类方法名描述Handler消息处理handleMessage响应RILJ发出的消息回调handlePollStateResult4个查询网络服务的消息响应方法EVENT_POLL_STATE_XXX更新网络服务信息pollState/mo
demTriggeredPollStategetOperator查询电信运营商信息、getDataRegistrationState查询移动数据注册状态、getVoiceRegistrationState查询语音注册状态和getNetworkSelectionMode查询
网络Mode,4个查询基本网络服务信息pollStateDone根据pollState的查询结果,完成mSS信息的更新并发出ServiceState变化的消息通知7.2ServiceStateTracker运行机制详解7.2.2代码结构_关键属性属
性类型描述mCiCommandsInterfaceRILJ对象mSSServiceState当前ServiceState对象mNewSSServiceState最新ServiceState对象mSignalStr
engthSignalStrength手机无线网络信号量mCellLocCellLocation小区信息mNewCellLocCellLocation最新小区信息mPhoneGsmCdmaPhoneGSMPhone对象7.2Ser
viceStateTracker运行机制详解7.2.3Handler消息处理机制1.消息注册mCi.setOnSignalStrengthUpdate(this,EVENT_SIGNAL_STRENG
TH_UPDATE,null);mCi.registerForCellInfoList(this,EVENT_UNSOL_CELL_INFO_LIST,null);mCi.registerForImsNetworkStateChanged(this,EVENT_IM
S_STATE_CHANGED,null);mCi.registerForRadioStateChanged(this,EVENT_RADIO_STATE_CHANGED,null);mCi.registerForNetworkStateChanged(th
is,EVENT_NETWORK_STATE_CHANGED,null);mCi.setOnNITZTime(this,EVENT_NITZ_TIME,null);mCi.setOnRestrictedStateChanged(this,EVENT_RESTRICTED
_STATE_CHANGED,null);7.2ServiceStateTracker运行机制详解7.2.3Handler消息处理机制2.消息响应caseEVENT_RADIO_STATE_CHANGED:modemTriggered
PollState();//查询网络服务基本信息break;caseEVENT_NETWORK_STATE_CHANGED:modemTriggeredPollState();//查询网络服务基本信息break;caseEVENT_S
IGNAL_STRENGTH_UPDATE:ar=(AsyncResult)msg.obj;mDontPollSignalStrength=true;onSignalStrengthResult(ar);//响应新的无线网络信号break;……7.
2ServiceStateTracker运行机制详解7.2.3Handler消息处理机制3.Callback处理机制caseEVENT_POLL_STATE_REGISTRATION:caseEVENT_POLL_STATE_GPRS:caseEVENT_POLL_ST
ATE_OPERATOR:ar=(AsyncResult)msg.obj;handlePollStateResult(msg.what,ar);break;caseEVENT_POLL_STATE_NETWORK_SELECTION_MODE:ar=(Async
Result)msg.obj;if(mPhone.isPhoneTypeGsm()){handlePollStateResult(msg.what,ar);}else{......}//CMDA网络制式处理逻辑break;四个查询网络服务的请求的响应方式都一样,调用handlePoll
StateResult方法,接着,重点解析handlePollStateResult方法中的处理逻辑。7.2ServiceStateTracker运行机制详解7.2.4与RILJ的交互机制1.被动接Handler消息7.2ServiceStateTracker运行机制详解7.2.4与RILJ的交互
机制2.主动发起请求7.3handlePollStateResult方法7.3.1异常处理if(ar.userObj!=mPollingContext)return;//请求与返回的消息不匹配,直接返回,不做处理if(ar.exception
!=null){//判断RILJ是否返回了异常信息CommandException.Errorerr=null;//匹配异常类型,具体可查看CommandException类中Error枚举类型定义if(ar.
exceptioninstanceofCommandException){//强制转换类型CommandException,并获取Errorerr=((CommandException)(ar.exception))
.getCommandError();}//无线通信模块的工作状态不可用if(err==CommandException.Error.RADIO_NOT_AVAILABLE){//RadiohascrashedorturnedoffcancelPollState();//清理查询上下文
mPollingContextreturn;}......记录异常日志信息}7.3handlePollStateResult方法7.3.2handlePollStateResultMessagehandlePollStateResultMessage
方法将分别处理四个不同网络服务信息查询的返回结果,其处理框架:switch(what){caseEVENT_POLL_STATE_REGISTRATION:{……break;}caseEVENT_POLL_STATE_GPRS:{……break;}caseEVENT_POLL_ST
ATE_OPERATOR:{……break;}caseEVENT_POLL_STATE_NETWORK_SELECTION_MODE:{……break;}default:loge("handlePollSt
ateResultMessage:UnexpectedRILresponsereceived:"+what);}7.3handlePollStateResult方法7.3.2handlePollStateResultMessage1.EVEN
T_POLL_STATE_REGISTRATION处理当前注册的语音网络服务信息的查询结果,VoiceRegStateResult对象保存了注册的语音网络服务信息、漫游标志和紧急呼救标志,重点关注getRegStateFromHalRegState
和regCodeToServiceState方法。2.EVENT_POLL_STATE_GPRS更新mNewSS的mVoiceRegState和mDataRegState的状态一致,GsmRoaming和mDataRoaming保持一致3.EVEN
T_POLL_STATE_OPERATOR处理当前注册的电信运营商网络服务信息的查询结果4.EVENT_POLL_STATE_NETWORK_SELECTION_MODE处理查询网络选择类型是手动选择还是自动选择7.3handlePo
llStateResult方法7.3.4继续更新mNewSShandlePollStateResult方法中调用pollStateDone方法完成查询网络服务信息结果的收尾工作,需要一个前提条件,就是EV
ENT_POLL_STATE_XXX类型的四个查询网络服务信息全部处理完成。mPollingContext[0]--;//计数器减一操作if(mPollingContext[0]==0){//计数器为0
说明当前查询网络服务信息已经全部处理if(mPhone.isPhoneTypeGsm()){//GSMupdateRoamingState();//更新mNewSS漫游标志mNewSS.setEmergencyOnly(m
EmergencyOnly);//更新mNewSS紧急呼救状态}else{......}pollStateDone();}7.3handlePollStateResult方法7.3.4pollStateDone方法完成收尾工作1.如何获取服务信息改变网络服务更新标志备注hasReg
istered/hasDeregistered语音网络驻网成功/失败标志hasDataAttached/hasDataDetached移动数据网络驻网成功/失败标志hasVoiceRegStateChangedhasDataRe
gStateChanged语音网络/移动数据网络驻网状态变化标志hasRilVoiceRadioTechnologyChangedhasRilDataRadioTechnologyChanged语音网络/移动数
据网络RadioTechnology变化标志hasLocationChanged小区信息变化标志hasChanged网络服务信息变化标志hasVoiceRoamingOnhasVoiceRoamingOff语音网络漫游状态标志hasDataRoamingOnhasDataRoamingOf
f数据网络漫游状态标志7.3handlePollStateResult方法7.3.4pollStateDone方法完成收尾工作2.更新mSS、mCellLoc对象ServiceStateTracker与RILJ对象的交互过程
中,首先是更新ServiceStateTracker对象的mNewXXX属性,在调用pollStateDone方法收尾时,更新ServiceStateTracker对象中对应的mXXX属性,即当前网络服务信息对象或属性当前信息更新的信息mSSmNewSSmCellLoc
mNewCellLocmReasonDataDeniedmNewReasonDataDeniedmMaxDataCallsmNewMaxDataCallsmRejectCodemNewRejectCode7.3handlePollStateResult方法
7.3.4pollStateDone方法完成收尾工作3.发出网络服务状态信息变化的消息通知pollStateDone方法中,一共判断出18个网络服务信息变化标志,这里重点介绍注册的通话服务状态信息变化后的处理逻辑,即hasChanged为true的情况。网络服
务信息在发生了变化以后,主要有两个方面的处理。a)调用updateSpnDisplay方法更新SPN的显示b)通过TelephonyManager设置驻网的电信运营商的名称和编号、是否漫游标志。7.4*#*#4636#*#*测试工具7.4*#*#4636#*#*测试工具7.4.1网络
服务信息TelephonyManager向ITelephonyRegistry服务监听了10个PhoneState变化的消息,Callback消息回调是mPhoneStateListener,它继承PhoneStateListener类,重写了父类的11个方法。mTeleph
onyManager.listen(mPhoneStateListener,PhoneStateListener.LISTEN_CALL_STATE|PhoneStateListener.LISTEN_DATA_CONNEC
TION_STATE|PhoneStateListener.LISTEN_DATA_ACTIVITY|PhoneStateListener.LISTEN_CELL_LOCATION|PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR|P
honeStateListener.LISTEN_CALL_FORWARDING_INDICATOR|PhoneStateListener.LISTEN_CELL_INFO|PhoneStateListener.LISTEN
_SERVICE_STATE|PhoneStateListener.LISTEN_SIGNAL_STRENGTHS|PhoneStateListener.LISTEN_DATA_CONNECTION_REAL_TIME_INFO);privatefinalPhon
eStateListenermPhoneStateListener=newPhoneStateListener(){@OverridepublicvoidonXXXChanged(intstate){updateXXX
();//更新界面显示……updateXXX调用}……重写父类PhoneStateListeneronXXXChanged方法}7.4*#*#4636#*#*测试工具7.4.2扩展ITelephonyRegist
ry7.4*#*#4636#*#*测试工具7.4.3展示小区信息RadioInfo类的mPhoneStateListener在显示Phoneinformation界面时,向ITelephonyRegistry服务注册PhoneSt
ateListener.LISTEN_CELL_LOCATION和PhoneStateListener.LISTEN_CELL_INFO两个关于小区信息的监听回调,小区信息变化后的Callback响应方法分别是:onCellLocationChanged和onCellInf
oChangedCellInfo作为abstract抽象类,有四个子类:CellInfoLte、CellInfoWcdma、CellInfoGsm和CellInfoCdma,分别代表这4G、3G和2G(GSM和CDMA)网络下的小区信息。7.4*#*
#4636#*#*测试工具7.4.4小区信息更新源头RadioInfo界面通过向ITelephonyRegistry系统服务注册小区信息变化的监听,mPhoneStateListener.onCellInfoChanged接
收到Callback回调,获取当前最新的小区信息列表从而显示在Phoneinformation界面。通过ITelephonyRegistry系统服务的学习,我们知道PhoneSate状态变化的消息源是com.an
droid.phone进程中的GsmCdmaPhone对象,反推onCellInfoChanged,可追溯到ServiceStateTracker响应RILJ发出的EVENT_UNSOL_CELL_INFO_LIST
消息回调,经过mPhone.notifyCellInfo->mNotifier.notifyCellInfo->mRegistry.notifyCellInfoForSubscriber调用过程,ITelephonyRegistry系统服务响应not
ifyCellInfoForSubscriber服务接口调用,最终遍历mRecords发出onCellInfoChanged调用,整个过程将传递CellInfo列表对象。7.4*#*#4636#*#*测试工具7.4.5
信号强度实时变化7.5飞行模式7.5.1飞行模式开启关闭入口逻辑进入网络设置界面,其操作路径为:Settings->Network&Internet,变可通过Airplanemode进行飞行模式的开关操作,开关飞行模式对应的代码
是:packages/apps/Settings/src/com/android/settings/AirplaneModeEnabler.java开关飞行模式主要有两个操作:a)更新Settings.G
lobal.AIRPLANE_MODE_ON系统设置信息b)发出ACTION_AIRPLANE_MODE_CHANGED的广播7.5飞行模式7.5.2Radio模块开启关闭Android源代码中Intent.ACTION_AIRPLANE_MODE_CHANGED
广播接收器,发现开启或关闭Radio无线通信模块的处理逻辑是在PhoneGlobals类中,PhoneAppBroadcastReceiver.onReceive接收到该广播后,经过handleAirplaneModeChange->maybeTurnCellOff/
maybeTurnCellOn->setRadioPowerOff/setRadioPowerOn->PhoneUtils.setRadioPower调用,最终调用到GsmCdmaPhone对象的setRadioPower方法;最终由GsmCdmaPhone对象的mSST
,即ServiceStateTracker向RILJ对象发起关闭或开启Radio无线通信模块的请求。7.5飞行模式7.5.3Wifi模块开启关闭frameworks/opt/net/wifi/service/
java/com/android/server/wifi/WifiServiceImpl.java代码中注册了Intent.ACTION_AIRPLANE_MODE_CHANGED类型的广播接收器mContext.registerReceiver(newBroadcastReceiv
er(){@OverridepublicvoidonReceive(Contextcontext,Intentintent){......//同步开关Wifi}},newIntentFilter(Intent
.ACTION_AIRPLANE_MODE_CHANGED));7.5飞行模式7.5.4蓝牙模块开启关闭frameworks/base/services/core/java/com/android/server/
BluetoothManagerService.java中监听Settings.Global.AIRPLANE_MODE_ON数据变化mContentResolver.registerContentObserver(Settings.Global.getUriFor(Settings.Global
.AIRPLANE_MODE_ON),true,mAirplaneModeObserver);//mAirplaneModeObserver发起开关蓝牙模块sendDisableMsg(REASON_AIRPLANE_MODE);sendEnableMsg(mQuie
tEnableExternal,REASON_AIRPLANE_MODE);7.6扩展SIM卡业务SIM卡SubscriberIdentificationModule的缩写,也称为用户身份识别卡,由CPU、ROM、RAM、EEPROM和I/O电路组成,与COS(Chip
OperationSystem)操作系统,构成一个完整的计算机系统,具有独立数据处理能力;COS控制SIM卡与外界信息交换,管理卡内存储器并在卡内部完成各种命令的处理。SIM卡发展至今,主要在尺寸和容量两个方面有大的变化;目前市面上主要的
三种尺寸SIM卡:a)标准卡(2FF)25x15x0.76mmb)Micro卡(3FF)15x12x0.76mmc)Nano卡(4FF)12.3x8.8x0.67mm在功能机时代,因手机机身储存大小的限制,SIM卡也会储存电话
号码、短信等信息,因此SIM卡在容量方面也有提升,从8K提升到64K容量,甚至512K以上的大容量。7.6扩展SIM卡业务7.6.1SIM卡业务分析SIM卡业务主要体现在四个方面:a)存储功能保存电话号码、短
信等信息到SIM卡。b)安全管理PIN、PIN2、PUK等安全管理。c)驻网鉴权移动网络端匹配SIM卡内驻网鉴权的计算结果,保障运营商发出的合法SIM卡才能接入和使用其移动网络,达到身份验证的目的。d)STKSTK(SIMToolKit),SIM
卡应用工具包,运行卡内的小应用程序与手机用户进行交互,实现增值服务。7.6扩展SIM卡业务7.6.1SIM卡业务分析SIM卡业务主要体现在四个方面:a)存储功能保存电话号码、短信等信息到SIM卡。b)安全管理PI
N、PIN2、PUK等安全管理。c)驻网鉴权移动网络端匹配SIM卡内驻网鉴权的计算结果,保障运营商发出的合法SIM卡才能接入和使用其移动网络,达到身份验证的目的。d)STKSTK(SIMToolKit),SIM卡应用工具包,运行卡内的小应用程序与手机用户进行交互,实现
增值服务。7.6扩展SIM卡业务7.6.1SIM卡业务分析随着智能手机的发展,存储功能、安全管理和STK已基本不再使用,SIM卡仅承担驻网鉴权业务,完成身份验证;SIM卡发展至今,在业务形态方面有什么变化吗?主要有
两个分支:’a)eSIMb)SoftSim7.6扩展SIM卡业务7.6.2驻网过程分析/*AnimplementationoftheGSMA3A8algorithm.(Specifically,COMP128.)**Copyright1998,MarcBriceno,IanGoldberg,
andDavidWagner.*Allrightsreserved.*......*/voidA3A8(/*in*/Byterand[16],/*in*/Bytekey[16],/*out*/Bytesimoutput[12]){Bytex[32],bit[128];inti,j,k,l,m,n,
y,z,next_bit;/*(LoadRANDintolast16bytesofinput)*/for(i=16;i<32;i++)x[i]=rand[i-16];/*(Loopeighttimes)*/for(i=1;i<9;i++){/*(Loadkeyintofirst16byte
sofinput)*/for(j=0;j<16;j++)x[j]=key[j];/*(Performsubstitutions)*/......}for(i=0;i<4;i++)simoutput[i]=(x[2*i]<<4)|x[2*i+1];for(i=0;i<6;i++)simoutpu
t[4+i]=(x[2*i+18]<<6)|(x[2*i+18+1]<<2)|(x[2*i+18+2]>>2);simoutput[4+6]=(x[2*6+18]<<6)|(x[2*6+18+1]<<2);simo
utput[4+7]=0;}7.6扩展SIM卡业务7.6.2驻网过程分析Milenage驻网鉴权算法,可参考《3GPPTS35.206》规范文档,详细描述了f1、f2、f3、f4和f5的原理和实现代码,其下载地址为:http://www.3gpp.org/ftp/Specs/archiv
e/35_series/35.206/,关键的信息如下:OPCa128-bitvaluederivedfromOPandKandusedwithinthecomputationofthefunctions.RANDa128-bitrandomchallenge
thatisaninputtothefunctionsf1,f1*,f2,f3,f4,f5andf5*.AKa48-bitanonymitykeythatistheoutputofeitherofthefu
nctionsf5andf5*.AMFa16-bitauthenticationmanagementfieldthatisaninputtothefunctionsf1andf1*.CKa128-bitconfidentialitykeythatisthe
outputofthefunctionf3.IKa128-bitintegritykeythatistheoutputofthefunctionf4.RESa64-bitsignedresponsethatis
theoutputofthefunctionf2.MAC-Aa64-bitnetworkauthenticationcodethatistheoutputofthefunctionf1.MAC-Sa64-bitresynchron
isationauthenticationcodethatistheoutputofthefunctionf1*.7.6扩展SIM卡业务7.6.3SoftSim业务实现分析基于Android平台实现SoftSim业务的实现,可分为两个关键步骤:1.模拟SIM卡App应用模拟COS(ChipO
perationSystem)操作系统对SIM卡的管理,完成APDU命令的响应逻辑,主要集中在模拟SIM卡文件系统和Milenage驻网鉴权算法这两个方面的实现。2.打通与应用APDU通道Modem与实
体SIM卡的APDU交互完成驻网鉴权,修改为与AP侧SoftSim应用APDU交互,扩展RIL接口,打通BP与APAPDU数据交换通道。7.7本章小结本章解析TelephonyServiceState网络服务业务,以ServiceStateTracker为核
心围绕handlePollStateResult和pollStateDone两个关键方法,管理mSS、mNewSS、mLastCellInfoList、mSignalStrength等网络服务信息,主要包括驻网信息(VoiceCal
l语音和DataCall移动数据驻网信息)、运营商信息、网络信号、小区信息等核心网络服务信息ServiceState。ServiceStateTracker运行机制与GsmCdmaCallTracke
r运行机制非常相似,包括主动向RILJ发起ServiceState网络服务信息查询和管理请求,以及ServiceStateTracker对象被动接收RILJ发出的网络服务信息变化的消息回调,一切都以Handler消息处
理机制为基础。4636工具和飞行模式作为ServiceState网络服务业务的扩展和实践,特别是4636工具中展示网络服务信息的两种获取方式,是帮助我们认识和理解ServiceState网络服务业务的利器;也是掌握GsmCdmaPhone对象直接获取方式和ITelephony
Registry注册监听/Callback回调的参考实现。了解A3A8和Milenage驻网鉴权算法原理和相关规范,以及SIM卡业务扩展eSIM和SoftSim。AndroidTelephony原理解析与开发指南第八章DataCall移动数
据业务•8.1DcTracker初始化过程–8.1.1Handler消息注册–8.1.2初始化ApnContext–8.1.3认识APN–8.1.4创建DcController–8.1.5注册Observer–8.1.6广
播接收器–8.1.7加载ApnSetting•8.2解析StateMachine–8.2.1State设计模式–8.2.2StateMachine核心类–8.2.3初始化流程–8.2.4运行流程–8.2.5小结第8章DataCall移动数据业务•8.3DataCon
nection–8.3.1关键属性–8.3.2关键方法–8.3.3StateMachine初始化流程•8.4开启移动数据业务–8.4.1流程分析–8.4.2前置条件分析–8.4.3DcActiveState收尾工作–8.4.4Suspend
挂起状态–8.4.5查看手机上网基本信息•8.5关闭移动数据业务•8.6DataConnection状态转换•8.7获取Android手机上网数据包–8.7.1使用tcpdump工具抓取TCP/IP数据包–8.7.
2使用Wireshark软件分析TCP/IP数据包•8.8本章小结8.1DcTracker初始化过程1.Handler消息注册对象DcTracker主要向RILJ、GsmCdmaCallTracker、ServiceStateTracker三
个对象发起HandlerMessage消息注册。2.Handler消息类型DcTracker注册的Handler消息类型,以DctConstants.EVENT_XXX为主。3.消息响应DcTracker作为自定义的Handler对象,在发起HandlerMessa
ge消息注册时,传入this对象,在handleMessage方法中响应Message消息回调。8.1.1Handler消息注册8.1DcTracker初始化过程1.networkConfigStrings内容networkCon
figStrings数组的内容从frameworks/base/core/res/res/values/config.xml中获取的2.创建NetworkConfig对象循环networkConfigStrings数组,首
先,根据网络配置的String字符串信息,创建NetworkConfig对象,然后使用NetworkConfig对象构造ApnContext对象3.创建并保存ApnContext对象,保存到三个集合列表中4.NetworkCo
nfig和ApnContext关系config.xml解析出网络配置信息从而创建了12个NetworkConfig对象,匹配10个NetworkConfig对象,关系是:NetworkConfig对象type属性
(config.xml配置字符串中的第二个配置项)为:ConnectivityManager.TYPE_MOBILE_XXX,对应关系参考initApnContexts的switch分支处理逻辑;因此,三个集合mApnContexts、mApnContexts
ById和mPrioritySortedApnContexts中均保存了10个ApnContext对象列表。8.1.2初始化ApnContext8.1DcTracker初始化过程APN(AccessPointName),它是Android手机移动数据上网业务必须配置的参数,用来决定手机通
过哪种接入方式来访问网络,其配置信息全部记录在telephony.db的SQLite数据库表名为carriers的表中。将此数据库文件pull到本地,然后可通过一些SQLite数据库工具(SqliteDev或SQLiteExpertProfessional)查看car
riers表的结构和其中的APN配置信息数据,pull操作详情如下。$adbpulldata/user_de/0/com.android.providers.telephony/databases/telephony.db.Nexus6P手机中预
置的APN信息,对应xml配置文件在Android8.1源码中的路径是:device/huawei/angler/apns-full-conf.xml。packages/providers/TelephonyProvider/src/com/and
roid/providers/telephony/TelephonyProvider.java中的initDatabase方法,将apns-full-conf.xml文件中的APN信息插入到carriers数据库表中。8.1.
3认识APN8.1DcTracker初始化过程DcTracker的mDcc属性就是DcController类型DcController类继承了StateMachine,有一个内部类DccDefaultSta
te对象mDccDefaultState,它继承了State类,实现了State状态模式8.1.4创建DcController8.1DcTracker初始化过程DcTracker的构造方法中完成了mApnObserver和mSettingsObserver两个对象的创建,并且完成Obse
rver的注册。mApnObserver监听Telephony.Carriers.CONTENT_URI,即Telephony数据库Carriers表中保存的APN信息发生改变;ApnObserver的onChang
e方法响应APN配置信息变化,通过sendMessage(obtainMessage(DctConstants.EVENT_APN_CHANGED))发出Handler消息,最终DcTracker的handleMessage方法响应。
8.1.5注册Observer8.1DcTracker初始化过程mIntentReceiver作为DcTracker的匿名内部类对象,它继承了BroadcastReceiver:IntentFilterf
ilter=newIntentFilter();filter.addAction(Intent.ACTION_SCREEN_ON);filter.addAction(Intent.ACTION_SCREEN
_OFF);filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);filter.addAction(INTENT_
DATA_STALL_ALARM);filter.addAction(INTENT_PROVISIONING_APN_ALARM);filter.addAction(CarrierConfigManager.ACTION_CARRIER_CO
NFIG_CHANGED);mPhone.getContext().registerReceiver(mIntentReceiver,filter,null,mPhone);8.1.6广播接收器8.1DcTracker初始化过程
Stringselection=Telephony.Carriers.NUMERIC+"='"+operator+"'";Cursorcursor=mPhone.getContext().getContentRes
olver().query(Telephony.Carriers.CONTENT_URI,null,selection,null,Telephony.Carriers._ID);与APN配置管理界面的处理一致,查询Carriers
数据库表,匹配出当前运营商的APN配置信息;最后创建ApnSetting对象,保存在mAllApnSettings列表中。ApnSetting类使用types、carrier、apn、proxy、port、mmsc、mmsProxy、m
msPort等28个属性来保存APN配置信息8.1.7加载ApnSetting8.2解析StateMachine8.2.1State设计模式8.2解析StateMachine8.2.2StateMachine
核心类8.2解析StateMachine8.2.3初始化流程8.2解析StateMachine8.2.4运行流程8.2解析StateMachine8.2.5小结android平台实现的State设计模式StateMa
chine,有以下三个特点。a)StateMachine类对外提供对State对象操作的相关接口,如addState、setInitialState和start这三个启动状态机的基本方法。b)SmHandler内部类作为自定义的Handler消息处理类,通过发送、接收和处理Handler
消息,来管理和更新所有的State对象,重点关注processMsg方法,用来处理所有State对象接收到的Handler消息。c)StateMachine管理的所有State状态对象之间有树状关系,一个State对象自己不处理的消息,会交给其父节点处理,如果父节点不能处理,又交给
它的父节点处理,直到根节点;这里涉及另外一个面向对象的设计模式,职责链模式(ChainofResponsibility),感兴趣的读者可自行学习此设计模式。8.3DataConnection8.3DataConnection8.3.1关键属性属性类型描述mPhonePhonePho
ne对象mDctDcTrackerDcTracker对象mApnSettingApnSettingAPN配置信息mApnContextsApnContextAPN上下文列表mConnectionParams
ConnectionParams连接参数mLinkPropertiesLinkProperties连接属性mNetworkInfoNetworkInfo网络信息mNetworkAgentNetworkAgentNetworkInfo的代理mXXXStateDcXXXSt
ate整覆盖了数据连接的六种状态mAcAsyncChannelAsyncChannel消息处理8.3DataConnection8.3.2关键方法分类方法说明对象创建makeDataConnection创建DataConnection并启动StateMachineDataCal
l操作onConnect发起setupDataCall请求tearDownData发起deactivateDataCall请求onSetupConnectionCompletedsetupDataCall请求的回调响应逻辑消息通知notifyAllOfConnec
ted根据mApnContexts发出消息通知notifyAllDisconnectCompletednotifyConnectCompleted通过DisconnectParams发出消息通知notifyDisconnectCompleted8.3DataConnection8.3.3
StateMachine初始化流程DataConnection的mName属性,其命名规则是“DC-数字”;六个State状态对象之间有一个简单的树状关系,在代码的排列上可以明显看出,mDefaultState作为根节点,而其他五个State
对象均作为它的子节点,即叶子节点。DataConnection的makeDataConnection方法中的逻辑中,完成了StateMachine初始化,有四个大的步骤:a)创建对象(State和SmHandler)b)addStatec)setInitialStated)start8.4
开启移动数据业务8.4.1流程分析8.4开启移动数据业务8.4.2前置条件分析1.isConnectablesetupDataOnConnectableApns方法中遍历mPrioritySortedApnContexts,找出isConnectable的Apn
Context对象,来激活移动数据业务2.isDataAlloweda)sDataAllowed关键判断条件,返回true值主要的条件如下:b)不在紧急呼救业务中,internalDataEnabled为truec)DcTracker.mA
ttached为true,DataReg移动数据网络注册成功d)RadioPower开启状态desiredPowerState和radioStateFromCarriere)SIM卡加载完成,recordsLoaded为truef)默认上网卡与当前DcTracker保持一致,de
faultDataSelected3.buildWaitingApnsDcTracker的buildWaitingApns方法,传的参数是ApnContext的requestedApnType和radioTech,返回ApnSetting对象列表8.4开启移动数据业务8
.4.3DcActiveState收尾工作DataConnection与RILJ交互,RIL层setupDataCall成功后,mActivatingState状态将转换为mActiveState状态,根据Stat
eMachine的处理机制,将调用此状态的enter方法a)更新mNetworkInfob)注册消息c)保存DataConnection对象到DcController.mDcListActiveByCid列表d)创建DcNetworkAgent对象8
.4开启移动数据业务8.4.4Suspend挂起状态caseEVENT_DATA_CONNECTION_VOICE_CALL_STARTED:caseEVENT_DATA_CONNECTION_VOICE_CALL_ENDED:{if(updateNetworkInfoSuspendS
tate()&&mNetworkAgent!=null){mNetworkAgent.sendNetworkInfo(mNetworkInfo);//发送更新后的NetworkInfo对象}retVal
=HANDLED;break;}updateNetworkInfoSuspendState中的方法通过GsmCdmaCallTracker获取当前通话状态,将设置两个状态:a)通话非IDLE状态设置NetworkInfo.DetailedState.SUSPENDEDb)IDL
E状态设置NetworkInfo.DetailedState.CONNECTED8.4开启移动数据业务8.4.5查看手机上网基本信息Nexus6P手机成功开启移动数据业务后,查看上网的基本信息$adbs
hellifconfigrmnet_data0Linkencap:UNSPECinetaddr:10.71.177.232Mask:255.255.255.240inet6addr:fe80::d653:279c:46a1:e7d/64Scope:LinkUPRUNNIN
GMTU:1500Metric:1RXpackets:56errors:0dropped:0overruns:0frame:0……$adbshelliproute10.71.177.224/28devrmnet_data0protokernelscop
elinksrc10.71.177.2328.5关闭移动数据业务8.6DataConnection状态转换8.7获取Android手机上网数据包8.7.1使用tcpdump工具抓取TCP/IP数据包抓取TCP数据包,将数据文件保存在虚拟设备的/sdcard/目录下的tcp.pcap文件中,可修改
数据文件保存的目录$adbshelltcpdump-iany-p-s0-w/sdcard/tcp.pcap将抓取的TCP数据包路径复制到计算机当前目录下$adbpull/sdcard/tcp.pcap.8.7获取Android手机上网数据包8.7.2使用Wireshark软件分
析TCP/IP数据包8.8本章小结本章主要解析DataCall移动数据业务,掌握以下几点。StateMachine状态机的运行原理和机制,以及在DataConnection类中的应用。其中重点理解State设计模式和ChainofResponsibility职责链模式,以及SmHandle
r消息转换和处理机制。开启或关闭DataCall移动数据业务的关键业务流程和运行机制。DcTracker的运行机制。与GsmCdmaCallTracker和ServiceStateTracker运行机制非常相似,但是它们之间最大不同在于
,DcTracker能直接接收和响应GsmCdmaCallTracker和ServiceStateTracker发出的Handler消息,比如移动数据连接Suspend挂起状态。AndroidTelephony原
理解析与开发指南第九章SMS&MMS业务•9.1短信MO流程–9.1.1进入短信应用–9.1.2短信编辑界面–9.1.3Action处理机制–9.1.4继续跟进短信发送流程–9.1.5phone进程中的短信发送流程•9.2扩展短信MO业务–9
.2.1确认短信发送结果–9.2.2重发机制–9.2.3状态报告•9.3短信MT流程–9.3.1RIL层接收短信消息–9.3.2GsmInboundSmsHandler–9.3.3Messaging应用接收新短信–9.3.4PDU–9.3.5短信业务小结第九章SMS&MMS业务•9.
4彩信关键业务逻辑–9.4.1彩信发送入口–9.4.2imms系统服务–9.4.3彩信MO流程–9.4.4DataCall–9.4.5doHttp–9.4.6接收彩信–9.4.7MmsService小结•9.5本章小结9.1短信MO流程ConversationListActivity.java文
件的路径,发现短信应用的代码库是:packages/apps/Messaging/,短信会话列表界面在AndroidManifest.xml中的配置信息。<activityandroid:name=".ui.conversationlist.Con
versationListActivity"android:configChanges="orientation|screenSize|keyboardHidden"android:screenOrientation="us
er"android:label="@string/app_name"android:theme="@style/BugleTheme.ConversationListActivity"><intent-
filter><actionandroid:name="android.intent.action.MAIN"/><categoryandroid:name="android.intent.category.LAUNCHER"/><catego
ryandroid:name="android.intent.category.DEFAULT"/><categoryandroid:name="android.intent.category.APP_MESSAGING"/></intent
-filter></activity>9.1.1进入短信应用9.1短信MO流程打开ConversationListActivity.java短信会话列表界面,点击屏幕右下角的新建短信按钮,便可进入短信编辑界面,输入短信的接收方电话号码以及短信的内容,点击右下角的发送按钮即可发出
短信,短信编辑界面的主要日志和代码。I/am_activity_launch_time(807):0,96371999,com.android.messaging/.ui.conversation.ConversationActivity,642,642]conversationFragment=
newConversationFragment();fragmentTransaction.add(R.id.conversation_fragment_container,conversationFragm
ent,ConversationFragment.FRAGMENT_TAG);9.1.2短信编辑界面9.1短信MO流程9.1.3Action处理机制9.1短信MO流程9.1.4继续跟进短信发送流程9.1短信MO流程9.1.5phone进程中的
短信发送流程9.2扩展短信MO业务9.2.1确认短信发送结果//创建Intent对象及相关参数getSendStatusIntent(context,SendStatusReceiver.MESSAGE_SENT
_ACTION,messageUri,partId,subId),0)privatestaticIntentgetSendStatusIntent(finalContextcontext,finalStringaction,finalUrirequestUri,finalintpart
Id,finalintsubId){finalIntentintent=newIntent(action,requestUri,context,SendStatusReceiver.class);in
tent.putExtra(SendStatusReceiver.EXTRA_PART_ID,partId);intent.putExtra(SendStatusReceiver.EXTRA_SUB_ID,subId);returnintent
;}mSentIntent.send将在Messaging应用中SendStatusReceiver将接收短信发送成功消息。9.2扩展短信MO业务9.2.2重发机制SMSDispatcher对象的handle
SendComplete方法,响应RILJ返回的短信发送结果,短信发送异常的处理逻辑:if(!isIms()&&ss!=ServiceState.STATE_IN_SERVICE){tracker.onFailed(mConte
xt,getNotInServiceError(ss),0/*errorCode*/);}elseif((((CommandException)(ar.exception)).getCommandError()==CommandException.Erro
r.SMS_FAIL_RETRY)&&tracker.mRetryCount<MAX_SEND_RETRIES){//重发次数为超过3次tracker.mRetryCount++;//增加重试次数MessageretryMsg=o
btainMessage(EVENT_SEND_RETRY,tracker);sendMessageDelayed(retryMsg,SEND_RETRY_DELAY);}else{//超过重试次数,短信发送失败处理tracker.onFailed
(mContext,error,errorCode);}9.2扩展短信MO业务9.2.3状态报告handleSendComplete中仅能确认短信成功发送给电信运营商短信中心,并无法确认对方是否已经收到;而短信发送报告更能真实的反应短信发送状态。//RIL消息日志D/R
ILJ(1525):[UNSL]<UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT[SUB0]D/RILJ(1525):[3871]>SMS_ACKNOWLEDGEsuccess=tru
ecause=1[SUB0]D/RILJ(1525):[3871]<SMS_ACKNOWLEDGE[SUB0]//GsmSMSDispatcher类构造方法注册Handler消息mCi.setOnSmsStatu
s(this,EVENT_NEW_SMS_STATUS_REPORT,null);//响应Message消息回调caseEVENT_NEW_SMS_STATUS_REPORT:handleStatusReport((AsyncResult)msg
.obj);//handleStatusReport的关键处理逻辑PendingIntentintent=tracker.mDeliveryIntent;9.3短信MT流程9.3.1RIL层接收短信消息Nexus6P手机接收一条短信,并查看其radio日志D/RILJ(15
25):[UNSL]<UNSOL_RESPONSE_NEW_SMS[SUB0]RILJ接收到UNSOL_RESPONSE_NEW_SMS类型的消息,找到RadioIndication.java中的newSms方法
,将发出mRil.mGsmSmsRegistrant.notifyRegistrant消息通知;而mGsmSmsRegistrant的注册方为:GsmInboundSmsHandler,其构造方法中的逻辑phone
.mCi.setOnNewGsmSms(getHandler(),EVENT_NEW_SMS,null);publicvoidsetOnNewGsmSms(Handlerh,intwhat,Objectobj){mG
smSmsRegistrant=newRegistrant(h,what,obj);}9.3短信MT流程9.3.2GsmInboundSmsHandlerGsmInboundSmsHandler继承于抽象类InboundSmsH
andler,InboundSmsHandler又继承于StateMachine类。共有五个状态对象,mDefaultState、mStartupState、mIdleState、mDeliveringState和mWaitingState,设置的初始化状态是mStartupState。
9.3短信MT流程9.3.3Messaging应用接收新短信Messaging应用接收到新短信后,主要有两个操作:a)通知栏展示接收到新短信update->createMessageNotification->processAndSend->sen
dNotification->fireOffNotification->doNotifydoNotify方法调用NotificationManager.notify发出新短信的状态栏消息通知。a)短信内容保存到本地数据库中db.be
ginTransaction();//开始事务try{//插入新短信信息BugleDatabaseOperations.insertNewMessageInTransaction(db,message);//更新短信会话信息BugleDatabaseOperati
ons.updateConversationMetadataInTransaction(db,conversationId,message.getMessageId(),message.getReceived
TimeStamp(),blocked,conversationServiceCenter,true/*shouldAutoSwitchSelfId*/);}finally{db.endTransaction();//结束事务}9.3短信MT流程9
.3.4PDUSmsMessage类getSubmitPdu和createFromPdu方法按照3GPPTS23.040规范实现的,《3GPPTS23.040V15.0.0(2018-03)》文档9.3短信MT流程9.3.
5短信业务小结9.4彩信关键业务逻辑9.4.1彩信发送入口SmsManager的sendMultimediaMessage方法,主要的逻辑是获取imms系统服务,并调用其sendMessage方法发送彩信publicvoidsendMultimediaMessage(Conte
xtcontext,UricontentUri,StringlocationUrl,BundleconfigOverrides,PendingIntentsentIntent){try{finalIMmsiMms=IMms.Stub.asInterface(ServiceManager.getS
ervice("imms"));android.util.Log.e("XXX","sendMultimediaMessage",newRuntimeException());iMms.sendMessage(getS
ubscriptionId(),ActivityThread.currentPackageName(),contentUri,locationUrl,configOverrides,sentIntent);}catch(Remote
Exceptione){......}}9.4彩信关键业务逻辑9.4.2imms系统服务IMms接口的实现有两个类MmsServiceBroker和MmsService,imms系统服务是MmsServiceBroker服务在system_server系统进程启动的过程
中加载,在onStart方法中调用publishBinderService("imms",newBinderService())增加名字为imms的系统服务,BinderService实现了IMms.Stub,实现的接口处理逻辑是代理MmsService服务
对应的接口;首先bind绑定MmsService服务获取ClientBinder对象,再通过Binder对象调用MmsService服务提供的服务接口。9.4彩信关键业务逻辑9.4.3彩信MO流程彩信的发送业务流程可分为四个步骤a)acquireNetwork请求MMS移动数
据业务b)ApnSettings.load加载MMS类型的APN设置信息c)doHttp创建http连接发送彩信内容d)releaseNetwork释放网络资源9.4彩信关键业务逻辑9.4.4DataCall9.4彩信关键业务逻辑9.4.5doHttppublicbyte[]exec
ute(StringurlString,byte[]pdu,Stringmethod,booleanisProxySet,StringproxyHost,intproxyPort,BundlemmsConfig,intsubId,S
tringrequestId)throwsMmsHttpException{HttpURLConnectionconnection=null;try{finalURLurl=newURL(urlString);//彩信APN配置的URL地址connection=(HttpURLCo
nnection)mNetwork.openConnection(url,proxy);if(METHOD_POST.equals(method)){finalOutputStreamout=newBufferedOutp
utStream(connection.getOutputStream());out.write(pdu);//向彩信服务其地址通过http写入发送彩信内容out.flush();out.close(
);}elseif(METHOD_GET.equals(method))......彩信接收处理逻辑}catch()......}finally{if(connection!=null){connection
.disconnect();}}}9.4彩信关键业务逻辑9.4.6接收彩信1.向Nexus6P手机发送一条彩信,InboundSmsHandler的DeliveringState状态将首先接收到一条比
较特殊的短信,在调用processMessagePart方法时,判断接收的端口号是2948,则按照WAPPush的方式处理。2.接着调用WapPushOverSms.dispatchWapPdu方法,将创建Action为Intent
s.WAP_PUSH_DELIVER_ACTION类型的Intent对象,再次调用InboundSmsHandler对象的dispatchIntent发出广播通知,SmsBroadcastReceiver接收此广播,将Action转换为I
ntents.WAP_PUSH_RECEIVED_ACTION类型消息,第二次调用dispatchIntent发出接收到WAPPush消息的广播通知。3.Messaging应用中的MmsWapPushReceiver将接收此广播,并激活ReceiveSmsMes
sageAction的executeAction后台异步处理机制。9.4彩信关键业务逻辑9.4.7MmsService小结1.MmsService服务提供了发送和接收彩信接口,imms服务的实现是msServiceBroker,它代理了MmsServi
ce服务。2.MmsRequest作为模板类实现了发送或接收彩信关键四个步骤的调度模板,首先请求MMS类型的DataCall移动数据业务,接着加载ApnSetting,然后,通过http下载或发送彩信内容,它有Sen
d和Download两个子类,最后releaseNetwork释放DataCall移动数据业务。3.MmsNetworkManager负责请求或释放MMS类型的DataCall移动数据业务。4.MmsHttp
Client负责http数据传输,实现了数据的上传和下载。9.5本章小结1.SMS短信的MO和MT流程,跨越了Messaging应用、TelephonyFramework和RIL层,最后RIL与Mode
m交互完成了短信的发送和接收。2.掌握SMSDispatcher发送短信的处理流程,InboundSmsHandler状态机接收短信的处理流程。3.掌握Messaging应用中Action处理机制。4.彩信是基于DataCall移动数据业务的网络应用,MMS类型
的DataCall移动数据业务作为彩信业务的核心机制,掌握ConnectivityService的处理机制,完成彩信移动数据连接的建立以及RequestNetwork的消息回调。AndroidTelephony原理解析与开发指南第十章RadioInterfaceLayer•10.1解析RILJ–
10.1.1认识RIL类–10.1.2RILRequest–10.1.3IRadio关联的服务–10.1.4RIL消息分类–10.1.5SolicitedRequest–10.1.6SolicitedResponse–10.1.7UnSolicited•10.2详解rild–10.2.1RIL_s
tartEventLoop–10.2.2获取RIL_RadioFunctions–10.2.3注册RIL_RadioFunctions•10.3libril初始化流程–10.3.1RIL_startEventLoop
–10.3.2RIL_register第十章RadioInterfaceLayer•10.4扩展hal接口–10.4.1增加接口定义–10.4.2验证生成的代码–10.4.3实现新增接口–10.4.4运行结果验证•10.5RILC运行机制–10.5.1Solicite
d消息–10.5.2UnSolicited消息•10.6本章小结10.1解析RILJ10.1.1认识RIL类10.1解析RILJ10.1.2RILRequestRILRequest类有两个非常关键的方法:obta
in和onError。RILRequest类中重载了obtain方法,一个是privatestaticobtain方法,将创建RILRequest对象;另一个是packagestaticobtain方法,作为privatestaticobtain方法的代理,提供
给RILJ对象调用。privatestaticRILRequestobtain(intrequest,Messageresult){RILRequestrr=null;synchronized(sPoolSync){//同步锁if(sPool!=
null){rr=sPool;//获取缓冲池中的RILRequest对象sPool=rr.mNext;rr.mNext=null;sPoolSize--;}}if(rr==null){rr=newRILRequest();//如果没有缓冲对象时,创
建RILRequest对象}rr.mSerial=sNextSerial.getAndIncrement();//AtomicInteger自动加1rr.mRequest=request;//保存RIL请求类型rr.mResult=result;//保存Message对象……returnrr;}
10.1解析RILJ10.1.3IRadio关联的服务hardware/interfaces/radio/1.0/Android.mk编译脚本中定义的MODULE,详情如下:LOCAL_MODULE:=android.hardware.radio-V1.0-javaLOCAL_MOD
ULE:=android.hardware.radio-V1.0-java-staticpublicclassRadioResponseextendsIRadioResponse.StubpublicclassRadioIndicationextendsIRadio
Indication.Stub//根据mPhoneId获取对应的IRadio系统服务mRadioProxy=IRadio.getService(HIDL_SERVICE_NAME[mPhoneId==null?0:mPhon
eId]);if(mRadioProxy!=null){mRadioProxy.linkToDeath(mRadioProxyDeathRecipient,mRadioProxyCookie.incrementAndGet());//Binder异常的处理//设置回调的两个服务m
RadioProxy.setResponseFunctions(mRadioResponse,mRadioIndication);10.1解析RILJ10.1.4RIL消息分类RIL层中的数据交互方式,根据消息来源按照其处
理方式可分为两大类:a)Solicitedb)UnSolicited比如常用的如dial拨号、answer接听电话、hangup挂断电话等这些AP侧主动请求的操作,称为Solicited消息;Solicited请求类的RIL消息,根据其消息
传递方向,可分为SolicitedRequest和SolicitedResponse种消息;正常情况下,SolicitedRequest与SolicitedResponse消息成对出现,请求和应答是一一对应的。BP侧主动上报的消息,如通话状态变化、新短信、新彩信、基站信息等,
是UnSolicited非请求类RIL消息,只有上报流程。10.1解析RILJ10.1.5SolicitedRequestpublicvoidgetDataRegistrationState(Messageresult){IRadioradi
oProxy=getRadioProxy(result);//获取IRadio服务调用对象if(radioProxy!=null){//创建并记录RILRequest对象RILRequestrr=obtainRequest(RIL_REQUEST_DATA_REGISTRATION_STATE,r
esult,mRILDefaultWorkSource);//记录RILJ发出的RIL请求日志if(RILJ_LOGD)riljLog(rr.serialString()+">"+requestToString(
rr.mRequest));try{radioProxy.getDataRegistrationState(rr.mSerial);//调用IRadio服务接口}catch(RemoteException|RuntimeExceptione){handleRadioProxyExce
ptionForRR(rr,"getDataRegistrationState",e);}}}10.1解析RILJ10.1.6SolicitedResponseSolicitedRequest和SolicitedResponse消息一一对
应。10.1解析RILJ10.1.7UnSolicitedcom.android.phone进程中的RadioIndication服务,将接收HAL层发出的UnSolicited消息接口调用,radioStateChanged为例
:publicvoidradioStateChanged(intindicationType,intradioState){mRil.processIndication(indicationType);//处理ACK消息//获取最新Radio状态Com
mandsInterface.RadioStatenewState=getRadioStateFromInt(radioState);if(RIL.RILJ_LOGD){//记录RIL_UNSOL_XXX日志mRil.unsljLogMore(RIL_UNSOL_RESPONSE_RADIO
_STATE_CHANGED,"radioStateChanged:"+newState);}mRil.setRadioState(newState);//更新Radio状态}10.2详解rildrild的代码路径是:hardware/ril/rild
,该代码库主要有三个代码文件:Android.mk、rild.c和rild.rc;首先查看Android.mk编译脚本,关键信息,详情如下:LOCAL_PATH:=$(callmy-dir)include$(CLEAR_VARS)LOCAL_SRC_FILES:=\rild.c//仅
有一个C代码文件LOCAL_MODULE:=rildLOCAL_INIT_RC:=rild.rc//安装配置信息include$(BUILD_EXECUTABLE)//编译生成rild可执行文件rild.c代码文件将编译出rild可执行文件
,接着查看rild.rc的配置信息,详情如下:serviceril-daemon/vendor/bin/hw/rildclassmainuserradiogroupradiocacheinetmiscaudiologreadprocwakelockcap
abilitiesBLOCK_SUSPENDNET_ADMINNET_RAW$adbshellps|greprildradio60216636012728binder_thread_read0Srild10.2详解rild10.2.1RIL_startEventLoop在rild的Androi
d.mk文件中可找到rild与libril的关系LOCAL_SHARED_LIBRARIES:=\libcutils\libdl\liblog\librilrild进程中调用的RIL_startEventLoop函数,是libril中的实现10.2详解rild10.2.2获取R
IL_RadioFunctions//定义rilInit函数指针constRIL_RadioFunctions*(*rilInit)(conststructRIL_Env*,int,char**);constRIL_RadioFunctions*funcs;dlHandl
e=dlopen(rilLibPath,RTLD_NOW);//打开动态链接库if(dlHandle==NULL){//失败处理RLOGE("dlopenfailed:%s",dlerror());exit(EXIT_FAILURE);//异常退出}rilInit=(
constRIL_RadioFunctions*(*)(conststructRIL_Env*,int,char**))dlsym(dlHandle,"RIL_Init");//获取动态链接库RIL_Init函数地址if(rilInit==NULL){//异常处理RLOGE("RIL_In
itnotdefinedorexportedin%s\n",rilLibPath);exit(EXIT_FAILURE);//异常退出}//调用动态库RIL_Init函数,返回funcsfuncs=rilInit(&s_rilEnv,argc,rilA
rgv);10.2详解rild10.2.3注册RIL_RadioFunctionsrild加载过程中最后的关键逻辑是注册RIL_RadioFunctions,只有一行代码的调用逻辑,RIL_register(funcs),其参数是获
取动态库文件中RIL_RadioFunctions结构体的地址,即指向RIL_RadioFunctions的指针。RIL_register函数在当前代码中的声明如下:externvoidRIL_regi
ster(constRIL_RadioFunctions*callbacks);与RIL_startEventLoop函数的声明相同,同样,hardware/ril/libril/ril.cppC++代码中实现了此函数,其函数声明是
:extern"C"voidRIL_register(constRIL_RadioFunctions*callbacks)。10.3libril初始化流程10.3.1RIL_startEventLoopextern"C"voidRIL_st
artEventLoop(void){//extern"C"标识此方法可供rild调用/*spinupeventLoopthreadandwaitforittogetstarted*/s_started=0;//启动标志pthre
ad_mutex_lock(&s_startupMutex);//增加pthread的同步锁pthread_attr_tattr;pthread_attr_init(&attr);//初始化pthread参数pthread_attr_setdetachstate(&attr,PTHRE
AD_CREATE_DETACHED);//创建基于eventLoop函数调用的子线程intresult=pthread_create(&s_tid_dispatch,&attr,eventLoop,NULL);if(result!=0
){//异常处理RLOGE("Failedtocreatedispatchthread:%s",strerror(result));gotodone;}while(s_started==0){//pthread启动标志,会在eventLoop方法中设置为1pthread_cond_
wait(&s_startupCond,&s_startupMutex);//等待s_startupCond通知}done:pthread_mutex_unlock(&s_startupMutex);}10.3libril初始化流程10
.3.1RIL_startEventLoopextern"C"voidRIL_startEventLoop(void){//extern"C"标识此方法可供rild调用/*spinupeventLoopthreadandwait
forittogetstarted*/s_started=0;//启动标志pthread_mutex_lock(&s_startupMutex);//增加pthread的同步锁pthread_attr_tattr;pthread_attr_init(&attr);/
/初始化pthread参数pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);//创建基于eventLoop函数调用的子线程intres
ult=pthread_create(&s_tid_dispatch,&attr,eventLoop,NULL);if(result!=0){//异常处理RLOGE("Failedtocreatedispatchthread:
%s",strerror(result));gotodone;}while(s_started==0){//pthread启动标志,会在eventLoop方法中设置为1pthread_cond_wait(&s_sta
rtupCond,&s_startupMutex);//等待s_startupCond通知}done:pthread_mutex_unlock(&s_startupMutex);}10.3libril初始化流程10.3.1RIL_startEve
ntLoopstaticvoid*eventLoop(void*param){ril_event_init();//初始化ril_event双向链表pthread_mutex_lock(&s_startupMutex);//增加pt
hread同步锁s_started=1;//修改启动状态为1pthread_cond_broadcast(&s_startupCond);//发出s_startupCond通知pthread_mutex_unlock(&s_startupMutex);//释放pthr
ead同步锁ret=pipe(filedes);//创建管道s_fdWakeupRead=filedes[0];//输入的fds_fdWakeupWrite=filedes[1];//输出的fdfcntl(s_fd
WakeupRead,F_SETFL,O_NONBLOCK);//创建RIL事件,关注s_fdWakeupRead和回调函数processWakeupCallbackril_event_set(&s_wakeupfd_event,s_fdWakeupRead,true,proces
sWakeupCallback,NULL);rilEventAddWakeup(&s_wakeupfd_event);//增加ril_event节点,并唤醒ril_event_loop();//开始循环监听和处理ril_event事件,只有在异常情况下退出循环RLOGE("errorineve
nt_loop_baseerrno:%d",errno);kill(0,SIGKILL);//异常,kill当前进程,init进程将重新拉起rild进程returnNULL;}10.3libril初始化流程10.3
.2RIL_registerextern"C"voidRIL_register(constRIL_RadioFunctions*callbacks){……参数判断//拷贝callbacks到s_callbacks本
地变量memcpy(&s_callbacks,callbacks,sizeof(RIL_RadioFunctions));s_registerCalled=1;//更改调用状态标志//两个for循环检查ril_commands.h和ril_unsol_commands.h头文件中的
RIL消息处理定义正确性,一旦有异常,则产生assert断言for(inti=0;i<(int)NUM_ELEMS(s_commands);i++){assert(i==s_commands[i].requestNumber);}for(inti=0;i<(int)NUM_ELEMS(s_unso
lResponses);i++){assert(i+RIL_UNSOL_RESPONSE_BASE==s_unsolResponses[i].requestNumber);}//注册服务radio::registerService(&s_callbacks,s_commands
);}10.3libril初始化流程10.3.2RIL_registervoidradio::registerService(RIL_RadioFunctions*callbacks,CommandInfo*commands){c
onfigureRpcThreadpool(1,true/*callerWillJoin*/);//初始化远程调用进程for(inti=0;i<simCount;i++){pthread_rwlock_t*radioServiceRwlockPtr=getRadioServi
ceRwlock(i);intret=pthread_rwlock_wrlock(radioServiceRwlockPtr);//同步锁assert(ret==0);radioService[i]=newRadioImpl;//创建R
adioImpl对象radioService[i]->mSlotId=i;oemHookService[i]=newOemHookImpl;//创建OemHookImpl对象oemHookService[i]->mSlotId=i;//注册系统服务android::status
_tstatus=radioService[i]->registerAsService(serviceNames[i]);status=oemHookService[i]->registerAsService(serviceNames[i]);ret=pthrea
d_rwlock_unlock(radioServiceRwlockPtr);//释放同步锁assert(ret==0);}s_vendorFunctions=callbacks;//三方functionss_commands=commands
;//本地commands}10.4扩展hal接口10.4.1增加接口定义hardware/interfaces/radio/1.0/IRadio.hal增加testRilReq接口onewaytestRilReq(int32_tserial,int32_treqNum);ha
rdware/interfaces/radio/1.0/IRadioResponse.hal增加testRilResp接口onewaytestRilResp(RadioResponseInfoinfo);10.4扩展hal接口10.4.2验证生成的代码查看IRadio.
java文件,以及新增的testRilReq接口publicinterfaceIRadioextendsandroid.hidl.base.V1_0.IBase{publicstaticfinalclassProxyimpleme
ntsIRadio{//Proxy代理类实现了IRadio接口@OverridepublicvoidtestRilReq(intserial,intreqNum)throwsandroid.os.Rem
oteException{android.os.HwParcel_hidl_request=newandroid.os.HwParcel();_hidl_request.writeInterfaceToken(IRadio.kInterfaceName);_hidl_reques
t.writeInt32(serial);_hidl_request.writeInt32(reqNum);//HwParcel序列化请求参数android.os.HwParcel_hidl_reply=new
android.os.HwParcel();try{//发起远程transact,注意131对应testRilReq请求mRemote.transact(131/*testRilReq*/,_hidl_request,_hidl_reply,android.os.IHw
Binder.FLAG_ONEWAY);_hidl_request.releaseTemporaryStorage();}finally{_hidl_reply.release();}}}10.4扩展hal接口10.4.2
验证生成的代码//内部抽象Stub类,继承HwBinder实现IRadio接口publicstaticabstractclassStubextendsandroid.os.HwBinderimplementsIRadi
o{@Override//Proxy类发起的远程调用publicvoidonTransact(int_hidl_code,android.os.HwParcel_hidl_request,finalandroid.os.HwParcel_hidl_reply,int_hidl_fla
gs)throwsandroid.os.RemoteException{switch(_hidl_code){case131/*testRilReq*/://131对应testRilReq接口调用{//HwPa
rcel反序列化,获取请求参数_hidl_request.enforceInterface(IRadio.kInterfaceName);intserial=_hidl_request.readInt32();in
treqNum=_hidl_request.readInt32();testRilReq(serial,reqNum);//调用IRadio远程实现的接口break;}}}}10.4扩展hal接口10.4.2验证生成的代码接着查看IRadio接口
相关的头文件关键信息namespaceandroid{namespacehardware{namespaceradio{namespaceV1_0{structIRadio:public::android::hidl::base::V1_0::IBase{......virtual
::android::hardware::Return<void>testRilReq(int32_tserial,int32_treqNum)=0;}}}}}关注BpHwRadio::_hidl_testRil
Req函数的关键逻辑_hidl_err=_hidl_data.writeInterfaceToken(BpHwRadio::descriptor);//参数序列化操作_hidl_err=_hidl_data.writeInt32(serial);_h
idl_err=_hidl_data.writeInt32(reqNum);//远程接口transact,131_hidl_err=::android::hardware::IInterface::asBinder(_hidl_this)->transact(1
31/*testRilReq*/,_hidl_data,&_hidl_reply,::android::hardware::IBinder::FLAG_ONEWAY);10.4扩展hal接口10.4.2验证生成的代
码接着查看IRadio接口相关的头文件关键信息namespaceandroid{namespacehardware{namespaceradio{namespaceV1_0{structIRadio:public::android::hidl::b
ase::V1_0::IBase{......virtual::android::hardware::Return<void>testRilReq(int32_tserial,int32_treqNum)=0;}}}}}关注BpHw
Radio::_hidl_testRilReq函数的关键逻辑_hidl_err=_hidl_data.writeInterfaceToken(BpHwRadio::descriptor);//参数序列化操作_hidl_err=_hidl_data.writeInt32(serial);_hidl
_err=_hidl_data.writeInt32(reqNum);//远程接口transact,131_hidl_err=::android::hardware::IInterface::asBinder(_hidl_this)->transact(131/*te
stRilReq*/,_hidl_data,&_hidl_reply,::android::hardware::IBinder::FLAG_ONEWAY);10.4扩展hal接口10.4.2验证生成的代码与IRadio.java内部类Proxy的testRilReq方法中的处理逻辑相同,序列化
请求参数,发起131编号远程transact调用;BnHwRadio本地响应onTransact远程调用,处理逻辑详情如下。::android::status_tBnHwRadio::onTransact(uint32_t_hidl_co
de,const::android::hardware::Parcel&_hidl_data,::android::hardware::Parcel*_hidl_reply,uint32_t_hidl_flags,Tr
ansactCallback_hidl_cb){::android::status_t_hidl_err=::android::OK;switch(_hidl_code){case131/*testRilReq*/:{_hi
dl_err=::android::hardware::radio::V1_0::BnHwRadio::_hidl_testRilReq(this,_hidl_data,_hidl_reply,_hidl_cb);break;}}}10.4扩展
hal接口10.4.2验证生成的代码131请求类型testRilReq,最后调用BnHwRadio::_hidl_testRilReq函数::android::status_tBnHwRadio::_hidl_te
stRilReq(::android::hidl::base::V1_0::BnHwBase*_hidl_this,const::android::hardware::Parcel&_hidl_data,::android::hardware::Parcel*_hidl_r
eply,TransactCallback_hidl_cb){int32_tserial;int32_treqNum;_hidl_err=_hidl_data.readInt32(&serial);//反序列化
读取请求参数_hidl_err=_hidl_data.readInt32(&reqNum);//通过this调用testRilReqstatic_cast<BnHwRadio*>(_hidl_this)->_hidl_mImpl->testRilReq(s
erial,reqNum);::android::hardware::writeToParcel(::android::hardware::Status::ok(),_hidl_reply);return_hidl_err;}10.4扩展hal接口10.4.
3实现新增接口1.RadioImpl类继承IRadio,因此需要在RadioImpl类中完成testRilReq接口的实现2.com.android.phone进程中RadioResponse对象实现了IRadioResponse接口,I
RadioResponse新增了接口,因此需要在RadioResponse.java代码中实现新增接口3.修改RILJ的构造方法,在构造方法的最后,增加testRilReq接口调用10.4扩展hal接口10.4.4运行结果验证
D/RILC(603):XXXtestRilReq:serial:100,reqNum:100011231266DXXX:testRilResp:{.type=SOLICITED,.serial=100,.err
or=NONE}$adbshellps|grepradioradio60316525213100binder_thread_read73646ad4e8Srildradio1123585435354468696SyS_epoll_wait7
6d4fbd3f8Scom.android.phone10.5RILC运行机制10.5.1Solicited消息Return<void>RadioImpl::dial(int32_tserial,constDial&dialInfo
){//保存Request请求信息,返回*RequestInfoRequestInfo*pRI=android::addRequestToList(serial,mSlotId,RIL_REQUEST_DIAL);//根据传入的拨号请求信息,初始化RIL_D
ialRIL_Dialdial={};......//继续发出Request请求CALL_ONREQUEST(RIL_REQUEST_DIAL,&dial,sizeOfDial,pRI,mSlotId);//收尾工作memsetAndFreeStrings(2,di
al.address,uusInfo.uusData);returnVoid();}10.5RILC运行机制10.5.1Solicited消息staticvoidonRequest(intrequest,void*data,size
_tdatalen,RIL_Tokent){switch(request){caseRIL_REQUEST_DIAL:requestDial(data,datalen,t);break;......}}staticvoidrequestDial(void
*data,size_tdatalen__unused,RIL_Tokent){RIL_Dial*p_dial;char*cmd;constchar*clir;intret;p_dial=(RIL_Dial*)data;ret=at_send_command(cmd,
NULL);//发送AT指令free(cmd);RIL_onRequestComplete(t,RIL_E_SUCCESS,NULL,0);//发起回调}#defineRIL_onRequestComple
te(t,e,response,responselen)s_rilenv->OnRequestComplete(t,e,response,responselen)10.5RILC运行机制10.5.1Solic
ited消息extern"C"voidRIL_onRequestComplete(RIL_Tokent,RIL_Errnoe,void*response,size_tresponselen){RequestInfo*pRI;in
tret;RIL_SOCKET_IDsocket_id=RIL_SOCKET_1;pRI=(RequestInfo*)t;//强制类型转换if(!checkAndDequeueRequestInfoI
fAck(pRI,false)){//获取RequestInfoRLOGE("RIL_onRequestComplete:invalidRIL_Token");return;}socket_id=pRI->socket_id;i
f(pRI->cancelled==0){intresponseType;......versionACK判断处理逻辑intrwlockRet=pthread_rwlock_rdlock(radioServiceRwlockP
tr);//rdlockassert(rwlockRet==0);//调用XXXResponse函数ret=pRI->pCI->responseFunction((int)socket_id,responseType,pRI->token,e,response,responselen);rwlo
ckRet=pthread_rwlock_unlock(radioServiceRwlockPtr);//unlockassert(rwlockRet==0);}free(pRI);//释放RequestInfo内存}10.5RILC运行机制10.5.1Soli
cited消息staticintcheckAndDequeueRequestInfoIfAck(structRequestInfo*pRI,boolisAck){intret=0;pthread_mutex_t*pe
ndingRequestsMutexHook=&s_pendingRequestsMutex;//s_pendingRequests链表中匹配RequestInfoRequestInfo**pendin
gRequestsHook=&s_pendingRequests;pthread_mutex_lock(pendingRequestsMutexHook);//同步锁for(RequestInfo**ppCur=pendingRequ
estsHook;*ppCur!=NULL;ppCur=&((*ppCur)->p_next)//循环pendingRequests链表){if(pRI==*ppCur){//匹配的是tokenret=1;*ppCur=(*
ppCur)->p_next;//断开匹配到的元素break;}}pthread_mutex_unlock(pendingRequestsMutexHook);//释放锁returnret;}10.5RILC运行机制1
0.5.1Solicited消息staticintcheckAndDequeueRequestInfoIfAck(structRequestInfo*pRI,boolisAck){intret=0;pthread_mutex_t*pendingRequestsMutexHook
=&s_pendingRequestsMutex;//s_pendingRequests链表中匹配RequestInfoRequestInfo**pendingRequestsHook=&s_pendingRequests;pthread_mutex_lock(pendingReq
uestsMutexHook);//同步锁for(RequestInfo**ppCur=pendingRequestsHook;*ppCur!=NULL;ppCur=&((*ppCur)->p_next)//循环pendingReque
sts链表){if(pRI==*ppCur){//匹配的是tokenret=1;*ppCur=(*ppCur)->p_next;//断开匹配到的元素break;}}pthread_mutex_unlock
(pendingRequestsMutexHook);//释放锁returnret;}10.5RILC运行机制10.5.1Solicited消息intradio::dialResponse(intslotId,intresponseType,intserial
,RIL_Errnoe,void*response,size_tresponseLen){if(radioService[slotId]->mRadioResponse!=NULL){RadioResponseInforesponseInfo={};p
opulateResponseInfo(responseInfo,serial,responseType,e);Return<void>retStatus=radioService[slotId]->mRa
dioResponse->dialResponse(responseInfo);radioService[slotId]->checkReturnStatus(retStatus);}else{RLOGE("dialResponse:radioService[%d]->mRadioRespon
se==NULL",slotId);}return0;}intradio::dialResponse(intslotId,intresponseType,intserial,RIL_Errnoe,void*response,size_tresponseLen){if(radioSe
rvice[slotId]->mRadioResponse!=NULL){RadioResponseInforesponseInfo={};populateResponseInfo(responseInfo,serial,responseType,e);//构建返
回结果Return<void>retStatus=//调用Phone进程IRadioResponse服务radioService[slotId]->mRadioResponse->dialResponse(responseInfo);radio
Service[slotId]->checkReturnStatus(retStatus);}else{RLOGE("dialResponse:radioService[%d]->mRadioResponse==NULL",slotId);}return0;}10.5RILC运行机制10.5
.1Solicited消息intradio::dialResponse(intslotId,intresponseType,intserial,RIL_Errnoe,void*response,size_tresponseLen){if(radioServ
ice[slotId]->mRadioResponse!=NULL){RadioResponseInforesponseInfo={};populateResponseInfo(responseInfo,se
rial,responseType,e);Return<void>retStatus=radioService[slotId]->mRadioResponse->dialResponse(responseInfo);radioService[slo
tId]->checkReturnStatus(retStatus);}else{RLOGE("dialResponse:radioService[%d]->mRadioResponse==NULL",slotId);}return
0;}intradio::dialResponse(intslotId,intresponseType,intserial,RIL_Errnoe,void*response,size_tresponseLen){if(radioService[slotId]->mRadioRes
ponse!=NULL){RadioResponseInforesponseInfo={};populateResponseInfo(responseInfo,serial,responseType,e);//构建返回结果Return<void>
retStatus=//调用Phone进程IRadioResponse服务radioService[slotId]->mRadioResponse->dialResponse(responseInfo);r
adioService[slotId]->checkReturnStatus(retStatus);}else{RLOGE("dialResponse:radioService[%d]->mRadioResponse==NULL",slotId);}return0;}10.5RILC运行机
制10.5.2UnSolicited消息extern"C"voidRIL_onUnsolicitedResponse(intunsolResponse,constvoid*data,size_tdatalen,RIL_SOCKET_IDsock
et_id){……//声明及异常处理//计算s_unsolResponses数组下标unsolResponseIndex=unsolResponse-RIL_UNSOL_RESPONSE_BASE;pthread_rwlock_t*radioS
erviceRwlockPtr=radio::getRadioServiceRwlock((int)soc_id);intrwlockRet=pthread_rwlock_rdlock(radioServic
eRwlockPtr);//同步锁assert(rwlockRet==0);//发起responseFunction调用ret=s_unsolResponses[unsolResponseIndex].response
Function((int)soc_id,responseType,0,RIL_E_SUCCESS,const_cast<void*>(data),datalen);rwlockRet=pthread_rwlock_unlock(radioServiceRwlockPtr);
//释放锁assert(rwlockRet==0);return;}10.5RILC运行机制10.5.2UnSolicited消息intradio::callStateChangedInd(intslotId,intindicationType,inttoken,RIL_Errnoe,void
*response,size_tresponseLen){if(radioService[slotId]!=NULL&&radioService[slotId]->mRadioIndication!=NULL){Return<void>retStatus=radi
oService[slotId]->mRadioIndication->callStateChanged(convertIntToRadioIndicationType(indicationType));radioService[slotId]->checkReturnStatus(r
etStatus);}else{RLOGE("callStateChangedInd:radioService[%d]->mRadioIndication==NULL",slotId);}return0;}10.5RIL
C运行机制10.6本章小结10.6本章小结1.RIL主要分RILJ和RILC两部分,RILJ运行在com.android.phone进程空间,TelephonyFramework框架层;RILC运行在Use
rLibraries系统运行库层中的HAL子层。2.rild、libril和三方RIL实现都运行在rild进程,通rild.rc配置文件由Linuxinit进程进行加载和管理。3.RILJ与RILC通过IRadio、IRadioIndication和IRadioResponse服务接口调用,完
成Solicited和UnSolicited消息交互。4.三方RIL库文件与Modem交互,完成Modem的操作控制和查询请求,以及接收Modem主动上报消息;可参考完全符合AndroidRIL运行框架libreference-ril,基于AT命令的实现方式。5.掌握Solicited和UnSo
licited消息在RILJ和RILC中的处理机制。