Advertisement

SubscriptionInfo和SubscriptionManager相关知识梳理

阅读量:

1. subid和slotid

slotid或者phoneid是指卡槽,双卡机器的卡槽1值为0,卡槽2值为1,依次类推。

订阅ID(Identifier):订阅ID标识符(Identifier),它作为数据库telephony.db中表siminfo的主键字段递增值存在(Incrementing value of the primary key)。该数据库位于"/data/user_de/0/com.android.providers.telephony/databases"目录中。

subid的值从1开始,每插入一个新卡,subId的值就会加1。

插入双卡会导致数据库中出现subid值为1和2的数据条目;在拔出并重新插入另一张sim卡片时不会新增任何数据项;只有当再次插入一张新的sim卡片时才会生成一条具有id为3的新数据记录。

注意:

1). subid是跟卡走的,slotid是跟卡槽走的。

2).

复制代码
 public int getSimState(int slotIdx);

    
 public String getSimOperator(int subId) ;
    
    
    
    
    代码解读

参数均为整型变量;需要注意区分是否为subid或slotid;对于双卡设备而言,subid可能取值为1和2;对应的slotid则为0和1;在插入一张卡片时需要注意;其中数值1在subid或slotid中均为有效取值。

2. Subscription和SubscriptionInfo

每一张SIM卡都与一个Subscription相关联;使用哪家的SIM卡就相当于注册(Registration)哪家的业务服务。
SIM卡所包含的数据即为SubscriptionInfo(Subscription Information),例如ICCID、MNC和MCC等参数;拥有多个SIM卡的朋友就会拥有多个对应的SubscriptionInfo。
其中ICCID:集成电路卡识别码(Integrated Circuit Card Identity),即SIM卡的唯一标识号码;这相当于手机号码的身份证号码。

SubscriptionInfo的各个成员如下:

复制代码
 //frameworks/base/telephony/java/android/telephony/SubscriptionInfo.java

    
 public class SubscriptionInfo implements Parcelable {//实现Parcelable是为了进程间ipc通信。
    
      @Override
    
     public void writeToParcel(Parcel dest, int flags) {
    
         dest.writeInt(mId);   //数据库id,递增主键,每一个iccid的卡会占用1个id
    
         dest.writeString(mIccId);  //sim卡的iccid,每张sim卡是唯一的
    
         dest.writeInt(mSimSlotIndex);  //sim卡插入卡槽值,0是卡1,1是卡2,没有插入则是-1
    
         dest.writeCharSequence(mDisplayName); //sim卡名称,用户可以自定义
    
         dest.writeCharSequence(mCarrierName); //运营商名称
    
         dest.writeInt(mNameSource);  //名称来源,是用户设置或者是从sim卡读取(一般就是运营商名称)等
    
         dest.writeInt(mIconTint);   //sim卡图标染色值,tint的概念可以百度google
    
         dest.writeString(mNumber);  //sim卡关联号码
    
         dest.writeInt(mDataRoaming);  //sim卡是否启用数据漫游
    
         dest.writeInt(mMcc);    //mcc,移动国家码,3位数字,中国是460
    
         dest.writeInt(mMnc);    //mnc,移动网络码,2位数字,如00,01等,表示运营商
    
         dest.writeString(mCountryIso); //国家iso代码 
    
         mIconBitmap.writeToParcel(dest, flags);  //sim卡图标
    
     }
    
     ......
    
 }
    
    
    
    
    代码解读

它是和TelephonyProvider数据库中的siminfo对应的。

复制代码
 //vendor/mediatek/proprietary/packages/providers/TelephonyProvider/src/com/android/providers/telephony/TelephonyProvider.java

    
 private void createSimInfoTable(SQLiteDatabase db) {
    
     if (DBG) log("dbh.createSimInfoTable:+");
    
     db.execSQL("CREATE TABLE " + SIMINFO_TABLE + "("
    
         + SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID + " INTEGER PRIMARY KEY AUTOINCREMENT,"
    
         + SubscriptionManager.ICC_ID + " TEXT NOT NULL,"
    
         + SubscriptionManager.SIM_SLOT_INDEX + " INTEGER DEFAULT " + SubscriptionManager.SIM_NOT_INSERTED + ","
    
         + SubscriptionManager.DISPLAY_NAME + " TEXT,"
    
         + SubscriptionManager.CARRIER_NAME + " TEXT,"
    
         + SubscriptionManager.NAME_SOURCE + " INTEGER DEFAULT " + SubscriptionManager.NAME_SOURCE_DEFAULT_SOURCE + ","
    
         + SubscriptionManager.COLOR + " INTEGER DEFAULT " + SubscriptionManager.COLOR_DEFAULT + ","
    
         + SubscriptionManager.NUMBER + " TEXT,"
    
         + SubscriptionManager.DISPLAY_NUMBER_FORMAT + " INTEGER NOT NULL DEFAULT " + SubscriptionManager.DISPLAY_NUMBER_DEFAULT + ","
    
         + SubscriptionManager.DATA_ROAMING + " INTEGER DEFAULT " + SubscriptionManager.DATA_ROAMING_DEFAULT + ","
    
         + SubscriptionManager.MCC + " INTEGER DEFAULT 0,"
    
         + SubscriptionManager.MNC + " INTEGER DEFAULT 0,"
    
         ...
    
         + SubscriptionManager.CB_OPT_OUT_DIALOG + " INTEGER DEFAULT 1"
    
         + ");");
    
     if (DBG) log("dbh.createSimInfoTable:-");
    
 }
    
    
    
    
    代码解读

创建表函数createSimInfoTable,并将所有常量均位于SubscriptionManager中声明;其名称暗示与对应的SubscriptionInfo存在关联;随后mtk增加了若干字段。

3. SubscriptionManager及其相关方法

该组件被设计为在第三方应用程序层中使用,并负责以下操作:

  1. 处理双卡配置相关的操作;
  2. 完成slotid与subId之间的转换操作;
  3. 提供完整的卡片信息数据。
复制代码
 SubscriptionManager //frameworks/base/telephony/java/android/telephony/SubscriptionManager.java

    
     1). 获取SubscriptionManager对象
    
         public static SubscriptionManager from(Context context);
    
         //SubscriptionManager mSubscrMgr = SubscriptionManager.from(mContext);//get Manager
    
  
    
     2). 第三方app获取slot和subId
    
         public int getDefaultDataPhoneId()  默认数据slotId
    
         public static int getDefaultDataSubscriptionId() 默认数据subId
    
  
    
         public int getDefaultSmsPhoneId()  默认短信slotId
    
         public static int getDefaultSmsSubscriptionId() 默认短信subId
    
  
    
         public static int getDefaultVoicePhoneId()  默认通话slotId
    
         public static int getDefaultVoiceSubscriptionId() 默认通话subId
    
  
    
         上述三个都返回-1的话使用
    
         public static int getDefaultSubscriptionId() 获取默认subId
    
  
    
     3). slotid和subId转换
    
         public static int getSlotIndex(int subId)
    
         public static int getPhoneId(int subId)
    
         public static int[] getSubId(int slotIndex)
    
  
    
     4). 第三方app获取SubscriptionInfo
    
         public SubscriptionInfo getActiveSubscriptionInfoForSimSlotIndex(int slotIndex) //根据卡槽获取对应的SubscriptionInfo
    
         public SubscriptionInfo getActiveSubscriptionInfo(int subId) //根据subId获取对应的SubscriptionInfo  
    
    
    
    
    代码解读

如2中所述,SubscriptionInfo代表了sim卡的相关数据,其常用方法如下:

复制代码
 SubscriptionInfo//frameworks/base/telephony/java/android/telephony/SubscriptionInfo.java

    
     public int getDataRoaming();//return the data roaming state for this subscription
    
     public CharSequence getDisplayName() ;//return the name displayed to the user that identifies this subscription
    
     public String getIccId() ;
    
     public int getMcc();
    
     public int getMnc() ;
    
     public String getNumber();//return the number of this subscription.
    
     public int getSimSlotIndex() //return the slot index of this Subscription's SIM card.
    
     public int getSubscriptionId() //return the subscription ID - subId 
    
    
    
    
    代码解读

在分析过程中发现,在分析过程中发现,在分析过程中能够基于slotId获取相应的subId;随后调用SubscriptionManager中的getActiviteSubscriptionInfo()方法来调用订阅管理器中获取SIM卡订阅信息;从而进一步获得该卡所属的国家代码(MCC)、运营商代码(MNC)以及ICCID等关键信息。

除了直接使用slotId之外,还可以通过调用SubscriptionManager的getActiviteSubscriptionInfoFromSimSlotIndex()方法来获取该SIM卡的subscriptionInfo信息。

注:以上为实现功能所做的操作步骤:首先由slotId获取subId;其次可采用MtkSubscriptionManager提供的静态方法getSubIdUsingPhoneId()来完成此功能。

复制代码
     public static int getSubIdUsingPhoneId(int phoneId);
    
    代码解读

4. SubscriptionManager和SubscriptionController

**

**

订阅管理器充当了订阅控制器的应用程序接口,在呈现当前电话订阅的相关信息方面发挥着重要作用。
订阅控制器位于phone进程中运行,并承担起双卡相关功能的实际落地工作,为订阅管理器提供必要的服务。
订阅管理器的功能主要通过binder与服务端进行交互连接,并借助ISub.aidl和SubscriptionController实现了内部沟通。
同样地,MtkSubscriptionManager通过IMtkSub.aidl与MtkSubscriptionControllerEx实现了跨平台的通信连接。
为了展示各组件之间的关联性,请参考getSubIdUsingPhoneId()方法的调用流程:

复制代码
 MtkSubscriptionManager

    
     public static int getSubIdUsingPhoneId(int phoneId) {
    
     if (VDBG) Rlog.d(LOG_TAG, "[getSubIdUsingPhoneId]+ phoneId:" + phoneId);
    
  
    
     int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
    
  
    
     try {
    
         IMtkSub iSub = IMtkSub.Stub.asInterface(ServiceManager.getService("isubstub"));
    
         if (iSub != null) {
    
             subId = iSub.getSubIdUsingPhoneId(phoneId);
    
         }
    
     } catch (RemoteException ex) {
    
         // ignore it
    
     }
    
     return subId;
    
     }
    
 public class MtkSubscriptionControllerEx extends IMtkSub.Stub {
    
     @Override
    
     public int getSubIdUsingPhoneId(int phoneId) {
    
     return MtkSubscriptionController.getMtkInstance().getSubIdUsingPhoneId(phoneId);
    
     }
    
 }
    
    
    
    
    代码解读

在该类中,通过调用MtkSubscriptionController.getMtkInstance()方法能够被该类实例化。

复制代码
 public class MtkSubscriptionController extends SubscriptionController {

    
     public static MtkSubscriptionController getMtkInstance() {
    
     synchronized (MtkSubscriptionController.class) {
    
         return sMtkInstance;
    
     }
    
     }
    
 }
    
    
    
    
    代码解读

然而,在MtkSubscriptionController类中,并未提供getSubI...这一功能。该功能实际上是继承自其父类 SubscriptionController 所实现的功能。该功能将通过调用其基类提供的 getSubI... 方法来执行操作。

复制代码
 public class SubscriptionController extends ISub.Stub {

    
     public int getSubIdUsingPhoneId(int phoneId) {
    
     int[] subIds = getSubId(phoneId);
    
     if (subIds == null || subIds.length == 0) {
    
         return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
    
     }
    
     return subIds[0];
    
     }
    
  
    
     /** * Return the subId for specified slot Id.
    
      * @deprecated
    
      */
    
     @Override
    
     @Deprecated
    
     public int[] getSubId(int slotIndex) {
    
     if (VDBG) printStackTrace("[getSubId]+ slotIndex=" + slotIndex);
    
  
    
     // Map default slotIndex to the current default subId.
    
     // TODO: Not used anywhere sp consider deleting as it's somewhat nebulous
    
     // as a slot maybe used for multiple different type of "connections"
    
     // such as: voice, data and sms. But we're doing the best we can and using
    
     // getDefaultSubId which makes a best guess.
    
     if (slotIndex == SubscriptionManager.DEFAULT_SIM_SLOT_INDEX) {
    
         slotIndex = getSlotIndex(getDefaultSubId());
    
         if (VDBG) logd("[getSubId] map default slotIndex=" + slotIndex);
    
     }
    
     ......
    
     // Create an array of subIds that are in this slot?
    
     ArrayList<Integer> subIds = new ArrayList<Integer>();
    
     for (Entry<Integer, Integer> entry: sSlotIndexToSubId.entrySet()) {
    
         int slot = entry.getKey();
    
         int sub = entry.getValue();
    
         if (slotIndex == slot) {
    
             subIds.add(sub);
    
         }
    
     }
    
  
    
     // Convert ArrayList to array
    
     int numSubIds = subIds.size();
    
     if (numSubIds > 0) {
    
         int[] subIdArr = new int[numSubIds];
    
         for (int i = 0; i < numSubIds; i++) {
    
             subIdArr[i] = subIds.get(i);
    
         }
    
         if (VDBG) logd("[getSubId]- subIdArr=" + subIdArr);
    
         return subIdArr;
    
     } else {
    
         if (DBG) logd("[getSubId]- numSubIds == 0, return DummySubIds slotIndex=" + slotIndex);
    
         return getDummySubIds(slotIndex);
    
     }
    
     }
    
 }
    
    
    
    
    代码解读

通过分析SubscriptionController类的继承关系可以看出,在其内部的方法中确实存在SubscriptionManager的getSubId()的实际操作。

复制代码
 public class SubscriptionManager {

    
     /** @hide */
    
     public static int[] getSubId(int slotIndex) {
    
     if (!isValidSlotIndex(slotIndex)) {
    
         logd("[getSubId]- fail");
    
         return null;
    
     }
    
     int[] subId = null;
    
     try {
    
         ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
    
         if (iSub != null) {
    
             subId = iSub.getSubId(slotIndex);
    
         }
    
     } catch (RemoteException ex) {
    
         // ignore it
    
     }
    
     return subId;
    
     }
    
 }
    
    
    
    
    代码解读

5. 其他

电话管理器实例
初始化SubscribersManager实例
通过动态反射初始化mTelMgr为一个TelephonyManager实例:
mTelMgr = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
开始监听电话状态变化
mTelMgr.listen(phoneStateListener[i], PhoneStateListener.LISTEN_SIGNAL_STRENGTHS);
获取卡槽数量
计算当前设备上的可用插槽数量:
mSlotCnt = mTelMgr.getSimCount();
从默认的TelephonyManager实例中获取当前插槽数量:
TelephonyManager.getDefault().getSimCount();

参考:

Android 双卡环境下IMSIPM实现与分析及虚拟手机号码发送短信的技术应用总结

subid和slotid

Android平台订阅信息更新流程

全部评论 (0)

还没有任何评论哟~