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

Commit fa02276b authored by Junyu Lai's avatar Junyu Lai
Browse files

[MS35] Remove getNetwork[Total|Uid]Bytes dependencies from NPMS

1. getNetworkTotalBytes was used for querying overall statistics
   that regards of the NetworkPolicy to calculate the remaining
   data warning/limit quota that needs to be send to the lower layer.
2. getNetworkUidBytes was used for querying overall statistics of
   apps to find out the rapid traffic that caused by an abnormal
   app behavior.

This change replaces getNetwork[Total|Uid]Bytes with APIs that are
about to expose, and introduces a dependencies object for better
unit test injection.

Test: atest NetworkPolicyManagerServiceTest
Bug: 204830222

Change-Id: I802d2316fb22886e951456df0941c09176c981f8
parent 0ca70fff
Loading
Loading
Loading
Loading
+9 −1
Original line number Diff line number Diff line
@@ -142,7 +142,15 @@ public class NetworkStatsManager {
        setAugmentWithSubscriptionPlan(true);
    }

    /** @hide */
    /**
     * Set poll on open flag to indicate the poll is needed before service gets statistics
     * result. This is default enabled. However, for any non-privileged caller, the poll might
     * be omitted in case of rate limiting.
     *
     * @param pollOnOpen true if poll is needed.
     * @hide
     */
    // @SystemApi(client = MODULE_LIBRARIES)
    public void setPollOnOpen(boolean pollOnOpen) {
        if (pollOnOpen) {
            mFlags |= FLAG_POLL_ON_OPEN;
+84 −30
Original line number Diff line number Diff line
@@ -151,6 +151,8 @@ import android.app.IUidObserver;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.usage.NetworkStats;
import android.app.usage.NetworkStatsManager;
import android.app.usage.UsageStatsManagerInternal;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -181,7 +183,6 @@ import android.net.NetworkRequest;
import android.net.NetworkSpecifier;
import android.net.NetworkStack;
import android.net.NetworkStateSnapshot;
import android.net.NetworkStats;
import android.net.NetworkTemplate;
import android.net.TelephonyNetworkSpecifier;
import android.net.TrafficStats;
@@ -455,6 +456,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    private ConnectivityManager mConnManager;
    private PowerManagerInternal mPowerManagerInternal;
    private PowerWhitelistManager mPowerWhitelistManager;
    @NonNull
    private final Dependencies mDeps;

    /** Current cached value of the current Battery Saver mode's setting for restrict background. */
    @GuardedBy("mUidRulesFirstLock")
@@ -706,7 +709,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    public NetworkPolicyManagerService(Context context, IActivityManager activityManager,
            INetworkManagementService networkManagement) {
        this(context, activityManager, networkManagement, AppGlobals.getPackageManager(),
                getDefaultClock(), getDefaultSystemDir(), false);
                getDefaultClock(), getDefaultSystemDir(), false, new Dependencies(context));
    }

    private static @NonNull File getDefaultSystemDir() {
@@ -718,9 +721,59 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
                Clock.systemUTC());
    }

    static class Dependencies {
        final Context mContext;
        final NetworkStatsManager mNetworkStatsManager;
        Dependencies(Context context) {
            mContext = context;
            mNetworkStatsManager = mContext.getSystemService(NetworkStatsManager.class);
            // Query stats from NetworkStatsService will trigger a poll by default.
            // But since NPMS listens stats updated event, and will query stats
            // after the event. A polling -> updated -> query -> polling loop will be introduced
            // if polls on open. Hence, while NPMS manages it's poll requests explicitly, set
            // flag to false to prevent a polling loop.
            mNetworkStatsManager.setPollOnOpen(false);
        }

        long getNetworkTotalBytes(NetworkTemplate template, long start, long end) {
            Trace.traceBegin(TRACE_TAG_NETWORK, "getNetworkTotalBytes");
            try {
                final NetworkStats.Bucket ret = mNetworkStatsManager
                        .querySummaryForDevice(template, start, end);
                return ret.getRxBytes() + ret.getTxBytes();
            } catch (RuntimeException e) {
                Slog.w(TAG, "Failed to read network stats: " + e);
                return 0;
            } finally {
                Trace.traceEnd(TRACE_TAG_NETWORK);
            }
        }

        @NonNull
        List<NetworkStats.Bucket> getNetworkUidBytes(
                @NonNull NetworkTemplate template, long start, long end) {
            Trace.traceBegin(TRACE_TAG_NETWORK, "getNetworkUidBytes");
            final List<NetworkStats.Bucket> buckets = new ArrayList<>();
            try {
                final NetworkStats stats = mNetworkStatsManager.querySummary(template, start, end);
                while (stats.hasNextBucket()) {
                    final NetworkStats.Bucket bucket = new NetworkStats.Bucket();
                    stats.getNextBucket(bucket);
                    buckets.add(bucket);
                }
            } catch (RuntimeException e) {
                Slog.w(TAG, "Failed to read network stats: " + e);
            } finally {
                Trace.traceEnd(TRACE_TAG_NETWORK);
            }
            return buckets;
        }
    }

    @VisibleForTesting
    public NetworkPolicyManagerService(Context context, IActivityManager activityManager,
            INetworkManagementService networkManagement, IPackageManager pm, Clock clock,
            File systemDir, boolean suppressDefaultPolicy) {
            File systemDir, boolean suppressDefaultPolicy, Dependencies deps) {
        mContext = Objects.requireNonNull(context, "missing context");
        mActivityManager = Objects.requireNonNull(activityManager, "missing activityManager");
        mNetworkManager = Objects.requireNonNull(networkManagement, "missing networkManagement");
@@ -741,6 +794,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
        mUidEventHandler = new Handler(mUidEventThread.getLooper(), mUidEventHandlerCallback);

        mSuppressDefaultPolicy = suppressDefaultPolicy;
        mDeps = Objects.requireNonNull(deps, "missing Dependencies");

        mPolicyFile = new AtomicFile(new File(systemDir, "netpolicy.xml"), "net-policy");

@@ -1167,21 +1221,34 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    };

    /**
     * Receiver that watches for {@link INetworkStatsService} updates, which we
     * Receiver that watches for {@link NetworkStatsManager} updates, which we
     * use to check against {@link NetworkPolicy#warningBytes}.
     */
    final private BroadcastReceiver mStatsReceiver = new BroadcastReceiver() {
    private final NetworkStatsBroadcastReceiver mStatsReceiver =
            new NetworkStatsBroadcastReceiver();
    private class NetworkStatsBroadcastReceiver extends BroadcastReceiver {
        private boolean mIsAnyIntentReceived = false;
        @Override
        public void onReceive(Context context, Intent intent) {
            // on background handler thread, and verified
            // READ_NETWORK_USAGE_HISTORY permission above.

            mIsAnyIntentReceived = true;

            synchronized (mNetworkPoliciesSecondLock) {
                updateNetworkRulesNL();
                updateNetworkEnabledNL();
                updateNotificationsNL();
            }
        }

        /**
         * Return whether any {@code ACTION_NETWORK_STATS_UPDATED} intent is received.
         * Used to determine if NetworkStatsService is ready.
         */
        public boolean isAnyIntentReceived() {
            return mIsAnyIntentReceived;
        }
    };

    /**
@@ -1405,15 +1472,17 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
        long maxBytes = 0;
        int maxUid = 0;

        final NetworkStats stats = getNetworkUidBytes(template, start, end);
        NetworkStats.Entry entry = null;
        for (int i = 0; i < stats.size(); i++) {
            entry = stats.getValues(i, entry);
            final long bytes = entry.rxBytes + entry.txBytes;
        // Skip if not ready. NetworkStatsService will block public API calls until it is
        // ready. To prevent NPMS be blocked on that, skip and fail fast instead.
        if (!mStatsReceiver.isAnyIntentReceived()) return null;

        final List<NetworkStats.Bucket> stats = mDeps.getNetworkUidBytes(template, start, end);
        for (final NetworkStats.Bucket entry : stats) {
            final long bytes = entry.getRxBytes() + entry.getTxBytes();
            totalBytes += bytes;
            if (bytes > maxBytes) {
                maxBytes = bytes;
                maxUid = entry.uid;
                maxUid = entry.getUid();
            }
        }

@@ -5369,25 +5438,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {

    @Deprecated
    private long getTotalBytes(NetworkTemplate template, long start, long end) {
        return getNetworkTotalBytes(template, start, end);
    }

    private long getNetworkTotalBytes(NetworkTemplate template, long start, long end) {
        try {
            return mNetworkStats.getNetworkTotalBytes(template, start, end);
        } catch (RuntimeException e) {
            Slog.w(TAG, "Failed to read network stats: " + e);
            return 0;
        }
    }

    private NetworkStats getNetworkUidBytes(NetworkTemplate template, long start, long end) {
        try {
            return mNetworkStats.getNetworkUidBytes(template, start, end);
        } catch (RuntimeException e) {
            Slog.w(TAG, "Failed to read network stats: " + e);
            return new NetworkStats(SystemClock.elapsedRealtime(), 0);
        }
        // Skip if not ready. NetworkStatsService will block public API calls until it is
        // ready. To prevent NPMS be blocked on that, skip and fail fast instead.
        if (!mStatsReceiver.isAnyIntentReceived()) return 0;
        return mDeps.getNetworkTotalBytes(template, start, end);
    }

    private boolean isBandwidthControlEnabled() {
+71 −118

File changed.

Preview size limit exceeded, changes collapsed.