logcat -s NetworkSettingsActivity EthernetImpl PppoeManager PppoeServiceImpl PppoeNetworkFactory pppd pppoe ConnectivityService
一、问题描述
应用程序API
frameworks/base/core/java/android/net/pppoe/PppoeManager.java
public void connectPppoe(final String account, final String password) {
connectPppoe(account, password, "eth0");
}
转载:linux ppp pppoe
1.在Android5.0系统上移植rp-pppoe后,并打开内核中所有相关ppp的选项;运行如下:
pppoe -d //发现pppoe-server设备,mac地址如下
21258:d8:49:0b:8b:81:5f
通过pppd认证连接:
pppd pty "pppoe -I eth0" user *********** password ******
2.结果
busybox ifconfig
eth0 Link encap:Ethernet HWaddr 00:44:22:11:44:11
inet addr:192.168.1.6 Bcast:192.168.1.255 Mask:255.255.255.0
inet6 addr: fe80::244:22ff:fe11:4411/64 Scope:Link
UP BROADCAST RUNNING ALLMULTI MULTICAST MTU:1500 Metric:1
RX packets:646 errors:0 dropped:126 overruns:0 frame:0
TX packets:994 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:30
RX bytes:410306 (400.6 KiB) TX bytes:147322 (143.8 KiB)
Interrupt:201 Base address:0x4000
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:16436 Metric:1
RX packets:14 errors:0 dropped:0 overruns:0 frame:0
TX packets:14 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:916 (916.0 B) TX bytes:916 (916.0 B)
ppp0 Link encap:Point-to-Point Protocol
inet addr:117.36.23.177 P-t-P:117.36.20.1 Mask:255.255.255.255
UP POINTOPOINT RUNNING NOARP MULTICAST MTU:1492 Metric:1
RX packets:15 errors:0 dropped:0 overruns:0 frame:0
TX packets:80 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:3
RX bytes:1098 (1.0 KiB) TX bytes:8191 (7.9 KiB)
ppp0正确获取。
busybox route -e
Kernel IP routing table
Destination Gateway Genmask Flags MSS Window irtt Iface
default 117.36.23.177 0.0.0.0 UG 0 0 0 ppp0
default * 0.0.0.0 U 0 0 0 ppp0
117.36.20.1 * 255.255.255.255 UH 0 0 0 ppp0
192.168.1.0 * 255.255.255.0 U 0 0 0 eth0
默认网关为ppp0的IP地址;也有到达拨号路由器117.36.20.1的路由。
3.错误问题
ping不通路由器网关117.36.20.1,ping不通百度。
ping www.baidu.com
busybox traceroute www.baidu.com
traceroute to www.baidu.com (180.97.33.107), 30 hops max, 38 byte packets
1 192.168.1.1 (192.168.1.1) 5.261 ms 5.137 ms 5.271 ms
2
* * *
3 * *
二、问题分析
从上边看出百度的IP180.97.33.107拿的是正确的;可以排除DNS问题。
起初怀疑是route问题;删除192.168.1.0(busybox route del -net 192.168.1.0 netmask 255.255.255.0)的route并配置其他路由(busybox route add -net 117.36.20.1 gw 117.36.23.177 netmask 255.255.0.0 ppp0)以后,问题还是存在。
后来通过ping -I ppp0 www.baidu.com,通了。
我们可以将问题定位为;网络数据在PPPOE连接以后;没有切换到PPPOE,而是还在Ethernet上。
三、Android网络切换分析
这里我们必须要通过调试Android5.0系统的网络切换策略来处理了。
1.Android系统支持的网络类型xml
frameworks/base/services/core/java/com/android/server/ConnectivityService.java
public ConnectivityService(Context context, INetworkManagementService netManager,
INetworkStatsService statsService, INetworkPolicyManager policyManager) {
......
String[] naStrings = context.getResources().getStringArray(com.android.internal.R.array.networkAttributes);
......
}
如下资源文件,也就是system/framework/framework-res.apk
frameworks/base/core/res/res/values/config.xml
- "wifi,1,1,1,-1,true"
- "ethernet,9,9,9,-1,true"
- "pppoe,18,18,1,-1,true"
上处xml中该值应该为18;系统Code错误写成15,这个定义需要如下相对应:
frameworks/base/core/java/android/net/ConnectivityManager.java
public class ConnectivityManager {
......
public static final int TYPE_WIFI = 1;
public static final int TYPE_ETHERNET = 9;
public static final int TYPE_PPPOE = 18;
public static final int MAX_RADIO_TYPE = TYPE_PPPOE;
public static final int MAX_NETWORK_TYPE = TYPE_PPPOE;
public static final int DEFAULT_NETWORK_PREFERENCE = TYPE_WIFI;
......
}
至此;系统可以通过配置文件去支持PPPOE。
2.PPPOE网络服务启动
Android系统中管理网络策略的主体为ConnectivityService,因此、需要PppoeService向其注册监听信息。
frameworks/base/services/java/com/android/server/SystemServer.java
public final class SystemServer {
private static final String PPPOE_SERVICE_CLASS =
"com.android.server.pppoe.PppoeService";
public static void main(String[] args) {
new SystemServer().run();
}
private void run() {
try {
startBootstrapServices();
startCoreServices();
startOtherServices();
} catch (Throwable ex) {
Slog.e("System", "******************************************");
Slog.e("System", "************ Failure starting system services", ex);
throw ex;
}
}
private void startOtherServices() {
//启动网络管理服务
try {
Slog.i(TAG, "NetworkManagement Service");
networkManagement = NetworkManagementService.create(context);
ServiceManager.addService(Context.NETWORKMANAGEMENT_SERVICE, networkManagement);
} catch (Throwable e) {
reportWtf("starting NetworkManagement Service", e);
}
//启动网络评分服务
try {
Slog.i(TAG, "Network Score Service");
networkScore = new NetworkScoreService(context);
ServiceManager.addService(Context.NETWORK_SCORE_SERVICE, networkScore);
} catch (Throwable e) {
reportWtf("starting Network Score Service", e);
}
//启动网络状态服务
try {
Slog.i(TAG, "NetworkStats Service");
networkStats = new NetworkStatsService(context, networkManagement, alarm);
ServiceManager.addService(Context.NETWORK_STATS_SERVICE, networkStats);
} catch (Throwable e) {
reportWtf("starting NetworkStats Service", e);
}
//启动网络策略服务
try {
Slog.i(TAG, "NetworkPolicy Service");
networkPolicy = new NetworkPolicyManagerService(
context, mActivityManagerService,
(IPowerManager)ServiceManager.getService(Context.POWER_SERVICE),
networkStats, networkManagement);
ServiceManager.addService(Context.NETWORK_POLICY_SERVICE, networkPolicy);
} catch (Throwable e) {
reportWtf("starting NetworkPolicy Service", e);
}
//启动WIFI相关服务
mSystemServiceManager.startService(WIFI_P2P_SERVICE_CLASS);
mSystemServiceManager.startService(WIFI_SERVICE_CLASS);
mSystemServiceManager.startService(
"com.android.server.wifi.WifiScanningService");
mSystemServiceManager.startService("com.android.server.wifi.RttService");
//启动以太网服务
if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_ETHERNET)) {
mSystemServiceManager.startService(ETHERNET_SERVICE_CLASS);
}
//启动PPPOE服务
if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_PPPOE)) {
mSystemServiceManager.startService(PPPOE_SERVICE_CLASS);
}
//启动网络连接服务
try {
Slog.i(TAG, "Connectivity Service");
connectivity = new ConnectivityService(
context, networkManagement, networkStats, networkPolicy);
ServiceManager.addService(Context.CONNECTIVITY_SERVICE, connectivity);
networkStats.bindConnectivityManager(connectivity);
networkPolicy.bindConnectivityManager(connectivity);
} catch (Throwable e) {
reportWtf("starting Connectivity Service", e);
}
//网络时间更新服务
try {
Slog.i(TAG, "NetworkTimeUpdateService");
networkTimeUpdater = new NetworkTimeUpdateService(context);
} catch (Throwable e) {
reportWtf("starting NetworkTimeUpdate service", e);
}
}
}
我们在这里关心其中的网络连接服务CONNECTIVITY_SERVICE和PPPOE网络服务PPPOE_SERVICE_CLASS。
frameworks/opt/net/pppoe/java/com/android/server/pppoe/PppoeService.java
public final class PppoeService extends SystemService {
final PppoeServiceImpl mImpl;
public PppoeService(Context context) {
super(context);
mImpl = new PppoeServiceImpl(context);
}
public void onBootPhase(int phase) {
if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
mImpl.start();
}
}
}
frameworks/opt/net/pppoe/java/com/android/server/pppoe/PppoeServiceImpl.java
public class PppoeServiceImpl extends IPppoeManager.Stub {
public PppoeServiceImpl(Context context) {
mContext = context;
Log.i(TAG, "Creating PppoeConfigStore");
IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
mNMService = INetworkManagementService.Stub.asInterface(b); //网络管理服务交互
mTracker = new PppoeNetworkFactory(); //重要!!!!和ConnectivityService交互
mPppoeState = "disconnect";
}
public void start() {
startMonitorThread(); //监听PPPOE或PPPD进程状态,与底层交互
Log.i(TAG, "Starting Pppoe service");
mCM = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);//网络连接状态
HandlerThread handlerThread = new HandlerThread("PppoeServiceThread");
handlerThread.start();
mHandler = new Handler(handlerThread.getLooper());
mTracker.start(mContext, mHandler);
}
private void startMonitorThread() {
mSocketThread = new Thread("pppoe_monitor_thread") {
public void run() {
LocalServerSocket server2 = new LocalServerSocket("pppoe.localsocket"); //与底层通信
/*
external/ppp/pppd/utils.c
void report_ppp_status(char interface[],int status){
char *name="pppoe.localsocket";//与java上层相同哦
}
*/
receiver2 = server2.accept();
if (receiver2 != null) {
String event = br.readLine();
handleEvent(event);
Log.i(TAG, "socket event = " + event);
}
}
};
mSocketThread.start();
}
private void handleEvent(String event) {
setPppoeStatus(pppStatus, true);
}
public void setPppoeStatus(String status, boolean sendBroadcast) {
sendPppBroadcast(mPppoeState);
}
private void sendPppBroadcast(String pppState) {
Intent intent = new Intent();
intent.setAction("android.net.pppoe.PPPOE_STATE_ACTION"/*"com.mstar.android.pppoe.PPPOE_STATE_ACTION"*/); //add by tank向PppoeNetworkFactory发送广播
intent.putExtra("PppoeStatus", pppState);
mContext.sendBroadcast(intent);
}
}
frameworks/opt/net/pppoe/java/com/android/server/pppoe/PppoeNetworkFactory.java
class PppoeNetworkFactory {
PppoeNetworkFactory() {
mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_PPPOE, 0, NETWORK_TYPE, "");
mNetworkInfo.setIsAvailable(false);
mLinkProperties = new LinkProperties();
initNetworkCapabilities();
mPppoeManager = null;
}
public synchronized void start(Context context, Handler target) {
mFactory = new LocalNetworkFactory(NETWORK_TYPE, context, target.getLooper());
mFactory.setCapabilityFilter(mNetworkCapabilities);
mFactory.setScoreFilter(-1); // this set high when we have an iface
mFactory.register(); //向ConnectivityService注册
/*
frameworks/base/core/java/android/net/NetworkFactory.java
public void register() {
if (DBG) log("Registering NetworkFactory");
if (mMessenger == null) {
mMessenger = new Messenger(this);
ConnectivityManager.from(mContext).registerNetworkFactory(mMessenger, LOG_TAG);
}
}
frameworks/base/services/core/java/com/android/server/ConnectivityService.java
public void registerNetworkFactory(Messenger messenger, String name) {
NetworkFactoryInfo nfi = new NetworkFactoryInfo(name, messenger, new AsyncChannel());
mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_FACTORY, nfi));
}
private class InternalHandler extends Handler {
public void handleMessage(Message msg) {
case EVENT_REGISTER_NETWORK_FACTORY: {
handleRegisterNetworkFactory((NetworkFactoryInfo)msg.obj);
break;
}
}
}
private void handleRegisterNetworkFactory(NetworkFactoryInfo nfi) {
if (DBG) log("Got NetworkFactory Messenger for " + nfi.name);
mNetworkFactoryInfos.put(nfi.messenger, nfi);
nfi.asyncChannel.connect(mContext, mTrackerHandler, nfi.messenger);
}
*/
mContext = context;
IntentFilter filter = new IntentFilter();
filter.addAction(PppoeManager.PPPOE_STATE_ACTION);
mPppoeStateReceiver = new PppoeStateReceiver();
mContext.registerReceiver(mPppoeStateReceiver, filter);
mNetworkAgent = null;
updateInterfaceState(true);
}
}
3.PPPOE网络状态监听
从上处2的源码情景分析中,我们看到pppd进程连接成功以后会通过“pppoe.localsocket”与PppoeServiceImpl通信;而PppoeServiceImpl会通过广播“android.net.pppoe.PPPOE_STATE_ACTION”通知PppoeNetworkFactory。下边直接看PppoeNetworkFactory。
frameworks/opt/net/pppoe/java/com/android/server/pppoe/PppoeNetworkFactory.java
class PppoeNetworkFactory {
private class PppoeStateReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
checkPppoeManager(context);
String action = intent.getAction();
if (action.equals(PppoeManager.PPPOE_STATE_ACTION)) { //广播
String pppState = intent.getStringExtra(PppoeManager.PPPOE_STATE_STATUE);
updateInterfaceState(true);
notifyStateChange(pppState); //主要是这里
}
}
}
private void notifyStateChange(String status) {
if (status.equals(PppoeManager.PPPOE_STATE_CONNECT)
|| status.equals(PppoeManager.PPPOE_STATE_DISCONNECT)) {
if (status.equals(PppoeManager.PPPOE_STATE_CONNECT)) {
updateLinkProperties(); //主要是这里
} else if (status.equals(PppoeManager.PPPOE_STATE_DISCONNECT)) {
mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED,null,null);
mNetworkInfo.setIsAvailable(false);
}
}
}
private void updateLinkProperties() {
mNetworkAgent = new NetworkAgent(mFactory.getLooper(), mContext,
NETWORK_TYPE, mNetworkInfo, mNetworkCapabilities, mLinkProperties,
NETWORK_SCORE)
}
}
frameworks/base/core/java/android/net/NetworkAgent.java
public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni,
NetworkCapabilities nc, LinkProperties lp, int score, NetworkMisc misc) {
ConnectivityManager cm = (ConnectivityManager)mContext.getSystemService(
Context.CONNECTIVITY_SERVICE);
cm.registerNetworkAgent(new Messenger(this), new NetworkInfo(ni),
new LinkProperties(lp), new NetworkCapabilities(nc), score, misc);
}
frameworks/base/services/core/java/com/android/server/ConnectivityService.java
public void registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo,
LinkProperties linkProperties, NetworkCapabilities networkCapabilities,
int currentScore, NetworkMisc networkMisc) {
mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_AGENT, nai));
}
//消息机制不分析了,同上边registerNetworkFactory
private void handleRegisterNetworkAgent(NetworkAgentInfo na) {
updateNetworkInfo(na, networkInfo);
}
private void updateNetworkInfo(NetworkAgentInfo networkAgent, NetworkInfo newInfo) {
rematchNetworkAndRequests(networkAgent, false);
}
private void rematchNetworkAndRequests(NetworkAgentInfo newNetwork, boolean nascent) {
if (currentNetwork == null ||
currentNetwork.getCurrentScore() <= newNetwork.getCurrentScore()) { //modify by tank from < to <=
if (currentNetwork != null) {
if (DBG) log(" accepting network in place of " + currentNetwork.name());
currentNetwork.networkRequests.remove(nri.request.requestId);
currentNetwork.networkLingered.add(nri.request);
affectedNetworks.add(currentNetwork);
} else {
if (DBG) log(" accepting network in place of null");
}
......
keep = true;
......
sendUpdatedScoreToFactories(nri.request, newNetwork.getCurrentScore());
if (mDefaultRequest.requestId == nri.request.requestId) {
isNewDefault = true;
}
}
}
......
if (keep) {
if (isNewDefault) {
makeDefault(newNetwork);
synchronized (ConnectivityService.this) {
if (mNetTransitionWakeLock.isHeld()) {
mHandler.sendMessageDelayed(mHandler.obtainMessage(
EVENT_CLEAR_NET_TRANSITION_WAKELOCK,
mNetTransitionWakeLockSerialNumber, 0),
1000);
}
}
}
}
}
从上处代码可以看到;核心处理网卡切换是在ConnectivityService.java中rematchNetworkAndRequests函数的上处片段,具体执行到最底层是什么操作、我还没有研究。
有机会在做往下层的分析。
四、问题解决
我们知道了问题所在;网络没有从Ethernet切换到PPPOE。
问题解决:PPPOE在连接以后通过广播机制通知ConnectivityService.java在rematchNetworkAndRequests函数中最切换。