本文以 Android 7.0 为源码,对PhoneAPP 启动及 相关 Telephony 类的加载进行简单介绍
1、PhoneAPP 的启动
为了了解 PhoneAPP 是如何启动的,首先让我们看下对应 配置文件 AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
package="com.android.phone"
coreApp="true"
android:sharedUserId="android.uid.phone"
android:sharedUserLabel="@string/phoneAppLabel"
>
.....
<application android:name="PhoneApp"
android:persistent="true"
android:label="@string/phoneAppLabel"
android:icon="@mipmap/ic_launcher_phone"
android:allowBackup="false"
android:supportsRtl="true"
android:usesCleartextTraffic="true"
android:defaultToDeviceProtectedStorage="true"
android:directBootAware="true">
....
如上,关注到两个重要属性:persistent 为 true 表示应用是常驻的,directBootAware 为 true 表示应用是可直接启动的,这两个字段决定了PhoneApp开机后,将被ActivityManagerService启动。
总的说来,开机由SystemServer进程创建出AM和PM,PM会加载Application的信息。 当AM的SystemReady被调用后,将利用PM得到persistent和directBootAware属性值为 true的应用列表,PhoneApp就在其中。 AM利用socket向zygote发送消息,启动PhoneApp对应的进程。 zygote进程启动PhoneApp进程后,将利用反射调用PhoneApp中ActivityThread的main函数。 ActivityThread的main函数被调用后,将利用binder通信向AM发送消息;AM进行对应的处理,处理完成后,同样利用binder通信将处理结果返回给ActivityThread。 最后ActivityThread收到处理结果后,完成最后的准备工作(设置参数之类),并调用PhoneApp的onCreate函数。(来自ZhangJianIsAStark)
PS:从 Android N 开始,在首次开机时,在用户尚未来得及解锁设备之前,设备可直接启动到一种名为 Direct Boot(直接启动)的新模式中。在此模式下,操作系统可以全功能运行,但不允许访问私有应用数据,只能运行经过更新、可支持直接启动功能的应用。
2、PhoneAPP 启动后相关类加载关系图
3、相关代码说明
packages/services/Telephony/src/com/android/phone/PhoneGlobals.java
public void onCreate() {
if (VDBG) Log.v(LOG_TAG, "onCreate()...");
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) {
// Initialize the telephony framework
PhoneFactory.makeDefaultPhones(this);
// Start TelephonyDebugService After the default phone is created.
Intent intent = new Intent(this, TelephonyDebugService.class);
startService(intent);
mCM = CallManager.getInstance();
for (Phone phone : PhoneFactory.getPhones()) {
mCM.registerPhone(phone);
}
// Create the NotificationMgr singleton, which is used to display
// status bar icons and control other status bar behavior.
notificationMgr = NotificationMgr.init(this);
// If PhoneGlobals has crashed and is being restarted, then restart.
mHandler.sendEmptyMessage(EVENT_RESTART_SIP);
// Create an instance of CdmaPhoneCallState and initialize it to IDLE
cdmaPhoneCallState = new CdmaPhoneCallState();
cdmaPhoneCallState.CdmaPhoneCallStateInit();
// before registering for phone state changes
mPowerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
mWakeLock = mPowerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, LOG_TAG);
// lock used to keep the processor awake, when we don't care for the display.
mPartialWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK
| PowerManager.ON_AFTER_RELEASE, LOG_TAG);
mKeyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
// Get UpdateLock to suppress system-update related events (e.g. dialog show-up)
// during phone calls.
mUpdateLock = new UpdateLock("phone");
if (DBG) Log.d(LOG_TAG, "onCreate: mUpdateLock: " + mUpdateLock);
CallLogger callLogger = new CallLogger(this, new CallLogAsync());
callGatewayManager = CallGatewayManager.getInstance();
// Create the CallController singleton, which is the interface
// to the telephony layer for user-initiated telephony functionality
// (like making outgoing calls.)
callController = CallController.init(this, callLogger, callGatewayManager);
// Create the CallerInfoCache singleton, which remembers custom ring tone and
// send-to-voicemail settings.
//
// The asynchronous caching will start just after this call.
callerInfoCache = CallerInfoCache.init(this);
phoneMgr = PhoneInterfaceManager.init(this, PhoneFactory.getDefaultPhone());
configLoader = CarrierConfigLoader.init(this);
// Create the CallNotifer singleton, which handles
// asynchronous events from the telephony layer (like
// launching the incoming-call UI when an incoming call comes
// in.)
notifier = CallNotifier.init(this);
// A-28074:zhaojian at 20170224 for CMCC NetworkType
boolean isCmccDeepCoopMode = this.getPackageManager().hasSystemFeature(LeFeatures.TELEPHONY_CMCC_NETWORK_TYPE_DEEP_COOP);
if (isCmccDeepCoopMode) {
leCmccDeepCoopHandler = new LeCmccDeepCoopHandler(this);
}
// E-28074:zhaojian at 20170224 for CMCC NetworkType
PhoneUtils.registerIccStatus(mHandler, EVENT_SIM_NETWORK_LOCKED);
// register for MMI/USSD
mCM.registerForMmiComplete(mHandler, MMI_COMPLETE, null);
// register connection tracking to PhoneUtils
PhoneUtils.initializeConnectionHandler(mCM);
// Register for misc other intent broadcasts.
IntentFilter intentFilter =
new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED);
intentFilter.addAction(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED);
intentFilter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
intentFilter.addAction(TelephonyIntents.ACTION_RADIO_TECHNOLOGY_CHANGED);
intentFilter.addAction(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED);
intentFilter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
intentFilter.addAction(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED);
registerReceiver(mReceiver, intentFilter);
//set the default values for the preferences in the phone.
PreferenceManager.setDefaultValues(this, R.xml.network_setting, false);
PreferenceManager.setDefaultValues(this, R.xml.call_feature_setting, false);
// Make sure the audio mode (along with some
// audio-mode-related state of our own) is initialized
// correctly, given the current state of the phone.
PhoneUtils.setAudioMode(mCM);
}
cdmaOtaProvisionData = new OtaUtils.CdmaOtaProvisionData();
cdmaOtaConfigData = new OtaUtils.CdmaOtaConfigData();
cdmaOtaScreenState = new OtaUtils.CdmaOtaScreenState();
cdmaOtaInCallScreenUiState = new OtaUtils.CdmaOtaInCallScreenUiState();
simActivationManager = new SimActivationManager();
// XXX pre-load the SimProvider so that it's ready
resolver.getType(Uri.parse("content://icc/adn"));
// TODO: Register for Cdma Information Records
// phone.registerCdmaInformationRecord(mHandler, EVENT_UNSOL_CDMA_INFO_RECORD, null);
// Read HAC settings and configure audio hardware
if (getResources().getBoolean(R.bool.hac_enabled)) {
int hac = android.provider.Settings.System.getInt(
getContentResolver(),
android.provider.Settings.System.HEARING_AID,
0);
AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
audioManager.setParameter(SettingsConstants.HAC_KEY,
hac == SettingsConstants.HAC_ENABLED
? SettingsConstants.HAC_VAL_ON : SettingsConstants.HAC_VAL_OFF);
}
}
frameworks/opt/telephony/src/java/com/android/internal/telephony/PhoneFactory.java
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 initialization new 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 checks whether it is single SIM or multi SIM mode */ 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"); telephonyComponentFactory.initSubscriptionController( context, sCommandsInterfaces); // Instantiate UiccController so that all other classes can just // call getInstance() sUiccController = UiccController.make(context, sCommandsInterfaces); for (int i = 0; i < numPhones; i++) { Phone phone = null; int phoneType = TelephonyManager.getPhoneType(networkModes[i]); if (phoneType == PhoneConstants.PHONE_TYPE_GSM) { 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 packages SmsApplication.initSmsPackageMonitor(context); sMadeDefaults = true; Rlog.i(LOG_TAG, "Creating SubInfoRecordUpdater "); sSubInfoRecordUpdater = telephonyComponentFactory.makeSubscriptionInfoUpdater( 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. 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); 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); } } }
frameworks/opt/telephony/src/java/com/android/internal/telephony/GsmCdmaPhone.java
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);
}
private void initOnce(CommandsInterface ci) {
if (ci instanceof SimulatedRadioControl) {
mSimulatedRadioControl = (SimulatedRadioControl) ci;
}
mCT = mTelephonyComponentFactory.makeGsmCdmaCallTracker(this);
mIccPhoneBookIntManager = mTelephonyComponentFactory.makeIccPhoneBookInterfaceManager(this);
PowerManager pm
= (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, LOG_TAG);
mIccSmsInterfaceManager = mTelephonyComponentFactory.makeIccSmsInterfaceManager(this);
mIccCardProxy = mTelephonyComponentFactory.makeIccCardProxy(mContext, mCi, mPhoneId);
mCi.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null);
mCi.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
mCi.registerForOn(this, EVENT_RADIO_ON, null);
mCi.setOnSuppServiceNotification(this, EVENT_SSN, null);
//GSM
mCi.setOnUSSD(this, EVENT_USSD, null);
mCi.setOnSs(this, EVENT_SS, null);
//CDMA
mCdmaSSM = mTelephonyComponentFactory.getCdmaSubscriptionSourceManagerInstance(mContext,
mCi, this, EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED, null);
mEriManager = mTelephonyComponentFactory.makeEriManager(this, mContext,
EriManager.ERI_FROM_XML);
mCi.setEmergencyCallbackMode(this, EVENT_EMERGENCY_CALLBACK_MODE_ENTER, null);
mCi.registerForExitEmergencyCallbackMode(this, EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE,
null);
// get the string that specifies the carrier OTA Sp number
mCarrierOtaSpNumSchema = TelephonyManager.from(mContext).getOtaSpNumberSchemaForPhone(
getPhoneId(), "");
mResetModemOnRadioTechnologyChange = SystemProperties.getBoolean(
TelephonyProperties.PROPERTY_RESET_ON_RADIO_TECH_CHANGE, false);
mCi.registerForRilConnected(this, EVENT_RIL_CONNECTED, null);
mCi.registerForVoiceRadioTechChanged(this, EVENT_VOICE_RADIO_TECH_CHANGED, null);
mContext.registerReceiver(mBroadcastReceiver, new IntentFilter(
CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED));
}
private void initRatSpecific(int precisePhoneType) {
mPendingMMIs.clear();
mIccPhoneBookIntManager.updateIccRecords(null);
mEsn = null;
mMeid = null;
mPrecisePhoneType = precisePhoneType;
logd("Precise phone type " + mPrecisePhoneType);
TelephonyManager tm = TelephonyManager.from(mContext);
if (isPhoneTypeGsm()) {
mCi.setPhoneType(PhoneConstants.PHONE_TYPE_GSM);
tm.setPhoneType(getPhoneId(), PhoneConstants.PHONE_TYPE_GSM);
mIccCardProxy.setVoiceRadioTech(ServiceState.RIL_RADIO_TECHNOLOGY_UMTS);
} else {
mCdmaSubscriptionSource = mCdmaSSM.getCdmaSubscriptionSource();
// This is needed to handle phone process crashes
String inEcm = SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE, "false");
mIsPhoneInEcmState = inEcm.equals("true");
if (mIsPhoneInEcmState) {
// Send a message which will invoke handleExitEmergencyCallbackMode
mCi.exitEmergencyCallbackMode(
obtainMessage(EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE));
}
mCi.setPhoneType(PhoneConstants.PHONE_TYPE_CDMA);
tm.setPhoneType(getPhoneId(), PhoneConstants.PHONE_TYPE_CDMA);
mIccCardProxy.setVoiceRadioTech(ServiceState.RIL_RADIO_TECHNOLOGY_1xRTT);
// Sets operator properties by retrieving from build-time system property
String operatorAlpha = SystemProperties.get("ro.cdma.home.operator.alpha");
String operatorNumeric = SystemProperties.get(PROPERTY_CDMA_HOME_OPERATOR_NUMERIC);
logd("init: operatorAlpha='" + operatorAlpha
+ "' operatorNumeric='" + operatorNumeric + "'");
if (mUiccController.getUiccCardApplication(mPhoneId, UiccController.APP_FAM_3GPP) ==
null || isPhoneTypeCdmaLte() || isPhoneTypeCdma()) {
if (!TextUtils.isEmpty(operatorAlpha)) {
logd("init: set 'gsm.sim.operator.alpha' to operator='" + operatorAlpha + "'");
tm.setSimOperatorNameForPhone(mPhoneId, operatorAlpha);
}
if (!TextUtils.isEmpty(operatorNumeric)) {
logd("init: set 'gsm.sim.operator.numeric' to operator='" + operatorNumeric +
"'");
logd("update icc_operator_numeric=" + operatorNumeric);
tm.setSimOperatorNumericForPhone(mPhoneId, operatorNumeric);
SubscriptionController.getInstance().setMccMnc(operatorNumeric, getSubId());
// Sets iso country property by retrieving from build-time system property
setIsoCountryProperty(operatorNumeric);
// Updates MCC MNC device configuration information
logd("update mccmnc=" + operatorNumeric);
MccTable.updateMccMncConfiguration(mContext, operatorNumeric, false);
}
}
// Sets current entry in the telephony carrier table
updateCurrentCarrierInProvider(operatorNumeric);
}
}