Google 官方变更说明:

已更新 DHCP 服务器
为了更好地构造“IP 服务器”服务体系,我们删除了 dnsmasq。Android 10 将其 DHCPv4 服务器功能替换为单独的组件,该组件主要使用 Java 编写,以便更好地与 Java 框架控制平面集成。这提高了 DHCP 服务器的安全性和可更新性。如需了解详情,请参阅 packages/modules/NetworkStack/src/android/net/dhcp/DhcpServer.java。

此更改无需任何操作即可实现:默认情况下,发布和更新到 Android 10 的所有设备均使用 DhcpServer。如果您对 DHCP 服务器进行了自定义,则可以通过设置全局设置 tether_enable_legacy_dhcp_server=1 来还原 Android 9 行为。新的 DhcpServer 包含在网络组件模块中,因此,对 DHCP 服务器功能的任何自定义都应在上游进行。

DhcpServer 是依赖于 NetworkStack 服务。因此先分析 NetworkStack 服务的创建过程和功能实现。首先 NetworkStack 在 SystemServer 中启动:
[SystemServer.java]

traceBeginAndSlog("StartNetworkStack");
try {
    NetworkStackClient.getInstance().start(context);
} catch (Throwable e) {
    reportWtf("starting Network Stack", e);
}
traceEnd();

NetworkStackClient 为单例模式,调用其 start 函数启动 NetworkStack 服务:
[NetworkStackClient.java]

public void start(Context context) {
    final PackageManager pm = context.getPackageManager();
    Intent intent = getNetworkStackIntent(pm, true /* inSystemProcess */);
    ...
    final String packageName = intent.getComponent().getPackageName();
    if (!context.bindServiceAsUser(intent, new NetworkStackConnection(context, packageName),
            Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT, UserHandle.SYSTEM)) {
        maybeCrashWithTerribleFailure(
                "Could not bind to network stack in-process, or in app with " + intent,
                context, packageName);
        return;
    }
}

NetworkStack 服务的实现源码如下:

packages/modules/NetworkStack/

NetworkStackService 类作为服务的入口,定义如下:
[NetworkStackService.java]

public class NetworkStackService extends Service {
    public static synchronized IBinder makeConnector(Context context) {
        if (sConnector == null) {
            sConnector = new NetworkStackConnector(context);
        }
        return sConnector;
    }

    @NonNull
    @Override
    public IBinder onBind(Intent intent) {
        return makeConnector(this);
    }
}

当通过 bindServiceAsUser 启动服务时,onBind 将会被调用,并返回 IBinder 给服务代理端,此时代理端的 onServiceConnected 回调会被调用:
[NetworkStackClient.java]

private class NetworkStackConnection implements ServiceConnection {
    ...
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        logi("Network stack service connected");
        registerNetworkStackService(service);
    }
}

调用 registerNetworkStackService 注册 network_stack 服务,代码实现如下:
[NetworkStackClient.java]

private void registerNetworkStackService(@NonNull IBinder service) {
    final INetworkStackConnector connector = INetworkStackConnector.Stub.asInterface(service);

    ServiceManager.addService(Context.NETWORK_STACK_SERVICE, service, false /* allowIsolated */,
            DUMP_FLAG_PRIORITY_HIGH | DUMP_FLAG_PRIORITY_NORMAL);
    ...
        mConnector = connector;
    ...
}

通过 service 参数构造 INetworkStackConnector 对象,保存到 mConnector 域中,并向 service manager 注册。如果不注册服务,通过 mConnector 域已经可以使用 network_stack 服务了,至于为什么要注册到 service manager,目前来看,可能是为了将服务的暴露出来,可供其它系统组件使用,同时可以通过 dumpsys 对服务进行调试。这里不探讨这么设计的更深意图。继续分析服务端的实现,具体的服务是通过 NetworkStackService 的内部类 NetworkStackConnector 实现。
[NetworkStackService.java]

private static class NetworkStackConnector extends INetworkStackConnector.Stub
        implements NetworkStackServiceManager {
    @Override
    public void makeDhcpServer(@NonNull String ifName, @NonNull DhcpServingParamsParcel params,
            @NonNull IDhcpServerCallbacks cb) throws RemoteException {
        ...
    }
}

上面代码只截取了 DHCP 相关接口。显然 makeDhcpServer 用来创建 DHCP server。通过以上分析,可以得出以下结论:
1、NetworkStack 的作用是为了创建和注册 network_stack 服务,后续工作由 network_stack 服务承担。
2、network_stack 是一个服务中转站,通过 network_stack 可以创建 DHCP 服务等。

那么谁创建了 DHCP 服务呢?这需要提到另一个系统服务 connectivity。同样 connectivity 在 SystemServer 中启动:
[SystemServer.java]

traceBeginAndSlog("StartConnectivityService");
try {
    connectivity = new ConnectivityService(
            context, networkManagement, networkStats, networkPolicy);
    ServiceManager.addService(Context.CONNECTIVITY_SERVICE, connectivity,
            /* allowIsolated= */ false,
            DUMP_FLAG_PRIORITY_HIGH | DUMP_FLAG_PRIORITY_NORMAL);
    networkPolicy.bindConnectivityManager(connectivity);
} catch (Throwable e) {
    reportWtf("starting Connectivity Service", e);
}
traceEnd();

在 ConnectivityService 构造函数中,创建了 Tethering 对象,并通过 INetworkManagementService 监测网络变化:
[ConnectivityService.java]

mTethering = makeTethering();
mNMS.registerObserver(mTethering);

如果创建新的网络节点,会触发 Tethering 的 interfaceAdded 回调:
[Tethering.java]

@Override
public void interfaceAdded(String iface) {
    if (VDBG) Log.d(TAG, "interfaceAdded " + iface);
    synchronized (mPublicSync) {
        maybeTrackNewInterfaceLocked(iface);
    }
}

maybeTrackNewInterfaceLocked 源码如下:
[Tethering.java]

private void maybeTrackNewInterfaceLocked(final String iface, int interfaceType) {
    ...
    mLog.log("adding TetheringInterfaceStateMachine for: " + iface);
    final TetherState tetherState = new TetherState(
            new IpServer(iface, mLooper, interfaceType, mLog, mNMService, mStatsService,
                         makeControlCallback(), mConfig.enableLegacyDhcpServer,
                         mDeps.getIpServerDependencies()));
    mTetherStates.put(iface, tetherState);
    tetherState.ipServer.start();
}

这里创建 IpServer 和 TetherState。其中 IpServer 为状态机。其定义如下:
[IpServer.java]

public class IpServer extends StateMachine {
    public static class Dependencies {
        public void makeDhcpServer(String ifName, DhcpServingParamsParcel params,
                DhcpServerCallbacks cb) {
            NetworkStackClient.getInstance().makeDhcpServer(ifName, params, cb);
        }
    }
}

当热点被创建的时候,会触发以下调用:
[Tethering.java]

tetherState.ipServer.sendMessage(IpServer.CMD_TETHER_REQUESTED, requestedState);

其中 ipServer 即为前面新建 IpServer 对象,这里发送 CMD_TETHER_REQUESTED 消息,IpServer 收到消息会触发状态改变,从而调用 LocalHotspotState 的 enter 函数,父类 BaseServingState 的 enter 也会被调用:
[IpServer.java]

public void enter() {
    if (!startIPv4()) {
        mLastError = ConnectivityManager.TETHER_ERROR_IFACE_CFG_ERROR;
        return;
    }

    try {
        mNMService.tetherInterface(mIfaceName);
    } catch (Exception e) {
        mLog.e("Error Tethering: " + e);
        mLastError = ConnectivityManager.TETHER_ERROR_TETHER_IFACE_ERROR;
        return;
    }

    if (!startIPv6()) {
        mLog.e("Failed to startIPv6");
        // TODO: Make this a fatal error once Bluetooth IPv6 is sorted.
        return;
    }
}

其中 startIPv4 函数启动了 DHCP 协议,具体的是内部调用 startDhcp 启动 DHCP server。而 startDhcp 是通过内部类 Dependencies 对象调用 network_stack 服务的 makeDhcpServer 接口实现 DHCP server 启动。那么服务端的 makeDhcpServer 会被调用。
[DhcpServer.java]

public class DhcpServer extends IDhcpServer.Stub {
    @Override
    public void start(@Nullable INetworkStackStatusCallback cb) {
        mDeps.checkCaller();
        mHandlerThread.start();
        mHandler = new ServerHandler(mHandlerThread.getLooper());
        sendMessage(CMD_START_DHCP_SERVER, cb);
    }

    @Override
    public void stop(@Nullable INetworkStackStatusCallback cb) {
        mDeps.checkCaller();
        sendMessage(CMD_STOP_DHCP_SERVER, cb);
    }
}

从继承关系可以看出,DhcpServer 对象具备 binder 跨进程通信能力,上面代码中的 start 和 stop 就是暴露给客户端的接口。前面提到调用回调,将 server 传给代理,现在来看代理如何处理回调:
[IpServer.java]

public void onDhcpServerCreated(int statusCode, IDhcpServer server) throws RemoteException {
    getHandler().post(() -> {
        ...
        mDhcpServer = server;
        try {
            mDhcpServer.start(new OnHandlerStatusCallback() {
                @Override
                public void callback(int startStatusCode) {
                    if (startStatusCode != STATUS_SUCCESS) {
                        mLog.e("Error starting DHCP server: " + startStatusCode);
                        handleError();
                    }
                }
            });
        } catch (RemoteException e) {
            e.rethrowFromSystemServer();
        }
    });
}

这里直接调用了 start 函数处理启动“真正的" DHCP 服务。首先服务端会发送 CMD_START_DHCP_SERVER 消息,对应的 Handler 处理此消息:
[DhcpServer.java]

case CMD_START_DHCP_SERVER:
    mPacketListener = mDeps.makePacketListener();
    mPacketListener.start();
    cb = (INetworkStackStatusCallback) msg.obj;

以上创建了 mPacketListener 对象,用于监听 DHCP 数据包,当收到网络客户端数据包时,会调用 onReceive 回调:

protected void onReceive(@NonNull DhcpPacket packet, @NonNull Inet4Address srcAddr,
        int srcPort) {
    processPacket(packet, srcPort);
}

最终通过 processPacket 处理此数据包,根据不同数据类型,做不同处理,包括分配 ip 地址和租期。具体分配原理在此不表,详细可查阅 DHCP 协议说明。

调试方法:

dumpsys network_stack