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 frameworkPhoneFactory.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 initializationnew 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 checkswhether 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初始化PhoneFactoryif (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 packagesSmsApplication.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

   @Overridepublic void handleMessage (Message msg) {synchronized (mLock) {//1.首先从Message中取出PhoneIdInteger 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 0if (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_SUPPORTEDlogStr = "Unexpected error getting slot status: " + ar.exception;Rlog.e(LOG_TAG, logStr);sLocalLog.log(logStr);} else {// REQUEST_NOT_SUPPORTEDlogStr = "onGetSlotStatusDone: request not supported; marking "+ "mIsSlotStatusSupported to false";log(logStr);sLocalLog.log(logStr);mIsSlotStatusSupported = false;}return;}ArrayList<IccSlotStatus> status = (ArrayList<IccSlotStatus>) 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 slotif (!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 validif (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 mPhoneIdToSlotIdSet<Integer> 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 changedIntent 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 mUiccCardif (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 applicationsif (DBG) log(ics.mApplications.length + " applications");for (int i = 0; i < mUiccApplications.length; i++) {if (mUiccApplications[i] == null) {//Create newly added Applicationsif (i < ics.mApplications.length) {mUiccApplications[i] = new UiccCardApplication(this,ics.mApplications[i], mContext, mCi);}} else if (i >= ics.mApplications.length) {//Delete removed applicationsmUiccApplications[i].dispose();mUiccApplications[i] = null;} else {//Update the restmUiccApplications[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实例化IccFileHandlermIccFh = createIccFileHandler(as.app_type);//根据AppType实例化IccRecordsmIccRecords = 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 readymLockedRecordsReqReason = LOCKED_RECORDS_REQ_REASON_NONE;// recordsToLoad is set to 0 because no requests are made yetmRecordsToLoad = 0;mCi.setOnSmsOnSim(this, EVENT_SMS_ON_SIM, null);//初始化成员变量// Start off by setting empty stateresetRecords();//注册监听,如果已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);}@Overridepublic 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);//读取IMSImCi.getIMSIForApp(mParentApp.getAid(), obtainMessage(EVENT_GET_IMSI_DONE));mRecordsToLoad++;//从EF_ICCID(0x2fe2)读取ICCIDmFh.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 linenew 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)三个地址上读取SPNgetSpnFsm(true, null);//从EF_SPDI(0x6fcd)读取SPDImFh.loadEFTransparent(EF_SPDI, obtainMessage(EVENT_GET_SPDI_DONE));mRecordsToLoad++;//从EF_PNN(0x6fc5)读取PNNmFh.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 allif (false) { // XXXmFh.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.mRecordSizemCi.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 fatallogw("Exception parsing SIM record", exc);} finally {// Count up record load responses even if they are failsif (isRecordLoadResponse) {onRecordLoaded();  //读取完毕后每次都会调用改方法}}
/***读取ICCID 、读取SPDI 、读取VoiceMail、读取SPN、读取PNN;* 回到fetchSimRecords()方法,每加载一项,mRecordsToLoad就加1;* 等到某一项读取数据完毕,handleMessage()方法被执行,就会调onRecordLoaded()方法*/@Overrideprotected void onRecordLoaded() {// One record loaded successfully or failed, In either case// we need to update the recordsToLoad count//每查询完一条记录,mRecordsToLoad减1mRecordsToLoad -= 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;}}
@Overrideprotected 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集合中全部通知一遍

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

Android9.0 SIM卡初始化---更新数据相关推荐

  1. Android 9.0 SIM卡初始化流程

    转载:https://blog.csdn.net/linyongan/article/details/51406123 本文主要讲述Android 9.0 SIM卡初始化流程,这个过程也涉及到UICC ...

  2. android miui9.0改装条例,小米8青春版获得基于Android9.0定制的MIUI更新

    原标题:小米8青春版获得基于Android9.0定制的MIUI更新 集微网消息,在今年9月,小米发布了小米8青春版,它采用6.26英寸2280*1080分辨率的LCD材质屏幕,搭载高通骁龙660处理器 ...

  3. 华为android9.0升级,华为官方更新消息:这几款手机9月5日分批推送安卓9.0系统升级...

    原标题:华为官方更新消息:这几款手机9月5日分批推送安卓9.0系统升级 随着手机技术的不断发展,不仅手机更新换代加快,就连手机系统也在快速更新,可能很多花粉刚刚升级了基于Android8.0的EMUI ...

  4. 解决Android 6.0 Sim卡 iccid获取不完整问题

    diff --git a/android/frameworks/opt/telephony/src/java/com/android/internal/telephony/uicc/IccUtils. ...

  5. Android 7.0 高通平台-telephony-机器无Sim卡情况下,获取SIM卡状态方法getSimState偶现为6,而不是1

    TelephonyManager.java -------->getSimState接口 /** * Returns a constant indicating the state of the ...

  6. SIM(USIM)卡中的数据和2G/3G网络的鉴权

    标签: sim usim卡 数据 2g/3g 网络 鉴权 杂谈 分类: 基础知识     通常SIM(USIM)卡内的数据包括IMSI.ICCID.Ki(2G).Key(3G).OPC(3G).PIN ...

  7. android复制sim卡上的短信到手机,将数据从SIM卡轻松传输到新手机的最佳方法

    购买新手机后,您需要将旧手机上的所有内容转移到新手机,包括SIM卡中的数据. 有时,当您将SIM卡中的文件切换到新智能手机时,可能会丢失该文件. 因此,您必须手动逐个添加联系人. 有没有有效的方法将S ...

  8. 苹果在更新了ios13.4.1后,sim卡更新后,联通4G变得非常非常的慢

    问题描述: 苹果在更新了ios13.4.1后,sim卡程序更新后,联通4G变得非常非常的慢. 解决方法: 电脑上使用爱思助手,连接手机,选择更多工具, 选择ipcc, 然后在更多版本里面下载你所用io ...

  9. 手机MODEM 开发(33)---SIM卡基础知识

    SIM卡基础知识 什么是SIM卡 SIM卡是(Subscriber Identification Module 客户识别模块)的缩写,也称为用户身份识别卡,移动无线终端必须装上此卡方能使用.SIM卡是 ...

最新文章

  1. Vue多个单文件组件使用
  2. 为什么(#39;b#39;+#39;a#39;+ +#39;a#39;+#39;a#39;)。toLowerCase()#39;banana#39;的结果?
  3. 传文件进云服务器,传文件进云服务器
  4. css箭头超链接,css超链接
  5. Android程序开发中关于设置全屏无效问题
  6. asp.net小技巧:摆脱路径的困扰(二)
  7. 配置Apache虚拟机
  8. JSF,Servlet和JSP有什么区别?
  9. Q93:PLY文件对应图形法向量反向问题——以bunny10K为例
  10. HQChart 股市图表
  11. 上传文件与下载文件不一致的怪事
  12. 2019开放大学计算机应用基础,国家开放大学2019年电大计算机应用基础考试试题一试卷(国家开放大学).doc...
  13. 柴静《看见》读书笔记
  14. 数据分析神经网络模型图,神经网络模型数据处理
  15. HTML荧光文字动态效果,利用HTML5实现文字放射发光动画特效
  16. phython在file同时写入两个_Flink集成数据湖之实时数据写入iceberg
  17. 浅谈Nginx转发匹配规则
  18. 水滴IP告诉你:代理ip的功能是什么?能否隐藏自身的真实ip?
  19. [小程序] 微信开发者工具下载与安装 WXMLfor if 模板页面引用 tabBar
  20. JAVA MemCache 史无前例的详细讲解【转】

热门文章

  1. TONG LI DIAN ZI - 你要害人害到什么时候
  2. 服务器删除登录日志文件,CentOS查看登录日志及其它安全日志 清空删除系统日志的方法...
  3. 2017年计算机应用基础,计算机应用基础考试试题及答案
  4. 平安夜,还做那只「花好夜猿」吗?
  5. 缓存方案coolKie、localStorage、sessionStorage介绍和简单的使用
  6. 发现【Stable-Diffusion WEBUI】的插件:不健康内容过滤器
  7. SmartDraw 2010 破解
  8. 城域网条件下网络信息安全策略探讨
  9. 关于二级消防工程师考务的通知
  10. 换新网络后,群辉NAS如何手动更换为新静态IP