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需要加把劲。

更多相关文章

  1. android 完美获取状态栏高度
  2. android隐藏标题栏和状态
  3. android实现Parcelable序列化对象
  4. Android Intent传递对象和集合
  5. Android Audio代码分析17 - setvolume函数

随机推荐

  1. TP6之多数据库,路由设置与多应用模式
  2. JS基本数据类型
  3. 【记账小程序】记账系统备注与收入功能完
  4. JS判断当前屏幕是否支持触摸
  5. JS 对象基本用法
  6. PHP:【商城后台管理系统】admin超级管理
  7. python抓取微信撤回消息
  8. PHP:【商城后台管理系统】admin超级管理
  9. thinkphp多数据库访问 - 创建博客页面路
  10. 数组的一些基本函数