移植EthernetSettings

Android 13 在Settings搜索没有发现以太网设置,应该是移除了,但是客户的设备需要,所以移植Android 11的.

以太网相关的功能在Android13中进行模块化,提取到packages/modules/Connectivity/中,
EthernetManager相关代码从framework移到packages/modules/Connectivity/下.

Android 13 internet界面有无网络,会显示不同的界面!

--- a/packages/modules/Connectivity/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java
+++ b/packages/modules/Connectivity/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java
@@ -16,11 +16,16 @@

 package com.android.server.ethernet;

+import static android.net.EthernetManager.ETHERNET_STATE_DISABLED;
+import static android.net.EthernetManager.ETHERNET_STATE_ENABLED;
 import static android.net.NetworkCapabilities.TRANSPORT_TEST;

 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.content.BroadcastReceiver;
 import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;

@@ -63,6 +69,14 @@ public class EthernetServiceImpl extends IEthernetManager.Stub {
         mContext = context;
         mHandler = handler;
         mTracker = tracker;
+        //add xxx
+        IntentFilter intentFilter = new IntentFilter();
+        intentFilter.addAction("xx.action.xx.ethernet.open");
+        intentFilter.addAction("xx.action.xx.ethernet.close");
+        mEthernetSwitchBroadcast = new EthernetSwitchBroadcastReceiver();
+        context.registerReceiver(mEthernetSwitchBroadcast, intentFilter);
+        //add xxx
+
     }

     private void enforceAutomotiveDevice(final @NonNull String methodName) {
@@ -77,9 +91,63 @@ public class EthernetServiceImpl extends IEthernetManager.Stub {

     public void start() {
         Log.i(TAG, "Starting Ethernet service");
-        mTracker.start();
-        mStarted.set(true);
+        //add xxx
+        //mTracker.start();
+        //mStarted.set(true);
+        mEthernetState = getEthernetState();
+        boolean is_enabled = false;
+        if (mEthernetState == ETHERNET_STATE_ENABLED) {
+            is_enabled = true;
+        }
+        mTracker.start(is_enabled);
+        mStarted.set(is_enabled);
+        //add xxx
+    }
+
+    //add xxx
+    private EthernetSwitchBroadcastReceiver mEthernetSwitchBroadcast;
+    private int mState = -1;
+    private int mEthernetState; //-1 init 0 disable 1 enable
+
+    private int getEthernetState() {
+        int state = SystemProperties.getInt("xxx_ethernet_on", 0);
+        return state;
+    }
+
+    private void setEthernetState(int state) {
+        //SystemProperties.set("xxx__ethernet_on", state + "");
+    }
+
+    public synchronized void setState(int state) {
+        Log.i(TAG, "setState from mState=" + mState + " to state=" + state);
+        if (mState != state) {
+            mState = state;
+            if (state == ETHERNET_STATE_DISABLED) {
+                //setEthernetState(ETHERNET_STATE_DISABLED);
+                mTracker.setIntefaceState(false);
+                mStarted.set(false);
+            } else {
+                //setEthernetState(ETHERNET_STATE_ENABLED);
+                mTracker.setIntefaceState(true);
+                mStarted.set(true);
+            }
+        }
+    }
+
+    class EthernetSwitchBroadcastReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            Log.d(TAG, "EthernetSwitchBroadcastReceiver action:" + action);
+            if (action.equals("xx.action.xx.ethernet.open")) {
+                setState(ETHERNET_STATE_ENABLED);
+            } else if (action.equals("xx.action.xx.ethernet.close")) {
+                setState(ETHERNET_STATE_DISABLED);
+            }
+
+        }
     }
+    //add xxx

     private void throwIfEthernetNotStarted() {
         if (!mStarted.get()) {
diff --git a/packages/modules/Connectivity/service-t/src/com/android/server/ethernet/EthernetTracker.java b/packages/modules/Connectivity/service-t/src/com/android/server/ethernet/EthernetTracker.java
index 1c02a6625f..34c8c8dc8d 100644
--- a/packages/modules/Connectivity/service-t/src/com/android/server/ethernet/EthernetTracker.java
+++ b/packages/modules/Connectivity/service-t/src/com/android/server/ethernet/EthernetTracker.java
@@ -43,6 +43,7 @@ import android.os.Handler;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.os.ServiceSpecificException;
+import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.Log;
@@ -173,7 +174,12 @@ public class EthernetTracker {
         mConfigStore = new EthernetConfigStore();
     }

+    //add xxx
     void start() {
+        start(true);
+    }
+
+    void start(boolean isEnabled) {
         mFactory.register();
         mConfigStore.read();

@@ -191,8 +197,31 @@ public class EthernetTracker {
             Log.e(TAG, "Could not register InterfaceObserver " + e);
         }

-        mHandler.post(this::trackAvailableInterfaces);
+        if (isEnabled) {
+            mHandler.post(this::trackAvailableInterfaces);
+        }
+    }
+
+    public synchronized void setIntefaceState(boolean isFaceUp) {
+        try {
+            String[] interfaces = getInterfaces(true);
+            for (String iface : interfaces) {
+                if (isTrackingInterface(iface)) {
+                    if (isFaceUp) {
+                        NetdUtils.setInterfaceUp(mNetd, iface);
+                    } else {
+                        NetdUtils.setInterfaceDown(mNetd, iface);
+                    }
+                }
+            }
+            if (isFaceUp) {
+                mHandler.post(this::trackAvailableInterfaces);
+            }
+        } catch (Exception e) {
+            Log.e(TAG, "Error change eth isFaceUp : " + isFaceUp);
+        }
     }
+    //add xxx

     void updateIpConfiguration(String iface, IpConfiguration ipConfiguration) {
         if (DBG) {
@@ -521,7 +550,7 @@ public class EthernetTracker {
         }

         final String hwAddress = config.hwAddr;
-
+        Settings.System.putString(mContext.getContentResolver(), "sys_tex_hwAddress", hwAddress);//add xx xx
         NetworkCapabilities nc = mNetworkCapabilities.get(iface);
         if (nc == null) {
             // Try to resolve using mac address

Android13 有线网开关研究
Android13 原生以太网实现设置静态IP
Android13 MTK平台添加以太网设置静态IP菜单

问题补充:再/packages/modules/Connectivity/service-t/src/com/android/server/ethernet/ 目录下,
想利用SystemProperties.set()保存数据,但是编译报错,error: cannot find symbol,但是我明明导入了!
为什么这么确认我导入,因为还引用了SystemProperties.getInt().然后控制变量,定位到问题是SystemProperties.set()无法再这个目录使用.
为什么会有这个问题呢?我百度大法,有了一些大致的猜想!然后去查看了它的Android.bp

packages/modules/Connectivity/service-t/Android.bp

// This builds T+ services depending on framework-connectivity-t
// hidden symbols separately from the S+ services, to ensure that S+
// services cannot accidentally depend on T+ hidden symbols from
// framework-connectivity-t.
java_library {
    name: "service-connectivity-tiramisu-pre-jarjar",
    sdk_version: "system_server_current",
    // TODO(b/210962470): Bump this to at least S, and then T.
    min_sdk_version: "30",
    srcs: [
        ":service-connectivity-tiramisu-sources",
    ],
    libs: [ 

问题可能关于sdk_version这个属性有关!
当然上面的都只是猜测,只是做个记录,为什么无法编译的bug还没解决.

然后去询问大佬,大佬提供一个思路,让我用反射去调用它,确实编译通过了,数据也能保存.
(ps:我太执着于解决那个编译报错,而忘记了自己的目的!目的是啥,是利用SystemProperties.set()保存数据,
既然(正常)固定的调用方式编译报错,然后一时半会又搞不定编译报错(难点:报错信息不够明确,无法定位).
应该先去想还有什么其它的方式可能调用SystemProperties.set(),先达成目的,然后再回来想想那个编译报错.)

+++ b/packages/modules/Connectivity/service-t/src/com/android/server/ethernet/EthernetTracker.java
+import java.lang.reflect.Method;
@@ -551,6 +552,7 @@ public class EthernetTracker {

         final String hwAddress = config.hwAddr;
+        setProperty("sys.xxx.xxx",hwAddress);
         NetworkCapabilities nc = mNetworkCapabilities.get(iface);
         if (nc == null) {
             // Try to resolve using mac address
@@ -578,6 +580,17 @@ public class EthernetTracker {
         }
     }

+    //add text
+    private void setProperty(String key, String value){
+        try {
+            Class<?> c =  Class.forName("android.os.SystemProperties");
+            Method method = c.getMethod("set",String.class,String.class);
+            method.invoke(c,key,value);
+        }catch (Exception e){
+            Log.d(TAG,"xxxxxxxxxx");
+        }
+    }
+    //add text

大佬的博客,感谢大佬
Android 使用反射机制获取或设置系统属性
Android高版本源码编译提示error: cannot find symbol
内置 APP 如何访问隐藏 API

Ethernet更新

新增以太网打开关闭的函数

./packages/modules/Connectivity/framework-t/src/android/net/EthernetManager.java
    @RequiresPermission(anyOf = {
            NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
            android.Manifest.permission.NETWORK_STACK,
            android.Manifest.permission.NETWORK_SETTINGS})
    @SystemApi(client = MODULE_LIBRARIES)
    public void setEthernetEnabled(boolean enabled) {
        try {
            mService.setEthernetEnabled(enabled);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }
//需要权限和系统应用签名(SystemApi) 

Android 13 Ethernet变更

Anrdoir 13 adout static net ip
frameworks/base/core/java/android/net/EthernetManager.java //上层用于管理以太网,app可调用

packages/modules/Connectivity/framework/src/android/net/IpConfiguration.java//用来配置动态/静态IP

packages/modules/Connectivity/framework/src/android/net/StaticIpConfiguration.java //静态IP参数类

ConnectivityService 日志TAG

import java.net.Inet4Address;
import java.net.InetAddress;
import android.net.EthernetManager;
import android.net.IpConfiguration;
import android.net.IpConfiguration.IpAssignment;
import android.net.IpConfiguration.ProxySettings;
import android.net.wifi.SupplicantState;
import android.net.wifi.WifiInfo;
import android.net.StaticIpConfiguration;
import android.net.LinkAddress;
import android.net.LinkProperties;

    private void setTextStaticIpConfiguration(Intent intent) {
        String ethMode = null;          // "static";
        String ethIpAddress = null;     //"192.168.1.xxx";
        String ethNetmask = null;       // "255.255.255.0";
        String ethGateway = null;       // "192.168.x.x";
        String ethdns1 = null;          // "192.168.x.x";
        String ethdns2 = null;          //"null";

        mEthManager = (EthernetManager)getSystemService(Context.ETHERNET_SERVICE);
        if (mEthManager == null) {
            Log.i(TAG, "setTextStaticIpConfiguration: fail to getSystemService :  " + Context.ETHERNET_SERVICE);
        }
        String[] ifaces = mEthManager.getAvailableInterfaces();
        if (ifaces.length > 0) {
            mIfaceName = ifaces[0];//"eth0";
        }
        if (null == mIfaceName) {
            Log.e(TAG, "setTextStaticIpConfiguration: get ethernet ifaceName failed");
            return;
        }

        Bundle bundle = intent.getExtras();
        if (bundle.getString("netMode") != null)
            ethMode = bundle.getString("netMode");
        if (bundle.getString("ipaddr") != null)
            ethIpAddress = bundle.getString("ipaddr");
        if (bundle.getString("netMask") != null)
            ethNetmask = bundle.getString("netMask");
        if (bundle.getString("gateway") != null)
            ethGateway = bundle.getString("gateway");
        if (bundle.getString("dns1") != null)
            ethdns1 = bundle.getString("dns1");
        if (bundle.getString("dns2") != null)
            ethdns2 = bundle.getString("dns2");

        Log.d(TAG, "static net:" + ethMode + "#" + ethIpAddress + "#" + ethNetmask + "#" + ethGateway + "#" + ethdns1 + "#" + ethdns2);

        if (ethMode == null || ethMode.equals("static")) {
            Inet4Address inetAddr = getIPv4Address(ethIpAddress);
            int prefixLength = maskStr2InetMask(ethNetmask);
            Inet4Address gatewayAddr = getIPv4Address(ethGateway);
            Inet4Address dnsAddr1 = getIPv4Address(ethdns1);
            Inet4Address dnsAddr2 = getIPv4Address(ethdns2);
            
            if (inetAddr == null || gatewayAddr == null || prefixLength <= 0) {
                Log.e(TAG, "ip, mask or dnsAddr is wrong-null");
                return;
            }
            if (inetAddr.getAddress().toString().isEmpty() || prefixLength == 0 || gatewayAddr.toString().isEmpty()) {
                Log.e(TAG, "ip,mask or dnsAddr is wrong-isEmpty");
                return;
            }

            List<InetAddress> arrayList = new ArrayList();
            if (dnsAddr1 != null && !dnsAddr1.toString().isEmpty()) {
                arrayList.add(dnsAddr1);
            }
            if (dnsAddr2 != null && !dnsAddr2.toString().isEmpty()) {
                arrayList.add(dnsAddr2);
            }

            mStaticIpConfiguration = new StaticIpConfiguration.Builder()
                    .setIpAddress(new LinkAddress(inetAddr, prefixLength))
                    .setGateway(gatewayAddr)
                    .setDnsServers(arrayList)
                    .build();

            mIpConfiguration = new IpConfiguration();
            mIpConfiguration.setIpAssignment(IpAssignment.STATIC);
            mIpConfiguration.setProxySettings(IpConfiguration.ProxySettings.NONE);
            mIpConfiguration.setStaticIpConfiguration(mStaticIpConfiguration);
            mEthManager.setConfiguration("eth0", mIpConfiguration);
        }
    }

关于设置静态ip后,设备重启后失效. 怀疑是静态ip没有被保存在系统,然后重启后ip切换为动态.
然后查看日志,确实如此:E DelayedDiskWrite: Error writing data file...

08-13 02:53:24.929   713   876 I EthernetTracker: updateIpConfiguration, iface: eth0, cfg: IP assignment: STATIC
08-13 02:53:24.929   713   876 I EthernetTracker: Static configuration: IP address 192.168.1.254/24 Gateway 192.168.1.1  DNS servers: [ 192.168.1.1 ] Domains 
08-13 02:53:24.929   713   876 I EthernetTracker: Proxy settings: NONE
08-13 02:53:24.932   713  2160 E DelayedDiskWrite: Error writing data file /data/misc/apexdata/com.android.tethering/misc/ethernet/ipconfig.txt
08-13 02:53:24.932   713   839 D EthernetNetworkFactory: updateInterface, iface: eth0, ipConfig: IP assignment: STATIC
08-13 02:53:24.932   713   839 D EthernetNetworkFactory: Static configuration: IP address 192.168.1.254/24 Gateway 192.168.1.1  DNS servers: [ 192.168.1.1 ] Domains 
08-13 02:53:24.932   713   839 D EthernetNetworkFactory: Proxy settings: NONE
08-13 02:53:24.932   713   839 D EthernetNetworkFactory: , old ipConfig: IP assignment: DHCP
08-13 02:53:24.932   713   839 D EthernetNetworkFactory: Proxy settings: NONE
08-13 02:53:24.932   713   839 D EthernetNetworkFactory: , capabilities: null, old capabilities: [ Transports: ETHERNET Capabilities: NOT_METERED&INTERNET&NOT_RESTRICTED&TRUSTED&NOT_VPN&NOT_ROAMING&NOT_CONGESTED&NOT_SUSPENDED&NOT_VCN_MANAGED LinkUpBandwidth>=100000Kbps LinkDnBandwidth>=100000Kbps Specifier: <EthernetNetworkSpecifier (eth0)> UnderlyingNetworks: Null], listener: null
08-13 02:53:24.932   713   839 D EthernetNetworkFactory: reconnecting Ethernet
08-13 02:53:24.969   713  1219 D DhcpClient: doQuit
08-13 02:53:24.996   713  1219 D DhcpClient: DHCP Packet Handler stopped
08-13 02:53:24.997   713  1219 D DhcpClient: onQuitting
08-13 02:53:25.025   713   839 D EthernetNetworkFactory: Starting Ethernet IpClient(eth0)
08-13 02:53:25.025   713   840 D ConnectivityService: [100 ETHERNET] EVENT_NETWORK_INFO_CHANGED, going from CONNECTED to DISCONNECTED
08-13 02:53:25.025   713   840 D ConnectivityService: [100 ETHERNET] disconnected, was satisfying 17
08-13 02:53:25.030   713   839 I EthernetNetworkFactory: Ignoring stale IpClientCallbacks com.android.server.ethernet.EthernetNetworkFactory$NetworkInterfaceState$EthernetIpClientCallback@1a9aff9
08-13 02:53:25.031   713   839 D EthernetNetworkAgent: NetworkAgent: NetworkAgent channel lost        

Android 13 有线以太网静态ip保存逻辑梳理分析

//1.0
EthernetManager mEthManager = (EthernetManager)getSystemService(Context.ETHERNET_SERVICE);
mIpConfiguration = new IpConfiguration();
....
mEthManager.setConfiguration("eth0", mIpConfiguration);//去设置静态IP

//1.1
packages/modules/Connectivity/framework-t/src/android/net/EthernetManager.java

    public void setConfiguration(@NonNull String iface, @NonNull IpConfiguration config) {
        try {
            mService.setConfiguration(iface, config);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

//1.2   
packages/modules/Connectivity/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java
    @Override
    public void setConfiguration(String iface, IpConfiguration config) {
        ...
        // Fix this by making IpConfiguration a complete representation of static configuration.
        mTracker.updateIpConfiguration(iface, new IpConfiguration(config));
    }
    
//1.3 
packages/modules/Connectivity/service-t/src/com/android/server/ethernet/EthernetTracker.java

    void updateIpConfiguration(String iface, IpConfiguration ipConfiguration) {
        if (DBG) {
            Log.i(TAG, "updateIpConfiguration, iface: " + iface + ", cfg: " + ipConfiguration);
        }
        writeIpConfiguration(iface, ipConfiguration);//写入IpConfiguration相关信息,主要和静态ip关联
        mHandler.post(() -> {
            mFactory.updateInterface(iface, ipConfiguration, null, null);//更新ipConfiguration
            broadcastInterfaceStateChange(iface);//发送通知,告诉系统网络接口改变
        });
    }

    private void writeIpConfiguration(@NonNull final String iface,
            @NonNull final IpConfiguration ipConfig) {
        mConfigStore.write(iface, ipConfig);
        mIpConfigurations.put(iface, ipConfig);
    }

//1.4 
packages/modules/Connectivity/service-t/src/com/android/server/ethernet/EthernetConfigStore.java  

private static final String CONFIG_FILE = "ipconfig.txt";
    private static final String FILE_PATH = "/misc/ethernet/";
    private static final String LEGACY_IP_CONFIG_FILE_PATH = Environment.getDataDirectory()
            + FILE_PATH;
    private static final String APEX_IP_CONFIG_FILE_PATH = ApexEnvironment.getApexEnvironment(
            TETHERING_MODULE_NAME).getDeviceProtectedDataDir() + FILE_PATH;  
    
    private IpConfigStore mStore = new IpConfigStore();
    
    //关于读    
    public void read() {
        read(APEX_IP_CONFIG_FILE_PATH, LEGACY_IP_CONFIG_FILE_PATH, CONFIG_FILE);
    }
    //关于写
    public void write(String iface, IpConfiguration config) {
        write(iface, config, APEX_IP_CONFIG_FILE_PATH + CONFIG_FILE);
    }

    @VisibleForTesting
    void write(String iface, IpConfiguration config, String filepath) {
        boolean modified;

        synchronized (mSync) {
            if (config == null) {
                modified = mIpConfigurations.remove(iface) != null;
            } else {
                IpConfiguration oldConfig = mIpConfigurations.put(iface, config);
                modified = !config.equals(oldConfig);
            }

            if (modified) {
                mStore.writeIpConfigurations(filepath, mIpConfigurations);
            }
        }
    }
    
//1.5 
packages/modules/Connectivity/service-t/src/com/android/server/net/IpConfigStore.java
    //最后是这里写入
    @VisibleForTesting
    public static boolean writeConfig(DataOutputStream out, String configKey,
                                IpConfiguration config, int version) throws IOException {
        boolean written = false;

        try {
            switch (config.getIpAssignment()) {
                case STATIC:
                    out.writeUTF(IP_ASSIGNMENT_KEY);
                    out.writeUTF(config.getIpAssignment().toString());
                    StaticIpConfiguration staticIpConfiguration = config.getStaticIpConfiguration();
                    if (staticIpConfiguration != null) {
                        if (staticIpConfiguration.getIpAddress() != null) {
                            LinkAddress ipAddress = staticIpConfiguration.getIpAddress();
                            out.writeUTF(LINK_ADDRESS_KEY);
                            out.writeUTF(ipAddress.getAddress().getHostAddress());
                            out.writeInt(ipAddress.getPrefixLength());
                        }
                        if (staticIpConfiguration.getGateway() != null) {
                            out.writeUTF(GATEWAY_KEY);
                            out.writeInt(0);  // Default route.
                            out.writeInt(1);  // Have a gateway.
                            out.writeUTF(staticIpConfiguration.getGateway().getHostAddress());
                        }
                        for (InetAddress inetAddr : staticIpConfiguration.getDnsServers()) {
                            out.writeUTF(DNS_KEY);
                            out.writeUTF(inetAddr.getHostAddress());
                        }
                    }
                    written = true;
                    break;
                case DHCP:
                    out.writeUTF(IP_ASSIGNMENT_KEY);
                    out.writeUTF(config.getIpAssignment().toString());
                    written = true;
                    break;
                case UNASSIGNED:
                /* Ignore */
                    break;
        ...
    }        

Android 12 之前 数据保存于/data/misc/ethernet/ipconfig.txt.

根据上面分析的流程,数据是要被写入/data/misc/apexdata/com.android.tethering/misc/ethernet/ipconfig.txt,但是日志报错,说明写入失败了.
一般文件写入失败的原因,大多数是权限问题,但是这个日志么有看到关于权限的信息,所以排除.
AS(Android studio)或者adb查看设备是否有这个文件,发现都没有/misc/ethernet/这个目录,这可能就是导致无法写入的原因

xx:/ # ls -al /data/misc/apexdata/com.android.tethering/
total 9
drwxrwx--x  3 root   system 3452 2024-08-13 08:47 .
drwx--x--x 27 root   root   3452 2024-08-13 08:47 ..
drwx------  2 system system 3452 2024-08-13 08:51 netstats

所以创建一下这个目录,验证之后,解决问题,代码如下:

packages/modules/Connectivity/service-t/src/com/android/server/ethernet/EthernetConfigStore.java  

    void write(String iface, IpConfiguration config, String filepath) {
        boolean modified;

        synchronized (mSync) {
            if (config == null) {
                modified = mIpConfigurations.remove(iface) != null;
            } else {
                IpConfiguration oldConfig = mIpConfigurations.put(iface, config);
                modified = !config.equals(oldConfig);
            }

            if (modified) {
                //add text
                final File text_dir = new File(APEX_IP_CONFIG_FILE_PATH);
                if(!text_dir.exists()){
                    text_dir.mkdirs();
                }
                //add text
                mStore.writeIpConfigurations(filepath, mIpConfigurations);
            }
        }
    }

Android T设置静态ip地址,如果设置错误的网关,有线网会一直断开重连.设置正常的网关不会出现.
Android 13 设置静态ip导致有线网一直断开重连分析解决
RK3588 Android 12 Framework修改记录(八)Settings Ethernet以太网 多网卡设置静态IP

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部