CPHS service :卡内嵌入服务指令
* Once created UiccController registers with RIL for "on" and "unsol_sim_status_changed"
* notifications. When such notification arrives UiccController will call
* getIccCardStatus (GET_SIM_STATUS). Based on the response of GET_SIM_STATUS
* request appropriate tree of uicc objects will be created.
*
* 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
Android4.4 Telephony流程分析——SIM卡开机时的初始化
http://blog.csdn.net/canghai1129/article/details/41011527
PhoneApp作为Android系统中首屈一指的Application,其在创建的时候会构造出对整个系统来说至关重要的ril.java的实体,在这个rilj构造出来后,会与底层的rild connect上,并且连通他们之间通信的socket,这样手机的通话、短信功能才可用;
PhoneApp如此重要和基础,其是在哪里被创建出来的呢
在ActivityManagerService.java里的 SystemReady函数的最后有以下代码
加粗的函数getPersistentApplications可以get到phoneapp的info,然后使用函数addAppLocked把PhoneApp启动起来
<application在ActivityManagerService.java里的 SystemReady函数的最后有以下代码 android:name="PhoneApp"
android:persistent="true"
packages/services/Telephony/src/com/android/phone/PhoneApp.java
onCreate(
// We are running as the primary user, so should bring up the
// global phone state.
//这里是我们关注的,数据和语音所需的基础类在这里创建
mPhoneGlobals = new PhoneGlobals(this);
mPhoneGlobals.onCreate();
网上的参考信息是处理PSTN呼叫
mTelephonyGlobals = new TelephonyGlobals(this);
mTelephonyGlobals.onCreate();
)
packages/services/Telephony/src/com/android/phone/PhoneGlobals.java
CallController callController;
CallManager mCM;
CallNotifier notifier;
CallerInfoCache callerInfoCache;
NotificationMgr notificationMgr;
public PhoneInterfaceManager phoneMgr;
public SimActivationManager simActivationManager;
CarrierConfigLoader configLoader;
private CallGatewayManager callGatewayManager;
private Phone phoneInEcm;
onCreate(
// Initialize the telephony framework
PhoneFactory.makeDefaultPhones(this);
)
frameworks/opt/telephony/src/java/com/android/internal/telephony/PhoneFactory.java
//初始化phone与ril、UiccController、TelephonyNetworkFactory的关系// phone 都为GsmCdmaPhone
makeDefaultPhone(
sUiccController = UiccController.make(context, sCommandsInterfaces);
)
rild主动上报射频信号状态
RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED
GsmServiceStateTracker(更新网络状态)、SIMRecords(用IccFileHandler读取SIM卡内置紧急号码)和SIMRecordsEx(向RILD查询20位的Iccid)
所以总结来看,UiccController就是通过向RIL注册卡状态变化的监听,当底层一有变化时,会通过RIL上报给UiccController,这样就会触发其下发getIccCardStatus来查询卡状态,得到卡状态后更新其内部的UiccCard及UIccCardApplication等。所以phone或者其他state tracker service可以通过UiccController来获取到正确的卡信息
frameworks/opt/telephony/
UiccController.java
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);
mCis[i].registerForAvailable(this, EVENT_ICC_STATUS_CHANGED, index);
mCis[i].registerForNotAvailable(this, EVENT_RADIO_UNAVAILABLE, index);
mCis[i].registerForIccRefresh(this, EVENT_SIM_REFRESH, index);
}
}
handleMessage(
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;
)
onGetIccCardStatusDone(
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));
)
registerForIccChanged(mIccChangedRegistrants.add(r))
frameworks/opt/telephony/
UiccCard.java
update(mUiccApplications[i] = new UiccCardApplication(this,ics.mApplications[i], mContext, mCi);)
frameworks/opt/telephony/
UiccCardApplication.java
mIccRecords = createIccRecords(as.app_type, mContext, mCi);
frameworks/opt/telephony/
SIMRecords.java
mAdnCache = new AdnRecordCache(mFh);
mVmConfig = new VoiceMailConstants();
mSpnOverride = new SpnOverride();
frameworks/opt/telephony/
BaseCommands.java
registerForIccStatusChanged()
frameworks/opt/telephony/
RIL.java
processSolicited(
case RIL_REQUEST_ENTER_SIM_PUK:
case RIL_REQUEST_ENTER_SIM_PUK2:
case RIL_REQUEST_ENTER_SIM_PIN:
case RIL_REQUEST_ENTER_SIM_PIN2:
case RIL_REQUEST_CHANGE_SIM_PIN:
case RIL_REQUEST_CHANGE_SIM_PIN2:
case RIL_REQUEST_SET_FACILITY_LOCK:
case RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED:
mIccStatusChangedRegistrants.notifyRegistrants();
)
/packages/services/Telephony/src/com/android/services/telephony/
TelephonyGlobals.java
onCreate( TelecomAccountRegistry.getInstance(mContext).setupOnBoot(); )
packages/services/telephony
//拥有我们在通信时注册的所有数据,包括处理动态添加和删除SIM和SIP帐户。
TelecomAccountRegistry.java
/**
* Sets up all the phone accounts for SIMs on first boot.
*/
void setupOnBoot() {
// TODO: When this object "finishes" we should unregister by invoking
// SubscriptionManager.getInstance(mContext).unregister(mOnSubscriptionsChangedListener);
// This is not strictly necessary because it will be unregistered if the
// notification fails but it is good form.
// Register for SubscriptionInfo list changes which is guaranteed
// to invoke onSubscriptionsChanged the first time.
SubscriptionManager.from(mContext).addOnSubscriptionsChangedListener(
mOnSubscriptionsChangedListener);
// We also need to listen for changes to the service state (e.g. emergency -> in service)
// because this could signal a removal or addition of a SIM in a single SIM phone.
mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_SERVICE_STATE);
}
private OnSubscriptionsChangedListener mOnSubscriptionsChangedListener =
new OnSubscriptionsChangedListener() {
@Override
public void onSubscriptionsChanged() {
// Any time the SubscriptionInfo changes...rerun the setup
tearDownAccounts();
setupAccounts();
}
};
private final PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
@Override
public void onServiceStateChanged(ServiceState serviceState) {
int newState = serviceState.getState();
if (newState == ServiceState.STATE_IN_SERVICE && mServiceState != newState) {
tearDownAccounts();
setupAccounts();
}
mServiceState = newState;
}
};
-----------------------------------------------------------------------------------------------------
frameworks/base/telephony
SubscriptionManager.java
addOnSubscriptionsChangedListener(
try {
// We use the TelephonyRegistry as it runs in the system and thus is always
// available. Where as SubscriptionController could crash and not be available
ITelephonyRegistry tr = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService(
"telephony.registry"));
if (tr != null) {
tr.addOnSubscriptionsChangedListener(pkgForDebug, listener.callback);
}
)
frameworks/base/services
TelephonyRegistry.java
addOnSubscriptionsChangedListener(mRecords.add(r); )
notifySubscriptionInfoChanged(
for (Record r : mRecords) {
r.onSubscriptionsChangedListenerCallback.onSubscriptionsChanged();}
)
frameworks/opt/telephony/src/java/com/android/internal/telephony/
SubscriptionController.java
public void notifySubscriptionInfoChanged() {
ITelephonyRegistry tr = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService(
"telephony.registry"));
try {
if (DBG) logd("notifySubscriptionInfoChanged:");
tr.notifySubscriptionInfoChanged();
} catch (RemoteException ex) {
// Should never happen because its always available.
}
// FIXME: Remove if listener technique accepted.
broadcastSimInfoContentChanged();
}
setCarrierText( notifySubscriptionInfoChanged(); )
/**
* Generate and set carrier text based on input parameters
* @param showPlmn flag to indicate if plmn should be included in carrier text
* @param plmn plmn to be included in carrier text
* @param showSpn flag to indicate if spn should be included in carrier text
* @param spn spn to be included in carrier text
* @return true if carrier text is set, false otherwise
*/
public boolean setPlmnSpn(int slotId, boolean showPlmn, String plmn, boolean showSpn,
String spn) {
setCarrierText(carrierText, subIds[i]);
}
frameworks/opt/telephony/src/java/com/android/internal/telephony/
ServiceStateTracker.java
initOnce(
mSubscriptionManager.addOnSubscriptionsChangedListener(mOnSubscriptionsChangedListener);
)
updateSpnDisplay(){
然后回到updateSpnDisplay()方法中,此时将会通过mSS.getOperatorAlphaLong()得到当前的PLMN值,以及通过rule得到当前是否需要显示PLMN(showPlmn),然后通过iccRecords.getServiceProviderName()得到当前的SPN以及通过rule得到当前是否需要显示SPN。
}
onSubscriptionsChanged()
private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (!mPhone.isPhoneTypeGsm()) {
loge("Ignoring intent " + intent + " received on CDMA phone");
return;
}
if (intent.getAction().equals(Intent.ACTION_LOCALE_CHANGED)) {//系统语言切换
// update emergency string whenever locale changed
updateSpnDisplay();
} else if (intent.getAction().equals(ACTION_RADIO_OFF)) {
mAlarmSwitch = false;
DcTracker dcTracker = mPhone.mDcTracker;
powerOffRadioSafely(dcTracker);
}
}
};
--------------------------------------------------------------------------------------------------------
frameworks/base/telephony
TelephonyManager.java
public void listen(PhoneStateListener listener, int events) {
sRegistry.listenForSubscriber(listener.mSubId, getOpPackageName(),
listener.callback, events, notifyNow);
}
frameworks/base/service
TelephonyRegistry.java
listenForSubscriber(boolean notifyNow)
listen( //notifyNow 立即通知
mRecords.add(r);
r.callback.onServiceStateChanged
r.callback.onSignalStrengthChanged
r.callback.onCallStateChanged
r.callback.onDataConnectionStateChanged
r.callback.onDataActivity
r.callback.onSignalStrengthsChanged
r.callback.onCarrierNetworkChange
.............................
)
notifyServiceStateForPhoneId(
r.callback.onServiceStateChanged(new ServiceState(state));
broadcastServiceStateChanged(state, phoneId, subId);
)
frameworks/opt/telephony/src/java/com/android/internal/telephony/
DefaultPhoneNotifier.java
notifyServiceState( mRegistry.notifyServiceStateForPhoneId(phoneId, subId, ss); )
frameworks/opt/telephony/src/java/com/android/internal/telephony/
Phone.java
notifyServiceStateChangedP( mNotifier.notifyServiceState(this); )
frameworks/opt/telephony/src/java/com/android/internal/telephony/
GsmCdmaPhone.java
public void notifyServiceStateChanged(ServiceState ss) {
super.notifyServiceStateChangedP(ss);
}
frameworks/opt/telephony/src/java/com/android/internal/telephony/
ServiceStateTracker.java
initOnce(
mUiccController.registerForIccChanged(this, EVENT_ICC_CHANGED, null);
)
updateRilImsRadioTechnology( mPhone.notifyServiceStateChanged(mSS);)
pollStateDoneGsm( mPhone.notifyServiceStateChanged(mSS); )
pollStateDoneCdma( mPhone.notifyServiceStateChanged(mSS); )
pollStateDoneCdmaLte( mPhone.notifyServiceStateChanged(mSS); )
//todo: try to merge pollstate functions
private void pollStateDone() {
if (mPhone.isPhoneTypeGsm()) {
pollStateDoneGsm();
} else if (mPhone.isPhoneTypeCdma()) {
pollStateDoneCdma();
} else {
pollStateDoneCdmaLte();
}
}
handlePollStateResult(
pollStateDone()
)
pollState(
switch (mCi.getRadioState()) {
case RADIO_UNAVAILABLE:
mNewSS.setStateOutOfService();
mNewCellLoc.setStateInvalid();
setSignalStrengthDefaultValues();
mGotCountryCode = false;
mNitzUpdatedTime = false;
pollStateDone();
break;
case RADIO_OFF:
mNewSS.setStateOff();
mNewCellLoc.setStateInvalid();
setSignalStrengthDefaultValues();
mGotCountryCode = false;
mNitzUpdatedTime = false;
// don't poll for state when the radio is off
// EXCEPT, if the poll was modemTrigged (they sent us new radio data)
// or we're on IWLAN
if (!modemTriggered && ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN
!= mSS.getRilDataRadioTechnology()) {
pollStateDone();
break;
}
)
handleMessage(){
case EVENT_SIM_READY:
// Reset the mPreviousSubId so we treat a SIM power bounce
// as a first boot. See b/19194287
mOnSubscriptionsChangedListener.mPreviousSubId.set(-1);
pollState();
// Signal strength polling stops when radio is off
queueNextSignalStrengthPoll();
break;
case EVENT_ICC_CHANGED:
onUpdateIccAvailability();
}
onUpdateIccAvailability(
mUiccApplcation.registerForReady(this, EVENT_SIM_READY, null);
)
frameworks/opt/telephony
UiccCardApplication.java
public void registerForReady(Handler h, int what, Object obj) {
synchronized (mLock) {
Registrant r = new Registrant (h, what, obj);
mReadyRegistrants.add(r);
notifyReadyRegistrantsIfNeeded(r);
}
}
notifyReadyRegistrantsIfNeeded( mReadyRegistrants.notifyRegistrants(); )
update(
notifyPinLockedRegistrantsIfNeeded(null);
notifyReadyRegistrantsIfNeeded(null);
)