(M)SIM卡开机流程分析之默认APN设置
来源:互联网 发布:java socket异步接收 编辑:程序博客网 时间:2024/05/17 08:51
近日,一直在研究,默认APN的设置
当我们从代码和手机中看到,默认APN的显示是从content://telephony/carriers/preferapn的数据中查询到的,而这个是通过shared preference来保存的,当手机第一次插卡开机后,我们将preferapn.xml文件导出来后,我们发现其中已经写有值了,但是从TelephonyProvider.Java文件中,我们却没有发现任何写入的地方,那么这个默认APN究竟是如何写入和设定的呢?
结合LOG查看了插卡开机流程多日后,终于找到了其写入的位置,仅以此篇记录近期的成果。
继续查看setupDataOnConnectableApns方法
再查看trySetupData方法,其是将刚刚的buildWaitingApns返回的apnList传入的
可以看到,preferred apn就是在此处进行第一次设定的,而ApnSetting就是我们之前在buildWaitingApn中获取到的apnList的第一个ApnSetting
好了,到此结束
仅以此篇暂时记录目前的研究成果,若有错误,后续改正
当我们从代码和手机中看到,默认APN的显示是从content://telephony/carriers/preferapn的数据中查询到的,而这个是通过shared preference来保存的,当手机第一次插卡开机后,我们将preferapn.xml文件导出来后,我们发现其中已经写有值了,但是从TelephonyProvider.Java文件中,我们却没有发现任何写入的地方,那么这个默认APN究竟是如何写入和设定的呢?
结合LOG查看了插卡开机流程多日后,终于找到了其写入的位置,仅以此篇记录近期的成果。
首先,SIM卡的开机流程中,我们知道,是从PhoneFactory.java文件的makeDefaultPhone方法中开始的,而在其中,我们可以看到如下段
for (int i = 0; i < numPhones; i++) { PhoneBase phone = null; int phoneType = TelephonyManager.getPhoneType(networkModes[i]); if (phoneType == PhoneConstants.PHONE_TYPE_GSM) { phone = new GSMPhone(context, sCommandsInterfaces[i], sPhoneNotifier, i); } else if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) { phone = new CDMALTEPhone(context, sCommandsInterfaces[i], sPhoneNotifier, i); } Rlog.i(LOG_TAG, "Creating Phone with type = " + phoneType + " sub = " + i); sProxyPhones[i] = new PhoneProxy(phone); }创建Phone对象,今天我们就以GSMPhone对象来分析这个默认APN的流程
public GSMPhone(Context context, CommandsInterface ci, PhoneNotifier notifier, int phoneId) { this(context, ci, notifier, false, phoneId); }public GSMPhone(Context context, CommandsInterface ci, PhoneNotifier notifier, boolean unitTestMode, int phoneId) { super("GSM", notifier, context, ci, unitTestMode, phoneId); if (ci instanceof SimulatedRadioControl) { mSimulatedRadioControl = (SimulatedRadioControl) ci; } mCi.setPhoneType(PhoneConstants.PHONE_TYPE_GSM); mCT = new GsmCallTracker(this); mSST = new GsmServiceStateTracker(this); mDcTracker = new DcTracker(this); if (!unitTestMode) { mSimPhoneBookIntManager = new SimPhoneBookInterfaceManager(this); mSubInfo = new PhoneSubInfo(this); } 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.setOnUSSD(this, EVENT_USSD, null); mCi.setOnSuppServiceNotification(this, EVENT_SSN, null); mSST.registerForNetworkAttached(this, EVENT_REGISTERED_TO_NETWORK, null); mCi.setOnSs(this, EVENT_SS, null); setProperties(); log("GSMPhone: constructor: sub = " + mPhoneId); setProperties(); }其中,有创建DcTracker对象,查看这个类的构造方法
//***** Constructor public DcTracker(PhoneBase p) { super(p); ...... update(); ...... }首先,先调用了其父类的构造方法
/** * Default constructor */ protected DcTrackerBase(PhoneBase phone) { super(); mPhone = phone; ...... mUiccController = UiccController.getInstance(); mUiccController.registerForIccChanged(this, DctConstants.EVENT_ICC_CHANGED, null); ...... }再继续回到DcTracker的构造方法中,可以看到还调用了update方法,进入update方法中查看
public void update() { ...... registerForAllEvents(); onUpdateIcc(); ...... }进入onUpdateIcc方法
@Override protected void onUpdateIcc() { ...... IccRecords newIccRecords = getUiccRecords(UiccController.APP_FAM_3GPP); IccRecords r = mIccRecords.get(); if (r != newIccRecords) { ...... if (newIccRecords != null) { if (mPhone.getSubId() >= 0) { ...... mIccRecords.set(newIccRecords); newIccRecords.registerForRecordsLoaded( this, DctConstants.EVENT_RECORDS_LOADED, null); } } ...... } }通过IccRecords注册DctConstants.EVENT_RECORDS_LOADED消息,当全部加载完成后,发出EVENT_RECORDS_LOADED消息,在DcTracker中接收,并处理
@Override public void handleMessage (Message msg) { ...... switch (msg.what) { case DctConstants.EVENT_RECORDS_LOADED: onRecordsLoaded(); break; } }
private void onRecordsLoaded() { ...... createAllApnList(); setInitialAttachApn(); if (mPhone.mCi.getRadioState().isOn()) { if (DBG) log("onRecordsLoaded: notifying data availability"); notifyOffApnsOfAvailability(Phone.REASON_SIM_LOADED); } setupDataOnConnectableApns(Phone.REASON_SIM_LOADED); }再查看createAllApnList方法
/** * Based on the sim operator numeric, create a list for all possible * Data Connections and setup the preferredApn. */ private void createAllApnList() { mAllApnSettings = new ArrayList<ApnSetting>(); IccRecords r = mIccRecords.get(); String operator = (r != null) ? r.getOperatorNumeric() : ""; if (operator != null) { String selection = "numeric = '" + operator + "'"; String orderBy = "_id"; // query only enabled apn. // carrier_enabled : 1 means enabled apn, 0 disabled apn. // selection += " and carrier_enabled = 1"; if (DBG) log("createAllApnList: selection=" + selection); Cursor cursor = mPhone.getContext().getContentResolver().query( Telephony.Carriers.CONTENT_URI, null, selection, null, orderBy); if (cursor != null) { if (cursor.getCount() > 0) { mAllApnSettings = createApnList(cursor); } cursor.close(); } } addEmergencyApnSetting(); dedupeApnSettings(); if (mAllApnSettings.isEmpty()) { if (DBG) log("createAllApnList: No APN found for carrier: " + operator); mPreferredApn = null; // TODO: What is the right behavior? //notifyNoData(DataConnection.FailCause.MISSING_UNKNOWN_APN); } else { mPreferredApn = getPreferredApn(); if (mPreferredApn != null && !mPreferredApn.numeric.equals(operator)) { mPreferredApn = null; setPreferredApn(-1); } if (DBG) log("createAllApnList: mPreferredApn=" + mPreferredApn); } if (DBG) log("createAllApnList: X mAllApnSettings=" + mAllApnSettings); setDataProfilesAsNeeded(); }可以看到,在这个方法中,主要是通过当前SIM卡的numeric字段,从content://telephony/carriers数据库中获取所有numeric字段对应的APN信息(数据库信息是从哪儿来的,请查看TelephonyProvider.java文件),并且将所有的数据均插入mAllApnSettings中,在这段代码下方可以看到,还有获取preferred apn的数据,由于此前并未设定,因此此处无法获取到
继续查看setupDataOnConnectableApns方法
private void setupDataOnConnectableApns(String reason) { setupDataOnConnectableApns(reason, RetryFailures.ALWAYS); }
private void setupDataOnConnectableApns(String reason, RetryFailures retryFailures) { ...... for (ApnContext apnContext : mPrioritySortedApnContexts) { ArrayList<ApnSetting> waitingApns = null; ...... if (apnContext.getState() == DctConstants.State.FAILED || apnContext.getState() == DctConstants.State.RETRYING) { ...... // RetryFailures.ONLY_ON_CHANGE - check if the apns have changed int radioTech = mPhone.getServiceState().getRilDataRadioTechnology(); ArrayList<ApnSetting> originalApns = apnContext.getOriginalWaitingApns(); if (originalApns != null && originalApns.isEmpty() == false) { waitingApns = buildWaitingApns(apnContext.getApnType(), radioTech); if (originalApns.size() != waitingApns.size() || originalApns.containsAll(waitingApns) == false) { apnContext.releaseDataConnection(reason); } else { continue; } } else { continue; } ...... } if (apnContext.isConnectable()) { log("setupDataOnConnectableApns: isConnectable() call trySetupData"); apnContext.setReason(reason); trySetupData(apnContext, waitingApns); } } }这边有一个buildWaitingApns方法和trySetupData方法比较重要,我们继续分析这段
/** * Build a list of APNs to be used to create PDP's. * * @param requestedApnType * @return waitingApns list to be used to create PDP * error when waitingApns.isEmpty() */ private ArrayList<ApnSetting> buildWaitingApns(String requestedApnType, int radioTech) { ...... ArrayList<ApnSetting> apnList = new ArrayList<ApnSetting>(); ...... IccRecords r = mIccRecords.get(); String operator = (r != null) ? r.getOperatorNumeric() : ""; ...... boolean usePreferred = true; try { // 返回usePreferred的值为true usePreferred = ! mPhone.getContext().getResources().getBoolean(com.android. internal.R.bool.config_dontPreferApn); } catch (Resources.NotFoundException e) { if (DBG) log("buildWaitingApns: usePreferred NotFoundException set to true"); usePreferred = true; } // 我们知道此地,一样,无法取得值,返回mPreferredApn的值为null if (usePreferred) { mPreferredApn = getPreferredApn(); } if (DBG) { log("buildWaitingApns: usePreferred=" + usePreferred + " canSetPreferApn=" + mCanSetPreferApn + " mPreferredApn=" + mPreferredApn + " operator=" + operator + " radioTech=" + radioTech + " IccRecords r=" + r); } ...... if (mAllApnSettings != null) { ...... // 刚刚通过createAllApnList方法获取到的值 for (ApnSetting apn : mAllApnSettings) { if (apn.canHandleType(requestedApnType)) { if (ServiceState.bitmaskHasTech(apn.bearerBitmask, radioTech)) { if (DBG) log("buildWaitingApns: adding apn=" + apn); apnList.add(apn); } else { if (DBG) { log("buildWaitingApns: bearerBitmask:" + apn.bearerBitmask + " does " + "not include radioTech:" + radioTech); } } } else if (DBG) { log("buildWaitingApns: couldn't handle requesedApnType=" + requestedApnType); } } } else { loge("mAllApnSettings is null!"); } if (DBG) log("buildWaitingApns: X apnList=" + apnList); return apnList; }返回一个apnList,这个list是从mAllApnSettings中取到的,而其判断条件为该ApnSetting中是否包含需要的apnType,和是否符合我们的需要
再查看trySetupData方法,其是将刚刚的buildWaitingApns返回的apnList传入的
private boolean trySetupData(ApnContext apnContext, ArrayList<ApnSetting> waitingApns) { ...... apnContext.setWaitingApns(waitingApns); ...... boolean retValue = setupData(apnContext, radioTech); notifyOffApnsOfAvailability(apnContext.getReason()); ...... }再看setupData方法
private boolean setupData(ApnContext apnContext, int radioTech) { ...... ApnSetting apnSetting; DcAsyncChannel dcac = null; // 直接获取mWaitingApn List中的第一个ApnSetting apnSetting = apnContext.getNextWaitingApn(); ...... apnContext.setDataConnectionAc(dcac); apnContext.setApnSetting(apnSetting); apnContext.setState(DctConstants.State.CONNECTING); mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType()); Message msg = obtainMessage(); msg.what = DctConstants.EVENT_DATA_SETUP_COMPLETE; msg.obj = new Pair<ApnContext, Integer>(apnContext, generation); dcac.bringUp(apnContext, getInitialMaxRetry(), profileId, radioTech, mAutoAttachOnCreation.get(), msg, generation); if (DBG) log("setupData: initing!"); return true; }创建DataConnection,并设置其参数,设置完成后发送EVENT_DATA_SETUP_COMPLETE消息,在其父类DcTrackerBase.java文件中接收,并处理
@Override public void handleMessage(Message msg) { switch (msg.what) { ...... case DctConstants.EVENT_DATA_SETUP_COMPLETE: onDataSetupComplete((AsyncResult) msg.obj); break; } }在DcTracker的onDataSetupComplete方法中进行处理
/** * A SETUP (aka bringUp) has completed, possibly with an error. If * there is an error this method will call {@link #onDataSetupCompleteError}. */ @Override protected void onDataSetupComplete(AsyncResult ar) { DcFailCause cause = DcFailCause.UNKNOWN; boolean handleError = false; ApnContext apnContext = getValidApnContext(ar, "onDataSetupComplete"); ...... if (ar.exception == null) { DcAsyncChannel dcac = apnContext.getDcAc(); ...... ApnSetting apn = apnContext.getApnSetting(); ...... // everything is setup if(TextUtils.equals(apnContext.getApnType(),PhoneConstants.APN_TYPE_DEFAULT)) { SystemProperties.set(PUPPET_MASTER_RADIO_STRESS_TEST, "true"); if (mCanSetPreferApn && mPreferredApn == null) { if (DBG) log("onDataSetupComplete: PREFERED APN is null"); mPreferredApn = apn; if (mPreferredApn != null) { setPreferredApn(mPreferredApn.id); } } } ...... } ...... }
可以看到,preferred apn就是在此处进行第一次设定的,而ApnSetting就是我们之前在buildWaitingApn中获取到的apnList的第一个ApnSetting
好了,到此结束
仅以此篇暂时记录目前的研究成果,若有错误,后续改正
0 0
- (M)SIM卡开机流程分析之默认APN设置
- (M)SIM卡开机流程分析之主线分析
- (M)SIM卡开机流程分析之SPN加载
- (M)SIM卡开机流程分析之TelephonyDevController类分析
- (M)SIM卡开机流程分析之TelephonyManager类分析
- (M)SIM卡开机流程分析之UiccController类分析
- (M)SIM卡开机流程分析之RIL类分析
- (M)SIM卡开机流程分析之DefaultPhoneNotifier类分析
- (M)SIM卡开机流程分析之SubscriptionController类分析
- (M)SIM卡开机流程分析之显示名称加载
- SIM卡设置默认短信流程分析(数据流量和电话设置相似)
- 开机导入Sim卡联系人流程分析
- Android APN开发流程分析 、设置问题
- 开机设置卡1为发送短信的默认sim卡
- Android APN开发流程分析(一)
- Android APN开发流程分析(一)
- Android APN开发流程分析(一)
- Android APN开发流程分析(一)
- 389. Find the Difference
- 16. 函数指针
- Android基础知识06
- Linux的进程------进程的描述和进程的创建
- KinectV2 在ubuntu14.04 环境下安装
- (M)SIM卡开机流程分析之默认APN设置
- 机器学习入门系列02,Regression 回归:案例研究
- 网站的海量数据和高并发的解决方案(一)
- mysql 数据库集群
- IIS发布网站
- Android基础知识07
- 226. Invert Binary Tree
- BaseAdapter的封装和实现
- spring boot csrf