Android5.0网络策略导致PPPOE无法正常上网

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函数中最切换。

你可能感兴趣的:(移动操作系统之Android)