一、引言
在实际的项目开发中,特别用到以太网相关功能时,往往会涉及wifi和以太网同时打开的情况,android原生对于这块的兼容很少,只会有一个生效,会优先使用以太网,故此需要改变系统机制做兼容。
二、实现部分
思路:其实我们要做的无非就是让底层认为两者共存时现在就是要使用wifi上网的就行,那么我们就得在网络通路上做文章,也就是要配置“网络共存路由表”,大体上关于上层网络涉及的包就是Connectivity与system目录下的netd两个包,我们可以从这两个包的源码开始查看。
2.1、上层系统服务部分
1.ConnectivityService.java类的unneeded方法中过滤以太网和wifi的检测,使能共存
+++ b/packages/modules/Connectivity/service/src/com/android/server/ConnectivityService.java
@@ -322,11 +322,20 @@ public class ConnectivityService extends IConnectivityManager.Stub
private static final String TRAFFICCONTROLLER_ARG = "trafficcontroller";
private static final boolean DBG = true;
private static final boolean DDBG = Log.isLoggable(TAG, Log.DEBUG);
private static final boolean VDBG = Log.isLoggable(TAG, Log.VERBOSE);
private static final boolean LOGD_BLOCKED_NETWORKINFO = true;
/**
* Default URL to use for {@link #getCaptivePortalServerUrl()}. This should not be changed
* by OEMs for configuration purposes, as this value is overridden by
@@ -4601,6 +4610,21 @@ public class ConnectivityService extends IConnectivityManager.Stub
private boolean unneeded(NetworkAgentInfo nai, UnneededFor reason) {
ensureRunningOnConnectivityServiceThread();
+ // added by cgt ethernet and wifi coexist start
+ boolean needed = nai.isWIFI();
+ needed = nai.isETHERNET();
+ Log.d(TAG, "---> unneeded: needed=" + needed);
+ if (needed) {
+ return false;
+ }
+ // added by cgt ethernet and wifi coexist end
if (!nai.everConnected || nai.isVPN() || nai.isInactive()
|| nai.getScore().getKeepConnectedReason() != NetworkScore.KEEP_CONNECTED_NONE) {
return false;
2.NetworkAgentInfo.java类中添加判断当前网络是否是以太网或者wifi的方法
+++ b/packages/modules/Connectivity/service/src/com/android/server/connectivity/NetworkAgentInfo.java
@@ -943,6 +943,18 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo>, NetworkRa
return networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_VPN);
}
+ // added by cgt ethernet and wifi coexist start
+ /** Whether this network is a WIFI. */
+ public boolean isWIFI() {
+ return networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI);
+ }
+
+ /** Whether this network is a ETHERNET. */
+ public boolean isETHERNET() {
+ return networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET);
+ }
+ // added by cgt ethernet and wifi coexist end
+
/**
* Whether this network should propagate the capabilities from its underlying networks.
* Currently only true for VPNs.
3.NetworkRanker.java类中配置wifi优先并且在mightBeat方法中过滤wifi和以太网
+++ b/packages/modules/Connectivity/service/src/com/android/server/connectivity/NetworkRanker.java
@@ -46,10 +46,18 @@ import java.util.Collection;
import java.util.List;
import java.util.function.Predicate;
+// added by cgt ethernet and wifi coexist start
+import android.util.Log;
+// added by cgt ethernet and wifi coexist end
+
/**
* A class that knows how to find the best network matching a request out of a list of networks.
*/
public class NetworkRanker {
+ // added by cgt ethernet and wifi coexist start
+ private static final String TAG = "NetworkRanker";
+ // added by cgt ethernet and wifi coexist end
+
// Historically the legacy ints have been 0~100 in principle (though the highest score in
// AOSP has always been 90). This is relied on by VPNs that send a legacy score of 101.
public static final int LEGACY_INT_MAX = 100;
@@ -80,9 +88,25 @@ public class NetworkRanker {
}
// Transport preference order, if it comes down to that.
+ // added by cgt ethernet and wifi coexist start
- private static final int[] PREFERRED_TRANSPORTS_ORDER = { TRANSPORT_ETHERNET, TRANSPORT_WIFI,
+ //private static final int[] PREFERRED_TRANSPORTS_ORDER = { TRANSPORT_ETHERNET, TRANSPORT_WIFI,
+ // TRANSPORT_BLUETOOTH, TRANSPORT_CELLULAR };
+ private static int[] PREFERRED_TRANSPORTS_ORDER = { TRANSPORT_ETHERNET, TRANSPORT_WIFI,
+ TRANSPORT_BLUETOOTH, TRANSPORT_CELLULAR };
+ private static int[] PREFERRED_TRANSPORTS_ORDER_COEXIST = { TRANSPORT_WIFI, TRANSPORT_ETHERNET,
TRANSPORT_BLUETOOTH, TRANSPORT_CELLULAR };
+ static {
+ PREFERRED_TRANSPORTS_ORDER = PREFERRED_TRANSPORTS_ORDER_COEXIST;
+ }
+ // added by cgt ethernet and wifi coexist end
+
// Function used to partition a list into two working areas depending on whether they
// satisfy a predicate. All items satisfying the predicate will be put in |positive|, all
// items that don't will be put in |negative|.
@@ -310,6 +334,20 @@ public class NetworkRanker {
// is always better than no network.
if (null == champion) return true;
// If there is no champion, the offer can always beat.
+ // added by cgt ethernet and wifi coexist start
+ boolean needed = contestant.getCapsNoCopy().hasTransport(TRANSPORT_WIFI);
+ needed = contestant.getCapsNoCopy().hasTransport(TRANSPORT_ETHERNET);
+ Log.d(TAG, "---> mightBeat: needed=" + needed);
+ if (needed) {
+ return true;
+ }
+ // added by cgt ethernet and wifi coexist end
// Otherwise rank them.
final ArrayList<Scoreable> candidates = new ArrayList<>();
candidates.add(champion);
2.2、上层netd服务部分
1.RouteController.cpp类中的Init方法配置一条新的直通的路由信息取代原生的配置
diff --git a/system/netd/server/RouteController.cpp b/system/netd/server/RouteController.cpp
index d2af9a375a2..22377105e1f 100644
--- a/system/netd/server/RouteController.cpp
+++ b/system/netd/server/RouteController.cpp
@@ -40,6 +40,10 @@
#include "netid_client.h"
#include "netutils/ifc.h"
+// added by cgt ethernet and wifi coexist start
+#include <android-base/properties.h>
+// added by cgt ethernet and wifi coexist end
+
using android::base::StartsWith;
using android::base::StringPrintf;
using android::base::WriteStringToFile;
@@ -773,6 +777,18 @@ int RouteController::configureDummyNetwork() {
return 0;
}
+// added by cgt ethernet and wifi coexist start
+// Add a new rule to look up the 'main' table, with the same selectors as the "default network"
+// rule, but with a lower priority. We will never create routes in the main table; it should only be
+// used for directly-connected routes implicitly created by the kernel when adding IP addresses.
+// This is necessary, for example, when adding a route through a directly-connected gateway: in
+// order to add the route, there must already be a directly-connected route that covers the gateway.
+[[nodiscard]] static int addDirectlyConnectedRule() {
+ return modifyIpRule(RTM_NEWRULE, RULE_PRIORITY_DIRECTLY_CONNECTED, RT_TABLE_MAIN,
+ MARK_UNSET, MARK_UNSET, IIF_NONE, OIF_NONE, INVALID_UID, INVALID_UID);
+}
+// added by cgt ethernet and wifi coexist end
+
// Add an explicit unreachable rule close to the end of the prioriy list to make it clear that
// relying on the kernel-default "from all lookup main" rule at priority 32766 is not intended
// behaviour. We do flush the kernel-default rules at startup, but having an explicit unreachable
@@ -1259,6 +1275,13 @@ int RouteController::Init(unsigned localNetId) {
if (int ret = addLocalNetworkRules(localNetId)) {
return ret;
}
+ // added by cgt ethernet and wifi coexist start
+ if (int ret = addDirectlyConnectedRule()) {
+ return ret;
+ }
+ // added by cgt ethernet and wifi coexist end
if (int ret = addUnreachableRule()) {
return ret;
}
2.RouteController.h类中定义一个使用的变量
diff --git a/system/netd/server/RouteController.h b/system/netd/server/RouteController.h
index ff41678d551..2604266995c 100644
--- a/system/netd/server/RouteController.h
+++ b/system/netd/server/RouteController.h
@@ -82,6 +82,9 @@ constexpr int32_t RULE_PRIORITY_UID_DEFAULT_NETWORK = 29000;
// the network, it will not work. That will potentially cause a user-visible error.
constexpr int32_t RULE_PRIORITY_UID_DEFAULT_UNREACHABLE = 30000;
constexpr int32_t RULE_PRIORITY_DEFAULT_NETWORK = 31000;
+// added by cgt ethernet and wifi coexist start
+constexpr int32_t RULE_PRIORITY_DIRECTLY_CONNECTED = 9999;
+// added by cgt ethernet and wifi coexist end
constexpr int32_t RULE_PRIORITY_UNREACHABLE = 32000;
// clang-format on
三、结论
至此wifi以太网共存分享就完成了,其实都是项目促使我们去实现这些功能,每当有新需求时不要去抗拒,而是觉得自我又要得到提升,保持学习才能成长。