Hold wifi and mobile interfaces since boot in NetworkStatsService
In current design, the interface will be removed from the list if
the network disconnected which will cause getUidStatsForTransport()
returns unexpected snapshot to caller since the list is empty.
This change also remove interface name from all entries before
the method returns the result.
Ignore-AOSP-First: non-AOSP CL is included in the same topic
Bug: 231514741
Test: FrameworksNetTests
manual test
Change-Id: Ie60829a65d0d9b5b63ad353695a820c0586e3665
This commit is contained in:
committed by
Remi NGUYEN VAN
parent
3caf95c8fc
commit
a2f1cf3576
@@ -1299,6 +1299,17 @@ public final class NetworkStats implements Parcelable, Iterable<NetworkStats.Ent
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the interface name from all entries.
|
||||||
|
* This mutates the original structure in place.
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public void clearInterfaces() {
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
iface[i] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Only keep entries that match all specified filters.
|
* Only keep entries that match all specified filters.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import static android.content.Intent.ACTION_UID_REMOVED;
|
|||||||
import static android.content.Intent.ACTION_USER_REMOVED;
|
import static android.content.Intent.ACTION_USER_REMOVED;
|
||||||
import static android.content.Intent.EXTRA_UID;
|
import static android.content.Intent.EXTRA_UID;
|
||||||
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
|
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
|
||||||
|
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
|
||||||
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
|
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
|
||||||
import static android.net.NetworkStats.DEFAULT_NETWORK_ALL;
|
import static android.net.NetworkStats.DEFAULT_NETWORK_ALL;
|
||||||
import static android.net.NetworkStats.IFACE_ALL;
|
import static android.net.NetworkStats.IFACE_ALL;
|
||||||
@@ -172,6 +173,7 @@ import java.util.HashSet;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.Semaphore;
|
import java.util.concurrent.Semaphore;
|
||||||
@@ -343,11 +345,16 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
|||||||
@GuardedBy("mStatsLock")
|
@GuardedBy("mStatsLock")
|
||||||
private String mActiveIface;
|
private String mActiveIface;
|
||||||
|
|
||||||
/** Set of any ifaces associated with mobile networks since boot. */
|
/** Set of all ifaces currently associated with mobile networks. */
|
||||||
private volatile String[] mMobileIfaces = new String[0];
|
private volatile String[] mMobileIfaces = new String[0];
|
||||||
|
|
||||||
/** Set of any ifaces associated with wifi networks since boot. */
|
/* A set of all interfaces that have ever been associated with mobile networks since boot. */
|
||||||
private volatile String[] mWifiIfaces = new String[0];
|
@GuardedBy("mStatsLock")
|
||||||
|
private final Set<String> mAllMobileIfacesSinceBoot = new ArraySet<>();
|
||||||
|
|
||||||
|
/* A set of all interfaces that have ever been associated with wifi networks since boot. */
|
||||||
|
@GuardedBy("mStatsLock")
|
||||||
|
private final Set<String> mAllWifiIfacesSinceBoot = new ArraySet<>();
|
||||||
|
|
||||||
/** Set of all ifaces currently used by traffic that does not explicitly specify a Network. */
|
/** Set of all ifaces currently used by traffic that does not explicitly specify a Network. */
|
||||||
@GuardedBy("mStatsLock")
|
@GuardedBy("mStatsLock")
|
||||||
@@ -1564,17 +1571,37 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
|||||||
return dataLayer;
|
return dataLayer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String[] getAllIfacesSinceBoot(int transport) {
|
||||||
|
synchronized (mStatsLock) {
|
||||||
|
final Set<String> ifaceSet;
|
||||||
|
if (transport == TRANSPORT_WIFI) {
|
||||||
|
ifaceSet = mAllWifiIfacesSinceBoot;
|
||||||
|
} else if (transport == TRANSPORT_CELLULAR) {
|
||||||
|
ifaceSet = mAllMobileIfacesSinceBoot;
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("Invalid transport " + transport);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ifaceSet.toArray(new String[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public NetworkStats getUidStatsForTransport(int transport) {
|
public NetworkStats getUidStatsForTransport(int transport) {
|
||||||
PermissionUtils.enforceNetworkStackPermission(mContext);
|
PermissionUtils.enforceNetworkStackPermission(mContext);
|
||||||
try {
|
try {
|
||||||
final String[] relevantIfaces =
|
final String[] ifaceArray = getAllIfacesSinceBoot(transport);
|
||||||
transport == TRANSPORT_WIFI ? mWifiIfaces : mMobileIfaces;
|
|
||||||
// TODO(b/215633405) : mMobileIfaces and mWifiIfaces already contain the stacked
|
// TODO(b/215633405) : mMobileIfaces and mWifiIfaces already contain the stacked
|
||||||
// interfaces, so this is not useful, remove it.
|
// interfaces, so this is not useful, remove it.
|
||||||
final String[] ifacesToQuery =
|
final String[] ifacesToQuery =
|
||||||
mStatsFactory.augmentWithStackedInterfaces(relevantIfaces);
|
mStatsFactory.augmentWithStackedInterfaces(ifaceArray);
|
||||||
return getNetworkStatsUidDetail(ifacesToQuery);
|
final NetworkStats stats = getNetworkStatsUidDetail(ifacesToQuery);
|
||||||
|
// Clear the interfaces of the stats before returning, so callers won't get this
|
||||||
|
// information. This is because no caller needs this information for now, and it
|
||||||
|
// makes it easier to change the implementation later by using the histories in the
|
||||||
|
// recorder.
|
||||||
|
stats.clearInterfaces();
|
||||||
|
return stats;
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Log.wtf(TAG, "Error compiling UID stats", e);
|
Log.wtf(TAG, "Error compiling UID stats", e);
|
||||||
return new NetworkStats(0L, 0);
|
return new NetworkStats(0L, 0);
|
||||||
@@ -1955,7 +1982,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
|||||||
|
|
||||||
final boolean combineSubtypeEnabled = mSettings.getCombineSubtypeEnabled();
|
final boolean combineSubtypeEnabled = mSettings.getCombineSubtypeEnabled();
|
||||||
final ArraySet<String> mobileIfaces = new ArraySet<>();
|
final ArraySet<String> mobileIfaces = new ArraySet<>();
|
||||||
final ArraySet<String> wifiIfaces = new ArraySet<>();
|
|
||||||
for (NetworkStateSnapshot snapshot : snapshots) {
|
for (NetworkStateSnapshot snapshot : snapshots) {
|
||||||
final int displayTransport =
|
final int displayTransport =
|
||||||
getDisplayTransport(snapshot.getNetworkCapabilities().getTransportTypes());
|
getDisplayTransport(snapshot.getNetworkCapabilities().getTransportTypes());
|
||||||
@@ -2000,9 +2026,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
|||||||
|
|
||||||
if (isMobile) {
|
if (isMobile) {
|
||||||
mobileIfaces.add(baseIface);
|
mobileIfaces.add(baseIface);
|
||||||
|
// If the interface name was present in the wifi set, the interface won't
|
||||||
|
// be removed from it to prevent stats from getting rollback.
|
||||||
|
mAllMobileIfacesSinceBoot.add(baseIface);
|
||||||
}
|
}
|
||||||
if (isWifi) {
|
if (isWifi) {
|
||||||
wifiIfaces.add(baseIface);
|
mAllWifiIfacesSinceBoot.add(baseIface);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2044,9 +2073,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
|||||||
findOrCreateNetworkIdentitySet(mActiveUidIfaces, iface).add(ident);
|
findOrCreateNetworkIdentitySet(mActiveUidIfaces, iface).add(ident);
|
||||||
if (isMobile) {
|
if (isMobile) {
|
||||||
mobileIfaces.add(iface);
|
mobileIfaces.add(iface);
|
||||||
|
mAllMobileIfacesSinceBoot.add(iface);
|
||||||
}
|
}
|
||||||
if (isWifi) {
|
if (isWifi) {
|
||||||
wifiIfaces.add(iface);
|
mAllWifiIfacesSinceBoot.add(iface);
|
||||||
}
|
}
|
||||||
|
|
||||||
mStatsFactory.noteStackedIface(iface, baseIface);
|
mStatsFactory.noteStackedIface(iface, baseIface);
|
||||||
@@ -2055,16 +2085,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mMobileIfaces = mobileIfaces.toArray(new String[0]);
|
mMobileIfaces = mobileIfaces.toArray(new String[0]);
|
||||||
mWifiIfaces = wifiIfaces.toArray(new String[0]);
|
|
||||||
// TODO (b/192758557): Remove debug log.
|
// TODO (b/192758557): Remove debug log.
|
||||||
if (CollectionUtils.contains(mMobileIfaces, null)) {
|
if (CollectionUtils.contains(mMobileIfaces, null)) {
|
||||||
throw new NullPointerException(
|
throw new NullPointerException(
|
||||||
"null element in mMobileIfaces: " + Arrays.toString(mMobileIfaces));
|
"null element in mMobileIfaces: " + Arrays.toString(mMobileIfaces));
|
||||||
}
|
}
|
||||||
if (CollectionUtils.contains(mWifiIfaces, null)) {
|
|
||||||
throw new NullPointerException(
|
|
||||||
"null element in mWifiIfaces: " + Arrays.toString(mWifiIfaces));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int getSubIdForMobile(@NonNull NetworkStateSnapshot state) {
|
private static int getSubIdForMobile(@NonNull NetworkStateSnapshot state) {
|
||||||
@@ -2532,6 +2557,22 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
|||||||
}
|
}
|
||||||
pw.decreaseIndent();
|
pw.decreaseIndent();
|
||||||
|
|
||||||
|
pw.println("All wifi interfaces:");
|
||||||
|
pw.increaseIndent();
|
||||||
|
for (String iface : mAllWifiIfacesSinceBoot) {
|
||||||
|
pw.print(iface + " ");
|
||||||
|
}
|
||||||
|
pw.println();
|
||||||
|
pw.decreaseIndent();
|
||||||
|
|
||||||
|
pw.println("All mobile interfaces:");
|
||||||
|
pw.increaseIndent();
|
||||||
|
for (String iface : mAllMobileIfacesSinceBoot) {
|
||||||
|
pw.print(iface + " ");
|
||||||
|
}
|
||||||
|
pw.println();
|
||||||
|
pw.decreaseIndent();
|
||||||
|
|
||||||
// Get the top openSession callers
|
// Get the top openSession callers
|
||||||
final HashMap calls;
|
final HashMap calls;
|
||||||
synchronized (mOpenSessionCallsLock) {
|
synchronized (mOpenSessionCallsLock) {
|
||||||
|
|||||||
@@ -1180,9 +1180,12 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
|
|||||||
|
|
||||||
assertEquals(3, stats.size());
|
assertEquals(3, stats.size());
|
||||||
entry1.operations = 1;
|
entry1.operations = 1;
|
||||||
|
entry1.iface = null;
|
||||||
assertEquals(entry1, stats.getValues(0, null));
|
assertEquals(entry1, stats.getValues(0, null));
|
||||||
entry2.operations = 1;
|
entry2.operations = 1;
|
||||||
|
entry2.iface = null;
|
||||||
assertEquals(entry2, stats.getValues(1, null));
|
assertEquals(entry2, stats.getValues(1, null));
|
||||||
|
entry3.iface = null;
|
||||||
assertEquals(entry3, stats.getValues(2, null));
|
assertEquals(entry3, stats.getValues(2, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user