移动数据流程
切入点,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
// FIXMEthis 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 事件
}
16DataConnection.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)

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); // 进入数据模式(结束)
.....

}



本文转自:http://www.eoeandroid.com/forum.php?mod=viewthread&tid=246675

不知道是不是源头,感谢原作者。

更多相关文章

  1. mybatisplus的坑 insert标签insert into select无参数问题的解决
  2. 箭头函数的基础使用
  3. python起点网月票榜字体反爬案例
  4. Python技巧匿名函数、回调函数和高阶函数
  5. Android(安卓)UI学习 - Tab的学习和使用
  6. Android调用蓝牙功能
  7. Android下载网络图片到本地
  8. Android下调用收发短信邮件等
  9. 如何在Android设备中用NDK编译SQLite并且对SQLite进行操作(增删)-H

随机推荐

  1. color用法大全--Android布局背景颜色设置
  2. mac环境变量配置
  3. (转)#小美化#android 按钮圆角
  4. Android使用七牛上传图片踩坑及解决方案
  5. Android客户端和服务器端数据交互的第二
  6. Android——使用DatePicker和TimePicker
  7. Android判断当前界面是否是桌面(主页)
  8. 设置 quick-cocos2d-x 在 Mac 下的编译环
  9. android 如何中断一个子线程
  10. Android(安卓)高级编程--Fragment理解与