Sim卡初始化
启动过程中初始化 SIM卡的一些相关数据

主要的类及其作用:

PhoneGlobals :  里面的OnCreate直接调用了 PhoneFactory.makeDefaultPhones(this);
PhoneApp : TelephonyServer 入口里面初始化了两个对象一个是PhoneGlobals TelephonyGlobals
UiccController:整个Uicc相关信息的控制接口,监控SIM状态变化
UiccCard:Uicc卡的抽象,用来更新卡的状态
IccCardStatus:维护Uicc卡的状态,CardState&PinState
UiccCardApplication:Uicc的一个具体的应用,负责卡中数据读写,存取,pin和puk密码设置,解锁
CatService:主要负责SIM Tollkit相关
IccConstants:SIM卡中文件地址,不同数据在SIM卡上的字段地址。
IccRecords:记录SIM卡的数据
IccFileHandler:读取SIM卡数据以及处理接收的结果。

SIM卡初始化逻辑图:

 

 

第一步:服务启动TelephonyServer

1.PhoneApp.java   全路径 : android/packages/services/Telephony/src/com/android/phone/PhoneApp.java

    public void onCreate() {        if (UserHandle.myUserId() == 0) {            // We are running as the primary user, so should bring up the            // global phone state.            mPhoneGlobals = new PhoneGlobals(this);            //进入底层入口            mPhoneGlobals.onCreate();            mTelephonyGlobals = new TelephonyGlobals(this);            mTelephonyGlobals.onCreate();        }    }

2.PhoneGlobals.java   全路径 : android/packages/services/Telephony/src/com/android/phone/PhoneGlobals.java

public void onCreate() {        if (VDBG) Log.v(LOG_TAG, "onCreate()...");        Log.v(LOG_TAG, "onCreate()...启动 PhoneGlbals servces/TelephotyFramework");        ContentResolver resolver = getContentResolver();        // Cache the "voice capable" flag.        // This flag currently comes from a resource (which is        // overrideable on a per-product basis):        sVoiceCapable =                         getResources().getBoolean(com.android.internal.R.bool.config_voice_capable);        // ...but this might eventually become a PackageManager "system        // feature" instead, in which case we'd do something like:        // sVoiceCapable =        //           getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY_VOICE_CALLS);        if (mCM == null) {            Log.v(LOG_TAG,"调用 PhoneFactory.makeDefaultPhones(this)");            // Initialize the telephony framework            PhoneFactory.makeDefaultPhones(this);//进入optFramework            ..............            .................            ...................            .......................        }    }

第二部:Framewrok/opt/Telephony

1.PhoneFactory.java  全路径:android\frameworks\opt\telephony\src\java\com\android\internal\telephony\PhoneFactory.java

UiccController.make(context, sCommandsInterfaces)开始初始化UiccController

UiccController是整个UICC相关信息的控制接口,UiccController的实例化就是在RIL与UiccController之间建立关系,这样的话,当SIM卡发送变化时UiccContrller就可以马上知道并且做出相应的操作。

UiccController对象是在PhoneFactory中makeDefaultPhone()方法中初始化的,有个细节有个细节值得注意的是sCommandsInterfaces数组的i对应的是PhoneId。

 /**     * FIXME replace this with some other way of making these     * instances     */    public static void makeDefaultPhone(Context context) {        synchronized (sLockProxyPhones) {            if (!sMadeDefaults) {                sContext = context;                // create the telephony device controller.                TelephonyDevController.create();                int retryCount = 0;                for(;;) {                    boolean hasException = false;                    retryCount ++;                    try {                        // use UNIX domain socket to                        // prevent subsequent initialization                        new LocalServerSocket("com.android.internal.telephony");                    } catch (java.io.IOException ex) {                        hasException = true;                    }                    if ( !hasException ) {                        break;                    } else if (retryCount > SOCKET_OPEN_MAX_RETRY) {                        throw new RuntimeException("PhoneFactory probably already running");                    } else {                        try {                            Thread.sleep(SOCKET_OPEN_RETRY_MILLIS);                        } catch (InterruptedException er) {                        }                    }                }                sPhoneNotifier = new DefaultPhoneNotifier();                TelephonyComponentFactory telephonyComponentFactory                        = TelephonyComponentFactory.getInstance();                int cdmaSubscription = CdmaSubscriptionSourceManager.getDefault(context);                Rlog.i(LOG_TAG, "Cdma Subscription set to " + cdmaSubscription);                /* In case of multi SIM mode two instances of Phone, RIL are created,                   where as in single SIM mode only instance. isMultiSimEnabled() function checks                   whether it is single SIM or multi SIM mode */                int numPhones = TelephonyManager.getDefault().getPhoneCount();                // Return whether or not the device should use dynamic binding or the static                // implementation (deprecated)                boolean isDynamicBinding = sContext.getResources().getBoolean(                        com.android.internal.R.bool.config_dynamic_bind_ims);                // Get the package name of the default IMS implementation.                String defaultImsPackage = sContext.getResources().getString(                        com.android.internal.R.string.config_ims_package);                // Start ImsResolver and bind to ImsServices.                Rlog.i(LOG_TAG, "ImsResolver: defaultImsPackage: " + defaultImsPackage);                sImsResolver = new ImsResolver(sContext, defaultImsPackage, numPhones,                        isDynamicBinding);                sImsResolver.initPopulateCacheAndStartBind();                int[] networkModes = new int[numPhones];                sPhones = new Phone[numPhones];                sCommandsInterfaces = new RIL[numPhones];                sTelephonyNetworkFactories = new TelephonyNetworkFactory[numPhones];                for (int i = 0; i < numPhones; i++) {                    // reads the system properties and makes commandsinterface                    // Get preferred network type.                    networkModes[i] = RILConstants.PREFERRED_NETWORK_MODE;                    Rlog.i(LOG_TAG, "Network Mode set to " + Integer.toString(networkModes[i]));                    sCommandsInterfaces[i] = telephonyComponentFactory.makeRIL(context,                            networkModes[i], cdmaSubscription, i);                }                Rlog.i(LOG_TAG, "Creating SubscriptionController");                telephonyComponentFactory.initSubscriptionController(context, sCommandsInterfaces);                //得到UiccController对象                // Instantiate UiccController so that all other classes can just                // call getInstance()                sUiccController = UiccController.make(context, sCommandsInterfaces);//通过make初始化PhoneFactory                if (context.getPackageManager().hasSystemFeature(                        PackageManager.FEATURE_TELEPHONY_EUICC)) {                    sEuiccController = EuiccController.init(context);                    sEuiccCardController = EuiccCardController.init(context);                }                for (int i = 0; i < numPhones; i++) {                    Phone phone = null;                    int phoneType = TelephonyManager.getPhoneType(networkModes[i]);                    if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {                        //sCommandsInterfaces的i对应的是PhoneId;sCommandsInterfaces数组的i对应的是PhoneId。                        phone = telephonyComponentFactory.makePhone(context,                                sCommandsInterfaces[i], sPhoneNotifier, i,                                PhoneConstants.PHONE_TYPE_GSM,                                telephonyComponentFactory);                    } else if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {                        phone = telephonyComponentFactory.makePhone(context,                                sCommandsInterfaces[i], sPhoneNotifier, i,                                PhoneConstants.PHONE_TYPE_CDMA_LTE,                                telephonyComponentFactory);                    }                    Rlog.i(LOG_TAG, "Creating Phone with type = " + phoneType + " sub = " + i);                    sPhones[i] = phone;                }                // Set the default phone in base class.                // FIXME: This is a first best guess at what the defaults will be. It                // FIXME: needs to be done in a more controlled manner in the future.                sPhone = sPhones[0];                sCommandsInterface = sCommandsInterfaces[0];                // Ensure that we have a default SMS app. Requesting the app with                // updateIfNeeded set to true is enough to configure a default SMS app.                ComponentName componentName =                        SmsApplication.getDefaultSmsApplication(context, true /* updateIfNeeded */);                String packageName = "NONE";                if (componentName != null) {                    packageName = componentName.getPackageName();                }                Rlog.i(LOG_TAG, "defaultSmsApplication: " + packageName);                // Set up monitor to watch for changes to SMS packages                SmsApplication.initSmsPackageMonitor(context);                sMadeDefaults = true;                Rlog.i(LOG_TAG, "Creating SubInfoRecordUpdater ");                sSubInfoRecordUpdater = telephonyComponentFactory.makeSubscriptionInfoUpdater(                        BackgroundThread.get().getLooper(), context, sPhones, sCommandsInterfaces);                SubscriptionController.getInstance().updatePhonesAvailability(sPhones);                // Start monitoring after defaults have been made.                // Default phone must be ready before ImsPhone is created because ImsService might                // need it when it is being opened. This should initialize multiple ImsPhones for                // ImsResolver implementations of ImsService.                for (int i = 0; i < numPhones; i++) {                    sPhones[i].startMonitoringImsService();                }                ITelephonyRegistry tr = ITelephonyRegistry.Stub.asInterface(                        ServiceManager.getService("telephony.registry"));                SubscriptionController sc = SubscriptionController.getInstance();                sSubscriptionMonitor = new SubscriptionMonitor(tr, sContext, sc, numPhones);                sPhoneSwitcher = telephonyComponentFactory.                        makePhoneSwitcher(MAX_ACTIVE_PHONES, numPhones,                        sContext, sc, Looper.myLooper(), tr, sCommandsInterfaces,                        sPhones);                sProxyController = ProxyController.getInstance(context, sPhones,                        sUiccController, sCommandsInterfaces, sPhoneSwitcher);                sIntentBroadcaster = IntentBroadcaster.getInstance(context);                sNotificationChannelController = new NotificationChannelController(context);                sTelephonyNetworkFactories = new TelephonyNetworkFactory[numPhones];                for (int i = 0; i < numPhones; i++) {                    sTelephonyNetworkFactories[i] = new TelephonyNetworkFactory(                            sPhoneSwitcher, sc, sSubscriptionMonitor, Looper.myLooper(),                            sContext, i, sPhones[i].mDcTracker);                }                telephonyComponentFactory.makeExtTelephonyClasses(                        context, sPhones, sCommandsInterfaces);            }        }    }

2.UiccController.java  全路android\frameworks\opt\telephony\src\java\com\android\internal\telephony\uicc\UiccController.java

在UiccController.java的make()方法中new了一个UiccController对象,

 public static UiccController make(Context c, CommandsInterface[] ci) {        synchronized (mLock) {            if (mInstance != null) {                throw new RuntimeException("UiccController.make() should only be called once");            }            //实例化UiccController对象            mInstance = new UiccController(c, ci);            return mInstance;        }    }   private UiccController(Context c, CommandsInterface []ci) {        if (DBG) log("Creating UiccController");        Log.v("InitSimCartId","初始化 UiccContrort....");        mContext = c;        mCis = ci;        if (DBG) {            String logStr = "config_num_physical_slots = " + c.getResources().getInteger(                    com.android.internal.R.integer.config_num_physical_slots);            log(logStr);            sLocalLog.log(logStr);        }        int numPhysicalSlots = c.getResources().getInteger(                com.android.internal.R.integer.config_num_physical_slots);        // Minimum number of physical slot count should be equals to or greater than phone count,        // if it is less than phone count use phone count as physical slot count.        if (numPhysicalSlots < mCis.length) {            numPhysicalSlots = mCis.length;        }        mUiccSlots = new UiccSlot[numPhysicalSlots];        mPhoneIdToSlotId = new int[ci.length];        Arrays.fill(mPhoneIdToSlotId, INVALID_SLOT_ID);        if (VDBG) logPhoneIdToSlotIdMapping();        mRadioConfig = RadioConfig.getInstance(mContext);        mRadioConfig.registerForSimSlotStatusChanged(this, EVENT_SLOT_STATUS_CHANGED, null);        Log.v("InitSimCartId","mCis 事件注册.......");        for (int i = 0; i < mCis.length; i++) {            // i对应的是PhoneId            //注册监听四种事件  mCis 就是RIL            //对ICC状态的任何更改触发            mCis[i].registerForIccStatusChanged(this, EVENT_ICC_STATUS_CHANGED, i);//EVENT_ICC_STATUS_CHANGED监听SIM卡的状态变化            //启动任何过渡!RadioState.isAvailable()            mCis[i].registerForAvailable(this, EVENT_RADIO_AVAILABLE, i);            //在任何转换时触发RADIO_OFF or !RadioState.isAvailable()            mCis[i].registerForNotAvailable(this, EVENT_RADIO_UNAVAILABLE, i);//EVENT_RADIO_UNAVAILABLE(一旦radio变成不可用状态,就清空SIM卡的信息)            //设置SIM刷新通知的处理程序。            mCis[i].registerForIccRefresh(this, EVENT_SIM_REFRESH, i);        }        mLauncher = new UiccStateChangedLauncher(c, this);    }

       在上面UiccController的构造方法中可以看到,注册了四个事件EVENT_ICC_STATUS_CHANGED(监听SIM卡的状态变化),EVENT_RADIO_UNAVAILABLE(一旦radio变成不可用状态,就清空SIM卡的信息),EVENT_SIM_REFRESH。index对应的是PhoneId,当上面这三种消息上来时,就知道对应哪个Phone对象,也就对应那张卡。
      当接收到EVENT_ICC_STATUS_CHANGED消息后,UiccController调用RIL.java的getIccCardStatus()方法给MODEM发送RIL_REQUEST_GET_SIM_STATUS消息,查询SIM卡的状态。

回到Handler

   @Override    public void handleMessage (Message msg) {        synchronized (mLock) {            //1.首先从Message中取出PhoneId            Integer phoneId = getCiIndex(msg);            if (phoneId < 0 || phoneId >= mCis.length) {                Rlog.e(LOG_TAG, "Invalid phoneId : " + phoneId + " received with event "                        + msg.what);                return;            }            sLocalLog.log("handleMessage: Received " + msg.what + " for phoneId " + phoneId);            AsyncResult ar = (AsyncResult)msg.obj;            switch (msg.what) {                case EVENT_ICC_STATUS_CHANGED:  //如果拔卡和插卡就会触发到这个位置                    Log.v("InitSimCartId","事件注册 : 对ICC状态的任何更改触发  EVENT_ICC_STATUS_CHANGED ");                    if (DBG) log("Received EVENT_ICC_STATUS_CHANGED, calling getIccCardStatus");                    //2.查询当前SIM卡的状态                    mCis[phoneId].getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE,                            phoneId));                    break;                case EVENT_RADIO_AVAILABLE:                case EVENT_RADIO_ON:                    if (DBG) {                        log("Received EVENT_RADIO_AVAILABLE/EVENT_RADIO_ON, calling "                                + "getIccCardStatus");                    }                    mCis[phoneId].getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE,                            phoneId));                    // slot status should be the same on all RILs; request it only for phoneId 0                    if (phoneId == 0) {                        if (DBG) {                            log("Received EVENT_RADIO_AVAILABLE/EVENT_RADIO_ON for phoneId 0, "                                    + "calling getIccSlotsStatus");                        }                        mRadioConfig.getSimSlotsStatus(obtainMessage(EVENT_GET_SLOT_STATUS_DONE,                                phoneId));                    }                    Log.v("InitSimCartId","事件注册 : 启动任何过渡!RadioState.isAvailable() EVENT_RADIO_AVAILABLE");                    break;                case EVENT_GET_ICC_STATUS_DONE:                    if (DBG) log("Received EVENT_GET_ICC_STATUS_DONE");                    //3.处理查询到的状态信息                    onGetIccCardStatusDone(ar, phoneId);                    break;                case EVENT_SLOT_STATUS_CHANGED:                case EVENT_GET_SLOT_STATUS_DONE:                    if (DBG) {                        log("Received EVENT_SLOT_STATUS_CHANGED or EVENT_GET_SLOT_STATUS_DONE");                    }                    onGetSlotStatusDone(ar);                    break;                case EVENT_RADIO_UNAVAILABLE:                    if (DBG) log("EVENT_RADIO_UNAVAILABLE, dispose card");                    UiccSlot uiccSlot = getUiccSlotForPhone(phoneId);                    if (uiccSlot != null) {                        uiccSlot.onRadioStateUnavailable();                    }                    mIccChangedRegistrants.notifyRegistrants(new AsyncResult(null, phoneId, null));                    Log.v("InitSimCartId","事件注册 : 在任何转换时触发RADIO_OFF or !RadioState.isAvailable()  EVENT_RADIO_UNAVAILABLE");                    break;                case EVENT_SIM_REFRESH:                    if (DBG) log("Received EVENT_SIM_REFRESH");                    Log.v("InitSimCartId","事件注册 : 设置SIM刷新通知的处理程序  EVENT_SIM_REFRESH");                    onSimRefresh(ar, phoneId);                    break;                default:                    Rlog.e(LOG_TAG, " Unknown Event " + msg.what);                    break;            }        }    }

    在onGetSoltStartusDone(ar)里面主要是实例化UiccSlot对象,UiccSlot对象只是一个中介商而已  mUiccSlots[i] = new UiccSlot(mContext, isActive);

private synchronized void onGetSlotStatusDone(AsyncResult ar) {        if (!mIsSlotStatusSupported) {            if (VDBG) log("onGetSlotStatusDone: ignoring since mIsSlotStatusSupported is false");            return;        }        Throwable e = ar.exception;        if (e != null) {            String logStr;            if (!(e instanceof CommandException) || ((CommandException) e).getCommandError()                    != CommandException.Error.REQUEST_NOT_SUPPORTED) {                // this is not expected; there should be no exception other than                // REQUEST_NOT_SUPPORTED                logStr = "Unexpected error getting slot status: " + ar.exception;                Rlog.e(LOG_TAG, logStr);                sLocalLog.log(logStr);            } else {                // REQUEST_NOT_SUPPORTED                logStr = "onGetSlotStatusDone: request not supported; marking "                        + "mIsSlotStatusSupported to false";                log(logStr);                sLocalLog.log(logStr);                mIsSlotStatusSupported = false;            }            return;        }        ArrayList status = (ArrayList) ar.result;        if (!slotStatusChanged(status)) {            log("onGetSlotStatusDone: No change in slot status");            return;        }        sLastSlotStatus = status;        int numActiveSlots = 0;        for (int i = 0; i < status.size(); i++) {            IccSlotStatus iss = status.get(i);            boolean isActive = (iss.slotState == IccSlotStatus.SlotState.SLOTSTATE_ACTIVE);            if (isActive) {                numActiveSlots++;                // sanity check: logicalSlotIndex should be valid for an active slot                if (!isValidPhoneIndex(iss.logicalSlotIndex)) {                    throw new RuntimeException("Logical slot index " + iss.logicalSlotIndex                            + " invalid for physical slot " + i);                }                mPhoneIdToSlotId[iss.logicalSlotIndex] = i;            }            if (mUiccSlots[i] == null) {                if (VDBG) {                    log("Creating mUiccSlot[" + i + "]; mUiccSlots.length = " + mUiccSlots.length);                }                mUiccSlots[i] = new UiccSlot(mContext, isActive);            }            mUiccSlots[i].update(isActive ? mCis[iss.logicalSlotIndex] : null, iss);        }        if (VDBG) logPhoneIdToSlotIdMapping();        // sanity check: number of active slots should be valid        if (numActiveSlots != mPhoneIdToSlotId.length) {            throw new RuntimeException("Number of active slots " + numActiveSlots                    + " does not match the expected value " + mPhoneIdToSlotId.length);        }        // sanity check: slotIds should be unique in mPhoneIdToSlotId        Set slotIds = new HashSet<>();        for (int slotId : mPhoneIdToSlotId) {            if (slotIds.contains(slotId)) {                throw new RuntimeException("slotId " + slotId + " mapped to multiple phoneIds");            }            slotIds.add(slotId);        }        // broadcast slot status changed        Intent intent = new Intent(TelephonyManager.ACTION_SIM_SLOT_STATUS_CHANGED);        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);        intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);        mContext.sendBroadcast(intent, android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE);    }

3.UiccSlot.java  全路径:android\frameworks\opt\telephony\src\java\com\android\internal\telephony\uicc\UiccSlot.java

     仔细看UiccController初始化UiccSlot的时候就会发现最后调用的是 mUiccSlots[i].update(isActive ? mCis[iss.logicalSlotIndex] : null, iss);方法 update方法,看代码说话 !   在里面初始化了UiccCard

/**     * Update slot. The main trigger for this is a change in the ICC Card status.     * 更新slot。这种情况的主要触发因素是ICC卡状态的更改。     */    public void update(CommandsInterface ci, IccCardStatus ics, int phoneId) {        if (DBG) log("cardStatus update: " + ics.toString());        synchronized (mLock) {            CardState oldState = mCardState;            mCardState = ics.mCardState;            mIccId = ics.iccid;            mPhoneId = phoneId;            parseAtr(ics.atr);            mCi = ci;            RadioState radioState = mCi.getRadioState();            if (DBG) {                log("update: radioState=" + radioState + " mLastRadioState=" + mLastRadioState);            }            if (absentStateUpdateNeeded(oldState)) {                updateCardStateAbsent();                Log.v("UICCTest","absentStateUpdateNeeded(oldState)");            // Because mUiccCard may be updated in both IccCardStatus and IccSlotStatus, we need to            // create a new UiccCard instance in two scenarios:           // 由于mUiccCard可能在IccCardStatus和IccSlotStatus中都被更新,我们需要在两种情况下创建一个新的UiccCard实例:            //   1. mCardState is changing from ABSENT to non ABSENT.            //   2. The latest mCardState is not ABSENT, but there is no UiccCard instance.            } else if ((oldState == null || oldState == CardState.CARDSTATE_ABSENT                    || mUiccCard == null) && mCardState != CardState.CARDSTATE_ABSENT) {                // No notifications while radio is off or we just powering up                //根据radio的状态和卡的状态来判断有没有插拔SIM卡动作                if (radioState == RadioState.RADIO_ON && mLastRadioState == RadioState.RADIO_ON) {                    if (DBG) log("update: notify card added");                    sendMessage(obtainMessage(EVENT_CARD_ADDED, null));                }                Log.v("UICCTest","else If");                // card is present in the slot now; create new mUiccCard                if (mUiccCard != null) {                    loge("update: mUiccCard != null when card was present; disposing it now");                    mUiccCard.dispose();                }                if (!mIsEuicc) {                    Log.v("UICCTest","UiccCard()");                    mUiccCard = new UiccCard(mContext, mCi, ics, mPhoneId, mLock);                } else {                    Log.v("UICCTest","EuiccCard()");                    mUiccCard = new EuiccCard(mContext, mCi, ics, phoneId, mLock);                }            } else {                Log.v("UICCTest","mUiccCard.update");                if (mUiccCard != null) {                    mUiccCard.update(mContext, mCi, ics);                }            }            mLastRadioState = radioState;        }    }

4.UiccCard.java    全路径:android\frameworks\opt\telephony\src\java\com\android\internal\telephony\uicc\UiccCard.java

在UiccCard的构造方法中,最终还是调用了update()方法  里面初始化了UiccProfile

 public UiccCard(Context c, CommandsInterface ci, IccCardStatus ics, int phoneId, Object lock) {        if (DBG) log("Creating");        mCardState = ics.mCardState;        mPhoneId = phoneId;        mLock = lock;        update(c, ci, ics);    } public void update(Context c, CommandsInterface ci, IccCardStatus ics) {        synchronized (mLock) {            mCardState = ics.mCardState;            mContext = c;            mCi = ci;            mIccid = ics.iccid;            updateCardId();            if (mCardState != CardState.CARDSTATE_ABSENT) {                if (mUiccProfile == null) {                    mUiccProfile = TelephonyComponentFactory.getInstance().makeUiccProfile(                            mContext, mCi, ics, mPhoneId, this, mLock);                } else {                    mUiccProfile.update(mContext, mCi, ics);                }            } else {                throw new RuntimeException("Card state is absent when updating!");            }        }    }

5. UiccProfile.java  android\frameworks\opt\telephony\src\java\com\android\internal\telephony\uicc\UiccProfile.java

 /**     * Update the UiccProfile.     */    public void update(Context c, CommandsInterface ci, IccCardStatus ics) {        synchronized (mLock) {            mUniversalPinState = ics.mUniversalPinState;            mGsmUmtsSubscriptionAppIndex = ics.mGsmUmtsSubscriptionAppIndex;            mCdmaSubscriptionAppIndex = ics.mCdmaSubscriptionAppIndex;            mImsSubscriptionAppIndex = ics.mImsSubscriptionAppIndex;            mContext = c;            mCi = ci;            mTelephonyManager = (TelephonyManager) mContext.getSystemService(                    Context.TELEPHONY_SERVICE);            //update applications            if (DBG) log(ics.mApplications.length + " applications");            for (int i = 0; i < mUiccApplications.length; i++) {                if (mUiccApplications[i] == null) {                    //Create newly added Applications                    if (i < ics.mApplications.length) {                        mUiccApplications[i] = new UiccCardApplication(this,                                ics.mApplications[i], mContext, mCi);                    }                } else if (i >= ics.mApplications.length) {                    //Delete removed applications                    mUiccApplications[i].dispose();                    mUiccApplications[i] = null;                } else {                    //Update the rest                    mUiccApplications[i].update(ics.mApplications[i], mContext, mCi);                }            }            //创建CatService,用于读取STK的信息            createAndUpdateCatServiceLocked();            // Reload the carrier privilege rules if necessary.            log("Before privilege rules: " + mCarrierPrivilegeRules + " : " + ics.mCardState);            if (mCarrierPrivilegeRules == null && ics.mCardState == CardState.CARDSTATE_PRESENT) {                mCarrierPrivilegeRules = new UiccCarrierPrivilegeRules(this,                        mHandler.obtainMessage(EVENT_CARRIER_PRIVILEGES_LOADED));            } else if (mCarrierPrivilegeRules != null                    && ics.mCardState != CardState.CARDSTATE_PRESENT) {                mCarrierPrivilegeRules = null;            }            sanitizeApplicationIndexesLocked();            updateIccAvailability(true);        }    }

在UiccProfile.java的update方法中,实例化了UiccCardApplication对象,或者调UiccCardApplication的update()方法更新状态mCart记录着卡的状态,根据新旧mCartState就可以知道CARD_ADDE或者CARD_REMOVED

6.UiccCardApplication.java 全路径:android\frameworks\opt\telephony\src\java\com\android\internal\telephony\uicc\UiccCardApplication.java

最有用的就是mIccRecords = createIccRecords(as.app_type, mContext, mCi);//根据AppType创建对应的IccRecords 对象

创建了IccRecords对象里面开启一些注册

 public UiccCardApplication(UiccProfile uiccProfile,                        IccCardApplicationStatus as,                        Context c,                        CommandsInterface ci) {        if (DBG) log("Creating UiccApp: " + as);        mUiccProfile = uiccProfile;        mAppState = as.app_state;        mAppType = as.app_type;        mAuthContext = getAuthContext(mAppType);        mPersoSubState = as.perso_substate;        mAid = as.aid;        mAppLabel = as.app_label;        mPin1Replaced = (as.pin1_replaced != 0);        mPin1State = as.pin1;        mPin2State = as.pin2;        mIgnoreApp = false;        mContext = c;        mCi = ci;        //根据AppType实例化IccFileHandler        mIccFh = createIccFileHandler(as.app_type);        //根据AppType实例化IccRecords        mIccRecords = createIccRecords(as.app_type, mContext, mCi);//根据AppType创建对应的IccRecords 对象        if (mAppState == AppState.APPSTATE_READY) {            queryFdn();            //查询PIN1码的状态            queryPin1State();        }        //注册监听        mCi.registerForNotAvailable(mHandler, EVENT_RADIO_UNAVAILABLE, null);    } private IccRecords createIccRecords(AppType type, Context c, CommandsInterface ci) {        if (type == AppType.APPTYPE_USIM || type == AppType.APPTYPE_SIM) {            //实例化SIMRecords对象            return new SIMRecords(this, c, ci);        } else if (type == AppType.APPTYPE_RUIM || type == AppType.APPTYPE_CSIM){            return new RuimRecords(this, c, ci);        } else if (type == AppType.APPTYPE_ISIM) {            return new IsimUiccRecords(this, c, ci);        } else {            // Unknown app type (maybe detection is still in progress)            return null;        }    }

7.SIMRecords.java 全路径:android\frameworks\opt\telephony\src\java\com\android\internal\telephony\uicc\SIMRecords.java

对象实例化:
第一步是看 mParentApp.registerForReady(this, EVENT_APP_READY, null);注册监听,如果已ready然后进入SIMRecords里面的handlerMessage对应的case EVENT_APP_READY:里面调用了,onReady();方法

public SIMRecords(UiccCardApplication app, Context c, CommandsInterface ci) {        super(app, c, ci);        mAdnCache = new AdnRecordCache(mFh);        mVmConfig = new VoiceMailConstants();        mRecordsRequested = false;  // No load request is made till SIM ready        mLockedRecordsReqReason = LOCKED_RECORDS_REQ_REASON_NONE;        // recordsToLoad is set to 0 because no requests are made yet        mRecordsToLoad = 0;        mCi.setOnSmsOnSim(this, EVENT_SMS_ON_SIM, null);        //初始化成员变量        // Start off by setting empty state        resetRecords();        //注册监听,如果已ready,那么开始加载数据        mParentApp.registerForReady(this, EVENT_APP_READY, null);        mParentApp.registerForLocked(this, EVENT_APP_LOCKED, null);        mParentApp.registerForNetworkLocked(this, EVENT_APP_NETWORK_LOCKED, null);        if (DBG) log("SIMRecords X ctor this=" + this);    }   @Override    public void onReady() {        fetchSimRecords();    }

当执行到fetchSimRecords()方法时,才是开始加载EF文件信息
==============================EF相关文件介绍:===========================
SIM卡里的所有文件按树来组织:
主文件MF(Master File)——每一块SIM卡只有一个唯一的主文件, 其他所有文件都是它的子孙, 主文件只有文件头,里面存放着整个SIM卡的控制和管理信息
专用文件DF(Dedicated File)——也是只有一个文件头, 里面存放着整个目录的管理控制信息, 专用文件相当于一个目录的根.
基本文件EF(Elementary File)——既有文件头,也有文件体, 文件头存放该文件的位置和控制信息, 文件体存放真正的数据, 整个SIM卡中只有基本文件有文件体, 也只有基本文件才用来存放数据.。EF就是作手机通讯存储作用的文件。
=========================================================================

具体的读取SIM卡EF文件信息的过程是由IccFileHandler来实现的,根据EF文件的类型,调用不同的方法,loadEFTransparent()和laodEFLinearFixed()最终会调用RIL。java的 iccOForApp();

 

 

 

  protected void fetchSimRecords() {        mRecordsRequested = true;        if (DBG) log("fetchSimRecords " + mRecordsToLoad);        //读取IMSI        mCi.getIMSIForApp(mParentApp.getAid(), obtainMessage(EVENT_GET_IMSI_DONE));        mRecordsToLoad++;         //从EF_ICCID(0x2fe2)读取ICCID        mFh.loadEFTransparent(EF_ICCID, obtainMessage(EVENT_GET_ICCID_DONE));        //每开始load一条记录,mRecordsToLoad加1,等加载完一条记录后        //mRecordsToLoad就减1,当mRecordsToLoad等于0时说明已加载完所有数据了。        mRecordsToLoad++;        // FIXME should examine EF[MSISDN]'s capability configuration        // to determine which is the voice/data/fax line        new AdnRecordLoader(mFh).loadFromEF(EF_MSISDN, getExtFromEf(EF_MSISDN), 1,                    obtainMessage(EVENT_GET_MSISDN_DONE));        mRecordsToLoad++;        // Record number is subscriber profile //读取VoiceMail信息        mFh.loadEFLinearFixed(EF_MBI, 1, obtainMessage(EVENT_GET_MBI_DONE));        mRecordsToLoad++;        mFh.loadEFTransparent(EF_AD, obtainMessage(EVENT_GET_AD_DONE));        mRecordsToLoad++;        // Record number is subscriber profile 记录号是用户配置文件        mFh.loadEFLinearFixed(EF_MWIS, 1, obtainMessage(EVENT_GET_MWIS_DONE));        mRecordsToLoad++;        // Also load CPHS-style voice mail indicator, which stores        // the same info as EF[MWIS]. If both exist, both are updated        // but the EF[MWIS] data is preferred        // Please note this must be loaded after EF[MWIS]        mFh.loadEFTransparent(                EF_VOICE_MAIL_INDICATOR_CPHS,                obtainMessage(EVENT_GET_VOICE_MAIL_INDICATOR_CPHS_DONE));        mRecordsToLoad++;        // Same goes for Call Forward Status indicator: fetch both        // EF[CFIS] and CPHS-EF, with EF[CFIS] preferred.        loadCallForwardingRecords();        //从EF_SPN(0x6F46)、EF_SPN_CPHS(0x6f14)、EF_SPN_SHORT_CPHS(0x6f18)三个地址上读取SPN        getSpnFsm(true, null);        //从EF_SPDI(0x6fcd)读取SPDI        mFh.loadEFTransparent(EF_SPDI, obtainMessage(EVENT_GET_SPDI_DONE));        mRecordsToLoad++;        //从EF_PNN(0x6fc5)读取PNN        mFh.loadEFLinearFixed(EF_PNN, 1, obtainMessage(EVENT_GET_PNN_DONE));        mRecordsToLoad++;        mFh.loadEFTransparent(EF_SST, obtainMessage(EVENT_GET_SST_DONE));        mRecordsToLoad++;        mFh.loadEFTransparent(EF_INFO_CPHS, obtainMessage(EVENT_GET_INFO_CPHS_DONE));        mRecordsToLoad++;        mFh.loadEFTransparent(EF_CSP_CPHS,obtainMessage(EVENT_GET_CSP_CPHS_DONE));        mRecordsToLoad++;        mFh.loadEFTransparent(EF_GID1, obtainMessage(EVENT_GET_GID1_DONE));        mRecordsToLoad++;        mFh.loadEFTransparent(EF_GID2, obtainMessage(EVENT_GET_GID2_DONE));        mRecordsToLoad++;        mFh.loadEFTransparent(EF_PLMN_W_ACT, obtainMessage(EVENT_GET_PLMN_W_ACT_DONE));        mRecordsToLoad++;        mFh.loadEFTransparent(EF_OPLMN_W_ACT, obtainMessage(EVENT_GET_OPLMN_W_ACT_DONE));        mRecordsToLoad++;        mFh.loadEFTransparent(EF_HPLMN_W_ACT, obtainMessage(EVENT_GET_HPLMN_W_ACT_DONE));        mRecordsToLoad++;        mFh.loadEFTransparent(EF_EHPLMN, obtainMessage(EVENT_GET_EHPLMN_DONE));        mRecordsToLoad++;        mFh.loadEFTransparent(EF_FPLMN, obtainMessage(                    EVENT_GET_FPLMN_DONE, HANDLER_ACTION_NONE, -1));        mRecordsToLoad++;        loadEfLiAndEfPl();        mFh.getEFLinearRecordSize(EF_SMS, obtainMessage(EVENT_GET_SMS_RECORD_SIZE_DONE));        // XXX should seek instead of examining them all        if (false) { // XXX            mFh.loadEFLinearFixedAll(EF_SMS, obtainMessage(EVENT_GET_ALL_SMS_DONE));            mRecordsToLoad++;        }        //读取ICCID 、读取SPDI 、读取VoiceMail、读取SPN、读取PNN;        if (CRASH_RIL) {            String sms = "0107912160130310f20404d0110041007030208054832b0120"                         + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"                         + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"                         + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"                         + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"                         + "ffffffffffffffffffffffffffffff";            byte[] ba = IccUtils.hexStringToBytes(sms);            mFh.updateEFLinearFixed(EF_SMS, 1, ba, null,                            obtainMessage(EVENT_MARK_SMS_READ_DONE, 1));        }        if (DBG) log("fetchSimRecords " + mRecordsToLoad + " requested: " + mRecordsRequested);    }

8.IccFileHandler.java  全路径:android\frameworks\opt\telephony\src\java\com\android\internal\telephony\uicc\IccFileHandler.java

这个类是SIMRecords类中fetchSimRecords()方法里面的mFh对应的对象  ,该类属于Handler

 

   /**     * Load a SIM Transparent EF     *     * @param fileid EF id     * @param onLoaded     *     * ((AsyncResult)(onLoaded.obj)).result is the byte[]     *     */    public void loadEFTransparent(int fileid, Message onLoaded) {        Message response = obtainMessage(EVENT_GET_BINARY_SIZE_DONE,                        fileid, 0, onLoaded);        //先读取当前分区的长度lc.mRecordSize        mCi.iccIOForApp(COMMAND_GET_RESPONSE, fileid, getEFPath(fileid),                        0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, mAid, response);    }
 /**     * Load a record from a SIM Linear Fixed EF     * 具体的读取SIM卡EF文件信息的过程是由 IccFileHandler 来实现的     * @param fileid EF id     * @param path Path of the EF on the card     * @param recordNum 1-based (not 0-based) record number     * @param onLoaded     *     * ((AsyncResult)(onLoaded.obj)).result is the byte[]     *     */    public void loadEFLinearFixed(int fileid, String path, int recordNum, Message onLoaded) {        String efPath = (path == null) ? getEFPath(fileid) : path;        Message response                = obtainMessage(EVENT_GET_RECORD_SIZE_DONE,                        new LoadLinearFixedContext(fileid, recordNum, efPath, onLoaded));        //再根据lc.mRecordSize去读取具体内容。        mCi.iccIOForApp(COMMAND_GET_RESPONSE, fileid, efPath,                        0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, mAid, response);    }

 

 

9.SIMRecords.java 全路径:android\frameworks\opt\telephony\src\java\com\android\internal\telephony\uicc\SIMRecords.java

读ICCID,SPDI,VoiceMail,SPN,PNN

回到fetcheSimRecords()方法,每加载一项,mRecordsToload就会加1;等到某一项数据读取数据完毕,handleMessage()方法被执行,就会调onRecordLoaded()方法

       public void handleMessage(Message msg) {            .......            ......            .......            ...........         default:                    super.handleMessage(msg);   // IccRecords handles generic record load responses            }        } catch (RuntimeException exc) {            // I don't want these exceptions to be fatal            logw("Exception parsing SIM record", exc);        } finally {            // Count up record load responses even if they are fails            if (isRecordLoadResponse) {                onRecordLoaded();  //读取完毕后每次都会调用改方法            }        }
/**     *读取ICCID 、读取SPDI 、读取VoiceMail、读取SPN、读取PNN;     * 回到fetchSimRecords()方法,每加载一项,mRecordsToLoad就加1;     * 等到某一项读取数据完毕,handleMessage()方法被执行,就会调onRecordLoaded()方法     */    @Override    protected void onRecordLoaded() {        // One record loaded successfully or failed, In either case        // we need to update the recordsToLoad count        //每查询完一条记录,mRecordsToLoad减1        mRecordsToLoad -= 1;        if (DBG) log("onRecordLoaded " + mRecordsToLoad + " requested: " + mRecordsRequested);        //当mRecordsToLoad等于0,说明在fetchSimRecords()方法        //中启动加载的数据都已经加载完了。        //mRecordsToLoad的值会减1,直到mRecordsToLoad的值为0时,说明在fetchSimRecords()中启动加载的数据都已异步读取完成。就会进入onAllRecordsLoaded()方法。        if (getRecordsLoaded()) {            onAllRecordsLoaded();        } else if (getLockedRecordsLoaded() || getNetworkLockedRecordsLoaded()) {            onLockedAllRecordsLoaded();        } else if (mRecordsToLoad < 0) {            loge("recordsToLoad <0, programmer error suspected");            mRecordsToLoad = 0;        }    }
@Override    protected void onAllRecordsLoaded() {        if (DBG) log("record load complete");        setSimLanguageFromEF();        setVoiceCallForwardingFlagFromSimRecords();        // Some fields require more than one SIM record to set        //获取MCC + MNC 国际移动用户识别码        String operator = getOperatorNumeric();        Log.v("ImsiGetIMSIoperator","operator = "+operator);        if (!TextUtils.isEmpty(operator)) {            log("onAllRecordsLoaded set 'gsm.sim.operator.numeric' to operator='" +                    operator + "'");            mTelephonyManager.setSimOperatorNumericForPhone(                    mParentApp.getPhoneId(), operator);        } else {            log("onAllRecordsLoaded empty 'gsm.sim.operator.numeric' skipping");        }        String imsi = getIMSI();        Log.v("ImsiGetIMSIoperator","imsi = "+imsi);        if (!TextUtils.isEmpty(imsi) && imsi.length() >= 3) {            log("onAllRecordsLoaded set mcc imsi" + (VDBG ? ("=" + imsi) : ""));            mTelephonyManager.setSimCountryIsoForPhone(                    mParentApp.getPhoneId(), MccTable.countryCodeForMcc(                    Integer.parseInt(imsi.substring(0, 3))));        } else {            log("onAllRecordsLoaded empty imsi skipping setting mcc");        }        setVoiceMailByCountry(operator);        mLoaded.set(true);        //通知应用层        mRecordsLoadedRegistrants.notifyRegistrants(new AsyncResult(null, null, null));    }

通知应用层包括很多,在mRecordsLoadedRegistrantsj集合中全部通知一遍

通知项:有信号,电话,运营商等操作.....

更多相关文章

  1. Android(安卓)修改开机画面
  2. Android开发(1)——项目结构
  3. android常见错误之Nor…
  4. Android(安卓)WMS分析(一) WindowManager
  5. Error:(1, 0) Plugin with id 'android' not found.
  6. Android(安卓)studio 添加依赖库的方法
  7. Android关于PagerAdapter的使用方法的总结
  8. Android(安卓)判断当前的界面是否是桌面的方法
  9. Android(安卓)自定义camera

随机推荐

  1. Android(安卓)在程序界面上显示图片
  2. Android工具库
  3. 如何让Android横竖屏切换时不销毁当前act
  4. 【30篇突击 android】源码统计 十三
  5. 【Android】安卓中常用的图片加载方法
  6. Android(安卓)获取当前日期 时间
  7. Android(安卓)格式化内部存储
  8. Android获取设备状态栏status bar高度的
  9. android文件缓存,并SD卡创建目录未能解决
  10. android布局属性详解