[Network]Android N Ethernet新IP获取机制—IpManager
android N之前 Ethernet旧的ip获取
Android N之前,即android 5.0和android 6.0的IP获取机制都是通过/system/bin下面的dhcpcd的bin档去拿的ip
//EthernetNetworkFactory.java (frameworks\opt\net\ethernet\java\com\android\server\ethernet) public void onRequestNetwork() { // TODO: Handle DHCP renew. Thread dhcpThread = new Thread(new Runnable() { public void run() { ... DhcpResults dhcpResults = new DhcpResults(); // TODO: Handle DHCP renewals better. // In general runDhcp handles DHCP renewals for us, because // the dhcp client stays running, but if the renewal fails, // we will lose our IP address and connectivity without // noticing. //通过这个函数call到jni之后,最后run /system/bin/dhcpcd if (!NetworkUtils.runDhcp(mIface, dhcpResults)) { Log.e(TAG, "DHCP request error:" + NetworkUtils.getDhcpError()); // set our score lower than any network could go // so we get dropped. mFactory.setScoreFilter(-1); return; }
不知道是不是dhcpcd本身的问题,这段code其实不是稳定,超时拿不到ip的现象经常可以遇到。只能在这里多加几次try runDhcp。
android N新的拿IP的机制
android N不要了runDhcpcd(),而是通过DhcpClient,这个是android M引入的wifi那边另外一种获得ip的方式,DhcpClient是通过framework发送dhcpcd协议的UDP请求包直接去拿IP,不再使用开源的dhcpcd。在调用DhcpClient的基础之前,google还用了一个状态机IpManager来管理dhcpcd成功还是失败等状态,将ip赋值给IpConfiguration和LinkProperties传递到上层的framework。还有就是加入ipv6的支持,不过ipv6的部分目前还没做好。
//EthernetNetworkFactory.java (frameworks\opt\net\ethernet\java\com\android\server\ethernet) final Thread ipProvisioningThread = new Thread(new Runnable() { public void run() { if (DBG) { Log.d(TAG, String.format("starting ipProvisioningThread(%s): mNetworkInfo=%s", mIface, mNetworkInfo)); } LinkProperties linkProperties; IpConfiguration config = mEthernetManager.getConfiguration(); if (config.getIpAssignment() == IpAssignment.STATIC) { if (!setStaticIpAddress(config.getStaticIpConfiguration())) { // We've already logged an error. return; } linkProperties = config.getStaticIpConfiguration().toLinkProperties(mIface); } else { mNetworkInfo.setDetailedState(DetailedState.OBTAINING_IPADDR, null, mHwAddr); WaitForProvisioningCallback ipmCallback = new WaitForProvisioningCallback() { @Override public void onLinkPropertiesChange(LinkProperties newLp) { synchronized(EthernetNetworkFactory.this) { if (mNetworkAgent != null && mNetworkInfo.isConnected()) { mLinkProperties = newLp; mNetworkAgent.sendLinkProperties(newLp); } } } }; synchronized(EthernetNetworkFactory.this) { stopIpManagerLocked(); //IPManger,用这个代替之前的runDhcpcd() mIpManager = new IpManager(mContext, mIface, ipmCallback); if (config.getProxySettings() == ProxySettings.STATIC || config.getProxySettings() == ProxySettings.PAC) { mIpManager.setHttpProxy(config.getHttpProxy()); } final String tcpBufferSizes = mContext.getResources().getString( com.android.internal.R.string.config_ethernet_tcp_buffers); if (!TextUtils.isEmpty(tcpBufferSizes)) { mIpManager.setTcpBufferSizes(tcpBufferSizes); } final ProvisioningConfiguration provisioningConfiguration = mIpManager.buildProvisioningConfiguration() .withProvisioningTimeoutMs(0) .build(); //start mIpManager.startProvisioning(provisioningConfiguration); } //通过callback去拿到新的IP linkProperties = ipmCallback.waitForProvisioning(); if (linkProperties == null) { Log.e(TAG, "IP provisioning error"); // set our score lower than any network could go // so we get dropped. mFactory.setScoreFilter(-1); synchronized(EthernetNetworkFactory.this) { stopIpManagerLocked(); } return; } }
IpManager
IpManager,是wifi和Ethernet都会用到。把它定义为获取ip的管理器好了。
1.构造函数
public IpManager(Context context, String ifName, Callback callback) throws IllegalArgumentException { this(context, ifName, callback, INetworkManagementService.Stub.asInterface( ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE))); } /** * An expanded constructor, useful for dependency injection. */ public IpManager(Context context, String ifName, Callback callback, INetworkManagementService nwService) throws IllegalArgumentException { super(IpManager.class.getSimpleName() + "." + ifName); mTag = getName(); mContext = context; //网口的名字,eth0 or wlan0 mInterfaceName = ifName; mClatInterfaceName = CLAT_PREFIX + ifName; mCallback = new LoggingCallbackWrapper(callback); //NetworkManagementService对象,可以对Interface做一些操作 mNwService = nwService; //检测Interface的状态变化 mNetlinkTracker = new NetlinkTracker( mInterfaceName, new NetlinkTracker.Callback() { @Override public void update() { sendMessage(EVENT_NETLINK_LINKPROPERTIES_CHANGED); } }) { @Override public void interfaceAdded(String iface) { super.interfaceAdded(iface); if (mClatInterfaceName.equals(iface)) { mCallback.setNeighborDiscoveryOffload(false); } } @Override public void interfaceRemoved(String iface) { super.interfaceRemoved(iface); if (mClatInterfaceName.equals(iface)) { // TODO: consider sending a message to the IpManager main // StateMachine thread, in case "NDO enabled" state becomes // tied to more things that 464xlat operation. mCallback.setNeighborDiscoveryOffload(true); } } }; try { mNwService.registerObserver(mNetlinkTracker); } catch (RemoteException e) { Log.e(mTag, "Couldn't register NetlinkTracker: " + e.toString()); } //LinkProperties里面记录着网络相关的ip和dns等信息,这个在connectivityservice中会被使用到 resetLinkProperties(); mProvisioningTimeoutAlarm = new WakeupMessage(mContext, getHandler(), mTag + ".EVENT_PROVISIONING_TIMEOUT", EVENT_PROVISIONING_TIMEOUT); mDhcpActionTimeoutAlarm = new WakeupMessage(mContext, getHandler(), mTag + ".EVENT_DHCPACTION_TIMEOUT", EVENT_DHCPACTION_TIMEOUT); // Super simple StateMachine. //状态机,很简单,才三个状态 addState(mStoppedState); addState(mStartedState); addState(mStoppingState); setInitialState(mStoppedState); mLocalLog = new LocalLog(MAX_LOG_RECORDS); super.start(); }
2.ProvisioningConfiguration配置类
前面再IpManager开始之前,会new一个provisioningConfiguration
对象,这个configuration就指明,是否enabled ipv6,静态ip的对象是哪个,还有timeout的时间。
final ProvisioningConfiguration provisioningConfiguration =
mIpManager.buildProvisioningConfiguration()
.withProvisioningTimeoutMs(0)
.build();
public ProvisioningConfiguration() {} public ProvisioningConfiguration(ProvisioningConfiguration other) { mEnableIPv4 = other.mEnableIPv4; mEnableIPv6 = other.mEnableIPv6; mUsingIpReachabilityMonitor = other.mUsingIpReachabilityMonitor; mRequestedPreDhcpActionMs = other.mRequestedPreDhcpActionMs; mStaticIpConfig = other.mStaticIpConfig; mApfCapabilities = other.mApfCapabilities; mProvisioningTimeoutMs = other.mProvisioningTimeoutMs; }
3.mIpManager.startProvisioning(provisioningConfiguration);
开始获取IP啦~
public void startProvisioning(ProvisioningConfiguration req) { getNetworkInterface(); mCallback.setNeighborDiscoveryOffload(true); //发送CMD_START出来 sendMessage(CMD_START, new ProvisioningConfiguration(req)); }
一开始的状态时在StoppedState中,收到CMD_START跟着就会跳转到mStartedState
class StoppedState extends State { @Override public void enter() { try { mNwService.disableIpv6(mInterfaceName); mNwService.clearInterfaceAddresses(mInterfaceName); } catch (Exception e) { Log.e(mTag, "Failed to clear addresses or disable IPv6" + e); } resetLinkProperties(); if (mStartTimeMillis > 0) { recordMetric(IpManagerEvent.COMPLETE_LIFECYCLE); mStartTimeMillis = 0; } } @Override public boolean processMessage(Message msg) { switch (msg.what) { case CMD_STOP: break; case CMD_START: mConfiguration = (ProvisioningConfiguration) msg.obj; transitionTo(mStartedState); break;
先跑StartedState的enter函数,
class StartedState extends State { private boolean mDhcpActionInFlight; @Override public void enter() { //开始的时间 mStartTimeMillis = SystemClock.elapsedRealtime(); /** * For networks that support packet filtering via APF programs, {@code ApfFilter} * listens for IPv6 ICMPv6 router advertisements (RAs) and generates APF programs to * filter out redundant duplicate ones. * * Threading model: * A collection of RAs we've received is kept in mRas. Generating APF programs uses mRas to * know what RAs to filter for, thus generating APF programs is dependent on mRas. * mRas can be accessed by multiple threads: * - ReceiveThread, which listens for RAs and adds them to mRas, and generates APF programs. * - callers of: * - setMulticastFilter(), which can cause an APF program to be generated. * - dump(), which dumps mRas among other things. * - shutdown(), which clears mRas. * So access to mRas is synchronized. * * @hide */ mApfFilter = ApfFilter.maybeCreate(mConfiguration.mApfCapabilities, mNetworkInterface, mCallback, mMulticastFiltering); // TODO: investigate the effects of any multicast filtering racing/interfering with the // rest of this IP configuration startup. if (mApfFilter == null) { mCallback.setFallbackMulticastFilter(mMulticastFiltering); } //如果ipv6如果这么写的话,如果timout会存在卡到ipv4?ipv6和ipv4之间的逻辑关系应该是怎么样的? if (mConfiguration.mEnableIPv6) { // TODO: Consider transitionTo(mStoppingState) if this fails. startIPv6(); } //这个是arp邻居表的检测 if (mConfiguration.mUsingIpReachabilityMonitor) { mIpReachabilityMonitor = new IpReachabilityMonitor( mContext, mInterfaceName, new IpReachabilityMonitor.Callback() { @Override public void notifyLost(InetAddress ip, String logMsg) { mCallback.onReachabilityLost(logMsg); } }); } //启动ipv4 if (mConfiguration.mEnableIPv4) { if (!startIPv4()) { transitionTo(mStoppingState); } } }
startIPv6的部分还没写好,跳过,看ipv4的部分
private boolean startIPv4() { // If we have a StaticIpConfiguration attempt to apply it and // handle the result accordingly. //如果是静态ip,在这里设置一下 if (mConfiguration.mStaticIpConfig != null) { if (setIPv4Address(mConfiguration.mStaticIpConfig.ipAddress)) { handleIPv4Success(new DhcpResults(mConfiguration.mStaticIpConfig)); } else { if (VDBG) { Log.d(mTag, "onProvisioningFailure()"); } recordMetric(IpManagerEvent.PROVISIONING_FAIL); mCallback.onProvisioningFailure(new LinkProperties(mLinkProperties)); return false; } } else { // Start DHCPv4. //构造DhcpClient对象,发送dhcp client请求 mDhcpClient = DhcpClient.makeDhcpClient(mContext, IpManager.this, mInterfaceName); mDhcpClient.registerForPreDhcpNotification(); mDhcpClient.sendMessage(DhcpClient.CMD_START_DHCP); if (mConfiguration.mProvisioningTimeoutMs > 0) { final long alarmTime = SystemClock.elapsedRealtime() + mConfiguration.mProvisioningTimeoutMs; //通过闹钟去叫醒 /* mProvisioningTimeoutAlarm = new WakeupMessage(mContext, getHandler(), mTag + ".EVENT_PROVISIONING_TIMEOUT", EVENT_PROVISIONING_TIMEOUT); */ mProvisioningTimeoutAlarm.schedule(alarmTime); } } return true; }
4.DhcpClient
接收前面发过来的mDhcpClient.sendMessage(DhcpClient.CMD_START_DHCP);
, 跟着跳转到DhcpInitState
:
class StoppedState extends LoggingState { @Override public boolean processMessage(Message message) { super.processMessage(message); switch (message.what) { case CMD_START_DHCP: if (mRegisteredForPreDhcpNotification) { transitionTo(mWaitBeforeStartState); } else { transitionTo(mDhcpInitState); } return HANDLED; default: return NOT_HANDLED; } } }
class DhcpInitState extends PacketRetransmittingState { public DhcpInitState() { super(); } @Override //跑DhcpInitState的父类PacketRetransmittingState的enter public void enter() { super.enter(); startNewTransaction(); } protected boolean sendPacket() { return sendDiscoverPacket(); } protected void receivePacket(DhcpPacket packet) { if (!isValidPacket(packet)) return; if (!(packet instanceof DhcpOfferPacket)) return; mOffer = packet.toDhcpResults(); if (mOffer != null) { Log.d(TAG, "Got pending lease: " + mOffer); transitionTo(mDhcpRequestingState); } } }
重点是这里的CMD_KICK命令,发送这个命令,之后会调用sendPacket()函数,去发送请求包.
/** * Retransmits packets using jittered exponential backoff with an optional timeout. Packet * transmission is triggered by CMD_KICK, which is sent by an AlarmManager alarm. If a subclass * sets mTimeout to a positive value, then timeout() is called by an AlarmManager alarm mTimeout * milliseconds after entering the state. Kicks and timeouts are cancelled when leaving the * state. * * Concrete subclasses must implement sendPacket, which is called when the alarm fires and a * packet needs to be transmitted, and receivePacket, which is triggered by CMD_RECEIVED_PACKET * sent by the receive thread. They may also set mTimeout and implement timeout. */ abstract class PacketRetransmittingState extends LoggingState { private int mTimer; protected int mTimeout = 0; @Override public void enter() { super.enter(); initTimer(); maybeInitTimeout(); sendMessage(CMD_KICK); }
这里发送的是DHCPDISCOVER
dhcp协议的DISCOVER包
private boolean sendDiscoverPacket() { ByteBuffer packet = DhcpPacket.buildDiscoverPacket( DhcpPacket.ENCAP_L2, mTransactionId, getSecs(), mHwAddr, DO_UNICAST, REQUESTED_PARAMS); return transmitPacket(packet, "DHCPDISCOVER", DhcpPacket.ENCAP_L2, INADDR_BROADCAST); }
另外一边有一个接收函数,一直在收dhcp server的的数据包。
class ReceiveThread extends Thread { private final byte[] mPacket = new byte[DhcpPacket.MAX_LENGTH]; private volatile boolean mStopped = false; public void halt() { mStopped = true; closeSockets(); // Interrupts the read() call the thread is blocked in. } @Override public void run() { if (DBG) Log.d(TAG, "Receive thread started"); while (!mStopped) { int length = 0; // Or compiler can't tell it's initialized if a parse error occurs. try { length = Os.read(mPacketSock, mPacket, 0, mPacket.length); DhcpPacket packet = null; packet = DhcpPacket.decodeFullPacket(mPacket, length, DhcpPacket.ENCAP_L2); if (DBG) Log.d(TAG, "Received packet: " + packet); //发送CMD_RECEIVED_PACKET,把数据包往上面送 sendMessage(CMD_RECEIVED_PACKET, packet); } catch (IOException|ErrnoException e) { if (!mStopped) { Log.e(TAG, "Read error", e); DhcpErrorEvent.logReceiveError(mIfaceName); } } catch (DhcpPacket.ParseException e) { Log.e(TAG, "Can't parse packet: " + e.getMessage()); if (PACKET_DBG) { Log.d(TAG, HexDump.dumpHexString(mPacket, 0, length)); } DhcpErrorEvent.logParseError(mIfaceName, e.errorCode); } } if (DBG) Log.d(TAG, "Receive thread stopped"); } }
接收CMD_RECEIVED_PACKET
,我们还在PacketRetransmittingState 这个state中,所以他会处理这个CMD
abstract class PacketRetransmittingState extends LoggingState { private int mTimer; protected int mTimeout = 0; ... @Override public boolean processMessage(Message message) { super.processMessage(message); switch (message.what) { case CMD_KICK: sendPacket(); scheduleKick(); return HANDLED; case CMD_RECEIVED_PACKET: //这个会call到DhcpInitState的receivePacket函数 receivePacket((DhcpPacket) message.obj); return HANDLED; case CMD_TIMEOUT: timeout(); return HANDLED; default: return NOT_HANDLED; } }
接收的数据在这里被处理,处理完之后,将结果赋值给mOffer,意思是dhcp的offer数据包,里面当然就是存着ip的值,然后跳转到mDhcpRequestingState
protected void receivePacket(DhcpPacket packet) { if (!isValidPacket(packet)) return; //判断是不是server 放回的offer包 if (!(packet instanceof DhcpOfferPacket)) return; mOffer = packet.toDhcpResults(); if (mOffer != null) { Log.d(TAG, "Got pending lease: " + mOffer); transitionTo(mDhcpRequestingState); } }
这个DhcpRequestingState
是继承了PacketRetransmittingState ,还记得前面的CMD_KICK吗?scheduleKick()函数的调用,这个CMD_KICK会定时发送,理论上dicover包要发4次。server offer之后,就要跑client发送request了,当跑到这个statemachine里面的时候,就会跑DhcpRequestingState 这个里面的sendPacket()了,google大神真是牛。那这次send的是dhcp协议的什么数据包呢?
class DhcpRequestingState extends PacketRetransmittingState { public DhcpRequestingState() { mTimeout = DHCP_TIMEOUT_MS / 2; } protected boolean sendPacket() { return sendRequestPacket( INADDR_ANY, // ciaddr (Inet4Address) mOffer.ipAddress.getAddress(), // DHCP_REQUESTED_IP (Inet4Address) mOffer.serverAddress, // DHCP_SERVER_IDENTIFIER INADDR_BROADCAST); // packet destination address } protected void receivePacket(DhcpPacket packet) { if (!isValidPacket(packet)) return; if ((packet instanceof DhcpAckPacket)) { DhcpResults results = packet.toDhcpResults(); if (results != null) { setDhcpLeaseExpiry(packet); acceptDhcpResults(results, "Confirmed"); transitionTo(mConfiguringInterfaceState); } } else if (packet instanceof DhcpNakPacket) { // TODO: Wait a while before returning into INIT state. Log.d(TAG, "Received NAK, returning to INIT"); mOffer = null; transitionTo(mDhcpInitState); } } @Override protected void timeout() { // After sending REQUESTs unsuccessfully for a while, go back to init. transitionTo(mDhcpInitState); } }
DHCPREQUEST ciaddr
知道知道dhcp的协议,就知道发完discover包之后,要再发一个DHCPREQUEST。相当是这个ip我要了,然后等sever的ACK。
DHCP Client会以广播形式向DHCP Server发送DHCPRequest报文来续租IP地址。如果DHCP Client成功收到DHCP Server发送的DHCP ACK报文.
private boolean sendRequestPacket( Inet4Address clientAddress, Inet4Address requestedAddress, Inet4Address serverAddress, Inet4Address to) { // TODO: should we use the transaction ID from the server? final int encap = INADDR_ANY.equals(clientAddress) ? DhcpPacket.ENCAP_L2 : DhcpPacket.ENCAP_BOOTP; ByteBuffer packet = DhcpPacket.buildRequestPacket( encap, mTransactionId, getSecs(), clientAddress, DO_UNICAST, mHwAddr, requestedAddress, serverAddress, REQUESTED_PARAMS, null); String serverStr = (serverAddress != null) ? serverAddress.getHostAddress() : null; String description = "DHCPREQUEST ciaddr=" + clientAddress.getHostAddress() + " request=" + requestedAddress.getHostAddress() + " serverid=" + serverStr; return transmitPacket(packet, description, encap, to); }
sever ack之后,我们再次处理接收包。
protected void receivePacket(DhcpPacket packet) { if (!isValidPacket(packet)) return; if ((packet instanceof DhcpAckPacket)) { DhcpResults results = packet.toDhcpResults(); if (results != null) { setDhcpLeaseExpiry(packet); //这里会调用notifySuccess,发送CMD去通知IpManager说,IP拿到了 acceptDhcpResults(results, "Confirmed");//① //自己调到mConfiguringInterfaceState transitionTo(mConfiguringInterfaceState);//② } } else if (packet instanceof DhcpNakPacket) { // TODO: Wait a while before returning into INIT state. Log.d(TAG, "Received NAK, returning to INIT"); mOffer = null; transitionTo(mDhcpInitState); } }
①这里调用了notifySuccess()发生CMD去通知IpManager,IP获取成功了。
private void acceptDhcpResults(DhcpResults results, String msg) { mDhcpLease = results; mOffer = null; Log.d(TAG, msg + " lease: " + mDhcpLease); notifySuccess(); }
这里的mController指的是IpManager里面的接收者,发送CMD_POST_DHCP_ACTION
private void notifySuccess() { mController.sendMessage( CMD_POST_DHCP_ACTION, DHCP_SUCCESS, 0, new DhcpResults(mDhcpLease)); }
class StartedState extends State { .... // This message is only received when: // // a) initial address acquisition succeeds, // b) renew succeeds or is NAK'd, // c) rebind succeeds or is NAK'd, or // c) the lease expires, // // but never when initial address acquisition fails. The latter // condition is now governed by the provisioning timeout. case DhcpClient.CMD_POST_DHCP_ACTION: stopDhcpAction(); switch (msg.arg1) { case DhcpClient.DHCP_SUCCESS: handleIPv4Success((DhcpResults) msg.obj); break; case DhcpClient.DHCP_FAILURE: handleIPv4Failure(); break; default: Log.e(mTag, "Unknown CMD_POST_DHCP_ACTION status:" + msg.arg1); } break; ..... }
private void handleIPv4Success(DhcpResults dhcpResults) { mDhcpResults = new DhcpResults(dhcpResults); final LinkProperties newLp = assembleLinkProperties(); final ProvisioningChange delta = setLinkProperties(newLp); if (VDBG) { Log.d(mTag, "onNewDhcpResults(" + Objects.toString(dhcpResults) + ")"); } mCallback.onNewDhcpResults(dhcpResults); //这里分发dhcpResults dispatchCallback(delta, newLp); }
private void dispatchCallback(ProvisioningChange delta, LinkProperties newLp) { switch (delta) { case GAINED_PROVISIONING: if (VDBG) { Log.d(mTag, "onProvisioningSuccess()"); } recordMetric(IpManagerEvent.PROVISIONING_OK); mCallback.onProvisioningSuccess(newLp); break; case LOST_PROVISIONING: if (VDBG) { Log.d(mTag, "onProvisioningFailure()"); } recordMetric(IpManagerEvent.PROVISIONING_FAIL); mCallback.onProvisioningFailure(newLp); break; default: if (VDBG) { Log.d(mTag, "onLinkPropertiesChange()"); } mCallback.onLinkPropertiesChange(newLp); break; } }
dispatchCallback的结果最后会作用到WaitForProvisioningCallback ,这个就是前面EthernetNetworkFactory
中 linkProperties = ipmCallback.waitForProvisioning();,等待的结果。
public static class WaitForProvisioningCallback extends Callback { private LinkProperties mCallbackLinkProperties; public LinkProperties waitForProvisioning() { synchronized (this) { try { wait(); } catch (InterruptedException e) {} return mCallbackLinkProperties; } } @Override public void onProvisioningSuccess(LinkProperties newLp) { synchronized (this) { mCallbackLinkProperties = newLp; notify(); } } @Override public void onProvisioningFailure(LinkProperties newLp) { synchronized (this) { mCallbackLinkProperties = null; notify(); } } }
②这里跑入enter(),给IpManager发了一个CMD_CONFIGURE_LINKADDRESS
的CMD
class ConfiguringInterfaceState extends LoggingState { @Override public void enter() { super.enter(); mController.sendMessage(CMD_CONFIGURE_LINKADDRESS, mDhcpLease.ipAddress); } @Override public boolean processMessage(Message message) { super.processMessage(message); switch (message.what) { case EVENT_LINKADDRESS_CONFIGURED: transitionTo(mDhcpBoundState); return HANDLED; default: return NOT_HANDLED; } } }
我们返回到IpManager中去看,在IpManger中,我们还处于StartedState中哦:
class StartedState extends State { ...... case DhcpClient.CMD_CONFIGURE_LINKADDRESS: { final LinkAddress ipAddress = (LinkAddress) msg.obj; //将IP通过NetworkManagerService写到Interface上面 if (setIPv4Address(ipAddress)) { mDhcpClient.sendMessage(DhcpClient.EVENT_LINKADDRESS_CONFIGURED); } else { Log.e(mTag, "Failed to set IPv4 address!"); dispatchCallback(ProvisioningChange.LOST_PROVISIONING, new LinkProperties(mLinkProperties)); transitionTo(mStoppingState); } break; } ...... }
这个setIPv4Address很简单,调用了NetworkManagementService.setInterfaceConfig()
private boolean setIPv4Address(LinkAddress address) { final InterfaceConfiguration ifcg = new InterfaceConfiguration(); ifcg.setLinkAddress(address); try { mNwService.setInterfaceConfig(mInterfaceName, ifcg); if (VDBG) Log.d(mTag, "IPv4 configuration succeeded"); } catch (IllegalStateException | RemoteException e) { Log.e(mTag, "IPv4 configuration failed: ", e); return false; } return true; }
调用Netd,通过Commandlisten.java去往下跑,这里不跟了。
//NetworkManagementService.java (frameworks\base\services\core\java\com\android\server) @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(); } }
总结
不知道google加入的这个IpManager是否又有效,但是从整个框架看下来,为后面ipv6的加入可以说是打好了基础,加速ipv6时代的到来。因为apple已经开始强制要求app support ipv6了,android需要加把劲。
更多相关文章
- android 完美获取状态栏高度
- android隐藏标题栏和状态
- android实现Parcelable序列化对象
- Android Intent传递对象和集合
- Android Audio代码分析17 - setvolume函数