Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 15d18f70 authored by Junyu Lai's avatar Junyu Lai Committed by Gerrit Code Review
Browse files

Merge "Remove hidden API dependencies from StatsPullAtomService"

parents 96bc724b 25ca3f0e
Loading
Loading
Loading
Loading
+101 −118
Original line number Diff line number Diff line
@@ -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<StatsEvent> 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<StatsEvent> 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<StatsEvent> 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);
        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<NetworkStatsExt> 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<NetworkStats.Entry, NetworkStats.Entry> 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<NetworkStats.Entry, NetworkStats.Entry> 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;
    }