Android Telephony分析(四) ---- TelephonyManager详解
前言
TelephonyManager主要提供Telephony相关信息的查询/修改功能,以及Phone状态监听功能,封装的方法主要是提供给APP上层使用。
TelephonyManager.java 在frameworks\base\telephony\java\android\telephony目录下。
1. TelephonyManager整体结构
从TelephonyManager导入的文件中可以发现有四个接口
import com.android.internal.telecom.ITelecomService;
import com.android.internal.telephony.IPhoneSubInfo;
import com.android.internal.telephony.ITelephony;
import com.android.internal.telephony.ITelephonyRegistry;
分别对应下面这几个AIDL接口:
\frameworks\base\telecomm\java\com\android\internal\telecom\ITelecomService.aidl
\frameworks\base\telephony\java\com\android\internal\telephony\IPhoneSubInfo.aidl
\frameworks\base\telephony\java\com\android\internal\telephony\ITelephony.aidl
\frameworks\base\telephony\java\com\android\internal\telephony\ITelephonyRegistry.aidl
以可以猜测到,在TelephonyManager中可以得到这四种Service。
通过所有文件中搜索”extends 接口名.Stub”,如”extends ITelephony.Stub”,可以找到是哪些类实现了上面四个AIDL接口中的方法,整理可得:

在TelephonyManager中搜索”接口名.Stub.asInterface”,如”ITelephony.Stub.asInterface”,可以找到这四个Service的名字,整理可得:
private ITelecomService getTelecomService() {
return ITelecomService.Stub.asInterface(ServiceManager.getService(TELECOM_SERVICE));
}
@UnsupportedAppUsage
private IPhoneSubInfo getSubscriberInfo() {
// get it each time because that process crashes a lot
return IPhoneSubInfo.Stub.asInterface(ServiceManager.getService("iphonesubinfo"));
}
private ITelephony getITelephony() {
return ITelephony.Stub.asInterface(ServiceManager.getService(Context.TELEPHONY_SERVICE));
}
private ITelephonyRegistry getTelephonyRegistry() {
return ITelephonyRegistry.Stub.asInterface(ServiceManager.getService("telephony.registry"));
}

好了,下面分别对这四种Service进行分析:
1.1 TelecomServiceImpl—Telecom Service(TelecomLoaderService.java注册)
服务端TelecomServiceImpl中有mBinderImpl实现了ITelecomService接口中的方法
public class TelecomServiceImpl {
private final ITelecomService.Stub mBinderImpl = new ITelecomService.Stub() {
...
}
}
在TelecomLoaderService.java中,TelecomServiceImpl把自己注册到ServiceManager中,
ServiceManager.addService(Context.TELECOM_SERVICE, service);
所以在TelephonyManager中可以通过ServiceManager得到Telecom Service
private ITelecomService getTelecomService() {
//得到TelecomServiceImpl的代理对象
return ITelecomService.Stub.asInterface(ServiceManager.getService(Context.TELECOM_SERVICE));
}
其实Telecom Service的最常用客户端是TelecomManager.java。而在TelephonyManager中由于无法得到CallManager对象,所以只能依赖Telecom Service获取Call State。
/**
* Returns one of the following constants that represents the current state of all
* phone calls.
*
* {@link TelephonyManager#CALL_STATE_RINGING}
* {@link TelephonyManager#CALL_STATE_OFFHOOK}
* {@link TelephonyManager#CALL_STATE_IDLE}
*/
public int getCallState() {
try {
ITelecomService telecom = getTelecomService();
if (telecom != null) {
return telecom.getCallState();
}
} catch (RemoteException e) {
Log.e(TAG, "Error calling ITelecomService#getCallState", e);
}
return CALL_STATE_IDLE;
}
所以,总体上来说,虽然TelecomManager得到了Telecom Service,但其实作用不大。相反,Telecom Service中会反过来得到TelephonyManager对象,进一步实现自己的方法,如在TelecomServiceImpl.java中:
public String getVoiceMailNumber(PhoneAccountHandle accountHandle, String callingPackage) {
...
return getTelephonyManager().getVoiceMailNumber(subId);
...
}
private TelephonyManager getTelephonyManager() {
return (TelephonyManager)mContext.getSystemService(Context.TELEPHONY_SERVICE);
}
1.2 PhoneSubInfoController— “iphonesubinfo” Service(PhoneSubInfoController中注册)
服务端PhoneSubInfoController继承自IPhoneSubInfo.Stub
public class PhoneSubInfoController extends IPhoneSubInfo.Stub {...}
在创建Default Phone对象之后,ProxyController对象在PhoneFactory.java的makeDefaultPhone()中被初始化
public static void makeDefaultPhone(Context context) {
...
//先初始化ProxyController
mProxyController = ProxyController.getInstance(context, sProxyPhones,
mUiccController, sCommandsInterfaces);
...
}
private ProxyController(Context context, PhoneProxy[] phoneProxy, UiccController uiccController,
CommandsInterface[] ci) {
...
//在ProxyController的构造方法中初始化了PhoneSubInfoController对象
mPhoneSubInfoController = new PhoneSubInfoController(mContext, mPhones);
...
}
public PhoneSubInfoController(Context context, Phone[] phone) {
mPhone = phone;
if (ServiceManager.getService("iphonesubinfo") == null) {
//将PhoneSubInfoController实例注册到ServiceManager中
ServiceManager.addService("iphonesubinfo", this);
}
mContext = context;
mAppOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
}
所以在TelephonyManager中可以通过ServiceManager得到”iphonesubinfo” Service
private IPhoneSubInfo getSubscriberInfo() {
// get it each time because that process crashes a lot
return IPhoneSubInfo.Stub.asInterface(ServiceManager.getService("iphonesubinfo"));
}
通过”iphonesubinfo” Service可以得到software version、deviceID、VoiceMail Number等信息,TelephonyManager在这里只是对这些方法进一步封装,这些方法具体的实现,最后还是通过Phone实例和IsimRecords实例来完成的。
以getMsisdn()方法为例,最常见的调用方式如下: 
PhoneInterfaceManager.init
备注:在Android N中已删除PhoneSubInfo.java和PhoneSubInfoProxy.java,所以流程变得简单了。
1.3 PhoneInterfaceManager—Telephony Service(PhoneInterfaceManager中注册)
TelephonyManager依赖Telephony Service实现了大部分的方法。
PhoneInterfaceManager继承自ITelephony.Stub
public class PhoneInterfaceManager extends ITelephony.Stub {
PhoneInterfaceManager.java在 packages\services\telephony\src\com\android\phone目录下,显然它是运行在Phone进程中的。
在Phone进程启动时,Default Phone对象创建完之后,PhoneInterfaceManager对象在/packages/services/Telephony/src/com/android/phone/PhoneGlobals.java的onCreate()中被初始化:
public void onCreate() {
...
phoneMgr = PhoneInterfaceManager.init(this, PhoneFactory.getDefaultPhone());
...
}
/* package */ static PhoneInterfaceManager init(PhoneGlobals app, Phone phone) {
synchronized (PhoneInterfaceManager.class) {
if (sInstance == null) {
//初始化PhoneInterfaceManager
sInstance = new PhoneInterfaceManager(app, phone);
} else {
Log.wtf(LOG_TAG, "init() called multiple times! sInstance = " + sInstance);
}
return sInstance;
}
}
在PhoneInterfaceManager的构造方法中:
private PhoneInterfaceManager(PhoneGlobals app, Phone phone) {
//得到一些关键类
mApp = app;
mPhone = phone;
mCM = PhoneGlobals.getInstance().mCM;
mUserManager = (UserManager) app.getSystemService(Context.USER_SERVICE);
mAppOps = (AppOpsManager)app.getSystemService(Context.APP_OPS_SERVICE);
mMainThreadHandler = new MainThreadHandler();
mTelephonySharedPreferences =
PreferenceManager.getDefaultSharedPreferences(mPhone.getContext());
mSubscriptionController = SubscriptionController.getInstance();
publish();
}
private void publish() {
//将PhoneInterfaceManager实例注册到ServiceManager中
ServiceManager.addService("phone", this);
}
在PhoneInterfaceManager初始化的时候,把自己注册成SystemServer,这样客户端(如TelephonyManager)则可以通过ServiceManager把它取出来。
private ITelephony getITelephony() {
//得到PhoneInterfaceManager的代理对象
return ITelephony.Stub.asInterface(ServiceManager.getService(Context.TELEPHONY_SERVICE));
}
PhoneInterfaceManager中的方法,最后还是通过Phone实例来实现。
以isImsRegistered()方法为例,最常见的调用方式如下:

1.4 TelephonyRegistry—“telephony.registry” Service(SystemServer.java中注册)
TelephonyRegistry继承自ITelephonyRegistry.Stub
class TelephonyRegistry extends ITelephonyRegistry.Stub {
在SystemServer.java中,
telephonyRegistry = new TelephonyRegistry(context);
//将TelephonyRegistry实例注册到ServiceManager中
ServiceManager.addService("telephony.registry", telephonyRegistry);
所以在TelephonyManager中可以通过ServiceManager得到”telephony.registry” Service
if (sRegistry == null) {
sRegistry = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService(
"telephony.registry"));
}
TelephonyManager主要利用”telephony.registry” Service实现listen()方法,实现对Phone状态的监听的功能
public void listen(PhoneStateListener listener, int events) {
if (mContext == null) return;
try {
Boolean notifyNow = (getITelephony() != null);
sRegistry.listenForSubscriber(listener.mSubId, getOpPackageName(),
listener.callback, events, notifyNow);
} catch (RemoteException ex) {
// system process dead
} catch (NullPointerException ex) {
// system process dead
}
}
关于TelephonyRegistry,后续的文章会详细讲,目前先不用太关注。
2. 如何得到TelephonyManager对象
1、 假如没有Context,可以通过:
private static TelephonyManager sInstance = new TelephonyManager();
public static TelephonyManager getDefault() {
return sInstance;
}
2、如果能得到Context对象,可以通过:
//注意,这是从SystemService中取
TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
//或者
TelephonyManager mTelephonyManager = TelephonyManager.from(context);
3. 其他重要方法
TelephonyManager还提供了两个其他比较重要的方法:
/**
* Gets the telephony property.
*
* @hide
*/
public static String getTelephonyProperty(int phoneId, String property, String defaultVal) {
String propVal = null;
//根据key获取到value
String prop = SystemProperties.get(property);
if ((prop != null) && (prop.length() > 0)) {
//将value分割成字符串数组
String values[] = prop.split(",");
if ((phoneId >= 0) && (phoneId < values.length) && (values[phoneId] != null)) {
//取出phoneId对应的value
propVal = values[phoneId];
}
}
return propVal == null ? defaultVal : propVal;
} /**
* Sets the telephony property with the value specified.
*
* @hide
*/
public static void setTelephonyProperty(int phoneId, String property, String value) {
...
}
这样子就可以实现对于同一个key,不同phoneId可以存储不同的值。
————————————————
版权声明:本文为CSDN博主「linyongan」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/linyongan/article/details/52104394
Android Telephony分析(四) ---- TelephonyManager详解的更多相关文章
- Android Telephony分析(五) ---- TelephonyRegistry详解
本文紧接着上一篇文章<Android Telephony分析(四) —- TelephonyManager详解 >的1.4小节.从TelephonyRegistry的大部分方法中: 可以看 ...
- Android Telephony分析(三) ---- RILJ详解
前言 本文主要讲解RILJ工作原理,以便更好地分析代码,分析业务的流程.这里说的RILJ指的是RIL.java (frameworks\opt\telephony\src\java\com\andro ...
- Android Telephony分析(二) ---- RegistrantList详解
前言 本文主要讲解RegistrantList的原理,以及如何快速分析RegistrantList相关的代码流程.在Telephony模块中,在RIL.Tracker(ServiceStateTrac ...
- Android Telephony分析(一) ---- Phone详解
目录: Phone的继承关系与PhoneFactory(GsmCdmaPhone.ImsPhone.SipPhone) Phone进程的启动 Phone对象的初始化(DefaultPhoneNotif ...
- Android Telephony分析(六) ---- 接口扩展(实践篇)
本文将结合前面五篇文章所讲解的知识,综合起来,实现一个接口扩展的功能.如果还没有阅读过前面五篇文章的内容,请先阅读:<Android Telephony分析(一) — Phone详解 >& ...
- Android项目刮刮奖详解(四)
Android项目刮刮奖详解(三) 前言 上一期我们已经是完成了刮刮卡的基本功能,本期就是给我们的项目增加个功能以及美化一番 目标 增加功能 用户刮卡刮到一定程度的时候,清除遮盖层 在遮盖层放张图片, ...
- Android Telephony分析(七) ---- 接口扩展(异步转同步)
本文是基于上一篇<Android Telephony分析(六) —- 接口扩展(实践篇)>来写的.上一篇介绍的接口扩展的方法需要实现两部分代码:1. 从APP至RIL,发送请求:2. 从R ...
- [Android新手区] SQLite 操作详解--SQL语法
该文章完全摘自转自:北大青鸟[Android新手区] SQLite 操作详解--SQL语法 :http://home.bdqn.cn/thread-49363-1-1.html SQLite库可以解 ...
- 【Android 应用开发】Ubuntu 下 Android Studio 开发工具使用详解 (旧版本 | 仅作参考)
. 基本上可以导入项目开始使用了 ... . 作者 : 万境绝尘 转载请注明出处 : http://blog.csdn.net/shulianghan/article/details/21035637 ...
随机推荐
- Delphi 异常处理
Delphi错误:Stack overflow的解决方法 在编译Delphi程序时,执行一个内存记忆体的时候,提示:Project.exe raised exception class EStackO ...
- 笨办法学Python记录--习题38-40,复习前面,运用list操作函数
#习题38 区分列表和字符串,用到了split(字符串专用函数),join.append.pop(这些是list操作函数) ten_things = "Apples Oranges Crow ...
- unittest框架学习笔记二之discover
coding=utf-8'''Created on 2018/3/29 author:star Project:discover测试用例''' import unittest,time,oslist= ...
- ORM-Dapper:Dapper百科
ylbtech-ORM-Dapper:Dapper百科 1.返回顶部 2.返回顶部 3.返回顶部 4.返回顶部 5.返回顶部 6.返回顶部 作者:ylbtech出处:htt ...
- JVM 源码分析之 javaagent 原理完全解读
转载:https://infoq.cn/article/javaagent-illustrated 本文重点讲述 javaagent 的具体实现,因为它面向的是我们 Java 程序员,而且 agent ...
- POJ 1329 Circle Through Three Points(三角形外接圆)
题目链接:http://poj.org/problem?id=1329 #include<cstdio> #include<cmath> #include<algorit ...
- JUC源码分析-集合篇(七)PriorityBlockingQueue
JUC源码分析-集合篇(七)PriorityBlockingQueue PriorityBlockingQueue 是带优先级的无界阻塞队列,每次出队都返回优先级最高的元素,是二叉树最小堆的实现. P ...
- scala 列表List
列表: 列表是不可变,也就是说不能通过赋值改变列表的元素: 列表有递归结构,而数据是连续的 List 类型:List() 同样也是List(String) 列表是基于Nil (是空的)和::(列表从前 ...
- 7年Java后端被淘汰,一路北漂辛酸史。。。
作者:春天花会开foryou oschina.net/question/3465562_2281392 今天分享一位同行的经历: 本人Java开发6年半不到7年的样子. 英语专业,临毕业跟着隔壁专业去 ...
- <爬虫>相关的知识
1.概念.工具和HTTP 什么是爬虫 模拟客户端发送网络请求,获取响应,按照规则提取数据 爬虫的数据去哪了 展示到网页上(百度新闻,今日头条) 进行分析,从数据中寻找规律(指数网站:百度指数) 需要的 ...