From 25ca3f0e73dca837180c1a8eec4a58e56cfe51dc Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Mon, 10 Jan 2022 21:43:32 +0800 Subject: [PATCH] Remove hidden API dependencies from StatsPullAtomService NetworkStatsService is going to be moved into mainline module so the hidden API usages should be removed. Thus, this patch uses formal API to query data usage and refactor the slice networks stats method by formal API. Bug: 210073043 Test: build BytesTransferredTest and check the output of atoms adb shell cmd stats pull-source $ATOM_ID Change-Id: Ie609f6c3d381f097adc30dbb9b88c0cc933e16e2 --- .../stats/pull/StatsPullAtomService.java | 219 ++++++++---------- 1 file changed, 101 insertions(+), 118 deletions(-) diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java index bbd4d058dfafc..d4e7573bf216e 100644 --- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java +++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java @@ -18,9 +18,6 @@ package com.android.server.stats.pull; import static android.app.AppOpsManager.OP_FLAG_SELF; import static android.app.AppOpsManager.OP_FLAG_TRUSTED_PROXIED; -import static android.app.usage.NetworkStatsManager.FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN; -import static android.app.usage.NetworkStatsManager.FLAG_POLL_FORCE; -import static android.app.usage.NetworkStatsManager.FLAG_POLL_ON_OPEN; import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED; import static android.content.pm.PermissionInfo.PROTECTION_DANGEROUS; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; @@ -73,6 +70,7 @@ import android.app.ProcessMemoryState; import android.app.RuntimeAppOpAccessMessage; import android.app.StatsManager; import android.app.StatsManager.PullAtomMetadata; +import android.app.usage.NetworkStatsManager; import android.bluetooth.BluetoothActivityEnergyInfo; import android.bluetooth.BluetoothAdapter; import android.bluetooth.UidTraffic; @@ -86,8 +84,6 @@ import android.hardware.biometrics.BiometricsProtoEnums; import android.hardware.face.FaceManager; import android.hardware.fingerprint.FingerprintManager; import android.net.ConnectivityManager; -import android.net.INetworkStatsService; -import android.net.INetworkStatsSession; import android.net.Network; import android.net.NetworkRequest; import android.net.NetworkStats; @@ -181,6 +177,7 @@ import com.android.internal.os.StoragedUidIoStatsReader; import com.android.internal.os.SystemServerCpuThreadReader.SystemServiceCpuThreadTimes; import com.android.internal.util.CollectionUtils; import com.android.internal.util.FrameworkStatsLog; +import com.android.net.module.util.NetworkStatsUtils; import com.android.role.RoleManagerLocal; import com.android.server.BinderCallsStatsService; import com.android.server.LocalManagerRegistry; @@ -228,7 +225,7 @@ import java.util.concurrent.Executor; import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; -import java.util.function.BiConsumer; +import java.util.function.Function; /** * SystemService containing PullAtomCallbacks that are registered with statsd. @@ -324,6 +321,7 @@ public class StatsPullAtomService extends SystemService { private WifiManager mWifiManager; private TelephonyManager mTelephony; private SubscriptionManager mSubscriptionManager; + private NetworkStatsManager mNetworkStatsManager; @GuardedBy("mKernelWakelockLock") private KernelWakelockReader mKernelWakelockReader; @@ -769,7 +767,7 @@ public class StatsPullAtomService extends SystemService { mContext.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE); mStatsSubscriptionsListener = new StatsSubscriptionsListener(mSubscriptionManager); mStorageManager = (StorageManager) mContext.getSystemService(StorageManager.class); - + mNetworkStatsManager = mContext.getSystemService(NetworkStatsManager.class); // Initialize DiskIO mStoragedUidIoStatsReader = new StoragedUidIoStatsReader(); @@ -959,32 +957,6 @@ public class StatsPullAtomService extends SystemService { registerOemManagedBytesTransfer(); } - /** - * Return the {@code INetworkStatsSession} object that holds the necessary properties needed - * for the subsequent queries to {@link com.android.server.net.NetworkStatsService}. Or - * null if the service or binder cannot be obtained. Calling this method will trigger poll - * in NetworkStatsService with once per 15 seconds rate-limit, unless {@code bypassRateLimit} - * is set to true. This is needed in {@link #getUidNetworkStatsSnapshotForTemplate}, where - * bypassing the limit is necessary for perfd to supply realtime stats to developers looking at - * the network usage of their app. - */ - @Nullable - private INetworkStatsSession getNetworkStatsSession(boolean bypassRateLimit) { - final INetworkStatsService networkStatsService = - INetworkStatsService.Stub.asInterface( - ServiceManager.getService(Context.NETWORK_STATS_SERVICE)); - if (networkStatsService == null) return null; - - try { - return networkStatsService.openSessionForUsageStats( - FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN | (bypassRateLimit ? FLAG_POLL_FORCE - : FLAG_POLL_ON_OPEN), mContext.getOpPackageName()); - } catch (RemoteException e) { - Slog.e(TAG, "Cannot get NetworkStats session", e); - return null; - } - } - private IThermalService getIThermalService() { synchronized (mThermalLock) { if (mThermalService == null) { @@ -1115,8 +1087,8 @@ public class StatsPullAtomService extends SystemService { case FrameworkStatsLog.WIFI_BYTES_TRANSFER: { final NetworkStats stats = getUidNetworkStatsSnapshotForTransport(TRANSPORT_WIFI); if (stats != null) { - ret.add(new NetworkStatsExt(stats.groupedByUid(), new int[] {TRANSPORT_WIFI}, - /*slicedByFgbg=*/false)); + ret.add(new NetworkStatsExt(sliceNetworkStatsByUid(stats), + new int[] {TRANSPORT_WIFI}, /*slicedByFgbg=*/false)); } break; } @@ -1132,7 +1104,7 @@ public class StatsPullAtomService extends SystemService { final NetworkStats stats = getUidNetworkStatsSnapshotForTransport(TRANSPORT_CELLULAR); if (stats != null) { - ret.add(new NetworkStatsExt(stats.groupedByUid(), + ret.add(new NetworkStatsExt(sliceNetworkStatsByUid(stats), new int[] {TRANSPORT_CELLULAR}, /*slicedByFgbg=*/false)); } break; @@ -1223,23 +1195,19 @@ public class StatsPullAtomService extends SystemService { private void addNetworkStats(int atomTag, @NonNull List ret, @NonNull NetworkStatsExt statsExt) { - int size = statsExt.stats.size(); - final NetworkStats.Entry entry = new NetworkStats.Entry(); // For recycling - for (int j = 0; j < size; j++) { - statsExt.stats.getValues(j, entry); + for (NetworkStats.Entry entry : statsExt.stats) { StatsEvent statsEvent; - if (statsExt.slicedByFgbg) { // MobileBytesTransferByFgBg atom or WifiBytesTransferByFgBg atom. statsEvent = FrameworkStatsLog.buildStatsEvent( - atomTag, entry.uid, - (entry.set > 0), entry.rxBytes, entry.rxPackets, entry.txBytes, - entry.txPackets); + atomTag, entry.getUid(), + (entry.getSet() > 0), entry.getRxBytes(), entry.getRxPackets(), + entry.getTxBytes(), entry.getTxPackets()); } else { // MobileBytesTransfer atom or WifiBytesTransfer atom. statsEvent = FrameworkStatsLog.buildStatsEvent( - atomTag, entry.uid, entry.rxBytes, - entry.rxPackets, entry.txBytes, entry.txPackets); + atomTag, entry.getUid(), entry.getRxBytes(), + entry.getRxPackets(), entry.getTxBytes(), entry.getTxPackets()); } ret.add(statsEvent); } @@ -1247,13 +1215,12 @@ public class StatsPullAtomService extends SystemService { private void addBytesTransferByTagAndMeteredAtoms(@NonNull NetworkStatsExt statsExt, @NonNull List pulledData) { - final NetworkStats.Entry entry = new NetworkStats.Entry(); // for recycling - for (int i = 0; i < statsExt.stats.size(); i++) { - statsExt.stats.getValues(i, entry); + for (NetworkStats.Entry entry : statsExt.stats) { pulledData.add(FrameworkStatsLog.buildStatsEvent( - FrameworkStatsLog.BYTES_TRANSFER_BY_TAG_AND_METERED, entry.uid, - entry.metered == NetworkStats.METERED_YES, entry.tag, entry.rxBytes, - entry.rxPackets, entry.txBytes, entry.txPackets)); + FrameworkStatsLog.BYTES_TRANSFER_BY_TAG_AND_METERED, entry.getUid(), + entry.getMetered() == NetworkStats.METERED_YES, entry.getTag(), + entry.getRxBytes(), entry.getRxPackets(), entry.getTxBytes(), + entry.getTxPackets())); } } @@ -1268,12 +1235,11 @@ public class StatsPullAtomService extends SystemService { // Report NR connected in 5G non-standalone mode, or if the RAT type is NR to begin with. final boolean isNR = is5GNsa || statsExt.ratType == TelephonyManager.NETWORK_TYPE_NR; - final NetworkStats.Entry entry = new NetworkStats.Entry(); // for recycling - for (int i = 0; i < statsExt.stats.size(); i++) { - statsExt.stats.getValues(i, entry); + for (NetworkStats.Entry entry : statsExt.stats) { pulledData.add(FrameworkStatsLog.buildStatsEvent( - FrameworkStatsLog.DATA_USAGE_BYTES_TRANSFER, entry.set, entry.rxBytes, - entry.rxPackets, entry.txBytes, entry.txPackets, + FrameworkStatsLog.DATA_USAGE_BYTES_TRANSFER, + entry.getSet(), entry.getRxBytes(), entry.getRxPackets(), + entry.getTxBytes(), entry.getTxPackets(), is5GNsa ? TelephonyManager.NETWORK_TYPE_LTE : statsExt.ratType, // Fill information about subscription, these cannot be null since invalid data // would be filtered when adding into subInfo list. @@ -1287,15 +1253,13 @@ public class StatsPullAtomService extends SystemService { private void addOemDataUsageBytesTransferAtoms(@NonNull NetworkStatsExt statsExt, @NonNull List pulledData) { - final NetworkStats.Entry entry = new NetworkStats.Entry(); // for recycling final int oemManaged = statsExt.oemManaged; for (final int transport : statsExt.transports) { - for (int i = 0; i < statsExt.stats.size(); i++) { - statsExt.stats.getValues(i, entry); + for (NetworkStats.Entry entry : statsExt.stats) { pulledData.add(FrameworkStatsLog.buildStatsEvent( - FrameworkStatsLog.OEM_MANAGED_BYTES_TRANSFER, entry.uid, (entry.set > 0), - oemManaged, transport, entry.rxBytes, entry.rxPackets, entry.txBytes, - entry.txPackets)); + FrameworkStatsLog.OEM_MANAGED_BYTES_TRANSFER, entry.getUid(), + (entry.getSet() > 0), oemManaged, transport, entry.getRxBytes(), + entry.getRxPackets(), entry.getTxBytes(), entry.getTxPackets())); } } } @@ -1357,22 +1321,32 @@ public class StatsPullAtomService extends SystemService { final long currentTimeInMillis = MICROSECONDS.toMillis(SystemClock.currentTimeMicro()); final long bucketDuration = Settings.Global.getLong(mContext.getContentResolver(), NETSTATS_UID_BUCKET_DURATION, NETSTATS_UID_DEFAULT_BUCKET_DURATION_MS); - try { - // TODO (b/156313635): This is short-term hack to allow perfd gets updated networkStats - // history when query in every second in order to show realtime statistics. However, - // this is not a good long-term solution since NetworkStatsService will make frequent - // I/O and also block main thread when polling. - // Consider making perfd queries NetworkStatsService directly. - final NetworkStats stats = getNetworkStatsSession(template.getMatchRule() - == NetworkTemplate.MATCH_WIFI_WILDCARD).getSummaryForAllUid(template, - currentTimeInMillis - elapsedMillisSinceBoot - bucketDuration, - currentTimeInMillis, includeTags); - return stats; - } catch (RemoteException | NullPointerException e) { - Slog.e(TAG, "Pulling netstats for template=" + template + " and includeTags=" - + includeTags + " causes error", e); + + // TODO (b/156313635): This is short-term hack to allow perfd gets updated networkStats + // history when query in every second in order to show realtime statistics. However, + // this is not a good long-term solution since NetworkStatsService will make frequent + // I/O and also block main thread when polling. + // Consider making perfd queries NetworkStatsService directly. + if (template.getMatchRule() == MATCH_WIFI && template.getSubscriberIds().isEmpty()) { + mNetworkStatsManager.forceUpdate(); } - return null; + + final android.app.usage.NetworkStats queryNonTaggedStats = + mNetworkStatsManager.querySummary( + template, currentTimeInMillis - elapsedMillisSinceBoot - bucketDuration, + currentTimeInMillis); + + final NetworkStats nonTaggedStats = + NetworkStatsUtils.fromPublicNetworkStats(queryNonTaggedStats); + if (!includeTags) return nonTaggedStats; + + final android.app.usage.NetworkStats quaryTaggedStats = + mNetworkStatsManager.queryTaggedSummary(template, + currentTimeInMillis - elapsedMillisSinceBoot - bucketDuration, + currentTimeInMillis); + final NetworkStats taggedStats = + NetworkStatsUtils.fromPublicNetworkStats(quaryTaggedStats); + return nonTaggedStats.add(taggedStats); } @NonNull private List getDataUsageBytesTransferSnapshotForSub( @@ -1396,27 +1370,51 @@ public class StatsPullAtomService extends SystemService { return ret; } + @NonNull private NetworkStats sliceNetworkStatsByUid(@NonNull NetworkStats stats) { + return sliceNetworkStats(stats, + (entry) -> { + return new NetworkStats.Entry(null /* IFACE_ALL */, entry.getUid(), + NetworkStats.SET_ALL, NetworkStats.TAG_NONE, + NetworkStats.METERED_ALL, NetworkStats.ROAMING_ALL, + NetworkStats.DEFAULT_NETWORK_ALL, + entry.getRxBytes(), entry.getRxPackets(), + entry.getTxBytes(), entry.getTxPackets(), 0); + }); + } + @NonNull private NetworkStats sliceNetworkStatsByFgbg(@NonNull NetworkStats stats) { return sliceNetworkStats(stats, - (newEntry, oldEntry) -> { - newEntry.set = oldEntry.set; + (entry) -> { + return new NetworkStats.Entry(null /* IFACE_ALL */, NetworkStats.UID_ALL, + entry.getSet(), NetworkStats.TAG_NONE, + NetworkStats.METERED_ALL, NetworkStats.ROAMING_ALL, + NetworkStats.DEFAULT_NETWORK_ALL, + entry.getRxBytes(), entry.getRxPackets(), + entry.getTxBytes(), entry.getTxPackets(), 0); }); } @NonNull private NetworkStats sliceNetworkStatsByUidAndFgbg(@NonNull NetworkStats stats) { return sliceNetworkStats(stats, - (newEntry, oldEntry) -> { - newEntry.uid = oldEntry.uid; - newEntry.set = oldEntry.set; + (entry) -> { + return new NetworkStats.Entry(null /* IFACE_ALL */, entry.getUid(), + entry.getSet(), NetworkStats.TAG_NONE, + NetworkStats.METERED_ALL, NetworkStats.ROAMING_ALL, + NetworkStats.DEFAULT_NETWORK_ALL, + entry.getRxBytes(), entry.getRxPackets(), + entry.getTxBytes(), entry.getTxPackets(), 0); }); } @NonNull private NetworkStats sliceNetworkStatsByUidTagAndMetered(@NonNull NetworkStats stats) { return sliceNetworkStats(stats, - (newEntry, oldEntry) -> { - newEntry.uid = oldEntry.uid; - newEntry.tag = oldEntry.tag; - newEntry.metered = oldEntry.metered; + (entry) -> { + return new NetworkStats.Entry(null /* IFACE_ALL */, entry.getUid(), + NetworkStats.SET_ALL, entry.getTag(), + entry.getMetered(), NetworkStats.ROAMING_ALL, + NetworkStats.DEFAULT_NETWORK_ALL, + entry.getRxBytes(), entry.getRxPackets(), + entry.getTxBytes(), entry.getTxPackets(), 0); }); } @@ -1426,46 +1424,31 @@ public class StatsPullAtomService extends SystemService { * * This function iterates through each NetworkStats.Entry, sets its dimensions equal to the * default state (with the presumption that we don't want to slice on anything), and then - * applies the slicer lambda to allow users to control which dimensions to slice on. This is - * adapted from groupedByUid within NetworkStats.java + * applies the slicer lambda to allow users to control which dimensions to slice on. * - * @param slicer An operation taking into two parameters, new NetworkStats.Entry and old - * NetworkStats.Entry, that should be used to copy state from the old to the new. + * @param slicer An operation taking one parameter, NetworkStats.Entry, that should be used to + * get the state from entry to replace the default value. * This is useful for slicing by particular dimensions. For example, if we wished * to slice by uid and tag, we could write the following lambda: - * (new, old) -> { - * new.uid = old.uid; - * new.tag = old.tag; + * (entry) -> { + * return new NetworkStats.Entry(null, entry.getUid(), + * NetworkStats.SET_ALL, entry.getTag(), + * NetworkStats.METERED_ALL, NetworkStats.ROAMING_ALL, + * NetworkStats.DEFAULT_NETWORK_ALL, + * entry.getRxBytes(), entry.getRxPackets(), + * entry.getTxBytes(), entry.getTxPackets(), 0); * } - * If no slicer is provided, the data is not sliced by any dimensions. * @return new NeworkStats object appropriately sliced */ @NonNull private NetworkStats sliceNetworkStats(@NonNull NetworkStats stats, - @Nullable BiConsumer slicer) { - final NetworkStats ret = new NetworkStats(stats.getElapsedRealtime(), 1); - - final NetworkStats.Entry entry = new NetworkStats.Entry(); - entry.uid = NetworkStats.UID_ALL; - entry.iface = NetworkStats.IFACE_ALL; - entry.set = NetworkStats.SET_ALL; - entry.tag = NetworkStats.TAG_NONE; - entry.metered = NetworkStats.METERED_ALL; - entry.roaming = NetworkStats.ROAMING_ALL; - entry.defaultNetwork = NetworkStats.DEFAULT_NETWORK_ALL; - - final NetworkStats.Entry recycle = new NetworkStats.Entry(); // used for retrieving values - for (int i = 0; i < stats.size(); i++) { - stats.getValues(i, recycle); + @NonNull Function slicer) { + NetworkStats ret = new NetworkStats(stats.getElapsedRealtime(), 1); + NetworkStats.Entry entry = new NetworkStats.Entry(); + for (NetworkStats.Entry e : stats) { if (slicer != null) { - slicer.accept(entry, recycle); + entry = slicer.apply(e); } - - entry.rxBytes = recycle.rxBytes; - entry.rxPackets = recycle.rxPackets; - entry.txBytes = recycle.txBytes; - entry.txPackets = recycle.txPackets; - // Operations purposefully omitted since we don't use them for statsd. - ret.combineValues(entry); + ret = ret.addEntry(entry); } return ret; }