Android(安卓)6.0 Ethernet流程分析记录
1、Android 开机后,启动系统服务EthernetService(frameworks/opt/net/ethernet/java/com/android/server/ethnet/EthernetService.java),初始化一个EthernetServiceImpl(frameworks/opt/net/ethernet/java/com/android/server/ethnet/EthernetServiceImpl.java)对象,然后调用EthernetServiceImpl的start()方法;
2、初始化EthernetServiceImpl对象,创建EthernetConfigStore对象并调用readIpAndProxyConfigurations()方法,获取Ethernet 配置信息得到IpConfiguration对象;
public EthernetServiceImpl(Context context) { mContext = context; Log.i(TAG, "Creating EthernetConfigStore"); mEthernetConfigStore = new EthernetConfigStore(); mIpConfiguration = mEthernetConfigStore.readIpAndProxyConfigurations(); Log.i(TAG, "Read stored IP configuration: " + mIpConfiguration); mTracker = new EthernetNetworkFactory(mListeners); }
3、调用EthernetServiceImpl.start()方法,
public void start() { Log.i(TAG, "Starting Ethernet service"); HandlerThread handlerThread = new HandlerThread("EthernetServiceThread"); handlerThread.start(); mHandler = new Handler(handlerThread.getLooper()); mTracker.start(mContext, mHandler); mStarted.set(true); }
主要是进入EthernetNetworkFactory.start() ,注册相关监听,开启网络配置
public synchronized void start(Context context, Handler target) { // The services we use. IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); mNMService = INetworkManagementService.Stub.asInterface(b); mEthernetManager = (EthernetManager) context.getSystemService(Context.ETHERNET_SERVICE); // Interface match regex. mIfaceMatch = context.getResources().getString( com.android.internal.R.string.config_ethernet_iface_regex); // Create and register our NetworkFactory. mFactory = new LocalNetworkFactory(NETWORK_TYPE, context, target.getLooper()); mFactory.setCapabilityFilter(mNetworkCapabilities); mFactory.setScoreFilter(-1); // this set high when we have an iface mFactory.register(); mContext = context; mHandler = target;//201808016 chen // Start tracking interface change events. mInterfaceObserver = new InterfaceObserver(); try { mNMService.registerObserver(mInterfaceObserver); } catch (RemoteException e) { Log.e(TAG, "Could not register InterfaceObserver " + e); } // If an Ethernet interface is already connected, start tracking that. // Otherwise, the first Ethernet interface to appear will be tracked. try { final String[] ifaces = mNMService.listInterfaces(); for (String iface : ifaces) { synchronized(this) { if (maybeTrackInterface(iface)) { // We have our interface. Track it. // Note: if the interface already has link (e.g., if we // crashed and got restarted while it was running), // we need to fake a link up notification so we start // configuring it. Since we're already holding the lock, // any real link up/down notification will only arrive // after we've done this.//个人修改 if(!iface.equals("eth0")) { continue; }// if (mNMService.getInterfaceConfig(iface).hasFlag("running")) { updateInterfaceState(iface, true); } break; } } } } catch (RemoteException|IllegalStateException e) { Log.e(TAG, "Could not get list of interfaces " + e); } }
4、读取网络配置方法
EthernetConfigStore.readIpAndProxyConfigurations()如下,EthernetConfigStore 继承自 IpConfigStore
private static final String ipConfigFile = Environment.getDataDirectory() + "/misc/ethernet/ipconfig.txt"; public IpConfiguration readIpAndProxyConfigurations() { SparseArray networks = readIpAndProxyConfigurations(ipConfigFile);//d调用IpConfigStore中的方法 if (networks.size() == 0) { Log.w(TAG, "No Ethernet configuration found. Using default."); return new IpConfiguration(IpAssignment.DHCP, ProxySettings.NONE, null, null); } if (networks.size() > 1) { // Currently we only support a single Ethernet interface. Log.w(TAG, "Multiple Ethernet configurations detected. Only reading first one."); } return networks.valueAt(0); }
5、设置以太网,通过EthManager.setConfiguration(IpConfiguration)方法事件是调用的EthernetServiceImpl.setConfiguration
/** * Set Ethernet configuration */ @Override public void setConfiguration(IpConfiguration config) { if (!mStarted.get()) { Log.w(TAG, "System isn't ready enough to change ethernet configuration"); } enforceConnectivityInternalPermission(); synchronized (mIpConfiguration) { mEthernetConfigStore.writeIpAndProxyConfigurations(config); // TODO: this does not check proxy settings, gateways, etc. // Fix this by making IpConfiguration a complete representation of static configuration. if (!config.equals(mIpConfiguration)) { mIpConfiguration = new IpConfiguration(config); mTracker.stop(); mTracker.start(mContext, mHandler); } } }
在 setConfiguration中调用EthernetConfigStore.writeIpAndProxyConfigurations();将配置写入文件data//misc/ethernet/ipconfig.txt
public void writeIpAndProxyConfigurations(IpConfiguration config) { SparseArray networks = new SparseArray(); networks.put(0, config); writeIpAndProxyConfigurations(ipConfigFile, networks); }
同时调用mTracker.start(mContext, mHandler);
/** * Begin monitoring connectivity */ public synchronized void start(Context context, Handler target) { // The services we use. IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); mNMService = INetworkManagementService.Stub.asInterface(b); mEthernetManager = (EthernetManager) context.getSystemService(Context.ETHERNET_SERVICE); // Interface match regex. mIfaceMatch = context.getResources().getString( com.android.internal.R.string.config_ethernet_iface_regex); // Create and register our NetworkFactory. mFactory = new LocalNetworkFactory(NETWORK_TYPE, context, target.getLooper()); mFactory.setCapabilityFilter(mNetworkCapabilities); mFactory.setScoreFilter(-1); // this set high when we have an iface mFactory.register(); mContext = context; // Start tracking interface change events. mInterfaceObserver = new InterfaceObserver(); try { mNMService.registerObserver(mInterfaceObserver); } catch (RemoteException e) { Log.e(TAG, "Could not register InterfaceObserver " + e); } // If an Ethernet interface is already connected, start tracking that. // Otherwise, the first Ethernet interface to appear will be tracked. try { final String[] ifaces = mNMService.listInterfaces(); for (String iface : ifaces) { synchronized(this) { if (maybeTrackInterface(iface)) { // We have our interface. Track it. // Note: if the interface already has link (e.g., if we // crashed and got restarted while it was running), // we need to fake a link up notification so we start // configuring it. Since we're already holding the lock, // any real link up/down notification will only arrive // after we've done this. if (mNMService.getInterfaceConfig(iface).hasFlag("running")) { updateInterfaceState(iface, true); } break; } } } } catch (RemoteException|IllegalStateException e) { Log.e(TAG, "Could not get list of interfaces " + e); } }
发现进入maybeTrackInterface()方法,然后进入setInterfaceUp(),此时发现又调用了NetworkManagementService中的方法
frameworks/base/services/core/java/com/android/server/NetworkManagementService.java
private boolean maybeTrackInterface(String iface) { // If we don't already have an interface, and if this interface matches // our regex, start tracking it. if (!iface.matches(mIfaceMatch) || isTrackingInterface()) return false; Log.d(TAG, "Started tracking interface " + iface); try { setInterfaceUp(iface); } catch (IllegalStateException e) { Log.e(TAG, e.toString() + " (Ethernet IF abnormal)"); return false; } return true; } private void setInterfaceUp(String iface) { // Bring up the interface so we get link status indications. try { NetworkUtils.stopDhcp(iface); mNMService.setInterfaceUp(iface); String hwAddr = null; InterfaceConfiguration config = mNMService.getInterfaceConfig(iface); if (config == null) { Log.e(TAG, "Null iterface config for " + iface + ". Bailing out."); return; } synchronized (this) { if (!isTrackingInterface()) { setInterfaceInfoLocked(iface, config.getHardwareAddress()); mNetworkInfo.setIsAvailable(true); mNetworkInfo.setExtraInfo(mHwAddr); } else { Log.e(TAG, "Interface unexpectedly changed from " + iface + " to " + mIface); mNMService.setInterfaceDown(iface); } } } catch (RemoteException e) { Log.e(TAG, "Error upping interface " + mIface + ": " + e); } }
发现在NetworkManagementService中主要是通过setInterfaceConfig方法与底层通信,通过构建Command ,然后通过NativeDaemonConnector发送命令。
frameworks/base/services/core/java/com/android/server/NativeDaemonConnector.java
@Override public void setInterfaceDown(String iface) { mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); final InterfaceConfiguration ifcg = getInterfaceConfig(iface); ifcg.setInterfaceDown(); setInterfaceConfig(iface, ifcg); } @Override public void setInterfaceUp(String iface) { mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); final InterfaceConfiguration ifcg = getInterfaceConfig(iface); ifcg.setInterfaceUp(); setInterfaceConfig(iface, ifcg); }@Override public void setInterfaceConfig(String iface, InterfaceConfiguration cfg) { mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); LinkAddress linkAddr = cfg.getLinkAddress(); if (linkAddr == null || linkAddr.getAddress() == null) { throw new IllegalStateException("Null LinkAddress given"); } final Command cmd = new Command("interface", "setcfg", iface, linkAddr.getAddress().getHostAddress(), linkAddr.getPrefixLength()); for (String flag : cfg.getFlags()) { cmd.appendArg(flag); } try { mConnector.execute(cmd); } catch (NativeDaemonConnectorException e) { throw e.rethrowAsParcelableException(); } }
附:IpConfigStore.java(frameworks/base/services/core/java/com/android/server/net/IpConfigStore.java),最终读取网络配置,设置网络等都会调用IpConfigStore中的方法
public class IpConfigStore { private static final String TAG = "IpConfigStore"; private static final boolean DBG = true; protected final DelayedDiskWrite mWriter; /* IP and proxy configuration keys */ protected static final String ID_KEY = "id"; protected static final String IP_ASSIGNMENT_KEY = "ipAssignment"; protected static final String LINK_ADDRESS_KEY = "linkAddress"; protected static final String GATEWAY_KEY = "gateway"; protected static final String DNS_KEY = "dns"; protected static final String PROXY_SETTINGS_KEY = "proxySettings"; protected static final String PROXY_HOST_KEY = "proxyHost"; protected static final String PROXY_PORT_KEY = "proxyPort"; protected static final String PROXY_PAC_FILE = "proxyPac"; protected static final String EXCLUSION_LIST_KEY = "exclusionList"; protected static final String EOS = "eos"; protected static final int IPCONFIG_FILE_VERSION = 2; public IpConfigStore() { mWriter = new DelayedDiskWrite(); } private boolean writeConfig(DataOutputStream out, int configKey, IpConfiguration config) throws IOException { boolean written = false; try { switch (config.ipAssignment) { case STATIC: out.writeUTF(IP_ASSIGNMENT_KEY); out.writeUTF(config.ipAssignment.toString()); StaticIpConfiguration staticIpConfiguration = config.staticIpConfiguration; if (staticIpConfiguration != null) { if (staticIpConfiguration.ipAddress != null) { LinkAddress ipAddress = staticIpConfiguration.ipAddress; out.writeUTF(LINK_ADDRESS_KEY); out.writeUTF(ipAddress.getAddress().getHostAddress()); out.writeInt(ipAddress.getPrefixLength()); } if (staticIpConfiguration.gateway != null) { out.writeUTF(GATEWAY_KEY); out.writeInt(0); // Default route. out.writeInt(1); // Have a gateway. out.writeUTF(staticIpConfiguration.gateway.getHostAddress()); } for (InetAddress inetAddr : staticIpConfiguration.dnsServers) { out.writeUTF(DNS_KEY); out.writeUTF(inetAddr.getHostAddress()); } } written = true; break; case DHCP: out.writeUTF(IP_ASSIGNMENT_KEY); out.writeUTF(config.ipAssignment.toString()); written = true; break; case UNASSIGNED: /* Ignore */ break; default: loge("Ignore invalid ip assignment while writing"); break; } switch (config.proxySettings) { case STATIC: ProxyInfo proxyProperties = config.httpProxy; if(proxyProperties==null){break;} String exclusionList = proxyProperties.getExclusionListAsString(); out.writeUTF(PROXY_SETTINGS_KEY); out.writeUTF(config.proxySettings.toString()); out.writeUTF(PROXY_HOST_KEY); out.writeUTF(proxyProperties.getHost()); out.writeUTF(PROXY_PORT_KEY); out.writeInt(proxyProperties.getPort()); if (exclusionList != null) { out.writeUTF(EXCLUSION_LIST_KEY); out.writeUTF(exclusionList); } written = true; break; case PAC: ProxyInfo proxyPacProperties = config.httpProxy; if(proxyProperties==null){break;} out.writeUTF(PROXY_SETTINGS_KEY); out.writeUTF(config.proxySettings.toString()); out.writeUTF(PROXY_PAC_FILE); out.writeUTF(proxyPacProperties.getPacFileUrl().toString()); written = true; break; case NONE: out.writeUTF(PROXY_SETTINGS_KEY); out.writeUTF(config.proxySettings.toString()); written = true; break; case UNASSIGNED: /* Ignore */ break; default: loge("Ignore invalid proxy settings while writing"); break; } if (written) { out.writeUTF(ID_KEY); out.writeInt(configKey); }else{ loge("written false"); } } catch (NullPointerException e) { loge("Failure in writing " + config + e); } out.writeUTF(EOS); return written; } public void writeIpAndProxyConfigurations(String filePath, final SparseArray networks) { mWriter.write(filePath, new DelayedDiskWrite.Writer() { public void onWriteCalled(DataOutputStream out) throws IOException{ out.writeInt(IPCONFIG_FILE_VERSION); for(int i = 0; i < networks.size(); i++) { writeConfig(out, networks.keyAt(i), networks.valueAt(i)); } } }); } public SparseArray readIpAndProxyConfigurations(String filePath) { SparseArray networks = new SparseArray(); DataInputStream in = null; try { in = new DataInputStream(new BufferedInputStream(new FileInputStream(filePath))); int version = in.readInt(); if (version != 2 && version != 1) { loge("Bad version on IP configuration file, ignore read"); return null; } while (true) { int id = -1; // Default is DHCP with no proxy IpAssignment ipAssignment = IpAssignment.DHCP; ProxySettings proxySettings = ProxySettings.NONE; StaticIpConfiguration staticIpConfiguration = new StaticIpConfiguration(); String proxyHost = null; String pacFileUrl = null; int proxyPort = -1; String exclusionList = null; String key; do { key = in.readUTF(); try { if (key.equals(ID_KEY)) { id = in.readInt(); } else if (key.equals(IP_ASSIGNMENT_KEY)) { ipAssignment = IpAssignment.valueOf(in.readUTF()); } else if (key.equals(LINK_ADDRESS_KEY)) { LinkAddress linkAddr = new LinkAddress( NetworkUtils.numericToInetAddress(in.readUTF()), in.readInt()); if (linkAddr.getAddress() instanceof Inet4Address && staticIpConfiguration.ipAddress == null) { staticIpConfiguration.ipAddress = linkAddr; } else { loge("Non-IPv4 or duplicate address: " + linkAddr); } } else if (key.equals(GATEWAY_KEY)) { LinkAddress dest = null; InetAddress gateway = null; if (version == 1) { // only supported default gateways - leave the dest/prefix empty gateway = NetworkUtils.numericToInetAddress(in.readUTF()); if (staticIpConfiguration.gateway == null) { staticIpConfiguration.gateway = gateway; } else { loge("Duplicate gateway: " + gateway.getHostAddress()); } } else { if (in.readInt() == 1) { dest = new LinkAddress( NetworkUtils.numericToInetAddress(in.readUTF()), in.readInt()); } if (in.readInt() == 1) { gateway = NetworkUtils.numericToInetAddress(in.readUTF()); } RouteInfo route = new RouteInfo(dest, gateway); if (route.isIPv4Default() && staticIpConfiguration.gateway == null) { staticIpConfiguration.gateway = gateway; } else { loge("Non-IPv4 default or duplicate route: " + route); } } } else if (key.equals(DNS_KEY)) { staticIpConfiguration.dnsServers.add( NetworkUtils.numericToInetAddress(in.readUTF())); } else if (key.equals(PROXY_SETTINGS_KEY)) { proxySettings = ProxySettings.valueOf(in.readUTF()); } else if (key.equals(PROXY_HOST_KEY)) { proxyHost = in.readUTF(); } else if (key.equals(PROXY_PORT_KEY)) { proxyPort = in.readInt(); } else if (key.equals(PROXY_PAC_FILE)) { pacFileUrl = in.readUTF(); } else if (key.equals(EXCLUSION_LIST_KEY)) { exclusionList = in.readUTF(); } else if (key.equals(EOS)) { break; } else { loge("Ignore unknown key " + key + "while reading"); } } catch (IllegalArgumentException e) { loge("Ignore invalid address while reading" + e); } } while (true); if (id != -1) { IpConfiguration config = new IpConfiguration(); networks.put(id, config); switch (ipAssignment) { case STATIC: config.staticIpConfiguration = staticIpConfiguration; config.ipAssignment = ipAssignment; break; case DHCP: config.ipAssignment = ipAssignment; break; case UNASSIGNED: loge("BUG: Found UNASSIGNED IP on file, use DHCP"); config.ipAssignment = IpAssignment.DHCP; break; default: loge("Ignore invalid ip assignment while reading."); config.ipAssignment = IpAssignment.UNASSIGNED; break; } switch (proxySettings) { case STATIC: ProxyInfo proxyInfo = new ProxyInfo(proxyHost, proxyPort, exclusionList); config.proxySettings = proxySettings; config.httpProxy = proxyInfo; break; case PAC: ProxyInfo proxyPacProperties = new ProxyInfo(pacFileUrl); config.proxySettings = proxySettings; config.httpProxy = proxyPacProperties; break; case NONE: config.proxySettings = proxySettings; break; case UNASSIGNED: loge("BUG: Found UNASSIGNED proxy on file, use NONE"); config.proxySettings = ProxySettings.NONE; break; default: loge("Ignore invalid proxy settings while reading"); config.proxySettings = ProxySettings.UNASSIGNED; break; } } else { if (DBG) log("Missing id while parsing configuration"); } } } catch (EOFException ignore) { } catch (IOException e) { loge("Error parsing configuration: " + e); } finally { if (in != null) { try { in.close(); } catch (Exception e) {} } } return networks; } protected void loge(String s) { Log.e(TAG, s); } protected void log(String s) { Log.d(TAG, s); }}
更多相关文章
- android configChanges
- android 申请移动应用的签名生成方法
- Android(安卓)性能优化的一些方法
- Android(安卓)SDK下载和更新失败的解决方法
- AgentWeb WebView 与 Android交互 JS调用 Android
- Android(安卓)Drawable缓存
- 全屏、小屏、横屏、竖屏的切换
- Android(安卓)SDK下载和更新失败的解决方法!!!
- Android(安卓)5.0有哪些变化