Android5.0 Telephony框架初步分析--telecomm

2023-05-16

3.2   Telecomm关键类初始化和相互关系

 

3.2.1          Telecomm简述

Android5.0在Telephony的变化又比较大,增加了一个Telecomm模块,它位于界面应用如InCallUI和Phone框架之间,其具体的设计意图尚不明确,从代码分析上来看,流程比原来的架构复杂很多,可能是想把Phone进程独立得更开一些,类似于RIL进程,给应用提供一个扁平的Phone接口,不希望像以前一样,呼叫流程在Phone进程和应用进程的纵深过大,引起函数的耦合性太大,有些相同的函数会在不同的流程执行在不同的进程里面。

其改变前后的关系可用下面的图来简述:

 

之前函数的调用流程在不同进程间的接口不够平滑,现在添加新的Telecomm层后,整个软件框架就比较有序和易于管理。

 

 

对于telephony相关的部分,从5.0和4.4的代码比较来看,

1)在framework下面,5.0新增了telecomm和ims部分的代码,截图如下,

 

 

结合后面的代码分析,我们知道在framework部分的telecomm代码的作用是承上启下的关系,它通过aidl接口,一方面和Phone进行交互,这一层是以InCallService、ConnectionService为代表,它的相关部分会运行在Phone进程;另一方面,和TelecommApp进程下的服务如TelecomService通信,这一层以TelecomManager等为代表,但他们往往运行在应用进程里面。

 

2)在Package目录下,5.0的应用部分InCallUI下没有了manifest文件,Service目录则多了MMS、Telecomm目录,MMS部分为短彩信增加了新的服务流程,telecomm部分则添加了一些关键文件,如作为进程载体的TelecomApp.java文件,作为服务载体的TelecomServiceImpl.java,还有CallsManager、CallActivity等文件,这些文件的关系和作用将在后面逐步分解。。

 

 

 

 

 

3.2.2          Phone

 

新增加的Phone.java在 (frameworks\base\telecomm\java\android\telecom)目录下,其功能是“A unified virtual device providing a means of voice (and other) communication on a device.”,即作为一个虚拟设备提供通信服务。其类型如下,

           public final class Phone {

它的方法的实现主要依赖3个辅助类,InCallAdapter、Listener、Call,即呼叫适配器、监听器、控制器(?),后续展开分析。

 

对于Phone的初始化,我们可以通过其方法的调用关系找到,例如查找internalAddCall,我们就会发现调用者为InCallService,其中mPhone即为Phone的实例,

case MSG_ADD_CALL:

mPhone.internalAddCall((ParcelableCall) msg.obj);

 

在InCallService里,当收到MSG_SET_IN_CALL_ADAPTER消息时,会创建一个Phone实例,同时也顺带创建了一个InCallAdapter实例,

                case MSG_SET_IN_CALL_ADAPTER:

                    mPhone = new Phone(new InCallAdapter((IInCallAdapter) msg.obj));

                    onPhoneCreated(mPhone);

                    break;          

 

MSG_SET_IN_CALL_ADAPTER消息是setInCallAdapter发出的,它是在InCallService里实现的AIDL接口类的服务端方法,

    private final class InCallServiceBinder extends IInCallService.Stub {

        @Override

        public void setInCallAdapter(IInCallAdapter inCallAdapter) {

            mHandler.obtainMessage(MSG_SET_IN_CALL_ADAPTER, inCallAdapter).sendToTarget();

        }          

 

根据我们对service的了解,它在service类创建时创建binder,在service的onbind()方法里将binder实例传入,执行客户端的ServiceConnection的onServiceConnected方法,所以在客户端,onConnected被执行,之后就是客户端InCallController里的setInCallAdapter被调用,再间接调用前面提到的服务端的setInCallAdapter。

private class InCallServiceConnection implements ServiceConnection {

        /** {@inheritDoc} */

        @Override public void onServiceConnected(ComponentName name, IBinder service) {

            Log.d(this, "onServiceConnected: %s", name);

            onConnected(name, service);

        } 

 

    private void onConnected(ComponentName componentName, IBinder service) {

        ThreadUtil.checkOnMainThread();

 

        Log.i(this, "onConnected to %s", componentName);

 

        IInCallService inCallService = IInCallService.Stub.asInterface(service);

 

        try {

            inCallService.setInCallAdapter(new InCallAdapter(CallsManager.getInstance(),

                    mCallIdMapper));

            mInCallServices.put(componentName, inCallService);

        } catch (RemoteException e) {

            Log.e(this, e, "Failed to set the in-call adapter.");

            return;

        }

 

所以可以看出,Phone的实例就是在InCallService服务启动过程中创建的。

 

 

3.2.3          InCallController

 

 

 

前面提到的binder的客户端InCallController位于(packages\services\telecomm\src \com\android\server\telecom)目录,根据manifest文件,它运行在TelecomApp这个应用里,这是一个的5.0新进程。又根据android:persistent="true"这个属性我们知道,TelecomApp是开机自启动的。

 

InCallController是在CallsManager的构造函数里创建的,CallsManager又是在TelecomApp的onCreate方法里面创建的,

    public void onCreate() {

        super.onCreate();

 

        if (UserHandle.myUserId() == UserHandle.USER_OWNER) {

            // Note: This style of initialization mimics what will be performed once Telecom is

            // moved

            // to run in the system service. The emphasis is on ensuring that initialization of all

            // telecom classes happens in one place without relying on Singleton initialization.

            mMissedCallNotifier = new MissedCallNotifier(this);

            mPhoneAccountRegistrar = new PhoneAccountRegistrar(this);

 

            mCallsManager = new CallsManager(this, mMissedCallNotifier, mPhoneAccountRegistrar);

            CallsManager.initialize(mCallsManager);

 

            mTelecomService = new TelecomServiceImpl(mMissedCallNotifier, mPhoneAccountRegistrar,

                    mCallsManager, this);

            ServiceManager.addService(Context.TELECOM_SERVICE, mTelecomService);

 

            // Start the BluetoothPhoneService

            BluetoothPhoneService.start(this);

        }

    }          

 

所以,TelecomApp进程的启动过程中,创建了InCallController和CallsManager两个实例,这两个类实例相互关联。

 

 

3.2.4          TelecomService

 

实际上,并不存在TelecomService这个名字的文件或类名,但存在一个这样的服务。

 

还是在TelecomApp的onCreate方法里(如上),创建了一个TelecomServiceImpl类实例,它对应于TelecomService服务的AIDL服务端,它就是以类实例为服务端,并不像service里面bind的binder接口,并且,它被作为一个服务添加到serviceManager里面。

mTelecomService = new TelecomServiceImpl(mMissedCallNotifier, mPhoneAccountRegistrar,

                    mCallsManager, this);

ServiceManager.addService(Context.TELECOM_SERVICE, mTelecomService);

 

public class TelecomServiceImpl extends ITelecomService.Stub {          

TelecomServiceImpl依赖CallsManager、PhoneAccountRegistrar、MissedCallNotifier这几个类完成相应的功能。

 

TelecomService的客户端是TelecomManager,它通过getTelecomService获取到服务端接口,然后通过这个接口使用服务端的远程接口,

     private ITelecomService getTelecomService() {

        return ITelecomService.Stub.asInterface(ServiceManager.getService(Context.TELECOM_SERVICE));

    }

 

 

3.2.5          TelecomManager

 

TelecomManager在framework的android.telecom包里面,它在ContextImpl被创建,并加入到注册列表里,属于系统级的服务,

        registerService(TELECOM_SERVICE, new ServiceFetcher() {

                public Object createService(ContextImpl ctx) {

                    return new TelecomManager(ctx.getOuterContext());

                }});

 

应用要获取其实例,可以通过其from方法,也可以直接通过context.getSystemService(Context.TELECOM_SERVICE)这个语句来获取。

 

TelecomManager的功能则主要是对TelecomService提供的远程接口的封装,然后提供给应用使用,例如对于showInCallScreen方法,在TelecomServiceImpl提供服务端的远程方法,TelecomManager提供客户端访问接口,DialpadFragment等应用组件使用这个接口,

 TelecomServiceImpl.java (packages\services\telecomm\src\com\android\server\telecom):    public void showInCallScreen(boolean showDialpad)

 

TelecomManager.java (frameworks\base\telecomm\java\android\telecom):    public void showInCallScreen(boolean showDialpad)

 

DialpadFragment.java (packages\apps\dialer\src\com\android\dialer\dialpad):        getTelecomManager().showInCallScreen(showDialpad);

DialtactsActivity.java (packages\apps\dialer\src\com\android\dialer):            getTelecomManager().showInCallScreen(false);

 

虽然TelecomServiceImpl是在packages目录下,TelecomManager在frameworks目录下,但前者作为一个服务,在单独进程里为后者提供服务,后者则为应用进程提供接口服务,再通过binder进程通信访问前者的服务,其关系如下,

 

 

 

 

3.2.6          InCallService

 

InCallService是一个抽象类,继承于service,它由四大部分组成,Handler、InCallServiceBinder、VideoCall以及自身的一些方法,其中InCallServiceBinder是aidl接口的服务端实现,对应于前面提到的InCallController,它主要是给当前服务发送消息,Handler接收并处理这些消息,如前面提到,Handler会创建一个Telecom的Phone实例,然后使用Phone的接口处理应用请求,所以实际上,客户端的请求实际上是Phone来完成的,至于Phone是如何实现功能的,请参见Phone的分析,这里的几个关键类的相互关系如下,

 

 

InCallService的主要功能是给应用提供管理Phone call的途径,它的子类InCallServiceImpl完成真正服务实例的创建,当存在呼叫连接时,它bind到Telecomm,并接受呼叫状态的更新。

 

服务实例的绑定过程是在InCallController里面完成的,

     private void bind() {…

            Intent serviceIntent = new Intent(InCallService.SERVICE_INTERFACE);

            for (ResolveInfo entry : packageManager.queryIntentServices(serviceIntent, 0)) {

                    InCallServiceConnection inCallServiceConnection = new InCallServiceConnection();

                    ComponentName componentName = new ComponentName(serviceInfo.packageName,

                            serviceInfo.name);

                        Intent intent = new Intent(InCallService.SERVICE_INTERFACE);

                        intent.setComponent(componentName);

 

                        if (mContext.bindServiceAsUser(intent, inCallServiceConnection,

                                Context.BIND_AUTO_CREATE, UserHandle.CURRENT)) {

                            mServiceConnections.put(componentName, inCallServiceConnection);

                        }

…}

这个bind()是在onCallAdded()里被调用的,onCallAdded被调用的地方有两个:

CallsManager.java (packages\services\telecomm\src\com\android\server\telecom):            listener.onCallAdded(call);

Phone.java (frameworks\base\telecomm\java\android\telecom):            listener.onCallAdded(this, call);

 

他们都是通过listener的方式被调用的,通过分析两个类的listener,发现Phone的监听器主要在应用文件中注册,

CallList.java (packages\apps\incallui\src\com\android\incallui):        mPhone.addListener(mPhoneListener);

InCallPresenter.java (packages\apps\incallui\src\com\android\incallui):        mPhone.addListener(mPhoneListener);

 

CallsManager的监听器在其构造函数中注册,并且监听器类型为CallsManagerListener,

    private final Set<CallsManagerListener> mListeners = Collections.newSetFromMap(            new ConcurrentHashMap<CallsManagerListener, Boolean>(16, 0.9f, 1));

 

     CallsManager(Context context, MissedCallNotifier missedCallNotifier,

             PhoneAccountRegistrar phoneAccountRegistrar) {…

        mCallLogManager = new CallLogManager(context);

        mInCallController = new InCallController(context);

 

        mListeners.add(statusBarNotifier);

        mListeners.add(mCallLogManager);

        mListeners.add(mPhoneStateBroadcaster);

        mListeners.add(mInCallController);

        mListeners.add(mRinger);

…}

所以是CallsManager. addCall调用了InCallController的onCallAdded。addCall则会被来电、去电、会议电话等接口方法调用,如startOutgoingCall。

 

所以当有通话连接要产生时,会启动InCallService服务,其大致过程如下:

 

 

 

 

 

 

 

 

 

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android5.0 Telephony框架初步分析--telecomm 的相关文章

  • Android5.0 Telephony框架初步分析--telecomm

    3 2 Telecomm关键类初始化和相互关系 3 2 1 Telecomm简述 Android5 0在Telephony的变化又比较大 xff0c 增加了一个Telecomm模块 xff0c 它位于界面应用如InCallUI和Phone框
  • Android5.0+ Camera专栏终结

    本文均属自己阅读源码的点滴总结 xff0c 转账请注明出处谢谢 欢迎和大家交流 qq 1037701636 email gzzaigcn2009 64 163 com Software xff1a 系统源码Android5 1 寥寥几笔写在
  • Android 电话堆栈中的不同呼叫状态代表什么?

    The internal安卓类com android internal telephony Call包含一个名为 State 的枚举 定义如下 public enum State IDLE ACTIVE HOLDING DIALING AL
  • 如何从来电中获取电话号码?

    Android 中有来电时如何获取电话号码 Make a Broadcast receiver say ServiceReceiver在清单中分配其操作
  • 即使设备使用 WiFi,iOS 也会检查蜂窝技术是否可用

    这里需要一些帮助 我需要检测 iOS 设备是否 在某个时刻 具有蜂窝功能 无论是哪一个 我尝试使用可达性类别 但当用户连接到 WiFi 时问题就开始了 因为如果是这样的话 可达性无法检测到蜂窝网络 我也尝试使用这段代码 CTTelephon
  • android 中如何检测来电掉线

    我正在编写一个应用程序 该应用程序在电话通话期间在后台运行 并在通话结束后将坐标记录到文件中 我知道 Android 电话 API 可以检测用户手动断开呼叫 纠正我 如果我错了 但我想知道服务断开是否是由于掉话造成的 有没有办法或API可以
  • BroadcastReceiver获取ServiceState信息

    有谁知道在android中获取电话服务状态 IN SERVICE OUT OF SERVICE EMERGENCY ONLY POWER OFF 的方法 我希望有一个广播接收器来识别这些变化 但我找不到任何东西 我知道有一个侦听器 但我不确
  • 某些 SMS 消息如何传输发件人姓名?

    我注意到我从公司收到的某些短信带有 发件人姓名 例如 就在今天 我收到了一条来自我以前从未使用过的号码 不是我的联系人 的短信 但发件人姓名显示为 Adobe 我也从其他公司得到这个 例如 Facebook Google 和银行 它与电子邮
  • 如何使用 Twilio 拨打实时语音电话,而不仅仅是在接听电话时播放 MP3?

    为了通过 Twilio 从笔记本拨打电话号码 我创建了 ASP NET MVC 5 2 应用程序 我可以拨打一个号码并接听电话 但我不知道如何实现实时语音 能够通话 连接 而不仅仅是播放音乐 我在里面创建了一个动作方法HomeControl
  • 检测哪张SIM卡收到消息

    我正在尝试检测哪张 SIM 卡已在双 SIM 卡或三卡支持手机上的 BroadcastReceiver 中接收到传入消息 笔记 所有 SIM 卡都有相同的 SMSC 似乎信息可能位于带有密钥的 Intent extra 中 simSlot
  • “飞行模式”打开时SIM状态的值是多少

    我想知道返回的SIM状态值是多少TelephonyManager getSimState http developer android com reference android telephony TelephonyManager htm
  • 如何将我的应用程序设置为默认短信应用程序?

    我正在关注本教程 http android developers blogspot com 2013 10 getting your sms apps ready for kitkat html将我的应用程序设置为默认短信应用程序 但由于某
  • Android:获取基站和邻近小区的小区 ID 和 RSS

    我正在尝试获取以下数据 基站 CellID和RSS 识别哪个是基站 对于所有邻近站点 小区 ID 和 RSS 有各种 API 看起来我必须使用不同的 API telephonyManager 和 PhoneStateListener 我有点
  • 检测拨出电话是否已接听

    Once ACTION NEW OUTGOING CALL已广播 我需要捕获对方回答的以下事件 您能否建议如何实现这一目标 我知道这是可能的 因为 Android 拨号器应用程序会在接听电话时将绿色 Android 图标更改为该人的照片 更
  • 开源 FSK 解码器库? [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 有没有办法给某人打电话并在android中播放音频文件?

    我想创建一个紧急呼叫应用程序 如果触发 它会呼叫给定号码并播放音频文件 提供呼叫者无法提供的信息 为此 我需要拨打电话 但确保我可以用播放的音频文件替换扬声器中的任何声音 我可以在安卓中做到这一点吗 有什么办法呢 目前您无法使用 G1 执行
  • 使用 telephonyserivce.endcall() 在 android 中结束通话

    我正在开发一个应用程序 我想在其中结束拨出呼叫 这是主要课程 import android app Activity import android content ActivityNotFoundException import andro
  • 在 SQL Server 中计算呼叫的不同资费周期

    对于呼叫评级系统 我试图将电话呼叫持续时间分成不同资费周期的子持续时间 呼叫存储在 SQL Server 数据库中 并具有开始时间和总持续时间 夜间 0000 0800 高峰 0800 1900 和非高峰 1900 235959 时段的费率
  • Asterisk AGI:如何获取或设置全局变量的值?

    我使用 Asterisk 1 8 和 PHP 来编写 AGI 脚本 EDIT 我正在努力从 AGI PHP 脚本中设置和获取全局变量的值 我可以设置通道变量 但不能设置全局变量 使用 PHPAGI 库 Tried Set varname v
  • iOS 中的设备兼容性问题

    我们上传了一个应用程序 在第一个版本中 我们添加了设备功能 电话 以限制信息 plist 中的 iPhone 设备 在第二个版本中 我们忘记添加 电话 并提交给了应用商店 我们计划上传第三个版本 其中设备功能为 电话 但在提交到 App S

随机推荐

  • 2022 *CTF REVERSE 的 NaCl

    2022 CTF REVERSE 的 NaCl 下载附件 xff1a 照例扔入 exeinfope 中查看信息 xff1a 照例扔入虚拟机中运行一下 xff0c 查看主要回显信息 xff1a 照例扔入 IDA64 中查看伪代码 xff0c
  • python编码问题的一点笔记

    Python编码 xff1a 中文乱码问题 xff1a 如果开头不声明保存编码的格式是什么 xff0c 那么它会默认使用 ASCII 码保存文件 这时如果你的代码中有中文就会出错了 xff0c 即使你的中文是包含在注释里面的 声明中文编码格
  • 对 IDA 结构体操作的一些理解

    对 IDA 结构体操作的一些理解 前言 xff1a 刚学逆向时把 IDA pro 权威指南过了一遍 xff0c 但读得并不是很细 xff0c 满足日常使用还是没问题的 xff0c 但是对于一些细节的操作或提高效率的方法倒是没能掌握 比如 I
  • 第二届广东省大学生网络攻防大赛 pyre

    第二届广东省大学生网络攻防大赛 pyre 以前做过 pyc 逆向 xff0c 直接的 python exe 逆向还是第一次 xff1a 第一种方法 xff1a 用 pyinstxtractor py 将 exe 文件转换成 pyc 文件 用
  • 2022 年网刃杯 ez_algorithm

    2022 年网刃杯 ez algorithm 下载附件 xff1a 照例扔入 exeinfope 中查看信息 xff0c 64 位无壳 xff1a 照例运行一下 xff0c 查看主要回显信息 xff1a 照例扔入 IDA64 中查看伪代码
  • Base-N 算法加密解密实现:

    目录 Base N 算法加密解密实现 xff1a Base64 加密解密 xff1a xff08 C 语言 python xff09 Base32 加密解密 xff1a xff08 C 语言 xff09 Base N 算法加密解密实现 xf
  • 第二届广东省大学生网络攻防大赛 simple_re

    第二届广东省大学生网络攻防大赛 simple re 流程总结 xff1a xff08 思路原文出自 JANlittle 师傅 xff09 程序将关键函数以对象元素的形式存在对象里 xff0c 然后在申请内存中搭配指针间接调用 xff0c 关
  • 解析 DES 加密算法(C语言):

    目录 解析 DES 加密算法 C语言 xff1a DES 简介 xff1a DES 算法整体流程 xff1a DES 解密 xff1a C 语言代码实现加密解密逻辑 xff1a 解析 DES 加密算法 C语言 xff1a 内容修改自博客 x
  • x64dbg 基本使用技巧

    x64dbg 基本使用技巧 最近使用 DBG 多了起来 xff0c 所以查了一些资料来学习并整理成自适应的笔记 本文摘抄自 xff1a x64dbg 使用技巧与实用插件合集 官方网站 xff1a https x64dbg com DBG 根
  • freertos系统栈溢出检测机制简述

    FreeRTOS 提供了多种特性来辅助跟踪调试栈相关的问题 uxTaskGetStackHighWaterMark 函数 每个任务都独立维护自己的栈空间 xff0c 栈空间总量在任务创建时进行设定 uxTaskGetStackHighWat
  • 记一次 windows 桌面卡顿

    记一次 windows 桌面卡顿 这几天在 windows 桌面上的操作感觉非常不好 xff0c 一开始以为是电脑老化 网络卡顿 C 盘又被垃圾挤占空间 或什么自启动软件占了内存 xff0c 复制一个快捷键出来都要缓冲 然后就卸载了很多不常
  • 浏览 APT 报告中学习积累

    浏览 APT 报告中学习积累 工具网站积累 xff1a xff08 APT 报告搜寻网站 xff09 https ti qianxin com https feed watcherlab com index apt https malped
  • 《windows 程序设计》读书笔记 一

    目录 基础知识 主要的动态链接库 xff1a API 及内存管理模式 xff1a 第一个 Windows 程序解析 xff1a 头文件 xff1a Windows 程序的入口 xff1a MessageBox 函数 xff1a 基础知识 主
  • 《windows 程序设计》读书笔记 二

    目录 Unicode 历史及介绍 美国标准 ASCII xff1a Unicode 方案 xff1a 宽字符和 C 语言 xff1a 宽字符和 Windows xff1a Windows 函数调用 xff1a Unicode 和 Ascii
  • x86指令编码简述(机器码)

    目录 x86指令编码 xff1a 机器码的格式结构 xff1a Mod R M 字节与内存寻址模式探究 xff1a 实战部分机器指令类型 xff1a x86指令编码 xff1a 机器码的格式结构 xff1a 一般的 x86 机器指令格式 x
  • 记一次 cmd 打开 python 报错,环境变量已配置

    记一次 cmd 打开 python 报错 xff0c 环境变量已配置 输入 python 自动打开应用商店 xff0c 环境变量已配置 xff0c 并且我觉得我只有这一个 python 路径 xff01 排查了半天 xff0c 重启了半天
  • 《windows 程序设计》读书笔记 三

    目录 窗口与消息 窗口的创建 xff1a 系统结构 windows 窗口编程概述 xff1a HELLOWIN 程序及剖析 xff1a 若干难点 xff1a 用户程序调用系统还是系统调用用户程序 xff1a DefWindowProc 函数
  • 对 python 正则表达式字面字符串和模式字符串的一点思考

    python 的正则表达式是与 Perl 语言类似的正则表达式匹配操作 xff1a 模式和被搜索的字符串既可以是 Unicode 字符串 xff0c 也可以是 8 位字节串 xff0c 但是 Unicode 字符串与 8 位字节串不能混用
  • 记一次 PEview 的报错修正

    记一次 PEview 的报错修正 从 逆向工程核心原理 中提到的 https reversecore com 111 中下载的 PEview 在处理 32 位程序时其它目录都还行 xff0c 当点到 IMAGE NT HEADERS gt
  • Android5.0 Telephony框架初步分析--telecomm

    3 2 Telecomm关键类初始化和相互关系 3 2 1 Telecomm简述 Android5 0在Telephony的变化又比较大 xff0c 增加了一个Telecomm模块 xff0c 它位于界面应用如InCallUI和Phone框