Android 16系统 如何修改 eth0 IP ?

核心推荐 :Android 14+ / Android 16 优先使用 EthernetManager.updateConfiguration() + EthernetNetworkUpdateRequest。

该 API 是官方推荐的新接口(尤其适用于 Automotive 及新网络栈),支持异步回调、异常处理更完善,同样会将配置持久化到 /data/misc/ethernet/ipconfig.txt,重启后仍然生效。

1. 前提条件(必须满足)

项目 要求
签名 平台签名(platform.x509.pem + platform.pk8)
安装位置 /system/priv-app/ 或 /product/priv-app/ 或 /system_ext/priv-app/
sharedUserId android:sharedUserId="android.uid.system"(强烈推荐)
关键权限 MANAGE_ETHERNET_NETWORKS(Android 14+ 必须)、CONNECTIVITY_INTERNAL、NETWORK_STACK、CHANGE_NETWORK_STATE 等
接口名 通常为 eth0(可通过 EthernetManager.getAvailableInterfaces() 确认)

2. 系统 App 工程配置

2.1 AndroidManifest.xml

xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.yourcompany.ethernetconfig"
    android:sharedUserId="android.uid.system">

    <!-- Android 14+ 新 API 核心权限 -->
    <uses-permission android:name="android.permission.MANAGE_ETHERNET_NETWORKS" />
    <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
    <uses-permission android:name="android.permission.NETWORK_STACK" />
    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.INTERNET" />

    <application
        android:persistent="true"
        android:process="system"
        android:directBootAware="true">
        <!-- 你的 Activity / Service / Application -->
    </application>
</manifest>

2.2 privapp-permissions 白名单(必须)

在 frameworks/base/data/etc/privapp-permissions-platform.xml 或设备 overlay 中添加:

xml 复制代码
<privapp-permissions package="com.yourcompany.ethernetconfig">
    <permission name="android.permission.MANAGE_ETHERNET_NETWORKS"/>
    <permission name="android.permission.CONNECTIVITY_INTERNAL"/>
    <permission name="android.permission.NETWORK_STACK"/>
</privapp-permissions>

2.3 签名配置(build.gradle 示例)

gradle 复制代码
android {
    signingConfigs {
        platform {
            storeFile file("platform.keystore")   // 替换为你的 platform 密钥
            storePassword "android"
            keyAlias "platform"
            keyPassword "android"
        }
    }
    buildTypes {
        release {
            signingConfig signingConfigs.platform
        }
    }
}

2.4 AOSP Android.bp 示例

bp 复制代码
android_app {
    name: "EthernetConfig",
    srcs: ["src/**/*.java"],
    resource_dirs: ["res"],
    platform_apis: true,
    privileged: true,
    certificate: "platform",
    system_ext_specific: true,   // 或 product_specific / proprietary
}

在 device.mk 中加入:

makefile 复制代码
PRODUCT_PACKAGES += EthernetConfig

3. 新 API 核心实现(推荐)

Android 14 引入、Android 16 完全支持的新 API:

  • EthernetNetworkUpdateRequest
  • EthernetManager.updateConfiguration(String iface, EthernetNetworkUpdateRequest request, Executor executor, OutcomeReceiver<String, EthernetNetworkManagementException> receiver)

3.1 完整 Helper 类

java 复制代码
package com.yourcompany.ethernetconfig;

import android.content.Context;
import android.net.EthernetManager;
import android.net.EthernetNetworkManagementException;
import android.net.EthernetNetworkUpdateRequest;
import android.net.IpConfiguration;
import android.net.IpConfiguration.IpAssignment;
import android.net.IpConfiguration.ProxySettings;
import android.net.LinkAddress;
import android.net.StaticIpConfiguration;
import android.os.OutcomeReceiver;
import android.util.Log;

import java.net.InetAddress;
import java.net.Inet4Address;
import java.util.ArrayList;
import java.util.concurrent.Executor;

public class EthernetIpHelperNewApi {

    private static final String TAG = "EthernetIpHelperNewApi";
    private static final String IFACE = "eth0";   // 可通过 getAvailableInterfaces() 动态获取

    private final EthernetManager mEthManager;
    private final Executor mExecutor;

    public EthernetIpHelperNewApi(Context context) {
        mEthManager = context.getSystemService(EthernetManager.class);
        // 推荐使用主线程或自定义线程池
        mExecutor = context.getMainExecutor();
    }

    /**
     * 设置静态 IP(使用新 API,持久化)
     *
     * @param ip          例如 "192.168.1.100"
     * @param prefixOrMask 前缀长度 "24" 或掩码 "255.255.255.0"
     * @param gateway     网关,可为 null
     * @param dns1        主 DNS,可为 null
     * @param dns2        备 DNS,可为 null
     * @param callback    结果回调(可选)
     */
    public void setStaticIp(String ip,
                            String prefixOrMask,
                            String gateway,
                            String dns1,
                            String dns2,
                            ResultCallback callback) {
        try {
            // 1. 构建 StaticIpConfiguration
            StaticIpConfiguration.Builder staticBuilder = new StaticIpConfiguration.Builder();

            InetAddress ipAddr = InetAddress.getByName(ip);
            int prefix = parsePrefix(prefixOrMask);
            staticBuilder.setIpAddress(new LinkAddress(ipAddr, prefix));

            if (gateway != null && !gateway.isEmpty()) {
                staticBuilder.setGateway(InetAddress.getByName(gateway));
            }

            ArrayList<InetAddress> dnsList = new ArrayList<>();
            if (dns1 != null && !dns1.isEmpty()) {
                dnsList.add(InetAddress.getByName(dns1));
            }
            if (dns2 != null && !dns2.isEmpty()) {
                dnsList.add(InetAddress.getByName(dns2));
            }
            if (!dnsList.isEmpty()) {
                staticBuilder.setDnsServers(dnsList);
            }

            StaticIpConfiguration staticConfig = staticBuilder.build();

            // 2. 构建 IpConfiguration
            IpConfiguration config = new IpConfiguration();
            config.setIpAssignment(IpAssignment.STATIC);
            config.setProxySettings(ProxySettings.NONE);
            config.setStaticIpConfiguration(staticConfig);

            // 3. 构建新 API 请求
            EthernetNetworkUpdateRequest request = new EthernetNetworkUpdateRequest.Builder()
                    .setIpConfiguration(config)
                    .build();

            // 4. 调用新 API
            mEthManager.updateConfiguration(IFACE, request, mExecutor,
                    new OutcomeReceiver<String, EthernetNetworkManagementException>() {
                        @Override
                        public void onResult(String result) {
                            Log.i(TAG, "Static IP update success: " + result);
                            if (callback != null) {
                                callback.onSuccess(result);
                            }
                        }

                        @Override
                        public void onError(EthernetNetworkManagementException e) {
                            Log.e(TAG, "Static IP update failed", e);
                            if (callback != null) {
                                callback.onError(e);
                            }
                        }
                    });

        } catch (Exception e) {
            Log.e(TAG, "setStaticIp exception", e);
            if (callback != null) {
                callback.onError(e);
            }
        }
    }

    /**
     * 切换回 DHCP(使用新 API)
     */
    public void setDhcp(ResultCallback callback) {
        try {
            IpConfiguration config = new IpConfiguration();
            config.setIpAssignment(IpAssignment.DHCP);
            config.setProxySettings(ProxySettings.NONE);
            config.setStaticIpConfiguration(null);

            EthernetNetworkUpdateRequest request = new EthernetNetworkUpdateRequest.Builder()
                    .setIpConfiguration(config)
                    .build();

            mEthManager.updateConfiguration(IFACE, request, mExecutor,
                    new OutcomeReceiver<String, EthernetNetworkManagementException>() {
                        @Override
                        public void onResult(String result) {
                            Log.i(TAG, "DHCP update success: " + result);
                            if (callback != null) {
                                callback.onSuccess(result);
                            }
                        }

                        @Override
                        public void onError(EthernetNetworkManagementException e) {
                            Log.e(TAG, "DHCP update failed", e);
                            if (callback != null) {
                                callback.onError(e);
                            }
                        }
                    });
        } catch (Exception e) {
            Log.e(TAG, "setDhcp exception", e);
            if (callback != null) {
                callback.onError(e);
            }
        }
    }

    /**
     * 获取当前配置(旧 API 仍可用,或使用 getConfiguration)
     */
    public IpConfiguration getCurrentConfig() {
        return mEthManager.getConfiguration(IFACE);
    }

    /**
     * 获取可用接口列表
     */
    public String[] getAvailableInterfaces() {
        return mEthManager.getAvailableInterfaces();
    }

    private int parsePrefix(String maskOrPrefix) {
        if (maskOrPrefix.contains(".")) {
            // 255.255.255.0 → 24
            try {
                return android.net.NetworkUtils.netmaskToPrefixLength(
                        (Inet4Address) InetAddress.getByName(maskOrPrefix));
            } catch (Exception e) {
                Log.e(TAG, "parsePrefix failed", e);
                return 24; // 默认
            }
        }
        return Integer.parseInt(maskOrPrefix);
    }

    /** 结果回调接口 */
    public interface ResultCallback {
        void onSuccess(String result);
        void onError(Exception e);
    }
}

3.2 使用示例

java 复制代码
EthernetIpHelperNewApi helper = new EthernetIpHelperNewApi(this);

// 设置静态 IP
helper.setStaticIp(
    "192.168.1.100",      // IP
    "24",                 // 前缀长度(或 "255.255.255.0")
    "192.168.1.1",        // 网关
    "8.8.8.8",            // DNS1
    "8.8.4.4",            // DNS2
    new EthernetIpHelperNewApi.ResultCallback() {
        @Override
        public void onSuccess(String result) {
            // 成功,配置已持久化
            Log.i("Main", "IP 设置成功: " + result);
        }

        @Override
        public void onError(Exception e) {
            // 失败处理
            Log.e("Main", "IP 设置失败", e);
        }
    }
);

// 切换回 DHCP
helper.setDhcp(new EthernetIpHelperNewApi.ResultCallback() {
    @Override
    public void onSuccess(String result) {
        Log.i("Main", "已切换到 DHCP");
    }

    @Override
    public void onError(Exception e) {
        Log.e("Main", "切换 DHCP 失败", e);
    }
});

4. 新旧 API 对比

特性 旧 API setConfiguration() 新 API updateConfiguration()
引入版本 早期(@hide / @UnsupportedAppUsage) Android 14+
调用方式 同步 异步 + OutcomeReceiver
异常处理 抛出 Exception 结构化 EthernetNetworkManagementException
权限要求 CONNECTIVITY_INTERNAL 等 必须 MANAGE_ETHERNET_NETWORKS
持久化 是(写入 ipconfig.txt) 是(相同路径)
官方推荐(Android 16) 仍可用,但不推荐新项目 强烈推荐
Automotive / 新网络栈 兼容性一般 最佳支持

5. 编译与部署

  1. 将工程放入 packages/apps/YourEthernetConfig/

  2. 使用上方 Android.bp 配置

  3. 在 device.mk 添加 PRODUCT_PACKAGES += EthernetConfig

  4. 全编译或模块编译:

    bash 复制代码
    mmm packages/apps/YourEthernetConfig
  5. 刷机或 adb root && adb remount && adb push ...

6. 验证方法

bash 复制代码
# 查看当前接口状态
adb shell ip addr show eth0

# 查看持久化配置文件
adb shell cat /data/misc/ethernet/ipconfig.txt

# 重启验证是否持久化
adb reboot
adb shell ip addr show eth0

# 查看可用接口
adb shell dumpsys ethernet

7. 注意事项与常见问题

  1. 必须平台签名 + priv-app,普通签名应用无法调用。
  2. MANAGE_ETHERNET_NETWORKS 是 Android 14+ 新权限,必须在 privapp-permissions 中声明。
  3. 接口名不一定永远是 eth0,建议先调用 getAvailableInterfaces() 确认。
  4. 配置写入 /data/misc/ethernet/ipconfig.txt 后,系统网络栈会在启动时自动加载。
  5. 如果同时存在 init 脚本或 vendor 层强制配置,可能会产生冲突,优先使用 Framework API。
  6. 新 API 是异步的,UI 操作请在回调中更新状态。

总结推荐路径(Android 16)

  1. 做成 priv-app + 平台签名
  2. 使用 EthernetManager.updateConfiguration() + EthernetNetworkUpdateRequest
  3. 正确添加 MANAGE_ETHERNET_NETWORKS 权限白名单
  4. 配置自动持久化,重启后仍然生效

这是目前 Android 16 AOSP 上最符合官方架构、最干净、最可维护的系统 App 修改 eth0 IP 方案。

相关推荐
其实防守也摸鱼1 小时前
渗透测试学习计划(全栈综合 · 零基础进阶)
android·数据库·学习·安全·oracle·自动化·学习方法
释厄6231 小时前
BSD 简单真理循环论——简单真理 × 复杂循环=大一统
android·开发语言·kotlin
Brilliantwxx3 小时前
【STM32】 DMA 源码分析与实战(下):DMA 收发状态机与 HAL 分层
android·开发语言·stm32·单片机·嵌入式硬件·mcu
ao-weilai3 小时前
MySQL数据库:数据类型
android·数据库·mysql
天空之城--3 小时前
Android一周动态:Android 18首次官宣、Compose Material3 1.4转正(5趋势+5资讯)
android·人工智能·flutter·架构·android jetpack
恋猫de小郭3 小时前
Meta 分享怎么用 AI 迁移 Compose 项目不烧心
android·前端·flutter
纪念 2294 小时前
C++ string(一)
android·开发语言·c++
火柴就是我15 小时前
Flutter 项目本地 Maven 引入 AAR 找不到?一次 Gradle 路径问题排查
android
火柴就是我16 小时前
Android 打包报错 25.0.3
android·前端