本文只对有线网score分值流程做详细分析。
之前搞Android 有线网络和wifi,同时连通,并且设置优先级。已实现可以随时切换网络优先级。
刚开始是生效的,系统合入新TAG后,发现之前设置的优先级无效的!
所以网络优先级设置流程还是需要梳理,出现问题好定位解决。
Android网络的Score值,分值越高,越优先。
默认Score为:
Sim网络 50
wifi网络 60
有线网络 70
所以为啥Android手机连接wifi默认使用的是WiFi的网络。
但是有时候又会切换到手机网络,估计是有监听wifi信号情况,动态切换Score 来实现的。
本文主要是对有线网的Score进行分析,其他网络的切换可以进行参考。
并且你可以看到修改有线网的Score有两个地方。
主要日志:
130|console:/ # dumpsys connectivity
NetworkProviders for: UntrustedWifiNetworkFactory WifiNetworkFactory Ethernet
Active default network: 102
Current Networks:
NetworkAgentInfo{ ni{[type: Ethernet[], state: CONNECTED/CONNECTED, reason: (unspecified), extra: 02:ad:36:01:fe:7f, failover: false, available: true, roaming: false]}
network{102} lp{{InterfaceName: eth0 LinkAddresses: [ fe80::5faa:9218:a190:d7f3/64,170.168.20.2/24 ]
DnsAddresses: [ /170.168.20.1 ] ... Score{90} ... }
Requests: REQUEST:2 LISTEN:11 BACKGROUND_REQUEST:0 total:13
NetworkRequest [ REQUEST id=1, [ Capabilities: INTERNET&NOT_RESTRICTED&TRUSTED&NOT_VPN AdministratorUids: [] RequestorUid: 1000 RequestorPackageName: android] ]
NetworkRequest [ LISTEN id=4, [ Capabilities: FOREGROUND AdministratorUids: [] RequestorUid: 1000 RequestorPackageName: android] ]
...
//如果需要能实现同时连接wifi(前提是系统里面做了处理)
也会有对应的 NetworkAgentInfo 和 NetworkRequest
网络连接上的情况,可以在NetworkAgentInfo 里面看到 该网线的实际 Score 分值。
关闭有线网的情况打开有线网开关:
如果系统未做开关,可以使用ifconfig eth0 up/down 进行有线网开关,可以看出有线网的score变化。
有线网相关的处理在EthernetNetworkFactory.java 里面
11-25 07:14:27.139 754 872 D EthernetNetworkFactory: updateInterfaceLinkState, iface: eth0, up: false
//开始打开有线网
11-25 07:14:30.197 754 872 D EthernetNetworkFactory: updateInterfaceLinkState, iface: eth0, up: true
11-25 07:14:30.197 754 872 D EthernetNetworkFactory: Starting Ethernet IpClient(eth0)
11-25 07:14:30.281 754 872 I EthernetNetworkFactory: localScore = 90 //自己添加的日志打印,自己定义的分值
11-25 07:14:30.393 754 872 D EthernetNetworkFactory: acceptRequest, request: NetworkRequest [ REQUEST id=1, ..., score: 50 //发现改变了!!!
...
第一种方法查看实际起作用时的Score;
第二种方法可以查看到score的相关流程或者变化,直接grep -i score,也是可以的,但是日志会比较多。
三、流程梳理
有线网和wifi一样都是有对应的Service进行管理的。
有线网服务启动
1、最开始SystemServer.java
frameworks\base\services\java\com\android\server\SystemServer.java
/**
* The main entry point from zygote.
*/
public static void main(String[] args) {
new SystemServer().run();
}
private void run() {
。。。
// Start services.
try {
t.traceBegin("StartServices");
startBootstrapServices(t); //电源管理等偏硬件服务
startCoreServices(t); //重要的系统配置服务
startOtherServices(t); //网络或者显示等服务,AMS,WMS等都是在这里
} catch (Throwable ex) {
Slog.e("System", "******************************************");
Slog.e("System", "************ Failure starting system services", ex);
throw ex;
} finally {
t.traceEnd(); // StartServices
}
。。。
}
//启动其他系统服务
private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
t.traceBegin("startOtherServices");
if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_ETHERNET) ||
mPackageManager.hasSystemFeature(PackageManager.FEATURE_USB_HOST)) {
t.traceBegin("StartEthernet");
mSystemServiceManager.startService(ETHERNET_SERVICE_CLASS);
t.traceEnd();
}
}
private static final String ETHERNET_SERVICE_CLASS =
"com.android.server.ethernet.EthernetService";
frameworks\opt\net\ethernet\java\com\android\server\ethernet\EthernetService.java
public final class EthernetService extends SystemService {
private static final String TAG = "EthernetService";
final EthernetServiceImpl mImpl;
public EthernetService(Context context) {
super(context);
mImpl = new EthernetServiceImpl(context);
}
@Override
public void onStart() {
Log.i(TAG, "Registering service " + Context.ETHERNET_SERVICE);
publishBinderService(Context.ETHERNET_SERVICE, mImpl);
}
@Override
public void onBootPhase(int phase) { //系统准备好会回调这里
if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
mImpl.start();
}
}
}
frameworks\opt\net\ethernet\java\com\android\server\ethernet\EthernetServiceImpl.java
public class EthernetServiceImpl extends IEthernetManager.Stub {
private static final String TAG = "EthernetServiceImpl";
public void start() {
Log.i(TAG, "Starting Ethernet service");
HandlerThread handlerThread = new HandlerThread("EthernetServiceThread");
handlerThread.start();
mHandler = new Handler(handlerThread.getLooper());
mTracker = new EthernetTracker(mContext, mHandler);
//add isEnable Ethernet by liwenzhi ,Start
//mTracker.start(); //默认启动就是start,我这里是添加的有线网开关功能和记忆功能
//mStarted.set(true);
mEthernetState = getPersistedState(); //我自己添加的逻辑可以先不管
Log.i(TAG, "Ethernet Persisted mEthernetState " + mEthernetState);
boolean isEnabled = false;
if (mEthernetState == EthernetManager.ETHERNET_STATE_ENABLED) {
isEnabled = true;
}
mTracker.start(isEnabled); //根据情况是否打开有线网
mStarted.set(isEnabled);
//add isEnable Ethernet by liwenzhi ,End
}
}
Tracker.start的后续逻辑不继续跟踪,这个设计到有线网的启动流程的具体实现,跟本文的Score有点脱离了。
有线网监听网络接口变化:
frameworks\opt\net\ethernet\java\com\android\server\ethernet\EthernetTracker.java
final class EthernetTracker {
private final EthernetNetworkFactory mFactory;
//add isEnable Ethernet Switch by liwenzhi
//change state in bootstate
void start(boolean isEnabled) {
mConfigStore.read();
// Default interface is just the first one we want to track.
mIpConfigForDefaultInterface = mConfigStore.getIpConfigurationForDefaultInterface();
final ArrayMap configs = mConfigStore.getIpConfigurations();
for (int i = 0; i < configs.size(); i++) {
mIpConfigurations.put(configs.keyAt(i), configs.valueAt(i));
}
try {
mNMService.registerObserver(new InterfaceObserver());//监听网络变化,有线网/wifi的节点开关都会有回调
} catch (RemoteException e) {
Log.e(TAG, "Could not register InterfaceObserver " + e);
}
if (isEnabled) {
mHandler.post(this::trackAvailableInterfaces);
}
}
//网络节点变化的监听者,ifconfig可以看到网络节点
private class InterfaceObserver extends BaseNetworkObserver {
@Override
public void interfaceLinkStateChanged(String iface, boolean up) { //网络节点变化的回到方法
if (DBG) {
Log.i(TAG, "interfaceLinkStateChanged, iface: " + iface + ", up: " + up);
}
mHandler.post(() -> updateInterfaceState(iface, up));
}
@Override
public void interfaceAdded(String iface) {
mHandler.post(() -> maybeTrackInterface(iface));
}
@Override
public void interfaceRemoved(String iface) {
mHandler.post(() -> stopTrackingInterface(iface));
}
}
//通知EthernetNetworkFactory对象的 updateInterfaceLinkState 方法
private void updateInterfaceState(String iface, boolean up) {
final int mode = getInterfaceMode(iface);
final boolean factoryLinkStateUpdated = (mode == INTERFACE_MODE_CLIENT)
&& mFactory.updateInterfaceLinkState(iface, up);
。。。
}
}
直接使用ifconfig eth0 down/up,是可以看到上面方法有日志回调的。
继续追踪 updateInterfaceLinkState 方法实现。
网络变化的回调:updateInterfaceLinkState 方法
frameworks\opt\net\ethernet\java\com\android\server\ethernet\EthernetNetworkFactory.java
//change from 70 by liwenzhi
private final static int NETWORK_SCORE = 15; //默认有线网的Score
boolean updateInterfaceLinkState(String ifaceName, boolean up) {
if (!mTrackingInterfaces.containsKey(ifaceName)) {
return false;
}
if (DBG) {
Log.d(TAG, "updateInterfaceLinkState, iface: " + ifaceName + ", up: " + up);
}
NetworkInterfaceState iface = mTrackingInterfaces.get(ifaceName);
return iface.updateLinkState(up);
}
private static class NetworkInterfaceState {
final String name;
private @Nullable NetworkAgent mNetworkAgent;
。。。
/** Returns true if state has been modified */
boolean updateLinkState(boolean up) {
if (mLinkUp == up) return false;
mLinkUp = up;
stop();
if (up) {
start();
}
return true;
}
private void start() {
。。。
if (DBG) {
Log.d(TAG, String.format("Starting Ethernet IpClient(%s)", name));
}
mIpClientCallback = new IpClientCallbacksImpl();
IpClientUtil.makeIpClient(mContext, name, mIpClientCallback);
mIpClientCallback.awaitIpClientStart();
if (sTcpBufferSizes == null) {
sTcpBufferSizes = mContext.getResources().getString(
com.android.internal.R.string.config_ethernet_tcp_buffers);
}
provisionIpClient(mIpClient, mIpConfig, sTcpBufferSizes);
}
private class IpClientCallbacksImpl extends IpClientCallbacks {
private final ConditionVariable mIpClientStartCv = new ConditionVariable(false);
private final ConditionVariable mIpClientShutdownCv = new ConditionVariable(false);
。。。
//符合条件后,准备开启
@Override
public void onProvisioningSuccess(LinkProperties newLp) {
mHandler.post(() -> onIpLayerStarted(newLp));
}
}
void onIpLayerStarted(LinkProperties linkProperties) {
if (mNetworkAgent != null) {
Log.e(TAG, "Already have a NetworkAgent - aborting new request");
stop();
return;
}
mLinkProperties = linkProperties;
// Create our NetworkAgent.
final NetworkAgentConfig config = new NetworkAgentConfig.Builder()
.setLegacyType(mLegacyType)
.setLegacyTypeName(NETWORK_TYPE)
.build();
//getNetworkScore() 获取分值
mNetworkAgent = new NetworkAgent(mContext, mHandler.getLooper(),
NETWORK_TYPE, mCapabilities, mLinkProperties,
getNetworkScore(), config, mNetworkFactory.getProvider()) {
public void unwanted() {
if (this == mNetworkAgent) {
stop();
} else if (mNetworkAgent != null) {
Log.d(TAG, "Ignoring unwanted as we have a more modern " +
"instance");
} // Otherwise, we've already called stop.
}
};
mNetworkAgent.register();
mNetworkAgent.setLegacyExtraInfo(mHwAddress);
mNetworkAgent.markConnected();
}
//有线网实际获取的Score,会根据一些情况有改变
private int getNetworkScore() {
// never set the network score below 0.
if (!mLinkUp) {
return 0;
}
int[] transportTypes = mCapabilities.getTransportTypes();
if (transportTypes.length < 1) {
Log.w(TAG, "Network interface '" + mLinkProperties.getInterfaceName() + "' has no "
+ "transport type associated with it. Score set to zero");
return 0;
}
//change ethernet score by liwenzhi ,start
int localScore = Settings.System.getInt(mContext.getContentResolver(), "ethernet_score", NETWORK_SCORE); //自定义了Score值,方便动态修改
Log.i(TAG, "localScore = " + localScore);
return localScore;
//change ethernet score by liwenzhi ,end
}
}
从这里可以看出有线网的Score分值是在 getNetworkScore 方法里面获取的,
并且里面会有一些逻辑,Score的分值可能跟里面的逻辑情况相关。
后面又把 getNetworkScore 获取的分值,分发到 NetworkAgent 对象进行 register注册,
在根据register方法里面的逻辑。
frameworks\base\core\java\android\net\NetworkAgent.java
private NetworkAgent(@NonNull Looper looper, @NonNull Context context, @NonNull String logTag,
@NonNull NetworkCapabilities nc, @NonNull LinkProperties lp, int score,
@NonNull NetworkAgentConfig config, int providerId, @NonNull NetworkInfo ni,
boolean legacy) {
mHandler = new NetworkAgentHandler(looper);
LOG_TAG = logTag;
mIsLegacy = legacy;
mNetworkInfo = new NetworkInfo(ni);
this.providerId = providerId;
if (ni == null || nc == null || lp == null) {
throw new IllegalArgumentException();
}
mInitialConfiguration = new InitialConfiguration(context, new NetworkCapabilities(nc),
new LinkProperties(lp), score, config, ni);
}
//插入Score只是赋值了
private static class InitialConfiguration {
public final Context context;
public final NetworkCapabilities capabilities;
public final LinkProperties properties;
public final int score;
public final NetworkAgentConfig config;
public final NetworkInfo info;
InitialConfiguration(@NonNull Context context, @NonNull NetworkCapabilities capabilities,
@NonNull LinkProperties properties, int score, @NonNull NetworkAgentConfig config,
@NonNull NetworkInfo info) {
this.context = context;
this.capabilities = capabilities;
this.properties = properties;
this.score = score;
this.config = config;
this.info = info;
}
}
public Network register() {
if (VDBG) log("Registering NetworkAgent");
synchronized (mRegisterLock) {
if (mNetwork != null) {
throw new IllegalStateException("Agent already registered");
}
final ConnectivityManager cm = (ConnectivityManager) mInitialConfiguration.context
.getSystemService(Context.CONNECTIVITY_SERVICE);
//获取了之前赋值的 mInitialConfiguration.score
mNetwork = cm.registerNetworkAgent(new Messenger(mHandler),
new NetworkInfo(mInitialConfiguration.info),
mInitialConfiguration.properties, mInitialConfiguration.capabilities,
mInitialConfiguration.score, mInitialConfiguration.config, providerId);
mInitialConfiguration = null; // All this memory can now be GC'd
}
return mNetwork;
}
NetworkAgent 这个对象没啥代码,就是获取到数据,并且提供了 register 方法,调用ConnectivityManager。
重点是 ConnectivityManager.registerNetworkAgent 参数里面有score,继续往下跟!
frameworks\base\core\java\android\net\ConnectivityManager.java
这个类是公开的类!是一个SDK类,普通应用也能调用到里面一些方法,但是大都是系统应用才能调的方法。
private final IConnectivityManager mService;
@RequiresPermission(anyOf = {
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
android.Manifest.permission.NETWORK_FACTORY})
public Network registerNetworkAgent(Messenger messenger, NetworkInfo ni, LinkProperties lp,
NetworkCapabilities nc, int score, NetworkAgentConfig config, int providerId) {
try {
return mService.registerNetworkAgent(messenger, ni, lp, nc, score, config, providerId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
//具体实现的service
frameworks\base\services\core\java\com\android\server\ConnectivityService.java
继续根据registerNetworkAgent 方法的Score流程
public class ConnectivityService extends IConnectivityManager.Stub
implements PendingIntent.OnFinished {
public Network registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo,
LinkProperties linkProperties, NetworkCapabilities networkCapabilities,
int currentScore, NetworkAgentConfig networkAgentConfig, int providerId) {
。。。
LinkProperties lp = new LinkProperties(linkProperties);
// TODO: Instead of passing mDefaultRequest, provide an API to determine whether a Network
// satisfies mDefaultRequest.
final NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities);
//currentScore 传递到新创建的 NetworkAgentInfo 对象
final NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(),
new Network(mNetIdManager.reserveNetId()), new NetworkInfo(networkInfo), lp, nc,
currentScore, mContext, mTrackerHandler, new NetworkAgentConfig(networkAgentConfig),
this, mNetd, mDnsResolver, mNMS, providerId, Binder.getCallingUid());
// Make sure the LinkProperties and NetworkCapabilities reflect what the agent info says.
nai.getAndSetNetworkCapabilities(mixInCapabilities(nai, nc));
processLinkPropertiesFromAgent(nai, nai.linkProperties);
final String extraInfo = networkInfo.getExtraInfo();
final String name = TextUtils.isEmpty(extraInfo)
? nai.networkCapabilities.getSsid() : extraInfo;
if (DBG) log("registerNetworkAgent " + nai);
final long token = Binder.clearCallingIdentity();
return nai.network;
}
}
从上面代码可以看到有 currentScore 传递到 NetworkAgentInfo 对象中,
后续ConnectivityService 获取的Score都是从 NetworkAgentInfo 对象中获取,
所以要看Score在 NetworkAgentInfo 对象修改!
frameworks\base\services\core\java\com\android\server\connectivity\NetworkAgentInfo.java
// This represents the quality of the network with no clear scale.
private int mScore;
public NetworkAgentInfo(Messenger messenger, AsyncChannel ac, Network net, NetworkInfo info,
LinkProperties lp, NetworkCapabilities nc, int score, Context context,
Handler handler, NetworkAgentConfig config, ConnectivityService connService, INetd netd,
IDnsResolver dnsResolver, INetworkManagementService nms, int factorySerialNumber,
int creatorUid) {
this.messenger = messenger;
asyncChannel = ac;
network = net;
networkInfo = info;
linkProperties = lp;
networkCapabilities = nc;
mScore = score;
clatd = new Nat464Xlat(this, netd, dnsResolver, nms);
mConnService = connService;
mContext = context;
mHandler = handler;
networkAgentConfig = config;
this.factorySerialNumber = factorySerialNumber;
this.creatorUid = creatorUid;
}
public void setScore(final int score) {
mScore = score;
}
//这里有重新定义score的动作!!!
private int getCurrentScore(boolean pretendValidated) {
if (networkAgentConfig.explicitlySelected
&& (networkAgentConfig.acceptUnvalidated || pretendValidated)) {
return ConnectivityConstants.EXPLICITLY_SELECTED_NETWORK_SCORE; //100
}
int score = mScore;
if (!lastValidated && !pretendValidated && !ignoreWifiUnvalidationPenalty() && !isVPN()) { //之前的版本不会进入这里,后面发现有进入这里!
score -= ConnectivityConstants.UNVALIDATED_SCORE_PENALTY; //40
}
Log.d(TAG, "liwz getCurrentScore mScore = " + mScore + " ,score = " + score);
if (score < 0) score = 0;
return score;
}
这个类主要就是做一些数据存放,其实就是一个简单Bean。
里面的 getCurrentScore 方法有重新定义Score 的逻辑!
上面的代码可能比较多,挑着看和重点看就行。
(1)SystemServer.java 启动关键服务的入口类
(2)EthernetService.java 有线网服务
(3)EthernetServiceImpl.java 有线实现类
(4)EthernetTracker.java 网络节点变化监听类
(5)EthernetNetworkFactory.java 有线网工厂类,定义Score
(6)NetworkAgent.java 网络代理类,存放数据和调用CM
(7)ConnectivityManager.java 暴露的SDK,调用Service实现功能
(8)ConnectivityService.java 连接网络Service
(9)NetworkAgentInfo.java 网络代理类,存放数据和对象
系统第一次启动就是上面九个流程,如果是后续关开有线网,就是 4—>9的流程!
可以看到上面每个类都有各自的作用,NetworkAgent 和 NetworkAgentInfo 有点重复,应该也是有个各自的意义的。
NetworkAgent 更像中间人调用Manager,而NetworkAgentInfo 作用是数据封装,传递。
EthernetNetworkFactory.getNetworkScore 方法。
NetworkAgentInfo.getCurrentScore 方法。
第二个方法才是系统真正生效的Score方法。
如果你修改了网络优先级未起作用,可以在这两个方法添加打印看看,是那个逻辑导致的。
我的做法是直接把那些影响Score 的代码,简单粗暴注释!!
需要的可以学习参考:
Android adb查看网络连接情况
https://blog.csdn.net/wenzhi20102321/article/details/122161589
Android11 有线网和wifi优先级设置
https://blog.csdn.net/wenzhi20102321/article/details/122243516
Android9、11 有线网络开关设置
https://blog.csdn.net/wenzhi20102321/article/details/122243396