我们平时听过的卡 SIM, USIM, UIM等统称为:UICC — Universal Integrated Circuit Card
说白了,UICC就是 各种类型 SIM 卡的一个抽象,有一整套框架来对 UICC 卡进行管理,包括数据的增删改查,包括 SIM 卡的状态变化等~
8.IccUtils:里面一般全是静态方法,主要用来码制转换
9.CatService: 之所以把这个类拿出来单独放到这里,是因为和 Stk 交互都是通过这个类进行的,Stk 平时用的少,就是 SIM 卡工具包这个应用,Android 原生就有的应用,是运营商相关的。这个应用我改过很多次,用处不大,但是在天朝,必须有,因为很多运营商和银行(有特定银行的SIM卡)都需要这个和客户进行合作。
从代码层面分析一下UICC框架:
UiccController 本身是一个Handler,因为它 extends Handler,构造函数如下:
private UiccController(Context c, CommandsInterface ci) {
if (DBG) log("Creating UiccController");
mContext = c;
mCi = ci;
mCi.registerForIccStatusChanged(this, EVENT_ICC_STATUS_CHANGED, null);
mCi.registerForAvailable(this, EVENT_ICC_STATUS_CHANGED, null);
mCi.registerForNotAvailable(this, EVENT_RADIO_UNAVAILABLE, null);
mCi.registerForIccRefresh(this, EVENT_REFRESH, null);
}
构造函数会注册一些监听,然后在handleMessage处理回调:
public void handleMessage (Message msg) {
synchronized (mLock) {
switch (msg.what) {
case EVENT_ICC_STATUS_CHANGED:
if (DBG) log("Received EVENT_ICC_STATUS_CHANGED, calling getIccCardStatus");
mCi.getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE));
break;
case EVENT_GET_ICC_STATUS_DONE:
if (DBG) log("Received EVENT_GET_ICC_STATUS_DONE");
AsyncResult ar = (AsyncResult)msg.obj;
onGetIccCardStatusDone(ar);
break;
case EVENT_RADIO_UNAVAILABLE:
if (DBG) log("EVENT_RADIO_UNAVAILABLE ");
disposeCard(mUiccCard);
mUiccCard = null;
mIccChangedRegistrants.notifyRegistrants();
break;
case EVENT_REFRESH:
ar = (AsyncResult)msg.obj;
if (DBG) log("Sim REFRESH received");
if (ar.exception == null) {
handleRefresh((IccRefreshResponse)ar.result);
} else {
log ("Exception on refresh " + ar.exception);
}
break;
default:
Rlog.e(LOG_TAG, " Unknown Event " + msg.what);
}
}
}
mCi.getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE));
然后执行完毕会收到:EVENT_GET_ICC_STATUS_DONE
然后在:onGetIccCardStatusDone() 这个函数中 处理,创建UiccCard,或者更新card的状态
然后在UiccCard的 update() 方法中,会创建 UiccCardApplication 或者 更新 UiccCardApplication 的状态;
在UiccCardApplication 中,如果 UICC 需要PIN 解锁,则会发出需要PIN码 锁通知,进行 pin 码输入解锁,然后状态变化,继续更新 uicc card,uiccApplications 直到 UICC 状态 Ready,如果 UICC ready,则发出 UICC ready通知:
具体的流程可以参考下面的流程图:
其实读取UICC CARD数据有几个地方,那么在UiccCardApplication update()中就涉及到了读取 SIM 卡数据的地方:具体流程看下面:
UiccCardApplication 在创建的时候,还有更新的时候就会创建 IccFileHandler,IccRecords(注意这2个类都是父类,他们有具体的子类)
mIccFh = createIccFileHandler(as.app_type);
mIccRecords = createIccRecords(as.app_type, mContext, mCi);
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;
// Start off by setting empty state
resetRecords();
mParentApp.registerForReady(this, EVENT_APP_READY, null);
if (DBG) log("SIMRecords X ctor this=" + this);
}
public void registerForReady(Handler h, int what, Object obj) {
synchronized (mLock) {
Registrant r = new Registrant (h, what, obj);
mReadyRegistrants.add(r);
notifyReadyRegistrantsIfNeeded(r);
}
}
可以看到,注册到监听器中了。
那么什么时候通知的呢?
在UiccCardApplication 的 update() 方法,有一句这个:notifyReadyRegistrantsIfNeeded(null); 然后看下这个方法:
/**
* Notifies specified registrant, assume mLock is held.
*
* @param r Registrant to be notified. If null - all registrants will be notified
*/
private void notifyReadyRegistrantsIfNeeded(Registrant r) {
if (mDestroyed) {
return;
}
if (mAppState == AppState.APPSTATE_READY) {
if (mPin1State == PinState.PINSTATE_ENABLED_NOT_VERIFIED ||
mPin1State == PinState.PINSTATE_ENABLED_BLOCKED ||
mPin1State == PinState.PINSTATE_ENABLED_PERM_BLOCKED) {
loge("Sanity check failed! APPSTATE is ready while PIN1 is not verified!!!");
// Don't notify if application is in insane state
return;
}
if (r == null) {
if (DBG) log("Notifying registrants: READY");
mReadyRegistrants.notifyRegistrants();
} else {
if (DBG) log("Notifying 1 registrant: READY");
r.notifyRegistrant(new AsyncResult(null, null, null));
}
}
}
那么收到 SIM READY 的消息后的处理,见 SIMRecords,handleMessage() 方法,
case EVENT_APP_READY:
onReady();
break;
mFh.loadEFTransparent(EF_ICCID, obtainMessage(EVENT_GET_ICCID_DONE));
mFh.loadEFLinearFixed(EF_MBI, 1, obtainMessage(EVENT_GET_MBI_DONE));
/**
* 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);
mCi.iccIOForApp(COMMAND_GET_RESPONSE, fileid, getEFPath(fileid),
0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, mAid, response);
}
@Override
public void
iccIOForApp (int command, int fileid, String path, int p1, int p2, int p3,
String data, String pin2, String aid, 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_SIM_IO, result);
rr.mParcel.writeInt(command);
rr.mParcel.writeInt(fileid);
rr.mParcel.writeString(path);
rr.mParcel.writeInt(p1);
rr.mParcel.writeInt(p2);
rr.mParcel.writeInt(p3);
rr.mParcel.writeString(data);
rr.mParcel.writeString(pin2);
rr.mParcel.writeString(aid);
if (RILJ_LOGD) riljLog(rr.serialString() + "> iccIO: "
+ requestToString(rr.mRequest)
+ " 0x" + Integer.toHexString(command)
+ " 0x" + Integer.toHexString(fileid) + " "
+ " path: " + path + ","
+ p1 + "," + p2 + "," + p3
+ " aid: " + aid);
send(rr);
}
参考:http://www.netfoucs.com/article/songjinshi/60650.html