【Telephony】isub系统服务--> SubscriptionController.java

1. isub系统服务的创建和发布

开机启动
--> PhoneApp.onCreate()
--> PhoneGlobal.onCreate()
--> PhoneFactory.makeDefaultPhones(this);
--> TelephonyComponentFactory.getInstance().inject(SubscriptionController.class.getName())
                                           .initSubscriptionController(context);
--> SubscriptionController.init()

    public static SubscriptionController init(Context c) {
        synchronized (SubscriptionController.class) {		//同步锁
            if (sInstance == null) {             //单例模式
                sInstance = new SubscriptionController(c);
            } else {
                Log.wtf(LOG_TAG, "init() called multiple times!  sInstance = " + sInstance);
            }
            return sInstance;
        }
    }
--> new SubscriptionController()

    protected SubscriptionController(Context c) {
        internalInit(c);
        migrateImsSettings();
    }		
--> internalInit()
	
	    protected void internalInit(Context c) {
        mContext = c;
        mTelephonyManager = TelephonyManager.from(mContext);

        try {
            mUiccController = UiccController.getInstance();
        } catch(RuntimeException ex) {
            throw new RuntimeException(
                    "UiccController has to be initialised before SubscriptionController init");
        }

        mAppOps = (AppOpsManager)mContext.getSystemService(Context.APP_OPS_SERVICE);

        ServiceRegisterer subscriptionServiceRegisterer = TelephonyFrameworkInitializer
                .getTelephonyServiceManager()
                .getSubscriptionServiceRegisterer();
        if (subscriptionServiceRegisterer.get() == null) {
            subscriptionServiceRegisterer.register(this);  //注册服务
            mLastISubServiceRegTime = System.currentTimeMillis();
        }

        // clear SLOT_INDEX for all subs
        clearSlotIndexForSubInfoRecords();

        // Cache Setting values
        cacheSettingValues();

        // Initial invalidate activates caching.
        invalidateDefaultSubIdCaches();
        invalidateDefaultDataSubIdCaches();
        invalidateDefaultSmsSubIdCaches();
        invalidateActiveDataSubIdCaches();
        invalidateSlotIndexCaches();

        mContext.getContentResolver().registerContentObserver(
                SubscriptionManager.SIM_INFO_SUW_RESTORE_CONTENT_URI, false,
                new ContentObserver(new Handler()) {
                    @Override
                    public void onChange(boolean selfChange, Uri uri) {
                        if (uri.equals(SubscriptionManager.SIM_INFO_SUW_RESTORE_CONTENT_URI)) {
                            refreshCachedActiveSubscriptionInfoList();
                            notifySubscriptionInfoChanged();

                            SubscriptionManager subManager = SubscriptionManager.from(mContext);
                            for (SubscriptionInfo subInfo : getActiveSubscriptionInfoList(
                                    mContext.getOpPackageName(), mContext.getAttributionTag())) {
                                if (SubscriptionController.getInstance()
                                        .isActiveSubId(subInfo.getSubscriptionId())) {
                                    ImsManager imsManager = ImsManager.getInstance(mContext,
                                            subInfo.getSimSlotIndex());
                                    imsManager.updateImsServiceConfig();
                                }
                            }
                        }
                    }
                });

        if (DBG) logdl("[SubscriptionController] init by Context");
    }

--> subscriptionServiceRegisterer.register(this);                                          
 

2. SIM卡加载

--> SubscriptionInfoUpdater.updateInternalIccState()

    /**
     * Update subscriptions when given a new ICC state.
     */
    public void updateInternalIccState(String simStatus, String reason, int phoneId) {
        logd("updateInternalIccState to simStatus " + simStatus + " reason " + reason
                + " phoneId " + phoneId);
        int message = internalIccStateToMessage(simStatus);
        if (message != EVENT_INVALID) {
            sendMessage(obtainMessage(message, phoneId, 0, reason));
        }
    }
--> internalIccStateToMessage(simStatus)
	
    private int internalIccStateToMessage(String simStatus) {
        switch(simStatus) {
            case IccCardConstants.INTENT_VALUE_ICC_ABSENT: return EVENT_SIM_ABSENT;
            case IccCardConstants.INTENT_VALUE_ICC_UNKNOWN: return EVENT_SIM_UNKNOWN;
            case IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR: return EVENT_SIM_IO_ERROR;
            case IccCardConstants.INTENT_VALUE_ICC_CARD_RESTRICTED: return EVENT_SIM_RESTRICTED;
            case IccCardConstants.INTENT_VALUE_ICC_NOT_READY: return EVENT_SIM_NOT_READY;
            case IccCardConstants.INTENT_VALUE_ICC_LOCKED: return EVENT_SIM_LOCKED;
            case IccCardConstants.INTENT_VALUE_ICC_LOADED: return EVENT_SIM_LOADED;
            case IccCardConstants.INTENT_VALUE_ICC_READY: return EVENT_SIM_READY;
            case IccCardConstants.INTENT_VALUE_ICC_IMSI: return EVENT_SIM_IMSI;
            default:
                logd("Ignoring simStatus: " + simStatus);
                return EVENT_INVALID;
        }
    }	

--> handleMessage(EVENT_SIM_LOADED)
	
            case EVENT_SIM_LOADED:
                handleSimLoaded(msg.arg1);
                break;	
                
-->	handleSimLoaded	

    protected void handleSimLoaded(int phoneId) {
        logd("handleSimLoaded: phoneId: " + phoneId);

        // The SIM should be loaded at this state, but it is possible in cases such as SIM being
        // removed or a refresh RESET that the IccRecords could be null. The right behavior is to
        // not broadcast the SIM loaded.
        IccCard iccCard = PhoneFactory.getPhone(phoneId).getIccCard();
        if (iccCard == null) {  // Possibly a race condition.
            logd("handleSimLoaded: IccCard null");
            return;
        }
        IccRecords records = iccCard.getIccRecords();
        if (records == null) {  // Possibly a race condition.
            logd("handleSimLoaded: IccRecords null");
            return;
        }
        if (IccUtils.stripTrailingFs(records.getFullIccId()) == null) {
            logd("handleSimLoaded: IccID null");
            return;
        }

        // Call updateSubscriptionInfoByIccId() only if was not done earlier from SIM READY event
        if (sIccId[phoneId] == null) {
            sIccId[phoneId] = IccUtils.stripTrailingFs(records.getFullIccId());

            updateSubscriptionInfoByIccId(phoneId, true /* updateEmbeddedSubs */);  //更新
        }

        List<SubscriptionInfo> subscriptionInfos =
                mSubscriptionController.getSubInfoUsingSlotIndexPrivileged(phoneId); //获取subinfo
        if (subscriptionInfos == null || subscriptionInfos.isEmpty()) {
            loge("empty subinfo for phoneId: " + phoneId + "could not update ContentResolver");
        } else {
            for (SubscriptionInfo sub : subscriptionInfos) {
                int subId = sub.getSubscriptionId();
                TelephonyManager tm = (TelephonyManager)
                        sContext.getSystemService(Context.TELEPHONY_SERVICE);
                String operator = tm.getSimOperatorNumeric(subId);

                if (!TextUtils.isEmpty(operator)) {
                    if (subId == mSubscriptionController.getDefaultSubId()) {
                        MccTable.updateMccMncConfiguration(sContext, operator);
                    }
                    mSubscriptionController.setMccMnc(operator, subId);
                } else {
                    logd("EVENT_RECORDS_LOADED Operator name is null");
                }

                String iso = tm.getSimCountryIsoForPhone(phoneId);

                if (!TextUtils.isEmpty(iso)) {
                    mSubscriptionController.setCountryIso(iso, subId);
                } else {
                    logd("EVENT_RECORDS_LOADED sim country iso is null");
                }

                String msisdn = tm.getLine1Number(subId);
                if (msisdn != null) {
                    mSubscriptionController.setDisplayNumber(msisdn, subId);
                }

                String imsi = tm.createForSubscriptionId(subId).getSubscriberId();
                if (imsi != null) {
                    mSubscriptionController.setImsi(imsi, subId);
                }

                String[] ehplmns = records.getEhplmns();
                String[] hplmns = records.getPlmnsFromHplmnActRecord();
                if (ehplmns != null || hplmns != null) {
                    mSubscriptionController.setAssociatedPlmns(ehplmns, hplmns, subId);
                }

                /* Update preferred network type and network selection mode on SIM change.
                 * Storing last subId in SharedPreference for now to detect SIM change.
                 */
                SharedPreferences sp =
                        PreferenceManager.getDefaultSharedPreferences(sContext);
                int storedSubId = sp.getInt(CURR_SUBID + phoneId, -1);

                if (storedSubId != subId) {
                    // Only support automatic selection mode on SIM change.
                    PhoneFactory.getPhone(phoneId).getNetworkSelectionMode(
                            obtainMessage(EVENT_GET_NETWORK_SELECTION_MODE_DONE,
                                    new Integer(phoneId)));
                    // Update stored subId
                    SharedPreferences.Editor editor = sp.edit();
                    editor.putInt(CURR_SUBID + phoneId, subId);
                    editor.apply();
                }
            }
        }

        /**
         * The sim loading sequence will be
         *  1. ACTION_SUBINFO_CONTENT_CHANGE happens through updateSubscriptionInfoByIccId() above.
         *  2. ACTION_SIM_STATE_CHANGED/ACTION_SIM_CARD_STATE_CHANGED
         *  /ACTION_SIM_APPLICATION_STATE_CHANGED
         *  3. ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED
         *  4. restore sim-specific settings
         *  5. ACTION_CARRIER_CONFIG_CHANGED
         */
        broadcastSimStateChanged(phoneId, IccCardConstants.INTENT_VALUE_ICC_LOADED, null);
        broadcastSimCardStateChanged(phoneId, TelephonyManager.SIM_STATE_PRESENT);
        broadcastSimApplicationStateChanged(phoneId, TelephonyManager.SIM_STATE_LOADED);
        updateSubscriptionCarrierId(phoneId, IccCardConstants.INTENT_VALUE_ICC_LOADED);
        /* Sim-specific settings restore depends on knowing both the mccmnc and the carrierId of the
        sim which is why it must be done after #updateSubscriptionCarrierId(). It is done before
        carrier config update to avoid any race conditions with user settings that depend on
        carrier config*/
        restoreSimSpecificSettingsForPhone(phoneId);
        updateCarrierServices(phoneId, IccCardConstants.INTENT_VALUE_ICC_LOADED);
    }
--> 看一下更新 updateSubscriptionInfoByIccId()
	
    protected synchronized void updateSubscriptionInfoByIccId(int phoneId,
            boolean updateEmbeddedSubs) {
        logd("updateSubscriptionInfoByIccId:+ Start - phoneId: " + phoneId);
        if (!SubscriptionManager.isValidPhoneId(phoneId)) {
            loge("[updateSubscriptionInfoByIccId]- invalid phoneId=" + phoneId);
            return;
        }
        logd("updateSubscriptionInfoByIccId: removing subscription info record: phoneId "
                + phoneId);
        // Clear phoneId only when sim absent is not enough. It's possible to switch SIM profile
        // within the same slot. Need to clear the slot index of the previous sub. Thus always clear
        // for the changing slot first.
        mSubscriptionController.clearSubInfoRecord(phoneId);

        // If SIM is not absent, insert new record or update existing record.
        if (!ICCID_STRING_FOR_NO_SIM.equals(sIccId[phoneId]) && sIccId[phoneId] != null) {
            logd("updateSubscriptionInfoByIccId: adding subscription info record: iccid: "
                    + sIccId[phoneId] + ", phoneId:" + phoneId);
            mSubscriptionManager.addSubscriptionInfoRecord(sIccId[phoneId], phoneId);
        }

        List<SubscriptionInfo> subInfos =
                mSubscriptionController.getSubInfoUsingSlotIndexPrivileged(phoneId);
        if (subInfos != null) {
            boolean changed = false;
            for (int i = 0; i < subInfos.size(); i++) {
                SubscriptionInfo temp = subInfos.get(i);
                ContentValues value = new ContentValues(1);

                String msisdn = TelephonyManager.getDefault().getLine1Number(
                        temp.getSubscriptionId());

                if (!TextUtils.equals(msisdn, temp.getNumber())) {
                    value.put(SubscriptionManager.NUMBER, msisdn);
                    sContext.getContentResolver().update(SubscriptionManager
                            .getUriForSubscriptionId(temp.getSubscriptionId()), value, null, null);
                    changed = true;
                }
            }
            if (changed) {
                // refresh Cached Active Subscription Info List
                mSubscriptionController.refreshCachedActiveSubscriptionInfoList();
            }
        }

        // TODO investigate if we can update for each slot separately.
        if (isAllIccIdQueryDone()) {
            // Ensure the modems are mapped correctly
            if (mSubscriptionManager.isActiveSubId(
                    mSubscriptionManager.getDefaultDataSubscriptionId())) {
                mSubscriptionManager.setDefaultDataSubId(
                        mSubscriptionManager.getDefaultDataSubscriptionId());
            } else {
                logd("bypass reset default data sub if inactive");
            }
            setSubInfoInitialized();
        }

        UiccController uiccController = UiccController.getInstance();
        UiccSlot[] uiccSlots = uiccController.getUiccSlots();
        if (uiccSlots != null && updateEmbeddedSubs) {
            List<Integer> cardIds = new ArrayList<>();
            for (UiccSlot uiccSlot : uiccSlots) {
                if (uiccSlot != null && uiccSlot.getUiccCard() != null) {
                    int cardId = uiccController.convertToPublicCardId(
                            uiccSlot.getUiccCard().getCardId());
                    cardIds.add(cardId);
                }
            }
            updateEmbeddedSubscriptions(cardIds, (hasChanges) -> {
                if (hasChanges) {
                    mSubscriptionController.notifySubscriptionInfoChanged();
                }
                if (DBG) logd("updateSubscriptionInfoByIccId: SubscriptionInfo update complete");
            });
        }

        mSubscriptionController.notifySubscriptionInfoChanged();
        if (DBG) logd("updateSubscriptionInfoByIccId: SubscriptionInfo update complete");
    }
--> 查询Telephony SQLite数据库的siminfo表   
    SubscriptionController.getSubInfoUsingSlotIndexPrivileged

    public List<SubscriptionInfo> getSubInfoUsingSlotIndexPrivileged(int slotIndex) {
        if (DBG) logd("[getSubInfoUsingSlotIndexPrivileged]+ slotIndex:" + slotIndex);
        if (slotIndex == SubscriptionManager.DEFAULT_SIM_SLOT_INDEX) {
            slotIndex = getSlotIndex(getDefaultSubId());
        }
        if (!SubscriptionManager.isValidSlotIndex(slotIndex)) {
            if (DBG) logd("[getSubInfoUsingSlotIndexPrivileged]- invalid slotIndex");
            return null;
        }

        Cursor cursor = mContext.getContentResolver().query(SubscriptionManager.CONTENT_URI,
                null, SubscriptionManager.SIM_SLOT_INDEX + "=?",
                new String[]{String.valueOf(slotIndex)}, null);
        ArrayList<SubscriptionInfo> subList = null;
        try {
            if (cursor != null) {
                while (cursor.moveToNext()) {
                    SubscriptionInfo subInfo = getSubInfoRecord(cursor);
                    if (subInfo != null) {
                        if (subList == null) {
                            subList = new ArrayList<SubscriptionInfo>();
                        }
                        subList.add(subInfo);
                    }
                }
            }
        } finally {
            if (cursor != null) {
                cursor.close();
            }
        }
        if (DBG) logd("[getSubInfoUsingSlotIndex]- null info return");

        return subList;
    }

--> 将siminfo表中的字段值封装到SubscriptionInfo对象的属性中,然后返回对象。
	getSubInfoRecord()
	
    private SubscriptionInfo getSubInfoRecord(Cursor cursor) {
        int id = cursor.getInt(cursor.getColumnIndexOrThrow(
                SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID));
        String iccId = cursor.getString(cursor.getColumnIndexOrThrow(
                SubscriptionManager.ICC_ID));
        int simSlotIndex = cursor.getInt(cursor.getColumnIndexOrThrow(
                SubscriptionManager.SIM_SLOT_INDEX));
        String displayName = cursor.getString(cursor.getColumnIndexOrThrow(
                SubscriptionManager.DISPLAY_NAME));
        String carrierName = cursor.getString(cursor.getColumnIndexOrThrow(
                SubscriptionManager.CARRIER_NAME));
        int nameSource = cursor.getInt(cursor.getColumnIndexOrThrow(
                SubscriptionManager.NAME_SOURCE));
        int iconTint = cursor.getInt(cursor.getColumnIndexOrThrow(
                SubscriptionManager.HUE));
        String number = cursor.getString(cursor.getColumnIndexOrThrow(
                SubscriptionManager.NUMBER));
        int dataRoaming = cursor.getInt(cursor.getColumnIndexOrThrow(
                SubscriptionManager.DATA_ROAMING));
        String mcc = cursor.getString(cursor.getColumnIndexOrThrow(
                SubscriptionManager.MCC_STRING));
        String mnc = cursor.getString(cursor.getColumnIndexOrThrow(
                SubscriptionManager.MNC_STRING));
        String ehplmnsRaw = cursor.getString(cursor.getColumnIndexOrThrow(
                SubscriptionManager.EHPLMNS));
        String hplmnsRaw = cursor.getString(cursor.getColumnIndexOrThrow(
                SubscriptionManager.HPLMNS));
        String[] ehplmns = ehplmnsRaw == null ? null : ehplmnsRaw.split(",");
        String[] hplmns = hplmnsRaw == null ? null : hplmnsRaw.split(",");

        // cardId is the private ICCID/EID string, also known as the card string
        String cardId = cursor.getString(cursor.getColumnIndexOrThrow(
                SubscriptionManager.CARD_ID));
        String countryIso = cursor.getString(cursor.getColumnIndexOrThrow(
                SubscriptionManager.ISO_COUNTRY_CODE));
        // publicCardId is the publicly exposed int card ID
        int publicCardId = mUiccController.convertToPublicCardId(cardId);
        boolean isEmbedded = cursor.getInt(cursor.getColumnIndexOrThrow(
                SubscriptionManager.IS_EMBEDDED)) == 1;
        int carrierId = cursor.getInt(cursor.getColumnIndexOrThrow(
                SubscriptionManager.CARRIER_ID));
        UiccAccessRule[] accessRules;
        if (isEmbedded) {
            accessRules = UiccAccessRule.decodeRules(cursor.getBlob(
                    cursor.getColumnIndexOrThrow(SubscriptionManager.ACCESS_RULES)));
        } else {
            accessRules = null;
        }
        UiccAccessRule[] carrierConfigAccessRules = UiccAccessRule.decodeRules(cursor.getBlob(
            cursor.getColumnIndexOrThrow(SubscriptionManager.ACCESS_RULES_FROM_CARRIER_CONFIGS)));
        boolean isOpportunistic = cursor.getInt(cursor.getColumnIndexOrThrow(
                SubscriptionManager.IS_OPPORTUNISTIC)) == 1;
        String groupUUID = cursor.getString(cursor.getColumnIndexOrThrow(
                SubscriptionManager.GROUP_UUID));
        int profileClass = cursor.getInt(cursor.getColumnIndexOrThrow(
                SubscriptionManager.PROFILE_CLASS));
        int portIndex = cursor.getInt(cursor.getColumnIndexOrThrow(
                SubscriptionManager.PORT_INDEX));
        int subType = cursor.getInt(cursor.getColumnIndexOrThrow(
                SubscriptionManager.SUBSCRIPTION_TYPE));
        String groupOwner = getOptionalStringFromCursor(cursor, SubscriptionManager.GROUP_OWNER,
                /*defaultVal*/ null);
        boolean areUiccApplicationsEnabled = cursor.getInt(cursor.getColumnIndexOrThrow(
                SubscriptionManager.UICC_APPLICATIONS_ENABLED)) == 1;

        int usageSetting = cursor.getInt(cursor.getColumnIndexOrThrow(
                SubscriptionManager.USAGE_SETTING));

        if (VDBG) {
            String iccIdToPrint = SubscriptionInfo.givePrintableIccid(iccId);
            String cardIdToPrint = SubscriptionInfo.givePrintableIccid(cardId);
            logd("[getSubInfoRecord] id:" + id + " iccid:" + iccIdToPrint + " simSlotIndex:"
                    + simSlotIndex + " carrierid:" + carrierId + " displayName:" + displayName
                    + " nameSource:" + nameSource + " iconTint:" + iconTint
                    + " dataRoaming:" + dataRoaming + " mcc:" + mcc + " mnc:" + mnc
                    + " countIso:" + countryIso + " isEmbedded:"
                    + isEmbedded + " accessRules:" + Arrays.toString(accessRules)
                    + " carrierConfigAccessRules: " + Arrays.toString(carrierConfigAccessRules)
                    + " cardId:" + cardIdToPrint + " portIndex:" + portIndex
                    + " publicCardId:" + publicCardId
                    + " isOpportunistic:" + isOpportunistic + " groupUUID:" + groupUUID
                    + " profileClass:" + profileClass + " subscriptionType: " + subType
                    + " carrierConfigAccessRules:" + carrierConfigAccessRules
                    + " areUiccApplicationsEnabled: " + areUiccApplicationsEnabled
                    + " usageSetting: " + usageSetting);
        }

        // If line1number has been set to a different number, use it instead.
        String line1Number = mTelephonyManager.getLine1Number(id);
        if (!TextUtils.isEmpty(line1Number) && !line1Number.equals(number)) {
            number = line1Number;
        }
        // FIXME(b/210771052): constructing a complete SubscriptionInfo requires a port index,
        // but the port index isn't available here. Should it actually be part of SubscriptionInfo?
        SubscriptionInfo info = new SubscriptionInfo(id, iccId, simSlotIndex, displayName,
                carrierName, nameSource, iconTint, number, dataRoaming, /* icon= */ null,
                mcc, mnc, countryIso, isEmbedded, accessRules, cardId, publicCardId,
                isOpportunistic, groupUUID, /* isGroupDisabled= */ false , carrierId, profileClass,
                subType, groupOwner, carrierConfigAccessRules, areUiccApplicationsEnabled,
                portIndex, usageSetting);
        info.setAssociatedPlmns(ehplmns, hplmns);
        return info;
    }

你可能感兴趣的:(Telephony,Telephony)