移动数据流程 切入点,setting 中 ”启用移动数据“ 1: Settings.java (packages\apps\phone\src\com\android\phone) 开始点击启用移动数据的按钮 protected void onCreate(Bundle icicle) { super.onCreate(icicle); addPreferencesFromResource(R.xml.network_setting); .... mButtonDataEnabled = (CheckBoxPreference) prefSet.findPreference(BUTTON_DATA_ENABLED_KEY); // 启动移动数据的按钮 2: Settings.java (packages\apps\phone\src\com\android\phone) 点击启用移动数据 执行代码: cm.setMobileDataEnabled(mButtonDataEnabled.isChecked());// 网络数据开关 打开后执行的语句 public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) { /** TODO: Refactor and get rid of the if's using subclasses */ .... } else if (preference == mButtonDataEnabled) { if (DBG) log("onPreferenceTreeClick: preference == mButtonDataEnabled."); ConnectivityManager cm = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE); cm.setMobileDataEnabled(mButtonDataEnabled.isChecked());// lhj enable 网络数据开关 调用 setMobileDateEnabled 函数 return true; } .... } 3: ConnectivityManager.java (frameworks\base\core\java\android\net) 调用 setMobileDataEnabled 函数 public void setMobileDataEnabled(boolean enabled) { // setMobileDataEnabled 函数 try { mService.setMobileDataEnabled(enabled); // 调用 ConnectivityService.java 中的 setMobileDateEnabled 函数 } catch (RemoteException e) { } } 4: ConnectivityService.java (frameworks\base\services\java\com\android\server) 调用 setMobileDateEnabled 函数 public void setMobileDataEnabled(boolean enabled) { enforceChangePermission();// 获取权限 if (DBG) log("setMobileDataEnabled(" + enabled + ")"); mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_MOBILE_DATA, (enabled ? ENABLED : DISABLED), 0));// 发送消息 EVENT_SET_MOBILE_DATA } 5:ConnectivityService.java (frameworks\base\services\java\com\android\server) public void handleMessage(Message msg) { NetworkInfo info; switch (msg.what) { ....... case EVENT_SET_MOBILE_DATA: // 收到消息后 执行case EVENT_SET_MOBILE_DATA { boolean enabled = (msg.arg1 == ENABLED); handleSetMobileData(enabled);//事件触发后设置移动数据 执行handleSetMobileData 函数 break; } ....... 6: ConnectivityService.java (frameworks\base\services\java\com\android\server) handleSetMobileData 函数 private void handleSetMobileData(boolean enabled) { if (mNetTrackers[ConnectivityManager.TYPE_MOBILE] != null) { if (VDBG) { log(mNetTrackers[ConnectivityManager.TYPE_MOBILE].toString() + enabled); } mNetTrackers[ConnectivityManager.TYPE_MOBILE].setUserDataEnable(enabled);// 调用setUserDataEnable 函数 } } 7:MobileDataStateTracker.java (frameworks\base\core\java\android\net) 调用setUserDataEnable 函数 public void setUserDataEnable(boolean enabled) { // setUserDataEnable 被调用 if (DBG) log("setUserDataEnable: E enabled=" + enabled); final AsyncChannel channel = mDataConnectionTrackerAc; if (channel != null) { channel.sendMessage(CMD_SET_USER_DATA_ENABLE, enabled ? ENABLED : DISABLED);// 发送消息 CMD_SET_USER_DATA_ENABLE mUserDataEnabled = enabled; } if (VDBG) log("setUserDataEnable: X enabled=" + enabled); } 8:DataConnectionTracker.java (frameworks\base\telephony\java\com\android\internal\telephony) 接收消息并处理 CMD_SET_USER_DATA_ENABLE public void handleMessage(Message msg) { switch (msg.what) { ....... case CMD_SET_USER_DATA_ENABLE: { // 接受 CMD_SET_USER_DATA_ENABLE 并执行case CMD_SET_USER_DATA_ENABLE final boolean enabled = (msg.arg1 == ENABLED) ? true : false; if (DBG) log("CMD_SET_USER_DATA_ENABLE enabled=" + enabled); onSetUserDataEnabled(enabled); //调用 OnSetUserDataEnable 函数 break; } ....... 9:DataConnectionTracker.java (frameworks\base\telephony\java\com\android\internal\telephony) 调用 OnSetUserDataEnable 函数 protected void onSetUserDataEnabled(boolean enabled) { // OnSetUserDataEnable 函数 synchronized (mDataEnabledLock) { final boolean prevEnabled = getAnyDataEnabled(); if (mUserDataEnabled != enabled) { mUserDataEnabled = enabled; Settings.Secure.putInt(mPhone.getContext().getContentResolver(), Settings.Secure.MOBILE_DATA, enabled ? 1 : 0); if (prevEnabled != getAnyDataEnabled()) { if (!prevEnabled) { resetAllRetryCounts(); onTrySetupData(Phone.REASON_DATA_ENABLED); // 调用onTrySetupData 函数 } else { onCleanUpAllConnections(Phone.REASON_DATA_DISABLED); } } } } } 10: GsmDataConnectionTracker.java (frameworks\base\telephony\java\com\android\internal\telephony\gsm) 调用onTrySetupData 函数 protected boolean onTrySetupData(String reason) { //onTrySetupData 函数 if (DBG) log("onTrySetupData: reason=" + reason); setupDataOnReadyApns(reason); // 调用setupDataOnReadyApns 函数 检查APN 列表 return true; } 11:GsmDataConnectionTracker.java (frameworks\base\telephony\java\com\android\internal\telephony\gsm) 调用setupDataOnReadyApns 函数 private void setupDataOnReadyApns(String reason) { // setupDataOnReadyApns 函数 .... // Only check for default APN state for (ApnContext apnContext : mApnContexts.values()) { if (apnContext.getState() == State.FAILED) { // By this time, alarms for all failed Apns // should be stopped if any. // Make sure to set the state back to IDLE // so that setup data can happen. apnContext.setState(State.IDLE); } if (apnContext.isReady()) { if (apnContext.getState() == State.IDLE) { apnContext.setReason(reason); trySetupData(apnContext); // apn ready 调用 trySetupData 函数 } } } } 12:GsmDataConnectionTracker.java (frameworks\base\telephony\java\com\android\internal\telephony\gsm) 调用 trySetupData 函数 private boolean trySetupData(ApnContext apnContext) {// trySetupData 函数 (关键函数) if (mPhone.getSimulatedRadioControl() != null) { // Assume data is connected on the simulator // FIXME this can be improved apnContext.setState(State.CONNECTED); // 调用setState 方法 mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType()); log("trySetupData: (fix?) We're on the simulator; assuming data is connected"); return true; } boolean desiredPowerState = mPhone.getServiceStateTracker().getDesiredPowerState(); if ((apnContext.getState() == State.IDLE || apnContext.getState() == State.SCANNING) && isDataAllowed(apnContext) && getAnyDataEnabled() && !isEmergency()) { if (apnContext.getState() == State.IDLE) { ArrayList<ApnSetting> waitingApns = buildWaitingApns(apnContext.getApnType()); if (waitingApns.isEmpty()) { if (DBG) log("trySetupData: No APN found"); notifyNoData(GsmDataConnection.FailCause.MISSING_UNKNOWN_APN, apnContext); notifyOffApnsOfAvailability(apnContext.getReason()); return false; } else { apnContext.setWaitingApns(waitingApns); if (DBG) { log ("trySetupData: Create from mAllApns : " + apnListToString(mAllApns)); } } } boolean retValue = setupData(apnContext);// 得到retValue 调用函数setupData 继续流程 14 步 notifyOffApnsOfAvailability(apnContext.getReason()); return retValue; } else { // TODO: check the condition. if (!apnContext.getApnType().equals(Phone.APN_TYPE_DEFAULT) && (apnContext.getState() == State.IDLE || apnContext.getState() == State.SCANNING)) mPhone.notifyDataConnectionFailed(apnContext.getReason(), apnContext.getApnType()); notifyOffApnsOfAvailability(apnContext.getReason()); return false; } } 13:ApnContext.java (frameworks\base\telephony\java\com\android\internal\telephony) (与流程无关) setState 方法 public synchronized void setState(DataConnectionTracker.State s) { // synchronized 关键字作用为锁定调用这个方法的对象 其他对象不能调用 if (DBG) { log("setState: " + s + " for type " + mApnType + ", previous state:" + mState); } mState = s; // 只是对于网络状态的改变 if (mState == DataConnectionTracker.State.FAILED) { if (mWaitingApns != null) { mWaitingApns.clear(); // when teardown the connection and set to IDLE } } } 14: GsmDataConnectionTracker.java (frameworks\base\telephony\java\com\android\internal\telephony\gsm) setupData 函数 private boolean setupData(ApnContext apnContext) { .... Message msg = obtainMessage(); msg.what = EVENT_DATA_SETUP_COMPLETE; msg.obj = apnContext; dc.bringUp(msg, apn); // 发送消息 调用bringup 继续往下 if (DBG) log("setupData: initing!"); return true; } 15:DataConnection.java (frameworks\base\telephony\java\com\android\internal\telephony) bringUp 函数 public void bringUp(Message onCompletedMsg, ApnSetting apn) { sendMessage(obtainMessage(EVENT_CONNECT, new ConnectionParams(apn, onCompletedMsg))); // 发送EVENT_CONNECT 事件 } 16 DataConnection.java (frameworks\base\telephony\java\com\android\internal\telephony) 收到EVENT_CONNECT 后执行的代码 public boolean processMessage(Message msg) { boolean retVal; switch (msg.what) { ...... case EVENT_CONNECT: ConnectionParams cp = (ConnectionParams) msg.obj; cp.tag = mTag; if (DBG) { log("DcInactiveState msg.what=EVENT_CONNECT." + "RefCount = " + mRefCount); } mRefCount = 1; onConnect(cp); // 调用onConnect 方法 transitionTo(mActivatingState); retVal = HANDLED; break; ...... 17: GsmDataConnection.java (frameworks\base\telephony\java\com\android\internal\telephony\gsm) onConnect 方法 void onConnect(ConnectionParams cp) { mApn = cp.apn; .... String protocol; if (phone.getServiceState().getRoaming()) { protocol = mApn.roamingProtocol; } else { protocol = mApn.protocol; } phone.mCM.setupDataCall( // 调用 setupDataCall 方法 Integer.toString(getRadioTechnology(RILConstants.SETUP_DATA_TECH_GSM)), Integer.toString(mProfileId), mApn.apn, mApn.user, mApn.password, Integer.toString(authType), protocol, msg); } 18: CommandsInterface.java (frameworks\base\telephony\java\com\android\internal\telephony) setupDataCall 函数的接口 函数原型在ril.java 中 (19步) public void setupDataCall(String radioTechnology, String profile, String apn, String user, String password, String authType, String protocol, Message result); 19 : RIL.java (frameworks\base\telephony\java\com\android\internal\telephony) setupDataCall 函数 public void setupDataCall(String radioTechnology, String profile, String apn, String user, String password, String authType, String protocol, Message result) { RILRequest rr = RILRequest.obtain(RIL_REQUEST_SETUP_DATA_CALL, result); //RIL_REQUEST_SETUP_DATA_CALL rr.mp.writeInt(7); rr.mp.writeString(radioTechnology); rr.mp.writeString(profile); rr.mp.writeString(apn); rr.mp.writeString(user); rr.mp.writeString(password); rr.mp.writeString(authType); rr.mp.writeString(protocol); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " " + radioTechnology + " " + profile + " " + apn + " " + user + " " + password + " " + authType + " " + protocol); send(rr); // 发送RIL_REQUEST_SETUP_DATA_CALL 请求 ( 到达RIL ) 20: Marvell-ril.c (hardware\ril\marvell-ril) (此文件为CP平台文件,android 自带的是reference-ril.c,以下分析为marvell平台) RIL_REQUEST_SETUP_DATA_CALL 对应的响应 static const struct request_info s_requests [] = { ..... {RIL_REQUEST_SETUP_DATA_CALL, SERVICE_PS,ril_request_setup_data_call},//ril_request_setup_data_call 方法 ..... } 21 : Ril-ps.c (hardware\ril\marvell-ril) ril_request_setup_data_call 方法 void ril_request_setup_data_call(int request, void *data, size_t datalen, RIL_Token token) { UNUSED(request); UNUSED(datalen); const char* radio_technology = ((const char **)data)[0]; const char* profile_type = ((const char **)data)[1]; const char* apn = ((const char **)data)[2]; const char* user = ((const char **)data)[3]; const char* passwd = ((const char **)data)[4]; const char* auth_type_str = ((const char **)data)[5]; const char* protocol = ((const char **)data)[6]; int profile = atoi(profile_type); int auth_type = atoi(auth_type_str); LOGD("%s: profile_type=%d, apn=%s, user=%s,passwd=%s,auth_type=%d, protocol=%s", __FUNCTION__, profile, apn, user ? user : "NULL", passwd ? passwd : "NULL", auth_type, protocol); syncSetupDefaultPDPConnection(token, profile, apn, auth_type, user, passwd, protocol); //继续syncSetupDefaultPDPConnection函数 } 22:Ril-ps.c (hardware\ril\marvell-ril) syncSetupDefaultPDPConnection函数 /* Prossess RIL_REQUEST_SETUP_DATA_CALL in sync way*/ static void syncSetupDefaultPDPConnection(RIL_Token token, int profile, const char* apn, int auth_type, const char* user, const char* passwd, const char* protocol) { ATResponse *p_response = NULL; int err = -1; int cid; RIL_Data_Call_Response result; char cmdString[MAX_AT_LENGTH]; char ipaddress[64]; char cid_str[8]; char ifname[32]; int is_ppp = is_ppp_enabled(); int af = strcasecmp(protocol, "IPv6") ? AF_INET: AF_INET6; if (is_ppp)// For PPP connection, alway use default one { profile = RIL_DATA_PROFILE_DEFAULT; //Ril.h (hardware\ril\mock-ril\src\cpp) 中RIL_DATA_PROFILE_DEFAULT=0 } if(profile < RIL_DATA_PROFILE_DEFAULT || profile >= MAX_DATA_CALLS) { LOGW("RIL_REQUEST_SETUP_DATA_CALL: Profile %d unsupportted! \n", profile); goto error; } cid = profile + 1; // cid=1 snprintf(cid_str, sizeof(cid_str), "%d", cid); snprintf(ifname, sizeof(ifname), modemType == WUKONG ? "ccinetwk%d" : "ccinet%d", profile); result.status = PDP_FAIL_NONE; result.cid = cid; result.ifname = is_ppp ? "ppp0" : ifname; result.type = (char*)protocol; err = getInterfaceAddr(af, result.ifname, ipaddress); //if same data profile is active and APN is same, return SUCCESS if (err == 0 && g_datacalls[profile].apn[0] && strcmp(apn, g_datacalls[profile].apn) == 0) { LOGD("The PDP CID %s is already active: IP address %s for Inteface %s", cid_str, ipaddress, result.ifname); result.addresses = ipaddress; result.dnses= getDNSList(result.ifname); result.gateways= getGateway(result.ifname); if(strlen(result.addresses) > 0) result.active = 2; RIL_onRequestComplete(token, RIL_E_SUCCESS, &result, sizeof(result)); return; } else if(err == 0)// if the same data profile is active and APN is changed, deactive it { LOGD("Data profile %d change APN from %s to %s, deactive cid %s firstly", profile, g_datacalls[profile].apn, apn, cid_str); sprintf(cmdString, "AT+CGACT=0,%s", cid_str); at_send_command_timeout(cmdString, NULL, TIMEOUT_CGACT_DEACT); sleep(3); //Workaround: it seems CP need sometime to clear the previous PDP context before reactiving it } /* Step1: Define the CID */ sprintf(cmdString, "AT+CGDCONT=%s,\"%s\",\"%s\"", cid_str, protocol, apn ); err = at_send_command(cmdString, &p_response); if (err < 0 || p_response->success == 0) { LOGW("Fail to define the PDP context: %s", cid_str); sprintf(cmdString, "AT+CGACT=0,%s", cid_str); at_send_command_timeout(cmdString, NULL, TIMEOUT_CGACT_DEACT); goto error; } at_response_free(p_response); p_response = NULL; /* Step2: set PPP auth parameters for direct IP type*/ if (!is_ppp) { if(auth_type == 3) //PAP /CHAP may be performed - baseband dependent. auth_type = 1; //use PAP as default sprintf(cmdString, "AT*AUTHReq=%s,%d,%s,%s", cid_str, auth_type, user ? user : "", passwd ? passwd : ""); at_send_command(cmdString, NULL); } /* Step3: Active the PDP Context */ sprintf(cmdString, "AT+CGDATA=\"%s\",%s", is_ppp ? "PPP" : "", cid_str); // 进入数据模式(结束) ..... } |
android 打开移动数据流程
最新推荐文章于 2024-07-11 15:36:44 发布