资讯专栏INFORMATION COLUMN

开机SIM卡加载

BicycleWarrior / 4075人阅读

摘要:以为例不同卡主要区别就是文件结构不同,因此各自实现方法接记录卡的文件信息,具体的读取卡文件信息的过程是由来实现的,以为例。构造方法在初始化时,卡状态是状态并且会广播出去然后在中设置模式。

1.UiccController 是处理SIM卡的核心类,其他关键类都是通过他产生

* Following is class diagram for uicc classes:
 *
 *                       UiccController
 *                            #
 *                            |
 *                        UiccCard
 *                          #   #
 *                          |   ------------------
 *                    UiccCardApplication    CatService
 *                      #            #
 *                      |            |
 *                 IccRecords    IccFileHandler
 *                 ^ ^ ^           ^ ^ ^ ^ ^
 *    SIMRecords---- | |           | | | | ---SIMFileHandler
 *    RuimRecords----- |           | | | ----RuimFileHandler
 *    IsimUiccRecords---           | | -----UsimFileHandler
 *                                 | ------CsimFileHandler
 *                                 ----IsimFileHandler
 *
 * Legend: # stands for Composition
 *         ^ stands for Generalization
 *
 * See also {@link com.android.internal.telephony.IccCard}
 * and {@link com.android.internal.telephony.uicc.IccCardProxy}

2 分析UiccController是如何初始化的
2.1 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.2 在PhoneGlobals.java的onCreate()中创建Phone

if (mCM == null) {
        // Initialize the telephony framework
        PhoneFactory.makeDefaultPhones(this);

2.3 PhoneFactory类makeDefaultPhone方法中初始化UiccController,UiccController是UICC的控制接口,与RIL建立监听关系,当SIM卡状态变化时,RIL通知UiccController.

sCommandsInterfaces = new RIL[numPhones];
sCommandsInterfaces[i] = new RIL(context, networkModes[i],cdmaSubscription, i);
    sUiccController = UiccController.make(context, sCommandsInterfaces);
        if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
                                phone = new GsmCdmaPhone(context,
                                        sCommandsInterfaces[i], sPhoneNotifier, i,
                                        PhoneConstants.PHONE_TYPE_GSM,
                                        TelephonyComponentFactory.getInstance());
                            } else if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
                                phone = new GsmCdmaPhone(context,
                                        sCommandsInterfaces[i], sPhoneNotifier, i,
                                        PhoneConstants.PHONE_TYPE_CDMA_LTE,
                                        TelephonyComponentFactory.getInstance());
                            }

2.4 看看UiccController的make方法中都对RIL注册了哪些监听

public static UiccController make(Context c, CommandsInterface[] ci) {
        synchronized (mLock) {
            if (mInstance != null) {
                throw new RuntimeException("MSimUiccController.make() should only be called once");
            }
            mInstance = new UiccController(c, ci);
            return (UiccController)mInstance;
        }
    }

private UiccController(Context c, CommandsInterface []ci) {

    if (DBG) log("Creating UiccController");
    mContext = c;
    mCis = ci;
    for (int i = 0; i < mCis.length; i++) {
        Integer index = new Integer(i);
        mCis[i].registerForIccStatusChanged(this, EVENT_ICC_STATUS_CHANGED, index);
        // TODO remove this once modem correctly notifies the unsols
        // If the device has been decrypted or FBE is supported, read SIM when radio state is
        // available.
        // Else wait for radio to be on. This is needed for the scenario when SIM is locked --
        // to avoid overlap of CryptKeeper and SIM unlock screen.
        if (DECRYPT_STATE.equals(SystemProperties.get("vold.decrypt")) ||
                StorageManager.isFileEncryptedNativeOrEmulated()) {
            mCis[i].registerForAvailable(this, EVENT_ICC_STATUS_CHANGED, index);
        } else {
            mCis[i].registerForOn(this, EVENT_ICC_STATUS_CHANGED, index);
        }
        mCis[i].registerForNotAvailable(this, EVENT_RADIO_UNAVAILABLE, index);
        mCis[i].registerForIccRefresh(this, EVENT_SIM_REFRESH, index);
    }
}

监听了三个事件:EVENT_ICC_STATUS_CHANGED/EVENT_RADIO_UNAVAILABLE/EVENT_SIM_REFRESH
index对应phoneId

registerForIccStatusChanged方法是CommandsInterface接口中定义
抽象类BaseCommands中实现
@Override
    public void registerForIccStatusChanged(Handler h, int what, Object obj) {
        Registrant r = new Registrant (h, what, obj);
        mIccStatusChangedRegistrants.add(r);
        }
mIccStatusChangedRegistrants是在RIL中发出通知
private void processUnsolicited (Parcel p, int type) {
    ....
    case RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED:
                if (RILJ_LOGD) unsljLog(response);

                if (mIccStatusChangedRegistrants != null) {
                    mIccStatusChangedRegistrants.notifyRegistrants();
                }
                break;

2.5 UiccController handleMessage方法中处理事件EVENT_ICC_STATUS_CHANGED,请求RIL getIccCardStatus()方法发送RIL_REQUEST_GET_SIM_STATUS消息给modem查询SIM卡状态,通过onGetIccCardStatusDone处理

@Override
    public void handleMessage (Message msg) {
        synchronized (mLock) {
            Integer index = getCiIndex(msg);

            if (index < 0 || index >= mCis.length) {
                Rlog.e(LOG_TAG, "Invalid index : " + index + " received with event " + msg.what);
                return;
            }

            AsyncResult ar = (AsyncResult)msg.obj;
            switch (msg.what) {
                case EVENT_ICC_STATUS_CHANGED:
                    if (DBG) log("Received EVENT_ICC_STATUS_CHANGED, calling getIccCardStatus");
                    mCis[index].getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE, index));
                    break;
                case EVENT_GET_ICC_STATUS_DONE:
                    if (DBG) log("Received EVENT_GET_ICC_STATUS_DONE");
                    onGetIccCardStatusDone(ar, index);
                    break;
                case EVENT_RADIO_UNAVAILABLE:
                    if (DBG) log("EVENT_RADIO_UNAVAILABLE, dispose card");
                    if (mUiccCards[index] != null) {
                        mUiccCards[index].dispose();
                    }
                    mUiccCards[index] = null;
                    mIccChangedRegistrants.notifyRegistrants(new AsyncResult(null, index, null));
                    break;
                case EVENT_SIM_REFRESH:
                    if (DBG) log("Received EVENT_SIM_REFRESH");
                    onSimRefresh(ar, index);
                    break;
                default:
                    Rlog.e(LOG_TAG, " Unknown Event " + msg.what);
            }
        }
    }

RIL.java
@Override
    public void
    getIccCardStatus(Message result) {
        //Note: This RIL request has not been renamed to ICC,
        //       but this request is also valid for SIM and RUIM
        RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_SIM_STATUS, result);

        if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));

        send(rr);
    }

2.6 在onGetIccCardStatusDone方法中,依据IccCardStatus创建UiccCard,每个UiccCard对应一张SIM卡,方法的最后通知注册UiccController监听,UiccCard的构造方法也是调用update方法
private synchronized void onGetIccCardStatusDone(AsyncResult ar, Integer index) {

    if (ar.exception != null) {
        Rlog.e(LOG_TAG,"Error getting ICC status. "
                + "RIL_REQUEST_GET_ICC_STATUS should "
                + "never return an error", ar.exception);
        return;
    }
    if (!isValidCardIndex(index)) {
        Rlog.e(LOG_TAG,"onGetIccCardStatusDone: invalid index : " + index);
        return;
    }

    IccCardStatus status = (IccCardStatus)ar.result;

    if (mUiccCards[index] == null) {
        //Create new card
        mUiccCards[index] = new UiccCard(mContext, mCis[index], status, index);
    } else {
        //Update already existing card
        mUiccCards[index].update(mContext, mCis[index] , status);
    }

    if (DBG) log("Notifying IccChangedRegistrants");
    mIccChangedRegistrants.notifyRegistrants(new AsyncResult(null, index, null));

}  

UiccController总结:
3.UiccCard
3.1 UiccCard构造方法

public UiccCard(Context c, CommandsInterface ci, IccCardStatus ics, int phoneId) {
        mCardState = ics.mCardState;
        mPhoneId = phoneId;
        update(c, ci, ics);
    }

public void update(Context c, CommandsInterface ci, IccCardStatus ics) {
        synchronized (mLock) {
            CardState oldState = mCardState;
            mCardState = ics.mCardState;
            mUniversalPinState = ics.mUniversalPinState;
            mGsmUmtsSubscriptionAppIndex = ics.mGsmUmtsSubscriptionAppIndex;
            mCdmaSubscriptionAppIndex = ics.mCdmaSubscriptionAppIndex;
            mImsSubscriptionAppIndex = ics.mImsSubscriptionAppIndex;
            mContext = c;
            mCi = ci;

            //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);
                }
            }

            createAndUpdateCatService();

            // Reload the carrier privilege rules if necessary.
            log("Before privilege rules: " + mCarrierPrivilegeRules + " : " + mCardState);
            if (mCarrierPrivilegeRules == null && mCardState == CardState.CARDSTATE_PRESENT) {
                mCarrierPrivilegeRules = new UiccCarrierPrivilegeRules(this,
                        mHandler.obtainMessage(EVENT_CARRIER_PRIVILIGES_LOADED));
            } else if (mCarrierPrivilegeRules != null && mCardState != CardState.CARDSTATE_PRESENT) {
                mCarrierPrivilegeRules = null;
            }

            sanitizeApplicationIndexes();

            RadioState radioState = mCi.getRadioState();
            if (DBG) log("update: radioState=" + radioState + " mLastRadioState="
                    + mLastRadioState);
            // No notifications while radio is off or we just powering up
            if (radioState == RadioState.RADIO_ON && mLastRadioState == RadioState.RADIO_ON) {
            //根据mCardState 和oldState 判断是ADD还是REMOVE card
                if (oldState != CardState.CARDSTATE_ABSENT &&
                        mCardState == CardState.CARDSTATE_ABSENT) {
                    if (DBG) log("update: notify card removed");
                    mAbsentRegistrants.notifyRegistrants();
                    mHandler.sendMessage(mHandler.obtainMessage(EVENT_CARD_REMOVED, null));
                } else if (oldState == CardState.CARDSTATE_ABSENT &&
                        mCardState != CardState.CARDSTATE_ABSENT) {
                    if (DBG) log("update: notify card added");
                    mHandler.sendMessage(mHandler.obtainMessage(EVENT_CARD_ADDED, null));
                }
            }
            mLastRadioState = radioState;
        }
    } 

在构造方法中调用update方法,在update中创建或者更新UiccCardApplication,
根据mCardState 和oldState 判断是ADD还是REMOVE card,当SIM卡拔出时,通知IccCardProxy, 以及promptForRestart。

createAndUpdateCatService();建CatService,用于读取STK的信息

protected void createAndUpdateCatService() {
        if (mUiccApplications.length > 0 && mUiccApplications[0] != null) {
            // Initialize or Reinitialize CatService
            if (mCatService == null) {
                mCatService = CatService.getInstance(mCi, mContext, this, mPhoneId);
            } else {
                ((CatService)mCatService).update(mCi, mContext, this);
            }
        } else {
            if (mCatService != null) {
                mCatService.dispose();
            }
            mCatService = null;
        }
    }

UiccCard主要就是创建UiccCardApplication和CatService,以及通知SIM Card ADD和REMOVE事件

4.UiccCardApplication
主要方法:

public void registerForReady(Handler h, int what, Object obj) {}  
public void registerForLocked(Handler h, int what, Object obj) {}  
public void registerForNetworkLocked(Handler h, int what, Object obj) {}  
public AppState getState() {}  
public AppType getType() {}  
public PersoSubState getPersoSubState() {}  
public String getAid() {}  
public PinState getPin1State() {}  
public IccFileHandler getIccFileHandler() {}  
public IccRecords getIccRecords() {}  
public void supplyPin (String pin, Message onComplete) {}  
public void supplyPuk (String puk, String newPin, Message onComplete) {}  
public void supplyPin2 (String pin2, Message onComplete) {}  
public void supplyPuk2 (String puk2, String newPin2, Message onComplete) {}  
public void supplyNetworkDepersonalization (String pin, Message onComplete) {}  
public boolean getIccLockEnabled() {}  
public boolean getIccFdnEnabled() {}  
public void setIccLockEnabled (boolean enabled, String password, Message onComplete) {}  
public void setIccFdnEnabled (boolean enabled, String password, Message onComplete) {}  
public void changeIccLockPassword(String oldPassword, String newPassword, Message onComplete) {}  
public void changeIccFdnPassword(String oldPassword, String newPassword, Message onComplete) {} 

UiccCardApplication的主要功能:创建对象IccFileHandler、IccRecords,并提供获取对象的接口;FDN/PIN/PUK设置和查询接口(通过RIL实现);查询UiccCardApplication状态信息(mAppState、mAppType)

public UiccCardApplication(UiccCard uiccCard,
                        IccCardApplicationStatus as,
                        Context c,
                        CommandsInterface ci) {
        if (DBG) log("Creating UiccApp: " + as);
        mUiccCard = uiccCard;
        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;

        mContext = c;
        mCi = ci;

        mIccFh = createIccFileHandler(as.app_type);
        mIccRecords = createIccRecords(as.app_type, mContext, mCi);
        if (mAppState == AppState.APPSTATE_READY) {
            queryFdn();
            queryPin1State();
        }
        mCi.registerForNotAvailable(mHandler, EVENT_RADIO_UNAVAILABLE, null);
    }

创建IccFileHandler:SIMFileHandler/RuimFileHandler/UsimFileHandler/CsimFileHandler/IsimFileHandler
创建IccRecords:SIMRecords/RuimRecords/IsimUiccRecords
查询Fdn号码/查询Pin码状态
4.1 UiccCardApplication的更新
SIM卡或者Radio状态改变时,ril通过UiccController更新UiccCard,由UiccCard更新UiccCardApplication调用update()

public void update (IccCardApplicationStatus as, Context c, CommandsInterface ci) {
        synchronized (mLock) {
            if (mDestroyed) {
                loge("Application updated after destroyed! Fix me!");
                return;
            }

            if (DBG) log(mAppType + " update. New " + as);
            //变量更新
            mContext = c;
            mCi = ci;
            AppType oldAppType = mAppType;
            AppState oldAppState = mAppState;
            PersoSubState oldPersoSubState = mPersoSubState;
            mAppType = as.app_type;
            mAuthContext = getAuthContext(mAppType);
            mAppState = as.app_state;
            mPersoSubState = as.perso_substate;
            mAid = as.aid;
            mAppLabel = as.app_label;
            mPin1Replaced = (as.pin1_replaced != 0);
            mPin1State = as.pin1;
            mPin2State = as.pin2;
           //更新IccRecords和IccFileHandler 
            if (mAppType != oldAppType) {
                if (mIccFh != null) { mIccFh.dispose();}
                if (mIccRecords != null) { mIccRecords.dispose();}
                mIccFh = createIccFileHandler(as.app_type);
                mIccRecords = createIccRecords(as.app_type, c, ci);
            }

            if (mPersoSubState != oldPersoSubState &&
                    mPersoSubState == PersoSubState.PERSOSUBSTATE_SIM_NETWORK) {
                notifyNetworkLockedRegistrantsIfNeeded(null);
            }

            if (mAppState != oldAppState) {
                if (DBG) log(oldAppType + " changed state: " + oldAppState + " -> " + mAppState);
                // If the app state turns to APPSTATE_READY, then query FDN status,
                //as it might have failed in earlier attempt.
                if (mAppState == AppState.APPSTATE_READY) {
                    queryFdn();
                    queryPin1State();
                }
                notifyPinLockedRegistrantsIfNeeded(null);
                notifyReadyRegistrantsIfNeeded(null);
            }
        }
    }

4.2

// 根据modem返回的不同卡类型,创建不同 IccRecords 对象  
  private IccRecords createIccRecords(AppType type, Context c, CommandsInterface ci) {  
      if (type == AppType.APPTYPE_USIM || type == AppType.APPTYPE_SIM) {  
          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;  
      }  
  }  
 // 根据modem返回的不同卡类型,创建不同 IccFileHandler 对象  
  private IccFileHandler createIccFileHandler(AppType type) {  
      switch (type) {  
          case APPTYPE_SIM:  
              return new SIMFileHandler(this, mAid, mCi);  
          case APPTYPE_RUIM:  
              return new RuimFileHandler(this, mAid, mCi);  
          case APPTYPE_USIM:  
              return new UsimFileHandler(this, mAid, mCi);  
          case APPTYPE_CSIM:  
              return new CsimFileHandler(this, mAid, mCi);  
          case APPTYPE_ISIM:  
              return new IsimFileHandler(this, mAid, mCi);  
          default:  
              return null;  
      }  
  }

5.CatService(接3)

6.IccFileHandler(接4)


从这些方法可以看出,IccFileHandler的主要作用就是提供SIM卡文件系统的读写操作,当调用这些方法时,需要传递要读写的文件系统地址,以及读写完毕后的回调函数,IccFileHandler会在读取完数据之后通知到调用者,并把返回值传递过去。

6.1 以UsimFileHandler为例

protected String getEFPath(int efid) {
        // TODO(): DF_GSM can be 7F20 or 7F21 to handle backward compatibility.
        // Implement this after discussion with OEMs.
        switch(efid) {
        case EF_SMS:
            return MF_SIM + DF_TELECOM;

        case EF_EXT6:
        case EF_MWIS:
        case EF_MBI:
        case EF_SPN:
        case EF_AD:
        case EF_MBDN:
        case EF_PNN:
        case EF_SPDI:
        case EF_SST:
        case EF_CFIS:
        case EF_GID1:
        case EF_GID2:
        case EF_MAILBOX_CPHS:
        case EF_VOICE_MAIL_INDICATOR_CPHS:
        case EF_CFF_CPHS:
        case EF_SPN_CPHS:
        case EF_SPN_SHORT_CPHS:
        case EF_INFO_CPHS:
        case EF_CSP_CPHS:
            return MF_SIM + DF_GSM;
        }
        String path = getCommonIccEFPath(efid);
        if (path == null) {
            Rlog.e(LOG_TAG, "Error: EF Path being returned in null");
        }
        return path;
    }

不同SIM卡主要区别就是文件结构不同,因此各自实现getEFPath方法
6.2
6.3

7.IccRecords(接4)
IccRecords 记录SIM卡的EF文件信息,具体的读取SIM卡EF文件信息的过程是由 IccFileHandler 来实现的,以 SIMRecords 为例。
7.1

主要方法:

父类的方法

// * Constructor

    public IccRecords(UiccCardApplication app, Context c, CommandsInterface ci) {
        mContext = c;
        mCi = ci;
        mFh = app.getIccFileHandler();
        mParentApp = app;
        mTelephonyManager = (TelephonyManager) mContext.getSystemService(
                Context.TELEPHONY_SERVICE);
    }
    
// ***** Constructor

    public SIMRecords(UiccCardApplication app, Context c, CommandsInterface ci) {
        super(app, c, ci);

        mAdnCache = new AdnRecordCache(mFh);

        mVmConfig = new VoiceMailConstants();
        mSpnOverride = new SpnOverride();

        mRecordsRequested = false;  // No load request is made till SIM ready

        // recordsToLoad is set to 0 because no requests are made yet
        mRecordsToLoad = 0;

        mCi.setOnSmsOnSim(this, EVENT_SMS_ON_SIM, null);
        mCi.registerForIccRefresh(this, EVENT_SIM_REFRESH, null);

        // Start off by setting empty state
        resetRecords();
        mParentApp.registerForReady(this, EVENT_APP_READY, null);
        mParentApp.registerForLocked(this, EVENT_APP_LOCKED, null);
        if (DBG) log("SIMRecords X ctor this=" + this);

        IntentFilter intentfilter = new IntentFilter();
        intentfilter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
        c.registerReceiver(mReceiver, intentfilter);
    }

以上的创建过程完成了两个重要任务:
创建Adn和VoiceMail缓存,这里的Adn缓存用于SIM卡联系人的增、删、改、查等功能;
监听UiccCardApplication的Ready状态;

@Override
    public void onReady() {
        fetchSimRecords();
    }

7.2 SIMRecords更新

protected void fetchSimRecords() {
        mRecordsRequested = true;

        if (DBG) log("fetchSimRecords " + mRecordsToLoad);

        mCi.getIMSIForApp(mParentApp.getAid(), obtainMessage(EVENT_GET_IMSI_DONE));
        mRecordsToLoad++;

        mFh.loadEFTransparent(EF_ICCID, obtainMessage(EVENT_GET_ICCID_DONE));
        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
        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();

        getSpnFsm(true, null);

        mFh.loadEFTransparent(EF_SPDI, obtainMessage(EVENT_GET_SPDI_DONE));
        mRecordsToLoad++;

        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));

        mFh.loadEFTransparent(EF_OPLMN_W_ACT, obtainMessage(EVENT_GET_OPLMN_W_ACT_DONE));

        mFh.loadEFTransparent(EF_HPLMN_W_ACT, obtainMessage(EVENT_GET_HPLMN_W_ACT_DONE));

        mFh.loadEFTransparent(EF_EHPLMN, obtainMessage(EVENT_GET_EHPLMN_DONE));

        mFh.loadEFTransparent(EF_FPLMN, obtainMessage(EVENT_GET_FPLMN_DONE));
        mRecordsToLoad++;

        loadEfLiAndEfPl();

        // XXX should seek instead of examining them all
        if (false) { // XXX
            mFh.loadEFLinearFixedAll(EF_SMS, obtainMessage(EVENT_GET_ALL_SMS_DONE));
            mRecordsToLoad++;
        }

        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);
    }

从log中可以看到更新流程:

    1572:09-12 15:33:37.899  2237  2237 D UiccCardApplication: Notifying 1 registrant: READY
    1588:09-12 15:33:37.956  2237  2237 D SIMRecords: [SIMRecords] fetchSimRecords 0
    查询IMSI:
    1589:09-12 15:33:37.957  2237  2237 D RILJ    : [3749]> getIMSI: GET_IMSI aid: a0000000871002ff86ffff89ffffffff [SUB0]
    查询ICCID:
    1590:09-12 15:33:37.962  2237  2237 D RILJ    : [3750]> iccIO: SIM_IO 0xc0 0x2fe2  path: 3F00,0,0,15 aid: a0000000871002ff86ffff89ffffffff [SUB0]
    查询电话号码:
    1593:09-12 15:33:37.969  2237  2237 D RILJ    : [3751]> iccIO: SIM_IO 0xc0 0x6f40  path: 3F007FFF,0,0,15 aid: a0000000871002ff86ffff89ffffffff [SUB0]
    查询EF_MBI 语音信箱号码:
    1594:09-12 15:33:37.971  2237  2237 D RILJ    : [3752]> iccIO: SIM_IO 0xc0 0x6fc9  path: 3F007FFF,0,0,15 aid: a0000000871002ff86ffff89ffffffff [SUB0]
    返回IMSI:
    1597:09-12 15:33:37.971  2237  2299 D RILJ    : [3749]< GET_IMSI  [SUB0]
    查询EF_AD:
    1598:09-12 15:33:37.975  2237  2237 D RILJ    : [3753]> iccIO: SIM_IO 0xc0 0x6fad  path: 3F007FFF,0,0,15 aid: a0000000871002ff86ffff89ffffffff [SUB0]
    查询EF_MWIS:
    1602:09-12 15:33:37.978  2237  2237 D RILJ    : [3754]> iccIO: SIM_IO 0xc0 0x6fca  path: 3F007FFF,0,0,15 aid: a0000000871002ff86ffff89ffffffff [SUB0]
    查询EF_VOICE_MAIL_INDICATOR_CPHS:
    1603:09-12 15:33:37.979  2237  2237 D RILJ    : [3755]> iccIO: SIM_IO 0xc0 0x6f11  path: 3F007FFF,0,0,15 aid: a0000000871002ff86ffff89ffffffff [SUB0]
    查询call forwarding  EF_CFIS:
    1604:09-12 15:33:37.984  2237  2237 D RILJ    : [3756]> iccIO: SIM_IO 0xc0 0x6fcb  path: 3F007FFF,0,0,15 aid: a0000000871002ff86ffff89ffffffff [SUB0]
    查询EF_CFF_CPHS:
    1605:09-12 15:33:37.989  2237  2237 D RILJ    : [3757]> iccIO: SIM_IO 0xc0 0x6f13  path: 3F007FFF,0,0,15 aid: a0000000871002ff86ffff89ffffffff [SUB0]
    查询EF_SPN:
    1606:09-12 15:33:37.991  2237  2237 D RILJ    : [3758]> iccIO: SIM_IO 0xc0 0x6f46  path: 3F007FFF,0,0,15 aid: a0000000871002ff86ffff89ffffffff [SUB0]
    查询EF_SPDI:
    1608:09-12 15:33:37.995  2237  2237 D RILJ    : [3759]> iccIO: SIM_IO 0xc0 0x6fcd  path: 3F007FFF,0,0,15 aid: a0000000871002ff86ffff89ffffffff [SUB0]
    查询EF_PNN:
    1609:09-12 15:33:37.997  2237  2237 D RILJ    : [3760]> iccIO: SIM_IO 0xc0 0x6fc5  path: 3F007FFF,0,0,15 aid: a0000000871002ff86ffff89ffffffff [SUB0]
    其他查询:
    1610:09-12 15:33:37.999  2237  2237 D RILJ    : [3761]> iccIO: SIM_IO 0xc0 0x6f38  path: 3F007FFF,0,0,15 aid: a0000000871002ff86ffff89ffffffff [SUB0]
1611:09-12 15:33:38.001  2237  2237 D RILJ    : [3762]> iccIO: SIM_IO 0xc0 0x6f16  path: 3F007FFF,0,0,15 aid: a0000000871002ff86ffff89ffffffff [SUB0]
1612:09-12 15:33:38.002  2237  2299 D RILJ    : [3751]< SIM_IO IccIoResult sw1:0x90 sw2:0x0 [SUB0]
1613:09-12 15:33:38.003  2237  2237 D RILJ    : [3763]> iccIO: SIM_IO 0xc0 0x6f15  path: 3F007FFF,0,0,15 aid: a0000000871002ff86ffff89ffffffff [SUB0]
1614:09-12 15:33:38.005  2237  2237 D RILJ    : [3764]> iccIO: SIM_IO 0xc0 0x6f3e  path: 3F007FFF,0,0,15 aid: a0000000871002ff86ffff89ffffffff [SUB0]
1615:09-12 15:33:38.010  2237  2237 D RILJ    : [3765]> iccIO: SIM_IO 0xc0 0x6f3f  path: 3F007FFF,0,0,15 aid: a0000000871002ff86ffff89ffffffff [SUB0]
1616:09-12 15:33:38.024  2237  2299 D RILJ    : [3753]< SIM_IO IccIoResult sw1:0x90 sw2:0x0 [SUB0]
1633:09-12 15:33:38.206  2237  2237 D RILJ    : [3766]> iccIO: SIM_IO 0xc0 0x6f60  path: 3F007FFF,0,0,15 aid: a0000000871002ff86ffff89ffffffff [SUB0]
1634:09-12 15:33:38.213  2237  2237 D RILJ    : [3767]> iccIO: SIM_IO 0xc0 0x6f61  path: 3F007FFF,0,0,15 aid: a0000000871002ff86ffff89ffffffff [SUB0]
1636:09-12 15:33:38.231  2237  2237 D RILJ    : [3768]> iccIO: SIM_IO 0xc0 0x6f62  path: 3F007FFF,0,0,15 aid: a0000000871002ff86ffff89ffffffff [SUB0]
1638:09-12 15:33:38.235  2237  2237 D RILJ    : [3769]> iccIO: SIM_IO 0xc0 0x6fd9  path: 3F007FFF,0,0,15 aid: a0000000871002ff86ffff89ffffffff [SUB0]
1639:09-12 15:33:38.237  2237  2237 D RILJ    : [3770]> iccIO: SIM_IO 0xc0 0x6f7b  path: 3F007FFF,0,0,15 aid: a0000000871002ff86ffff89ffffffff [SUB0]
1641:09-12 15:33:38.241  2237  2299 D RILJ    : [3764]< SIM_IO IccIoResult sw1:0x90 sw2:0x0 [SUB0]
1642:09-12 15:33:38.241  2237  2237 D RILJ    : [3771]> iccIO: SIM_IO 0xc0 0x6f05  path: 3F007FFF,0,0,15 aid: a0000000871002ff86ffff89ffffffff [SUB0]
1644:09-12 15:33:38.247  2237  2237 D RILJ    : [3772]> iccIO: SIM_IO 0xc0 0x2f05  path: 3F00,0,0,15 aid: a0000000871002ff86ffff89ffffffff [SUB0]
1646:09-12 15:33:38.248  2237  2237 D RILJ    : [3773]> iccIO: SIM_IO 0xc0 0x6f3c  path: 3F007FFF,0,0,15 aid: a0000000871002ff86ffff89ffffffff [SUB0]
1648:09-12 15:33:38.250  2237  2237 D SIMRecords: [SIMRecords] fetchSimRecords 20 requested: true

在ICCCardProxy中注册IccRecords事件监听

private void registerUiccCardEvents() {
        if (mUiccCard != null) {
            mUiccCard.registerForAbsent(this, EVENT_ICC_ABSENT, null);
        }
        if (mUiccApplication != null) {
            mUiccApplication.registerForReady(this, EVENT_APP_READY, null);
            mUiccApplication.registerForLocked(this, EVENT_ICC_LOCKED, null);
            mUiccApplication.registerForNetworkLocked(this, EVENT_NETWORK_LOCKED, null);
        }
        if (mIccRecords != null) {
            mIccRecords.registerForImsiReady(this, EVENT_IMSI_READY, null);
            mIccRecords.registerForRecordsLoaded(this, EVENT_RECORDS_LOADED, null);
            mIccRecords.registerForRecordsEvents(this, EVENT_ICC_RECORD_EVENTS, null);
        }
    }

加载完IMSI/record load complete会通知IccCardProxy更新SIM卡状态
7.3

8.IccCardProxy
在PhoneFactory makeDefaultPhone是会创建Phone,在Phone的初始化时会创建IccCardProxy,UiccController初始化之后.IccCardProxy实现IccCard接口,通过Phone getIccCard返回IccCardProxy实例,接口的注释:

/**
 * {@hide}
 * @Deprecated use UiccController.getUiccCard instead.
 *
 * Integrated Circuit Card (ICC) interface
 * An object of a class implementing this interface is used by external
 * apps (specifically PhoneApp) to perform icc card related functionality.
 *
 * Apps (those that have access to Phone object) can retrieve this object
 * by calling phone.getIccCard()
 *
 * This interface is implemented by IccCardProxy and the object PhoneApp
 * gets when it calls getIccCard is IccCardProxy.
 */

接口定义的方法都是通过持有UiccController/UiccCard/UiccCardApplication/IccRecords来实现

8.1 IccCardProxy初始化

    makeDefaultPhone方法:
    phone = new GsmCdmaPhone(context,
                                    sCommandsInterfaces[i], sPhoneNotifier, i,
                                    PhoneConstants.PHONE_TYPE_CDMA_LTE,
                                    TelephonyComponentFactory.getInstance());
构造方法:
public GsmCdmaPhone(Context context, CommandsInterface ci, PhoneNotifier notifier,
                        boolean unitTestMode, int phoneId, int precisePhoneType,
                        TelephonyComponentFactory telephonyComponentFactory) {
        super(precisePhoneType == PhoneConstants.PHONE_TYPE_GSM ? "GSM" : "CDMA",
                notifier, context, ci, unitTestMode, phoneId, telephonyComponentFactory);

        // phone type needs to be set before other initialization as other objects rely on it
        mPrecisePhoneType = precisePhoneType;
        initOnce(ci);
        initRatSpecific(precisePhoneType);
        mSST = mTelephonyComponentFactory.makeServiceStateTracker(this, this.mCi);
        // DcTracker uses SST so needs to be created after it is instantiated
        mDcTracker = mTelephonyComponentFactory.makeDcTracker(this);
        mSST.registerForNetworkAttached(this, EVENT_REGISTERED_TO_NETWORK, 

null);
            logd("GsmCdmaPhone: constructor: sub = " + mPhoneId);
        }
initOnce方法:
mIccCardProxy = mTelephonyComponentFactory.makeIccCardProxy(mContext, mCi, mPhoneId);
IccCardProxy实例的个数是与Phone的个数相对应的,有2个phone就会有两个IccCardProxy对象。
 IccCardProxy构造方法:
 public IccCardProxy(Context context, CommandsInterface ci, int phoneId) {
    if (DBG) log("ctor: ci=" + ci + " phoneId=" + phoneId);
    mContext = context;
    mCi = ci;
    mPhoneId = phoneId;
    mTelephonyManager = (TelephonyManager) mContext.getSystemService(
            Context.TELEPHONY_SERVICE);
    mCdmaSSM = CdmaSubscriptionSourceManager.getInstance(context,
            ci, this, EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED, null);
    mUiccController = UiccController.getInstance();
    mUiccController.registerForIccChanged(this, EVENT_ICC_CHANGED, null);
    ci.registerForOn(this,EVENT_RADIO_ON, null);
    ci.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_UNAVAILABLE, null);

    resetProperties();
    setExternalState(State.NOT_READY, false);
}

在IccCardProxy初始化时,SIM卡状态是NOT_READY状态并且会broadcastIccStateChangedIntent广播出去;然后在Phone中设置radio模式setVoiceRadioTech。
8.2 IccCardProxy事件处理
IccCardProxy构造方法中向UiccController中注册ICC_CARD_STATUS_CHANGED消息,UiccController在更新完自己内部的UiccCard之后会notify IccCardProxy更新内部各个实例,处理EVENT_ICC_CHANGED的方法updateIccAvailability():

private void updateIccAvailability() {
        synchronized (mLock) {
            //获取UiccCard
            UiccCard newCard = mUiccController.getUiccCard(mPhoneId);
            CardState state = CardState.CARDSTATE_ABSENT;
            UiccCardApplication newApp = null;
            IccRecords newRecords = null;
            if (newCard != null) {
                state = newCard.getCardState();
                //获取UiccCardApplication 
                newApp = newCard.getApplication(mCurrentAppType);
                if (newApp != null) {
                    //获取IccRecords 
                    newRecords = newApp.getIccRecords();
                }
            }

            if (mIccRecords != newRecords || mUiccApplication != newApp || mUiccCard != newCard) {
                if (DBG) log("Icc changed. Reregestering.");
                unregisterUiccCardEvents();
                mUiccCard = newCard;
                mUiccApplication = newApp;
                mIccRecords = newRecords;
                //注册UiccCard/UiccCardApplication/IccRecords 监听 
                registerUiccCardEvents();
            }
            //更新SIM卡状态判断是否发送广播
            updateExternalState();
        }
    }

监听事件:

private void registerUiccCardEvents() {
        if (mUiccCard != null) {
        //SIM卡拔出事件对外发送广播
            mUiccCard.registerForAbsent(this, EVENT_ICC_ABSENT, null);
        }
        if (mUiccApplication != null) {
            //SIM卡Ready对外发送广播
            mUiccApplication.registerForReady(this, EVENT_APP_READY, null);
            mUiccApplication.registerForLocked(this, EVENT_ICC_LOCKED, null);
            mUiccApplication.registerForNetworkLocked(this, EVENT_NETWORK_LOCKED, null);
        }
        if (mIccRecords != null) {
            mIccRecords.registerForImsiReady(this, EVENT_IMSI_READY, null);
            mIccRecords.registerForRecordsLoaded(this, EVENT_RECORDS_LOADED, null);
            mIccRecords.registerForRecordsEvents(this, EVENT_ICC_RECORD_EVENTS, null);
        }
    }

UiccController负责对卡槽的卡实时实例化或销毁对象,IccCardProxy监听UiccController里的变化并及时更新自己内部的状态,Phone实例通过getIccCard得到IccCardProxy实例来获取各种卡状态。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/70419.html

相关文章

  • 多测师肖sir___app测试(新增001)

    摘要:一介绍了解全称意思应用程序,理解就是手机软件,主要是指安装在智能手机上面的软件,完善原始安卓系统的不足和多样性,或者说个性化,以此满足各个人群的需求,例如微信抖音这些,都是。测试测试就是要找出中的。可以更好的模拟用户操作,确保的稳定性 ...

    SQC 评论0 收藏0
  • ADN加载流程

    摘要:加载流程定义在从上面可以看到,真正的是在中继承,处理的等操作,和卡交互完成后,将数据改变信息通知给然后将数据变化的发送给注册监听的应用,应用做相应的同步动作。 ADN加载流程:showImg(https://segmentfault.com/img/bVVuUm?w=926&h=682); IccProvider.javaIccProvider定义在/packages/services...

    A Loity 评论0 收藏0
  • 阿里云发布首个物联网安全方案 防大规模破解

    摘要:在今年杭州云栖大会上,阿里云正式对外发布产品,向客户提供低成本软硬结合多安全等级的物联网安全解决方案。具体而言,采用阿里云安全技术,实现复用卡安全载体和卡商安全产线,每个卡实现预置一机一密物联网安全解决方案。  2016年在美国发生的摄像头安全漏洞导致大半个美国断网、摄像头偷窥、智能门锁被破解,这些事件都给物联网安全敲响警钟。  在今年杭州云栖大会上,阿里云Link正式对外发布LinkSec...

    kidsamong 评论0 收藏0

发表评论

0条评论

BicycleWarrior

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<