Add metrics for requests satisfied by local networks

This change introduces `SatisfiedByLocalNetworkMetrics` to count the
number of `NetworkRequest`s per UID that can be satisfied by a
local-only network.

The purpose is to gather data on how many applications register callbacks
that would match non-thread local network connectivity.
This data helps in understanding app behavior and can inform
future development of local-only network features particularly
for the backward compatibility of existing NetworkRequests.

- A new class `SatisfiedByLocalNetworkMetrics` handles the counting and
  logging logic.
- `ConnectivityService` calls into this class upon `NetworkRequest`
  registration.
- Counts are logged to statsd.

Sample dumpsys output:
  SatisfiedByLocalNetworkMetrics: {LISTEN={10217=2}}

Bug: 406172997
Flag: EXEMPT controlled by the `satisfied_by_local_network_metrics`
Test: atest ConnectivityCoverageTests:android.net.connectivity.com.android.server.CSSatisfiedByLocalNetworkMetricsTest \
      ConnectivityCoverageTests:android.net.connectivity.com.android.metrics.SatisfiedByLocalNetworkMetricsTest \
      --update-device
Test: m statsd_testdrive && statsd_testdrive -e 10247
Test: Manual: atest dumpsys connectivity

Change-Id: I62f6299a1c726537b373e3e80d41a494323f3cf2
This commit is contained in:
Junyu Lai 2025-06-20 14:31:52 +08:00
commit c00cf63e8a

View file

@ -168,6 +168,7 @@ import static com.android.server.connectivity.ConnectivityFlags.NAMESPACE_TETHER
import static com.android.server.connectivity.ConnectivityFlags.QUEUE_CALLBACKS_FOR_FROZEN_APPS;
import static com.android.server.connectivity.ConnectivityFlags.QUEUE_NETWORK_AGENT_EVENTS_IN_SYSTEM_SERVER;
import static com.android.server.connectivity.ConnectivityFlags.REQUEST_RESTRICTED_WIFI;
import static com.android.server.connectivity.ConnectivityFlags.SATISFIED_BY_LOCAL_NETWORK_METRICS;
import static com.android.server.connectivity.ConnectivityFlags.WIFI_DATA_INACTIVITY_TIMEOUT;
import android.Manifest;
@ -344,6 +345,7 @@ import com.android.metrics.NetworkRequestCount;
import com.android.metrics.RequestCountForType;
import com.android.metrics.SatelliteAccessInfo;
import com.android.metrics.SatelliteCoarseUsageMetricsCollector;
import com.android.metrics.SatisfiedByLocalNetworkMetrics;
import com.android.modules.utils.BasicShellCommandHandler;
import com.android.modules.utils.build.SdkLevel;
import com.android.net.module.util.BaseNetdUnsolicitedEventListener;
@ -1095,6 +1097,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
private final IpConnectivityLog mMetricsLog;
private final DefaultNetworkRematchMetrics mDefaultNetworkRematchMetrics;
private final SatisfiedByLocalNetworkMetrics mSatisfiedByLocalNetworkMetrics;
@Nullable private final NetworkRequestStateStatsMetrics mNetworkRequestStateStatsMetrics;
@ -1731,6 +1734,15 @@ public class ConnectivityService extends IConnectivityManager.Stub
return new DefaultNetworkRematchMetrics();
}
/**
* @see SatisfiedByLocalNetworkMetrics
*/
@Nullable
public SatisfiedByLocalNetworkMetrics makeSatisfiedByLocalNetworkMetrics(Context context,
Handler handler) {
return new SatisfiedByLocalNetworkMetrics(context, handler);
}
/** Creates an L2capNetworkProvider */
public L2capNetworkProvider makeL2capNetworkProvider(Context context) {
return new L2capNetworkProvider(context);
@ -2122,6 +2134,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
mSatelliteCoarseUsageMetricsCollector = null;
mDefaultNetworkRematchMetrics = null;
}
if (mDeps.isFeatureNotChickenedOut(mContext, SATISFIED_BY_LOCAL_NETWORK_METRICS)) {
mSatisfiedByLocalNetworkMetrics =
mDeps.makeSatisfiedByLocalNetworkMetrics(mContext, mHandler);
} else {
mSatisfiedByLocalNetworkMetrics = null;
}
if (mDeps.flagConnectivityServiceDestroySocket()) {
mIpToNetworksMap = new HashMap<>();
@ -4364,6 +4382,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
ConnectivitySampleMetricsHelper.start(mContext, mHandler,
CONNECTIVITY_STATE_SAMPLE, this::sampleConnectivityStateToStatsEvent);
if (mSatisfiedByLocalNetworkMetrics != null) {
mSatisfiedByLocalNetworkMetrics.start();
}
// Wait PermissionMonitor to finish the permission update. Then MultipathPolicyTracker won't
// have permission problem. While CV#block() is unbounded in time and can in principle block
// forever, this replaces a synchronous call to PermissionMonitor#initialize, which
@ -4702,6 +4723,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (mConstrainedDataSatelliteMetrics) {
mSatelliteCoarseUsageMetricsCollector.dump(pw);
}
if (mSatisfiedByLocalNetworkMetrics != null) {
mSatisfiedByLocalNetworkMetrics.dump(pw);
}
pw.println();
pw.println("Legacy network activity:");
@ -8901,6 +8925,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
callingAttributionTag, declaredMethodsFlag);
if (DBG) log("requestNetwork for " + nri);
trackUidAndRegisterNetworkRequest(EVENT_REGISTER_NETWORK_REQUEST, nri);
if (mSatisfiedByLocalNetworkMetrics != null) {
mSatisfiedByLocalNetworkMetrics.logRequest(networkRequest, asUid);
}
if (timeoutMs > 0) {
mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_TIMEOUT_NETWORK_REQUEST,
nri), timeoutMs);
@ -9114,6 +9141,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
callingAttributionTag);
if (DBG) log("pendingRequest for " + nri);
trackUidAndRegisterNetworkRequest(EVENT_REGISTER_NETWORK_REQUEST_WITH_INTENT, nri);
if (mSatisfiedByLocalNetworkMetrics != null) {
mSatisfiedByLocalNetworkMetrics.logRequest(networkRequest, callingUid);
}
return networkRequest;
}
@ -9260,6 +9290,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (VDBG) log("listenForNetwork for " + nri);
trackUidAndRegisterNetworkRequest(EVENT_REGISTER_NETWORK_LISTENER, nri);
if (mSatisfiedByLocalNetworkMetrics != null) {
mSatisfiedByLocalNetworkMetrics.logRequest(networkRequest, callingUid);
}
return networkRequest;
}
@ -9285,6 +9318,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (VDBG) log("pendingListenForNetwork for " + nri);
trackUidAndRegisterNetworkRequest(EVENT_REGISTER_NETWORK_LISTENER_WITH_INTENT, nri);
if (mSatisfiedByLocalNetworkMetrics != null) {
mSatisfiedByLocalNetworkMetrics.logRequest(networkRequest, callingUid);
}
}
/** Returns the next Network provider ID. */