一、UiccController的主要功能
首先,UiccController是一个Handler的子类,这样它就具有分发和处理消息的能力。
public class UiccController extends Handler
在来看看UiccController的主要的公共API:
151 public UiccCard getUiccCard(int phoneId)
160 public UiccCard[] getUiccCards()
169 public IccRecords getIccRecords(int phoneId, int family)
269 public UiccCardApplication getUiccCardApplication(int phoneId, int family)
180 public IccFileHandler getIccFileHandler(int phoneId, int family)
192 public void registerForIccChanged(Handler h, int what, Object obj)ntroller
这里需要注意的是getUiccCard()和getUiccCards()方法,在android5.0以后,google也加入支持双卡的功能,而体现到具体的代码中就有UICC系统中的UiccCard对象,以及Phone应用中的Phone对象等。其会根据SIM卡的数量分别创建一个或两个实例,而对应的get方法也就需要传入对应的phoneId或slotId,比如此处就要传入phoneId获取对应的UiccCard 对象。
从上面提供的方法可以知道,UiccController的主要作用体现在两个方面:
1、创建并向外提供UiccCard、UiccCardApplication、IccRecords、IccFileHandler等对象
2、提供对SIM状态的监听
二、UiccController的创建过程
那么UiccController又是在什么时候在哪里创建的啦?答案是在开机启动Phone应用时在PhoneGlobals中通过PhoneFactory创建phone对象时创建的。
28public class PhoneApp extends Application {
35 @Override
36 public void onCreate() {
37 if (UserHandle.myUserId() == 0) {
38 // We are running as the primary user, so should bring up the
39 // global phone state.
40 mPhoneGlobals = new PhoneGlobals(this);
41 mPhoneGlobals.onCreate();
42
43 mTelephonyGlobals = new TelephonyGlobals(this);
44 mTelephonyGlobals.onCreate();
45 }
46 }
47}
PhoneGlobals.onCreat()
263 public void onCreate() {
264 if (VDBG) Log.v(LOG_TAG, "onCreate()...");
278 if (mCM == null) {
279 // Initialize the telephony framework
280 PhoneFactory.makeDefaultPhones(this);
}
进入PhoneFactory.makeDefaultPhones()
public static void makeDefaultPhone(Context context) {
int numPhones = TelephonyManager.getDefault().getPhoneCount();
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] = new RIL(context, networkModes[i],
cdmaSubscription, i);
}
Rlog.i(LOG_TAG, "Creating SubscriptionController");
SubscriptionController.init(context, sCommandsInterfaces);
// Instantiate UiccController so that all other classes can just
// call getInstance()
sUiccController = UiccController.make(context, sCommandsInterfaces);
}
可以看到这里通过TelephonyManager.getDefault().getPhoneCount()去获取当前需要创建的Phone数量,之后根据这个值创建了networkModes,sPhones,sCommandsInterfaces,sTelephonyNetworkFactories几个数组,然后根据sCommandsInterfaces去创建UiccController对象,这里的sCommandsInterfaces实际是RIL的实例,用于向UiccController上报SIM卡和radio层的状态改变。
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;
}
}
这里可以看出UiccController是单列模式,全局只有一个实例。
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);
}
}
在UiccController的构造方法中循环的取出RIL的实例,然后把UiccController自身注册到其中,其实就是添加到了RIL中的mIccStatusChangedRegistrants中,在SIM卡状态改变后会notify每一个mIccStatusChangedRegistrants中的观察者,所以这里是使用了观察者模式监听了EVENT_ICC_STATUS_CHANGED状态。注意这里是有传入一个index的,与RIL实例一一对应。
三、UiccController更新机制
前面说了UiccController在构造方法中就把自身注册到了RIL中,而RIL在SIM卡或radio状态改变时会主动上报。
当SIM卡状态发生改变时:
RIL.java
processUnsolicited (Parcel p, int type) {
case RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED:
if (RILJ_LOGD) unsljLog(response);
if (mIccStatusChangedRegistrants != null) {
mIccStatusChangedRegistrants.notifyRegistrants();
}
break;
}
前面说了UiccController本身是个Handler对象,当调用了mIccStatusChangedRegistrants.notifyRegistrants()就会进入其handleMessage()方法中:
@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;
}
}
}
这里因为前面注册的是EVENT_ICC_STATUS_CHANGED,所以会通过对应的index再次使用相应的RIL对象去查询当前SIM卡的状态,注意Message.what=EVENT_GET_ICC_STATUS_DONE,同样传入index参数,这是双卡特别参数。在RIL查询完SIM卡状态后会封装msg.obj再次发回来,进入case EVENT_GET_ICC_STATUS_DONE:
private synchronized void onGetIccCardStatusDone(AsyncResult ar, Integer index) {
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));
}
在这里通过ar.result获得了记录SIM卡实际状态信息的 IccCardStatus实例,并以此来创建或更新对应的UiccCard对象。同时也通过mIccChangedRegistrants.notifyRegistrants();通知UiccController中的SIM卡状态监听者。
1、UiccCard对象是在UiccController更新SIM卡状态时创建的;
2、其他对象可以通过registerForIccChanged()方法向UiccController申请监听SIM卡状态监听。