subId、slotId、SubscriptionInfo和SubscriptionManager的解释及关系说明

1. subid和slotid

slotid或者phoneid是指卡槽,双卡机器的卡槽1值为0,卡槽2值为1,依次类推。
subid:SubscriptionId(Subscription Identifier)。subid是数据库telephony.db的表siminfo的主键递增项,其中telephony.db在"/data/user_de/0/com.android.providers.telephony/databases"下。


image.png

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

插入双卡后数据库中就会有subid值为1和2的两个数据条目,拔卡插卡交换卡槽后,数据库并不会增加新项,只有插入一张新的sim卡才会增加一条id为3的数据条目。
注意:
subid对应卡,slotid对应卡槽

2. Subscription和SubscriptionInfo

每一张SIM卡都对应一个Subscription,用谁家的SIM卡就相当于订阅(Subscription)谁家的业务。
SIM卡的信息就是SubscriptionInfo(Subscription Information),比如iccid、MNC、MCC等,多张SIM卡就有多个SubscriptionInfo。
其中ICCID:Integrate circuit card identity,集成电路卡识别码,即SIM卡卡号,相当于手机号码的身份证。


image.png

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及其相关方法

SubscriptionManager为第三方app层使用,用于:
1). 获取和设置当前双卡设置(如当前默认拨号卡);
2). 进行slotid和subId转换等;
3). 获取当前的卡信息SubscriptionInfo。

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  

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卡的subscriptionInfo,进而可以获取该卡的mcc/mnc/iccid等信息。

也可以直接使用slotId,调用SubscriptionManager的getActiviteSubscriptionInfoFromSimSlotIndex()方法,获取SIM卡的subscriptionInfo。

注:由slotId得到subId,也可使用MtkSubscriptionManager(mtk自己定义的Subscription管理类)的静态方法getSubIdUsingPhoneId()

4. SubscriptionManager和SubscriptionController

image.png

SubscriptionManager是SubscriptionController的应用程序接口,提供有关当前电话订阅的信息。
SubscriptionController运行在phone进程中,是双卡相关功能正真实现端,为SubscriptionManager提供服务。
SubscriptionManager的功能基本都是通过binder调用SubscriptionController服务端来实现,使用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;
    }

其中MtkSubscriptionController.getMtkInstance()返回MtkSubscriptionController实例

public class MtkSubscriptionController extends SubscriptionController {
    public static MtkSubscriptionController getMtkInstance() {
        synchronized (MtkSubscriptionController.class) {
            return sMtkInstance;
        }
    }
}

但是MtkSubscriptionController类内并无getSubIdUsingPhoneId()方法,调用的是父类SubscriptionController的getSubIdUsingPhoneId()方法,getSubIdUsingPhoneId()方法调用的是getSubId()方法

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()的真正实现也是在SubscriptionController类的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;
    }
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 225,677评论 6 524
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 96,772评论 3 408
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 173,108评论 0 370
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 61,378评论 1 303
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 70,394评论 6 403
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 53,807评论 1 315
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 42,127评论 3 432
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 41,136评论 0 281
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 47,693评论 1 328
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 39,703评论 3 349
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 41,810评论 1 357
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 37,400评论 5 352
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 43,130评论 3 341
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 33,532评论 0 25
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 34,707评论 1 278
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 50,412评论 3 383
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 46,892评论 2 368

推荐阅读更多精彩内容