Android Telephony分析(四) ---- TelephonyManager详解

来源:互联网 发布:js产生1到3随机数 编辑:程序博客网 时间:2024/05/16 01:36

前言

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;
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

分别对应下面这几个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
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

所以可以猜测到,在TelephonyManager中可以得到这四种Service。 
通过所有文件中搜索”extends 接口名.Stub”,如”extends ITelephony.Stub”,可以找到是哪些类实现了上面四个AIDL接口中的方法,整理可得: 
这里写图片描述
在TelephonyManager中搜索”接口名.Stub.asInterface”,如”ITelephony.Stub.asInterface”,可以找到这四个Service的名字,整理可得:

接口服务端Service NameITelecomService.aidlTelecomServiceImpl.javatelecom (TELECOM_SERVICE)IPhoneSubInfo.aidlPhoneSubInfoController.javaiphonesubinfoITelephony.aidlPhoneInterfaceManager.javaphone (TELEPHONY_SERVICE)ITelephonyRegistry.aidlTelephonyRegistry.javatelephony.registry

好了,下面分别对这四种Service进行分析:


http://blog.csdn.net/linyongan 


1.1 TelecomServiceImpl—Telecom Service

服务端TelecomServiceImpl中有mBinderImpl实现了ITelecomService接口中的方法

public class TelecomServiceImpl {    private final ITelecomService.Stub mBinderImpl = new ITelecomService.Stub() {        ...    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

在TelecomLoaderService.java中,TelecomServiceImpl把自己注册到ServiceManager中,

    ServiceManager.addService(Context.TELECOM_SERVICE, service);
  • 1
  • 1

所以在TelephonyManager中可以通过ServiceManager得到Telecom Service

    private ITelecomService getTelecomService() {        //得到TelecomServiceImpl的代理对象        return ITelecomService.Stub.asInterface(ServiceManager.getService(Context.TELECOM_SERVICE));    }
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

其实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;    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

所以,总体上来说,虽然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
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

1.2 PhoneSubInfoController— “iphonesubinfo” Service

服务端PhoneSubInfoController继承自IPhoneSubInfo.Stub

public class PhoneSubInfoController extends IPhoneSubInfo.Stub {
  • 1
  • 1

在创建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);    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

所以在TelephonyManager中可以通过ServiceManager得到”iphonesubinfo” Service

    private IPhoneSubInfo getSubscriberInfo() {        // get it each time because that process crashes a lot        return IPhoneSubInfo.Stub.asInterface(ServiceManager.getService("iphonesubinfo"));    }
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

通过”iphonesubinfo” Service可以得到software version、deviceID、VoiceMail Number等信息,TelephonyManager在这里只是对这些方法进一步封装,这些方法具体的实现,最后还是通过Phone实例和IsimRecords实例来完成的。 
以getMsisdn()方法为例,最常见的调用方式如下: 
这里写图片描述 
备注:在Android N中已删除PhoneSubInfo.java和PhoneSubInfoProxy.java,所以流程变得简单了。

1.3 PhoneInterfaceManager—Telephony Service

TelephonyManager依赖Telephony Service实现了大部分的方法。 
PhoneInterfaceManager继承自ITelephony.Stub

public class PhoneInterfaceManager extends ITelephony.Stub {
  • 1
  • 1

PhoneInterfaceManager.java在 packages\services\telephony\src\com\android\phone目录下,显然它是运行在Phone进程中的。 
在Phone进程启动时,Default Phone对象创建完之后,PhoneInterfaceManager对象在PhoneGlobals的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;        }    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

在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);    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

在PhoneInterfaceManager初始化的时候,把自己注册成SystemServer,这样客户端(如TelephonyManager)则可以通过ServiceManager把它取出来。

    private ITelephony getITelephony() {        //得到PhoneInterfaceManager的代理对象        return ITelephony.Stub.asInterface(ServiceManager.getService(Context.TELEPHONY_SERVICE));    }
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

PhoneInterfaceManager中的方法,最后还是通过Phone实例来实现。 
以isImsRegistered()方法为例,最常见的调用方式如下: 
这里写图片描述

1.4 TelephonyRegistry—“telephony.registry” Service

TelephonyRegistry继承自ITelephonyRegistry.Stub

class TelephonyRegistry extends ITelephonyRegistry.Stub {
  • 1
  • 1

在SystemServer.java中,

    telephonyRegistry = new TelephonyRegistry(context);      //将TelephonyRegistry实例注册到ServiceManager中    ServiceManager.addService("telephony.registry", telephonyRegistry);  
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

所以在TelephonyManager中可以通过ServiceManager得到”telephony.registry” Service

    if (sRegistry == null) {        sRegistry = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService(                "telephony.registry"));    }
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

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        }    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

关于TelephonyRegistry,后续的文章会详细讲,目前先不用太关注。


2. 如何得到TelephonyManager对象

1、 假如没有Context,可以通过:

private static TelephonyManager sInstance = new TelephonyManager();  public static TelephonyManager getDefault() {      return sInstance;  } 
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

2、如果能得到Context对象,可以通过:

//注意,这是从SystemService中取TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); //或者TelephonyManager mTelephonyManager = TelephonyManager.from(context);
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

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) {        ...    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

这样子就可以实现对于同一个key,不同phoneId可以存储不同的值。


原文地址: http://blog.csdn.net/linyongan/article/details/52104394

0 0