NetworkCallback 无法收到回调
起因
某APP注册NetworkCallback无法收到回调,当使用默认的NetworkRequest可以收到回调
connMgr = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
networkCallback = new NetworkCallbackImpl();
NetworkRequest request = new NetworkRequest.Builder()
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) //12
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI) //1
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) //0
.build();
// 默认的NetworkRequest
//NetworkRequest request =new NetworkRequest.Builder().build();
if (connMgr != null) {
connMgr.registerNetworkCallback(request, networkCallback);
}
NetworkCallback 注册流程
// frameworks/base/core/java/android/net/ConnectivityManager.java
public void registerNetworkCallback(
NetworkRequest request, NetworkCallback networkCallback, Handler handler) {
CallbackHandler cbHandler = new CallbackHandler(handler);
NetworkCapabilities nc = request.networkCapabilities;
sendRequestForNetwork(nc, networkCallback, 0, LISTEN, TYPE_NONE, cbHandler);
}
private NetworkRequest sendRequestForNetwork(NetworkCapabilities need, NetworkCallback callback,
int timeoutMs, int action, int legacyType, CallbackHandler handler) {
// 省略
Messenger messenger = new Messenger(handler);
Binder binder = new Binder();
if (action == LISTEN) {
// 进入 ConnectivityService
request = mService.listenForNetwork(need, messenger, binder);
} else {
request = mService.requestNetwork(
need, messenger, timeoutMs, binder, legacyType);
}
// 省略
return request;
}
// frameworks/base/services/core/java/com/android/server/ConnectivityService.java
@Override
public NetworkRequest listenForNetwork(NetworkCapabilities networkCapabilities,
Messenger messenger, IBinder binder) {
if (!hasWifiNetworkListenPermission(networkCapabilities)) {
enforceAccessPermission();
}
NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities);
if (!ConnectivityManager.checkChangePermission(mContext)) {
// Apps without the CHANGE_NETWORK_STATE permission can't use background networks, so
// make all their listens include NET_CAPABILITY_FOREGROUND. That way, they will get
// onLost and onAvailable callbacks when networks move in and out of the background.
// There is no need to do this for requests because an app without CHANGE_NETWORK_STATE
// can't request networks.
// 添加NET_CAPABILITY_FOREGROUND的FLAG
nc.addCapability(NET_CAPABILITY_FOREGROUND);
}
ensureValidNetworkSpecifier(networkCapabilities);
NetworkRequest networkRequest = new NetworkRequest(nc, TYPE_NONE, nextNetworkRequestId(),
NetworkRequest.Type.LISTEN);
NetworkRequestInfo nri = new NetworkRequestInfo(messenger, networkRequest, binder);
if (VDBG) log("listenForNetwork for " + nri);
// 构建出nri, 然后sendmessage
mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_LISTENER, nri));
return networkRequest;
}
构建出NetworkRequestInfo, 然后sendmessage, 事件类型EVENT_REGISTER_NETWORK_LISTENER,最终调用到handleRegisterNetworkRequest
private void handleRegisterNetworkRequest(NetworkRequestInfo nri) {
mNetworkRequests.put(nri.request, nri); // 保存请求
mNetworkRequestInfoLogs.log("REGISTER " + nri);
if (nri.request.isListen()) {
for (NetworkAgentInfo network : mNetworkAgentInfos.values()) {
if (nri.request.networkCapabilities.hasSignalStrength() &&
network.satisfiesImmutableCapabilitiesOf(nri.request)) {
updateSignalStrengthThresholds(network, "REGISTER", nri.request);
}
}
}
rematchAllNetworksAndRequests(null, 0); //关键函数
if (nri.request.isRequest() && getNetworkForRequest(nri.request.requestId) == null) {
sendUpdatedScoreToFactories(nri.request, 0);
}
...
}
private void rematchAllNetworksAndRequests(NetworkAgentInfo changed, int oldScore) {
final long now = SystemClock.elapsedRealtime();
if (changed != null && oldScore < changed.getCurrentScore()) {
rematchNetworkAndRequests(changed, ReapUnvalidatedNetworks.REAP, now);
} else {
final NetworkAgentInfo[] nais = mNetworkAgentInfos.values().toArray(
new NetworkAgentInfo[mNetworkAgentInfos.size()]);
Arrays.sort(nais);
for (NetworkAgentInfo nai : nais) { //注册callbakc,走这个分支
rematchNetworkAndRequests(nai,
// Only reap the last time through the loop. Reaping before all rematching
// is complete could incorrectly teardown a network that hasn't yet been
// rematched.
(nai != nais[nais.length-1]) ? ReapUnvalidatedNetworks.DONT_REAP
: ReapUnvalidatedNetworks.REAP,
now);
}
}
}
关键函数rematchAllNetworksAndRequests就是遍历NetworkAgentInfo找到匹配的NetworkCapabilities,如果有就进行回调
NetworkAgentInfo生成
回调的Network就是这里创建的 new Network(reserveNetId())
public int registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo,
LinkProperties linkProperties, NetworkCapabilities networkCapabilities,
int currentScore, NetworkMisc networkMisc) {
enforceConnectivityInternalPermission();
LinkProperties lp = new LinkProperties(linkProperties);
lp.ensureDirectlyConnectedRoutes();
// TODO: Instead of passing mDefaultRequest, provide an API to determine whether a Network
// satisfies mDefaultRequest.
final NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(),
new Network(reserveNetId()), new NetworkInfo(networkInfo), lp,
new NetworkCapabilities(networkCapabilities), currentScore,
mContext, mTrackerHandler, new NetworkMisc(networkMisc), mDefaultRequest, this);
synchronized (this) {
nai.networkMonitor.systemReady = mSystemReady;
}
addValidationLogs(nai.networkMonitor.getValidationLogs(), nai.network,
networkInfo.getExtraInfo());
if (DBG) log("registerNetworkAgent " + nai);
mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_AGENT, nai));
return nai.network.netId;
}

从上图我们可以看出NetworkAgentInfo的网络信息,这部分开机启动的时候生成的,没有可重启机器试试
更多可以参考 网络连接评分机制之NetworkAgent
总结
- NetworkRequestInfo 网络请求信息,用户可以指定自己关注的信息
- NetworkAgentInfo 机器的网络信息
- rematchAllNetworksAndRequests 关键函数
如果NetworkAgentInfo中有满足NetworkRequestInfo的网络配置,此时就会进行回调
问题排查
前面已经介绍过在rematchAllNetworksAndRequests函数中匹配,最终会调用到processListenRequests函数
//
private void processListenRequests(NetworkAgentInfo nai, boolean capabilitiesChanged) {
// For consistency with previous behaviour, send onLost callbacks before onAvailable.
for (NetworkRequestInfo nri : mNetworkRequests.values()) {
NetworkRequest nr = nri.request;
if (!nr.isListen()) continue;
if (nai.isSatisfyingRequest(nr.requestId) && !nai.satisfies(nr)) {
nai.removeRequest(nri.request.requestId);
callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_LOST, 0);
}
}
if (capabilitiesChanged) {
notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_CAP_CHANGED);
}
for (NetworkRequestInfo nri : mNetworkRequests.values()) {
NetworkRequest nr = nri.request;
if (!nr.isListen()) continue;
if (nai.satisfies(nr) && !nai.isSatisfyingRequest(nr.requestId)) {
nai.addRequest(nr);
notifyNetworkAvailable(nai, nri); // 正常的触发回调
}
}
}
通过观察我们发现satisfies函数失败了,看看satisfies如何判断的
// Does this network satisfy request? // 该网络是否满足请求?
public boolean satisfies(NetworkRequest request) {
return created &&
request.networkCapabilities.satisfiedByNetworkCapabilities(networkCapabilities);
}
public boolean satisfiedByNetworkCapabilities(NetworkCapabilities nc) {
return satisfiedByNetworkCapabilities(nc, false);
}
// satisfiedByNetworkCapabilities 条件特别多
private boolean satisfiedByNetworkCapabilities(NetworkCapabilities nc, boolean onlyImmutable) {
return (nc != null &&
satisfiedByNetCapabilities(nc, onlyImmutable) &&
satisfiedByTransportTypes(nc) &&
(onlyImmutable || satisfiedByLinkBandwidths(nc)) &&
satisfiedBySpecifier(nc) &&
(onlyImmutable || satisfiedBySignalStrength(nc)));
}
private boolean satisfiedByNetCapabilities(NetworkCapabilities nc, boolean onlyImmutable) {
long networkCapabilities = this.mNetworkCapabilities;
if (onlyImmutable) { // 唯一不可变的
networkCapabilities = networkCapabilities & ~MUTABLE_CAPABILITIES;
}
return ((nc.mNetworkCapabilities & networkCapabilities) == networkCapabilities);
}
private boolean satisfiedByTransportTypes(NetworkCapabilities nc) {
return ((this.mTransportTypes == 0) ||
((this.mTransportTypes & nc.mTransportTypes) != 0));
}
条件想当的多,大致还是判断NetworkCapabilities 和TransportTypes是否匹配,以及带宽是否足够

使用frida对这两个函数进行调试,非常明显是TransportTypes不匹配,修改代码重新测试添加NetworkCapabilities.TRANSPORT_ETHERNET 即可收到回调
NetworkRequest request = new NetworkRequest.Builder()
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) //12
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI) //1
//.addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET) //3
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) //0
.build();
NetworkAgent创建
那么ETHERNET这个NetworkAgent哪里创建的?
// frameworks/opt/net/ethernet/java/com/android/server/ethernet/EthernetNetworkFactory.java
private void initNetworkCapabilities() {
mNetworkCapabilities = new NetworkCapabilities();
mNetworkCapabilities.addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET);
mNetworkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
mNetworkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
// We have no useful data on bandwidth. Say 100M up and 100M down. :-(
mNetworkCapabilities.setLinkUpstreamBandwidthKbps(100 * 1000);
mNetworkCapabilities.setLinkDownstreamBandwidthKbps(100 * 1000);
}
void onIpLayerStarted(LinkProperties linkProperties) {
if (mNetworkAgent != null) {
Log.e(TAG, "Already have a NetworkAgent - aborting new request");
stopIpManager();
return;
}
mLinkProperties = linkProperties;
mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, mHwAddr);
// Create our NetworkAgent.
mNetworkAgent = new NetworkAgent(mHandler.getLooper(), mContext,
NETWORK_TYPE, mNetworkInfo, mNetworkCapabilities, mLinkProperties,
NETWORK_SCORE) {
public void unwanted() {
if (this == mNetworkAgent) {
stopIpManager();
} else if (mNetworkAgent != null) {
Log.d(TAG, "Ignoring unwanted as we have a more modern " +
"instance");
} // Otherwise, we've already called stopIpManager.
}
};
}
下面是一些其他的NetworkAgent创建
// frameworks/base/services/core/java/com/android/server/connectivity/Vpn.java
private void agentConnect() {
LinkProperties lp = makeLinkProperties();
if (lp.hasIPv4DefaultRoute() || lp.hasIPv6DefaultRoute()) {
mNetworkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
} else {
mNetworkCapabilities.removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
}
mNetworkInfo.setDetailedState(DetailedState.CONNECTING, null, null);
NetworkMisc networkMisc = new NetworkMisc();
networkMisc.allowBypass = mConfig.allowBypass && !mLockdown;
long token = Binder.clearCallingIdentity();
try {
mNetworkAgent = new NetworkAgent(mLooper, mContext, NETWORKTYPE,
mNetworkInfo, mNetworkCapabilities, lp, 0, networkMisc) {
@Override
public void unwanted() {
// We are user controlled, not driven by NetworkRequest.
}
};
} finally {
Binder.restoreCallingIdentity(token);
}
....
}
// frameworks/opt/net/lowpan/service/java/com/android/server/lowpan/LowpanInterfaceTracker.java
private void bringUpNetworkAgent() {
if (mNetworkAgent == null) {
mNetworkAgent =
new NetworkAgent(
mNetworkFactory.getLooper(),
mContext,
NETWORK_TYPE,
mNetworkInfo,
mNetworkCapabilities,
mLinkProperties,
NETWORK_SCORE) {
public void unwanted() {
LowpanInterfaceTracker.this.sendMessage(CMD_UNWANTED, this);
};
};
}
}
// wifi
// frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiStateMachine.java
class L2ConnectedState extends State {
@Override
public void enter() {
mRssiPollToken++;
if (mEnableRssiPolling) {
sendMessage(CMD_RSSI_POLL, mRssiPollToken, 0);
}
if (mNetworkAgent != null) {
loge("Have NetworkAgent when entering L2Connected");
setNetworkDetailedState(DetailedState.DISCONNECTED);
}
setNetworkDetailedState(DetailedState.CONNECTING);
// 创建
mNetworkAgent = new WifiNetworkAgent(getHandler().getLooper(), mContext,
"WifiNetworkAgent", mNetworkInfo, mNetworkCapabilitiesFilter,
mLinkProperties, 60, mNetworkMisc);
clearTargetBssid("L2ConnectedState");
mCountryCode.setReadyForChange(false);
mWifiMetrics.setWifiState(WifiMetricsProto.WifiLog.WIFI_ASSOCIATED);
}
...
}
回调细节
对应函数onCapabilitiesChanged(@NonNull Network network, @NonNull NetworkCapabilities networkCapabilities)
将networkAgent.network 和 networkAgent.networkCapabilities 回调过去
private static void callCallbackForRequest(NetworkRequestInfo nri,
NetworkAgentInfo networkAgent, int notificationType, int arg1) {
...
Bundle bundle = new Bundle();
Message msg = Message.obtain();
if (notificationType != ConnectivityManager.CALLBACK_UNAVAIL) {
putParcelable(bundle, networkAgent.network); //对应network
}
switch (notificationType) {
case ConnectivityManager.CALLBACK_LOSING: {
msg.arg1 = arg1;
break;
}
case ConnectivityManager.CALLBACK_CAP_CHANGED: {
putParcelable(bundle, new NetworkCapabilities(networkAgent.networkCapabilities)); // 对应 networkCapabilities
break;
}
case ConnectivityManager.CALLBACK_IP_CHANGED: {
putParcelable(bundle, new LinkProperties(networkAgent.linkProperties));
break;
}
}
...
}

浙公网安备 33010602011771号