Skip to content

天楚锐齿

人工智能 云计算 大数据 物联网 IT 通信 嵌入式

天楚锐齿

  • 下载
  • 物联网
  • 云计算
  • 大数据
  • 人工智能
  • Linux&Android
  • 网络
  • 通信
  • 嵌入式
  • 杂七杂八

android9下增加对eth0以太网IP地址的配置(以及如何修改并编译SDK)

2020-03-08

增加对以太网IP地址的配置(app用反射方式获取EthernetManager和IEthernetManager的实例来用):

参考 https://github.com/Dufre/Android-Settings-Ethernet
$ vi frameworks/opt/net/ethernet/java/com/android/server/ethernet/EthernetServiceImpl.java
在dump()函数前面添加函数:
    public void updateIpConfiguration(String iface, IpConfiguration ipConfiguration){
        Log.i(TAG, “Enter in updateIpConfiguration, iface == ” + iface);
        mTracker.updateIpConfiguration(iface, ipConfiguration);
        enforceAccessPermission();
        start();
    }
就是在这个dump上面增加上面函数:
    @Override
    protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
$ vi frameworks/base/core/java/android/net/EthernetManager.java
在该行下增加:
     private static final int MSG_AVAILABILITY_CHANGED = 1000;
新加的:
    /**
     * @hide
     */
    public static final String ETHERNET_STATE_CHANGED_ACTION = “android.net.ethernet.ETHERNET_STATE_CHANGED”;
    /**
     * @hide
     */
    public static final String EXTRA_ETHERNET_STATE = “ethernet_state”;
    /**
     * @hide
     */
    public static final int ETHER_STATE_DISCONNECTED = 0;
    /**
     * @hide
     */
    public static final int ETHER_STATE_CONNECTING = 1;
    /**
     * @hide
     */
    public static final int ETHER_STATE_CONNECTED = 2;
    /**
     * @hide
     */
    public static final int ETHER_STATE_DISCONNECTING = 3;
在EthernetManager类的尾部添加该类的函数:
    public int getEthernetCarrierState(String ifname) {
        /*
        try {
            return mService.getEthernetCarrierState(ifname);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
        */
        return 0;
    }
    public String getEthernetMacAddress(String ifname) {
        /*
        try {
            return mService.getEthernetMacAddress(ifname);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
        */
        return “”;
    }
    public int getEthernetConnectState() {
        /*
        try {
            return mService.getEthernetConnectState();
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
        */
        return 0;
    }
    public String getIpAddress() {
        /*
        try {
            return mService.getIpAddress();
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
        */
        return “192.168.1.1”;
    }
    public String getNetmask() {
        /*
        try {
            return mService.getNetmask();
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
        */
        return “255.255.255.0”;
    }
    public String getGateway() {
        /*
        try {
            return mService.getGateway();
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
        */
        return “0.0.255.255”;
    }
    public String getDns() {
        /*
        try {
            return mService.getDns();
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
        */
        return “0.0.0.0”;
    }
    public String dumpCurrentState(int state) {
        /*
        try {
            return mService.dumpCurrentState(state);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
        */
        return “”;
    }
    
    public void disconnect(String iface) {
        /*
        try {
            mService.disconnect(iface);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
        */
    }
    
    
    public void updateIpConfiguration(String iface, IpConfiguration ipConfiguration){
        try {
            mService.updateIpConfiguration(iface, ipConfiguration);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }
$ vi frameworks/base/core/java/android/net/IEthernetManager.aidl
在该行下增加一行:
    void removeListener(in IEthernetServiceListener listener);
就是添加这个函数定义:
    void updateIpConfiguration(String iface, in IpConfiguration ipConfiguration);
$ vi frameworks/base/core/java/android/net/EthernetManager.java
去掉这里的@hide
* @hide
*/
@SystemService(Context.ETHERNET_SERVICE)
public class EthernetManager {
$ vi frameworks/base/core/java/android/net/IpConfiguration.java
去掉这里的@hide
/**
* A class representing a configured network.
* @hide
*/
public class IpConfiguration implements Parcelable {
$ vi frameworks/base/core/java/android/net/StaticIpConfiguration.java
去掉这里的@hide
* @hide
*/
public class StaticIpConfiguration implements Parcelable {
$ vi frameworks/base/core/java/android/net/EthernetManager.java
去掉这里的@link
     * the standard {@link android.content.Context#ETHERNET_SERVICE Context.ETHERNET_SERVICE}.
     */
    public EthernetManager(Context context, IEthernetManager service) {
$ vi frameworks/opt/net/ethernet/java/com/android/server/ethernet/EthernetServiceImpl.java
在public void setConfiguration(String iface, IpConfiguration config) { 底部增加:
该行下面:
        mTracker.updateIpConfiguration(iface, new IpConfiguration(config));
添加两行:
        mTracker.removeInterface(iface);
        mTracker.start();
    }
$ vi frameworks/opt/net/ethernet/java/com/android/server/ethernet/EthernetTracker.java
把
    private void removeInterface(String iface) {
改成:
    public void removeInterface(String iface) {

重新生成sdk库:

$ source build/envsetup.sh
$ lunch full_ac8257_demo-userdebug
$ make update-api
重新登录编译系统:
$ nohup ./allmake.sh -i &
重新生成sdk库:
$ ./allmake.sh sdklibs
生成位置: ac8257-androidP/sdklibs/

然后可以建立新的android studio 3.5的app

把生成的framework_classes.jar 放到 app/libs目录下。
然后源文件中可以导入以下类文件了:
import android.net.EthernetManager;
import android.net.IpConfiguration;
import android.net.LinkAddress;
import android.net.StaticIpConfiguration;
修改AndroidManifest.xml,设置为系统用户来启动app(当然需要系统签名),并且赋予网络访问权限:
<manifest xmlns:android=”http://schemas.android.com/apk/res/android“
package=”com.maxshu.forethernetipset”
android:sharedUserId=”android.uid.system”>
<uses-permission android:name=”android.permission.ACCESS_NETWORK_STATE” />
<uses-permission android:name=”android.permission.INTERNET” />
<uses-permission android:name=”android.permission.CHANGE_NETWORK_STATE” />
<uses-permission android:name=”android.permission.CONNECTIVITY_INTERNAL”/>
<uses-permission android:name=”android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS”/>
然后修改app目录下面的build.gradle,在android { 里面增加:
//为了避免 ask :app:mergeExtDexDebug FAILED 65535 错误。
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
然后需要优先使用framework_classes.jar里面的类,而不是android studio默认的sdk类,在app目录下面的build.gradle尾部增加(实际就是把app.iml文件的<orderEntry type=”jdk” jdkName=”Android API 29 Platform” jdkType=”Android SDK”/>这一行挪到其尾部):
preBuild {
doLast {
def imlFile = file(project.name + “.iml”)
println ‘Change ‘ + project.name + ‘.iml order’
try {
def parsedXml = (new XmlParser()).parse(imlFile)
def jdkNode = parsedXml.component[1].orderEntry.find { it.’@type’ == ‘jdk’ }
parsedXml.component[1].remove(jdkNode)
def sdkString = “Android API ” + android.compileSdkVersion.substring(“android-“.length()) + ” Platform”
new Node(parsedXml.component[1], ‘orderEntry’, [‘type’: ‘jdk’, ‘jdkName’: sdkString, ‘jdkType’: ‘Android SDK’])
groovy.xml.XmlUtil.serialize(parsedXml, new FileOutputStream(imlFile))
} catch (FileNotFoundException e) {
}
}
}
然后可以反射方式使用EthernetManager类和IEthernetManager类:
package com.maxshu.forethernetipset;
import android.content.Context;
import android.net.EthernetManager;
import android.net.IpConfiguration;
import android.net.LinkAddress;
import android.net.StaticIpConfiguration;
import android.text.TextUtils;
import android.util.Log;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.net.InetAddress;
import java.net.UnknownHostException;
public class EthernetIP {
private static final String TAG = “EthernetUtils”;
/**
* @param context use Application context is better
* @param ipAddress ip address: like 192.168.1.168
* @param mode : STATIC or DHCP, set static or dhcp ip mode
* @param netmask ip mask, like 255.255.255.0
* @param gateway gateway, like 192.168.1.1
* @param dns1 dns 1
* @param dns2 dns 2, if mode=static, then can use “” or null
* eg. dhcp mode: setEthernetIP(ApplicationContext, “DHCP”, “”, “”, “”, “”, “”);
* static mode: setEthernetIP(ApplicationContext, “STATIC”,
* “192.168.1.168”, “255.255.255.0”,
* “192.168.1.1”, “114.114.114.114”, “8.8.8.8”);
* for android 9.0
* */
public static void SetEthernetIP(Context context, String mode, String ipAddress, String netmask,
String gateway, String dns1, String dns2) {
if (context == null || (!”STATIC”.equals(mode) && !”DHCP”.equals(mode))) {
Log.d(TAG, ” setEthernetIP failed, param incorrect context=” + context + “, mode=” + mode);
return;
}
try {
// get EthernetManager instance by reflect @{
Class<?> ethernetManagerClass = Class
.forName(“android.net.EthernetManager“);
Class<?> iEthernetManagerClass = Class
.forName(“android.net.IEthernetManager“);
// 获取ETHERNET_SERVICE参数
String ETHERNET_SERVICE = (String) Context.class.getField(
“ETHERNET_SERVICE”).get(null);
// 获取ethernetManager服务对象
Object ethernetManager = context.getSystemService(ETHERNET_SERVICE);
// 获取在EthernetManager中的抽象类mService成员变量
Field mService = ethernetManagerClass.getDeclaredField(“mService”);
// 修改private权限
mService.setAccessible(true);
// 获取抽象类的实例化对象
Object mServiceObject = mService.get(ethernetManager);
Object ethernetManagerInstance = ethernetManagerClass
.getDeclaredConstructor(Context.class,
iEthernetManagerClass).newInstance(context,
mServiceObject);
EthernetManager mEthManager = (EthernetManager) ethernetManagerInstance;
// @}
String[] ifaces = mEthManager.getAvailableInterfaces();
if (ifaces.length <= 0) {
Log.e(TAG, ” setEthernetIP failed ifaces.length <= 0″);
return;
}
String mInterfaceName = ifaces[0];
Log.d(TAG, ” setEthernetIP mInterfaceName=” + mInterfaceName);
if (“DHCP”.equals(mode)) {
Log.i(TAG, ” setEthernetIP set dhcp started”);
IpConfiguration dhcpConfiguration = new IpConfiguration(IpConfiguration.IpAssignment.DHCP,
IpConfiguration.ProxySettings.NONE, null, null);
dhcpConfiguration.setIpAssignment(IpConfiguration.IpAssignment.DHCP);
mEthManager.setConfiguration(mInterfaceName, dhcpConfiguration);
return;
}
if (TextUtils.isEmpty(ipAddress)
|| TextUtils.isEmpty(netmask)
// || TextUtils.isEmpty(gateway) || TextUtils.isEmpty(dns1)) {
) {
Log.e(TAG, “setEthernetIP error has some param is null ipAddress=” + ipAddress
+ “, netmask=” + netmask + “, gateway=” + gateway
+ “, dns1=” + dns1 + “, dns2=” + dns2);
return;
}
StaticIpConfiguration mStaticIpConfiguration = new StaticIpConfiguration();
int prefixLength = NetUtils.MaskStr2InetMask(netmask);
InetAddress inetAddr = null;
InetAddress gatewayAddr = InetAddress.getByName(gateway);
InetAddress dnsAddr = InetAddress.getByName(dns1);
if (TextUtils.isEmpty(ipAddress)) {
inetAddr = InetAddress.getByName(NetUtils.getLocalIpAddress());
} else {
String[] ipStr = ipAddress.split(“\\.”);
byte[] ipBuf = new byte[4];
for (int i = 0; i < 4; i++) {
ipBuf[i] = (byte) (Integer.parseInt(ipStr[i]) & 0xff);
}
try {
inetAddr = InetAddress.getByAddress(ipBuf);
Log.d(TAG, “setEthernetIP address correct inetAddr=” + inetAddr);
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
if (inetAddr == null || inetAddr.getAddress().toString().isEmpty()
|| prefixLength == 0
//|| gatewayAddr.toString().isEmpty()
//|| dnsAddr == null || dnsAddr.toString().isEmpty()) {
) {
Log.d(TAG, ” setEthernetIP address incorrect inetAddr=” + inetAddr);
return;
}
Class<?> linkAddressClass = null;
linkAddressClass = Class.forName(“android.net.LinkAddress“);
Class[] cl = new Class[]{InetAddress.class, int.class};
Constructor cons = null;
//取得所有构造函数
try {
cons = linkAddressClass.getConstructor(cl);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
//给传入参数赋初值
Object[] x = {inetAddr, prefixLength};
try {
mStaticIpConfiguration.ipAddress = (LinkAddress) cons.newInstance(x);
Log.d(TAG, ” setEthernetIP mStaticIpConfiguration.ipAddress=” + mStaticIpConfiguration.ipAddress);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
if(!gateway.isEmpty()) {
mStaticIpConfiguration.gateway = gatewayAddr;
}
if(!dns1.isEmpty()) {
mStaticIpConfiguration.dnsServers.add(dnsAddr);
}
if (!dns2.isEmpty())
mStaticIpConfiguration.dnsServers.add(InetAddress.getByName(dns2));
Log.d(TAG, ” setEthernetIP mStaticIpConfiguration ====” + mStaticIpConfiguration
+ “, inetAddr=” + inetAddr + “, mEthManager=” + mEthManager);
IpConfiguration ipConfiguration = new IpConfiguration(IpConfiguration.IpAssignment.STATIC,
IpConfiguration.ProxySettings.NONE, mStaticIpConfiguration, null);
ipConfiguration.setIpAssignment(IpConfiguration.IpAssignment.STATIC);
ipConfiguration.setStaticIpConfiguration(mStaticIpConfiguration);
mEthManager.setConfiguration(mInterfaceName, ipConfiguration);
} catch (Exception e) {
Log.e(TAG, “setEthernetIP error e=” + e.getMessage(), e);
}
}
}
再加个辅助类NetUtils:
package com.maxshu.forethernetipset;
import android.content.Context;
import android.location.LocationManager;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.telephony.TelephonyManager;
import java.net.InetAddress;
import java.net.InterfaceAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Enumeration;
public class NetUtils {
// 网络是否可用
public static boolean isNetworkAvailable(Context context) {
ConnectivityManager connectivity = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
if (connectivity == null) {
return false;
} else {
NetworkInfo[] info = connectivity.getAllNetworkInfo();
if (info != null) {
for (int i = 0; i < info.length; i++) {
if (info[i].getState() == NetworkInfo.State.CONNECTED) {
return true;
}
}
}
}
return false;
}
// 得到当前网络类型
public static String getNetWorkType(Context context) {
ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = manager.getActiveNetworkInfo();
int type = networkInfo.getType();
if (type == ConnectivityManager.TYPE_WIFI) {
return “wifi”;
} else if (type == ConnectivityManager.TYPE_MOBILE) {
return “mobile”;
}
return “unknow”;
}
//当前网络是不是wifi
public static boolean isConnectedByWifi(Context context) {
try {
ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo ni = manager.getActiveNetworkInfo();
return (ni.getType() == ConnectivityManager.TYPE_WIFI ? true : false);
} catch (Exception e) {
}
return false;
}
// MOBILE网络是几G网2G?3G?4G?
// 返回几就是几G网
public static int getNetWorkClass(Context context) {
TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
switch (telephonyManager.getNetworkType()) {
case TelephonyManager.NETWORK_TYPE_GPRS:
case TelephonyManager.NETWORK_TYPE_EDGE:
case TelephonyManager.NETWORK_TYPE_CDMA:
case TelephonyManager.NETWORK_TYPE_1xRTT:
case TelephonyManager.NETWORK_TYPE_IDEN:
return 2;
case TelephonyManager.NETWORK_TYPE_UMTS:
case TelephonyManager.NETWORK_TYPE_EVDO_0:
case TelephonyManager.NETWORK_TYPE_EVDO_A:
case TelephonyManager.NETWORK_TYPE_HSDPA:
case TelephonyManager.NETWORK_TYPE_HSUPA:
case TelephonyManager.NETWORK_TYPE_HSPA:
case TelephonyManager.NETWORK_TYPE_EVDO_B:
case TelephonyManager.NETWORK_TYPE_EHRPD:
case TelephonyManager.NETWORK_TYPE_HSPAP:
return 3;
case TelephonyManager.NETWORK_TYPE_LTE:
return 4;
default:
return 0;// unknow
}
}
// wifi网络是否可用
public static boolean isWifiConnected(Context context) {
if (context != null) {
ConnectivityManager mConnectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo mWiFiNetworkInfo = mConnectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
if (mWiFiNetworkInfo != null) {
return mWiFiNetworkInfo.isAvailable();
}
}
return false;
}
//mobile网络是否可用
public static boolean isMobileConnected(Context context) {
if (context != null) {
ConnectivityManager mConnectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo mMobileNetworkInfo = mConnectivityManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
if (mMobileNetworkInfo != null) {
return mMobileNetworkInfo.isAvailable();
}
}
return false;
}
// 使用MOBILE网络时用来获取IP
public static String getLocalIpAddress() {
try {
for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements(); ) {
NetworkInterface intf = (NetworkInterface) en.nextElement();
for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements(); ) {
InetAddress inetAddress = (InetAddress) enumIpAddr.nextElement();
if (!inetAddress.isLoopbackAddress())
return inetAddress.getHostAddress().toString();
}
}
} catch (SocketException ex) {
}
return “0.0.0.0”;
}
// 使用Wifi时用来获取IP
public static String getWifiIpAddress(Context context) {
WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
WifiInfo wifiInfo = wifiManager.getConnectionInfo();
int ipAddress = wifiInfo.getIpAddress();
return intToIp(ipAddress);
}
// 获取wifi的ssid(即wifi名称)
public static String getWifiSsid(Context context) {
String ssidApn = “”;
try {
WifiManager wm = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
WifiInfo wi = wm.getConnectionInfo();
ssidApn = wi.getSSID();
} catch (Exception e) {
}
return ssidApn;
}
// 手机GPS是否开启
public static boolean isGpsEnable(Context context) {
LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
}
// 返回运营商名字
public static String getNetworkOperatorName(Context context) {
TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
return telephonyManager.getNetworkOperatorName();
}
private static String intToIp(int i) {
return String.format(“%d.%d.%d.%d”, (i & 0xff), (i >> 8 & 0xff), (i >> 16 & 0xff), (i >> 24 & 0xff));
}
public static int MaskStr2InetMask(String maskStr){
StringBuffer sb ;
String str;
int inetmask = 0;
int count = 0;
String[] ipSegment = maskStr.split(“\\.”);
for(int n =0; n<ipSegment.length;n++){
sb = toBin(Integer.parseInt(ipSegment[n]));
str = sb.reverse().toString();
count=0;
for(int i=0; i<str.length();i++){
i=str.indexOf(“1”,i);
if(i==-1){
break;
}
count++;
}
inetmask+=count;
}
return inetmask;
}
private static StringBuffer toBin(int x)
{
StringBuffer result = new StringBuffer();
result.append(x % 2);
x /= 2;
while (x > 0)
{
result.append(x % 2);
x /= 2;
}
return result;
}
}
4,581次阅读

Post navigation

前一篇:

Linux策略路由及iptables mangle、ip rule、ip route关系及一种Network is unreachable错误

后一篇:

使用Android的HIDL+AIDL方式编写从HAL层到APP层的程序

发表评论 取消回复

邮箱地址不会被公开。 必填项已用*标注

个人介绍

需要么,有事情这里找联系方式:关于天楚锐齿

=== 美女同欣赏,好酒共品尝 ===

微信扫描二维码赞赏该文章:

扫描二维码分享该文章:

分类目录

  • Linux&Android (79)
  • Uncategorized (1)
  • 下载 (28)
  • 云计算 (37)
  • 人工智能 (8)
  • 大数据 (24)
  • 嵌入式 (34)
  • 杂七杂八 (34)
  • 物联网 (59)
  • 网络 (23)
  • 通信 (21)

文章归档

近期文章

  • 使用Python渲染OpenGL的.obj和.mtl文件
  • 用LVGL图形库绘制二维码
  • Android使用Messenger和SharedMemory实现跨app的海量数据传输
  • CAN信号的c语言解析代码
  • QT qml下DBus的使用例子

近期评论

  • 硕发表在《使用Android的HIDL+AIDL方式编写从HAL层到APP层的程序》
  • maxshu发表在《使用Android的HIDL+AIDL方式编写从HAL层到APP层的程序》
  • Ambition发表在《使用Android的HIDL+AIDL方式编写从HAL层到APP层的程序》
  • Ambition发表在《使用Android的HIDL+AIDL方式编写从HAL层到APP层的程序》
  • maxshu发表在《Android9下用ethernet 的Tether模式来做路由器功能》

阅读量

  • 使用Android的HIDL+AIDL方式编写从HAL层到APP层的程序 - 16,806次阅读
  • 卸载深信服Ingress、SecurityDesktop客户端 - 12,078次阅读
  • 车机技术之Android Automotive - 6,661次阅读
  • 车机技术之车规级Linux-Automotive Grade Linux(AGL) - 5,862次阅读
  • Linux策略路由及iptables mangle、ip rule、ip route关系及一种Network is unreachable错误 - 5,711次阅读
  • 在Android9下用ndk编译vSomeIP和CommonAPI以及使用例子 - 5,658次阅读
  • linux下的unbound DNS服务器设置详解 - 5,601次阅读
  • linux的tee命令导致ssh客户端下的shell卡住不动 - 4,998次阅读
  • 车机技术之360°全景影像(环视)系统 - 4,897次阅读
  • libwebp(处理webp图像)的安装和使用 - 4,749次阅读

功能

  • 文章RSS
  • 评论RSS

联系方式

地址
深圳市科技园

时间
周一至周五:  9:00~12:00,14:00~18:00
周六和周日:10:00~12:00

标签

android AT命令 centos Hadoop hdfs ip ipv6 kickstart linux mapreduce mini6410 modem OAuth openstack os python socket ssh uboot 内核 协议 安装 嵌入式 性能 报表 授权 操作系统 数据 数据库 月报 模型 汽车 测试 深信服 深度学习 源代码 神经网络 统计 编译 网络 脚本 虚拟机 调制解调器 车机 金融
© 2023 天楚锐齿