当前位置: 首页 > news >正文

Android 13 移植EthernetSettings/Ethernet更新

移植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 xxxprivate 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 xxxvoid 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 xxxvoid 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 xxNetworkCapabilities 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//用来配置动态/静态IPpackages/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.javapublic 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@Overridepublic 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.javavoid 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);//更新ipConfigurationbroadcastInterfaceStateChange(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);}@VisibleForTestingvoid 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//最后是这里写入@VisibleForTestingpublic 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 textfinal File text_dir = new File(APEX_IP_CONFIG_FILE_PATH);if(!text_dir.exists()){text_dir.mkdirs();}//add textmStore.writeIpConfigurations(filepath, mIpConfigurations);}}}

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

相关文章:

Android 13 移植EthernetSettings/Ethernet更新

移植EthernetSettings Android 13 在Settings搜索没有发现以太网设置,应该是移除了,但是客户的设备需要,所以移植Android 11的. 以太网相关的功能在Android13中进行模块化,提取到packages/modules/Connectivity/中, EthernetManager相关代码从framework移到packages/modules/…...

极狐GitLab 如何设置访问令牌前缀?

极狐GitLab 是 GitLab 在中国的发行版&#xff0c;专门面向中国程序员和企业提供企业级一体化 DevOps 平台&#xff0c;用来帮助用户实现需求管理、源代码托管、CI/CD、安全合规&#xff0c;而且所有的操作都是在一个平台上进行&#xff0c;省事省心省钱。可以一键安装极狐GitL…...

leetcode日记(72)最大矩形

依旧是看了答案才知道大概方法…太难想到了 和上一道题思路相似&#xff01;可以直接调用上题的函数&#xff0c;只不过调用前的准备非常难想到&#xff0c;就是建造形状相同的矩阵&#xff0c;第i行j列的元素是i行中j列前相邻的“1”的个数。 class Solution { public:int m…...

自驾畅游保定:参观总督署,品美食文化

这是学习笔记的第 2490篇文章 前几天跟孩子聊天&#xff0c;孩子说暑假都没出去玩了&#xff0c;暑假旅行的作业咋写&#xff1f;让我有满满的负疚感&#xff0c;去附近的公园、吃点美食不算旅游&#xff0c;得了&#xff0c;得安排一下一日游。 几个月前心心念的去保定&#x…...

我常用的几个傻瓜式爬虫工具,收藏!

爬虫类工具主要两种&#xff0c;一种是编程语言第三方库&#xff0c;比如Python的scrapy、selenium等&#xff0c;需要有一定的代码基础&#xff0c;一种是图形化的web或桌面应用&#xff0c;比如Web Scraper、后羿采集器、八爪鱼采集器、WebHarvy等&#xff0c;接近于傻瓜式操…...

数据分析2 Numpy+Scipy+Matplotlib+Pandas

3.设置坐标范围 mp.xlim(水平坐标最小值, 水平坐标最大值) mp.ylim(垂直坐标最小值, 垂直坐标最大值) 代码&#xff1a;plt3.py 4.设置坐标刻度 mp.xticks(位置序列[, 标签序列]) mp.yticks(位置序列[, 标签序列]) 代码&#xff1a;plt4.py 5.设置坐标轴 坐标轴名&#xff1a;l…...

手机IP地址:是根据网络还是设备决定的?

在日益数字化的今天&#xff0c;手机已经成为我们日常生活中不可或缺的一部分。它不仅是我们沟通的桥梁&#xff0c;更是我们获取信息、享受娱乐和完成工作的得力助手。然而&#xff0c;在使用手机上网的过程中&#xff0c;你是否曾经好奇过手机的IP地址是如何被分配的&#xf…...

数据结构-常见的七大排序

上节中我们学习了七大排序中的五种(插入排序、希尔排序、堆排序、选择排序、交换排序) 数据结构-常见的七大排序-CSDN博客 这节我们将要学习快速排序(hoare、指针法、挖洞法(快排的延伸)、快速排序非递归(栈)) 1.快速排序 1.1 hoare法 1.1思路 1.选出一个key&#xff0c;一…...

离线安装部署springboot+vue系统到服务器

注意&#xff1a;首先服务器会有多个网卡&#xff0c;这些服务器的网卡连接所需要的文件可能不是我们默认的ifcfg-eth0/ifcfgens33,可以试着切换一下服务器网线插入的接口&#xff0c;要保证服务器网线插入的接口和网卡对应的文件一致 说明&#xff0c;在一些政府&#xff08;保…...

【STM32】ADC模拟数字转换(规则组单通道)

本篇博客重点在于标准库函数的理解与使用&#xff0c;搭建一个框架便于快速开发 目录 ADC简介 ADC时钟配置 引脚模拟输入模式 规则组通道选择 ADC初始化 工作模式 数据对齐 触发转换方式 连续与单次转换模式 扫描模式 组内的通道个数 ADC初始化框架 ADC上电 ADC校…...

WPF 数据模板DataTemplate、控件模板ControlTemplate、Style、ItemsPreseter

一言蔽之&#xff0c;Template就是“外衣”—— ControlTemplate是控件的外衣&#xff0c; DataTemplate是数据的外衣。 DataTemplate 它定义了一个数据对象的可视化结构 DataTemplate常用的地方有3处&#xff0c;分别是&#xff1a; ContentControl的ContentTemplate属性&…...

Windows下搭建Telegraf+Influxdb+Grafana(详解一)

InfluxDB&#xff08;时序数据库&#xff09;&#xff0c;常用使用场景&#xff1a;监控数据统计。 grafana&#xff0c;用作监控页面的前端展示。 telegraf&#xff0c;数据采集器。 所有的安装包都上传到网盘 链接: https://pan.baidu.com/s/1Lv6UnfueK7URx7emAatoYg 提取…...

同城搭子社交系统开发同城搭子群活动APP圈子动态小程序

引言 随着互联网技术的飞速发展&#xff0c;同城搭子社交系统作为一种新兴的社交模式&#xff0c;正逐渐在市场中占据一席之地。该系统通过搭子群活动和圈子动态等功能&#xff0c;为用户提供了一种高效、精准的社交体验。本文将从市场前景、使用人群、盈利模式以及运营推广等…...

大厂最佳实践 | Stripe 如何防止重复付款

为什么扣了我两笔钱&#xff1f; 2010年&#xff0c;美国加利福尼亚州的两兄弟打算创办一家公司&#xff0c;但他们发现建立网上支付十分困难。于是&#xff0c;他们决定开发一款在线支付服务&#xff0c;并将其命名为Stripe。 随着用户数量的不断增长&#xff0c;重复付费问题…...

Raspberry Pi Pico 2 上实现:实时机器学习(ML)音频噪音抑制功能

Arm 公司的首席软件工程师 Sandeep Mistry 为我们展示了一种全新的巧妙方法&#xff1a; 在 Raspberry Pi Pico 2 上如何将音频噪音抑制应用于麦克风输入。 机器学习&#xff08;ML&#xff09;技术彻底改变了许多软件应用程序的开发方式。应用程序开发人员现在可以为所需系统整…...

安全自动化和编排:如何使用自动化工具和编排技术来提高安全操作效率。(第二篇)

深入理解Kubernetes环境中的安全自动化与编排&#xff08;第二篇&#xff09; 1. 引言 Kubernetes作为现代容器编排平台的主流选择&#xff0c;正在被越来越多的企业用于部署和管理其容器化应用。在Kubernetes环境中实施安全自动化与编排&#xff0c;既能够提升系统的安全性&…...

HarmonyOS WebView

HarmonyOS WebView Web组件提供基础的前端页面加载的能力&#xff0c;包括加载网络页面、本地页面、html格式文本数据。Web组件提供丰富的页面交互的方式&#xff0c;包括&#xff1a;设置前端页面深色模式&#xff0c;新窗口中加载页面&#xff0c;位置权限管理&#xff0c;C…...

解决elementUI表格里嵌套输入框,检验时错误信息被遮挡

1.表格 自定义错误信息显示div <el-form-item label"租赁价格" prop"supplierId"><el-table-column prop"salePrice" label"销售价" align"center"><template slot-scope"scope"><el-form-…...

Unity读取Android外部文件

最近近到个小需求,需要读Android件夹中的图片.在这里做一个记录. 首先读写部分,这里以图片为例子: 一读写部分 写入部分: 需要注意的是因为只有这个地址支持外部读写,所以这里用到的地址都以 :Application.persistentDataPath为地址起始. private Texture2D __CaptureCamera…...

【5.3 python中的元组】

5.3 python中的元组 Python中的元组&#xff08;Tuple&#xff09;是一种用于存储多个项目&#xff08;可以是不同类型&#xff09;的序列数据结构&#xff0c;但它与列表&#xff08;List&#xff09;不同&#xff0c;主要区别在于元组是不可变的&#xff08;immutable&#…...

2025 后端自学UNIAPP【项目实战:旅游项目】6、我的收藏页面

代码框架视图 1、先添加一个获取收藏景点的列表请求 【在文件my_api.js文件中添加】 // 引入公共的请求封装 import http from ./my_http.js// 登录接口&#xff08;适配服务端返回 Token&#xff09; export const login async (code, avatar) > {const res await http…...

html-<abbr> 缩写或首字母缩略词

定义与作用 <abbr> 标签用于表示缩写或首字母缩略词&#xff0c;它可以帮助用户更好地理解缩写的含义&#xff0c;尤其是对于那些不熟悉该缩写的用户。 title 属性的内容提供了缩写的详细说明。当用户将鼠标悬停在缩写上时&#xff0c;会显示一个提示框。 示例&#x…...

学校时钟系统,标准考场时钟系统,AI亮相2025高考,赛思时钟系统为教育公平筑起“精准防线”

2025年#高考 将在近日拉开帷幕&#xff0c;#AI 监考一度冲上热搜。当AI深度融入高考&#xff0c;#时间同步 不再是辅助功能&#xff0c;而是决定AI监考系统成败的“生命线”。 AI亮相2025高考&#xff0c;40种异常行为0.5秒精准识别 2025年高考即将拉开帷幕&#xff0c;江西、…...

USB Over IP专用硬件的5个特点

USB over IP技术通过将USB协议数据封装在标准TCP/IP网络数据包中&#xff0c;从根本上改变了USB连接。这允许客户端通过局域网或广域网远程访问和控制物理连接到服务器的USB设备&#xff08;如专用硬件设备&#xff09;&#xff0c;从而消除了直接物理连接的需要。USB over IP的…...

Python Ovito统计金刚石结构数量

大家好,我是小马老师。 本文介绍python ovito方法统计金刚石结构的方法。 Ovito Identify diamond structure命令可以识别和统计金刚石结构,但是无法直接输出结构的变化情况。 本文使用python调用ovito包的方法,可以持续统计各步的金刚石结构,具体代码如下: from ovito…...

OD 算法题 B卷【正整数到Excel编号之间的转换】

文章目录 正整数到Excel编号之间的转换 正整数到Excel编号之间的转换 excel的列编号是这样的&#xff1a;a b c … z aa ab ac… az ba bb bc…yz za zb zc …zz aaa aab aac…; 分别代表以下的编号1 2 3 … 26 27 28 29… 52 53 54 55… 676 677 678 679 … 702 703 704 705;…...

快速排序算法改进:随机快排-荷兰国旗划分详解

随机快速排序-荷兰国旗划分算法详解 一、基础知识回顾1.1 快速排序简介1.2 荷兰国旗问题 二、随机快排 - 荷兰国旗划分原理2.1 随机化枢轴选择2.2 荷兰国旗划分过程2.3 结合随机快排与荷兰国旗划分 三、代码实现3.1 Python实现3.2 Java实现3.3 C实现 四、性能分析4.1 时间复杂度…...

加密通信 + 行为分析:运营商行业安全防御体系重构

在数字经济蓬勃发展的时代&#xff0c;运营商作为信息通信网络的核心枢纽&#xff0c;承载着海量用户数据与关键业务传输&#xff0c;其安全防御体系的可靠性直接关乎国家安全、社会稳定与企业发展。随着网络攻击手段的不断升级&#xff0c;传统安全防护体系逐渐暴露出局限性&a…...

【实施指南】Android客户端HTTPS双向认证实施指南

&#x1f510; 一、所需准备材料 证书文件&#xff08;6类核心文件&#xff09; 类型 格式 作用 Android端要求 CA根证书 .crt/.pem 验证服务器/客户端证书合法性 需预置到Android信任库 服务器证书 .crt 服务器身份证明 客户端需持有以验证服务器 客户端证书 .crt 客户端身份…...

小智AI+MCP

什么是小智AI和MCP 如果还不清楚的先看往期文章 手搓小智AI聊天机器人 MCP 深度解析&#xff1a;AI 的USB接口 如何使用小智MCP 1.刷支持mcp的小智固件 2.下载官方MCP的示例代码 Github&#xff1a;https://github.com/78/mcp-calculator 安这个步骤执行 其中MCP_ENDPOI…...