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

Commit 23868e9c authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge changes I325b13d5,I89719fe7

* changes:
  Add tether offload traffic to interface stats as well.
  Tell the system when tethering offload hits a limit.
parents cb3c24e3 f1912ca4
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -30,7 +30,10 @@ import android.net.NetworkStats;
 */
interface ITetheringStatsProvider {
    // Returns cumulative statistics for all tethering sessions since boot, on all upstreams.
    NetworkStats getTetherStats();
    // @code {how} is one of the NetworkStats.STATS_PER_* constants. If {@code how} is
    // {@code STATS_PER_IFACE}, the provider should not include any traffic that is already
    // counted by kernel interface counters.
    NetworkStats getTetherStats(int how);

    // Sets the interface quota for the specified upstream interface. This is defined as the number
    // of bytes, starting from zero and counting from now, after which data should stop being
+5 −0
Original line number Diff line number Diff line
@@ -82,6 +82,11 @@ public class NetworkStats implements Parcelable {
    /** {@link #roaming} value where roaming data is accounted. */
    public static final int ROAMING_YES = 1;

    /** Denotes a request for stats at the interface level. */
    public static final int STATS_PER_IFACE = 0;
    /** Denotes a request for stats at the interface and UID level. */
    public static final int STATS_PER_UID = 1;

    // TODO: move fields to "mVariable" notation

    /**
+16 −1
Original line number Diff line number Diff line
@@ -219,6 +219,21 @@ interface INetworkManagementService
     */
    void unregisterTetheringStatsProvider(ITetheringStatsProvider provider);

    /**
     * Reports that a tethering provider has reached a data limit.
     *
     * Currently triggers a global alert, which causes NetworkStatsService to poll counters and
     * re-evaluate data usage.
     *
     * This does not take an interface name because:
     * 1. The tethering offload stats provider cannot reliably determine the interface on which the
     *    limit was reached, because the HAL does not provide it.
     * 2. Firing an interface-specific alert instead of a global alert isn't really useful since in
     *    all cases of interest, the system responds to both in the same way - it polls stats, and
     *    then notifies NetworkPolicyManagerService of the fact.
     */
    void tetherLimitReached(ITetheringStatsProvider provider);

    /**
     ** PPPD
     **/
@@ -266,7 +281,7 @@ interface INetworkManagementService
    /**
     * Return summary of network statistics all tethering interfaces.
     */
    NetworkStats getNetworkStatsTethering();
    NetworkStats getNetworkStatsTethering(int how);

    /**
     * Set quota for an interface.
+22 −3
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT;
import static android.net.NetworkPolicyManager.FIREWALL_TYPE_BLACKLIST;
import static android.net.NetworkPolicyManager.FIREWALL_TYPE_WHITELIST;
import static android.net.NetworkStats.SET_DEFAULT;
import static android.net.NetworkStats.STATS_PER_UID;
import static android.net.NetworkStats.TAG_ALL;
import static android.net.NetworkStats.TAG_NONE;
import static android.net.NetworkStats.UID_ALL;
@@ -529,6 +530,18 @@ public class NetworkManagementService extends INetworkManagementService.Stub
        }
    }

    @Override
    public void tetherLimitReached(ITetheringStatsProvider provider) {
        mContext.enforceCallingOrSelfPermission(NETWORK_STACK, TAG);
        synchronized(mTetheringStatsProviders) {
            if (!mTetheringStatsProviders.containsKey(provider)) {
                return;
            }
            // No current code examines the interface parameter in a global alert. Just pass null.
            notifyLimitReached(LIMIT_GLOBAL_ALERT, null);
        }
    }

    // Sync the state of the given chain with the native daemon.
    private void syncFirewallChainLocked(int chain, SparseIntArray uidFirewallRules, String name) {
        int size = uidFirewallRules.size();
@@ -1810,7 +1823,13 @@ public class NetworkManagementService extends INetworkManagementService.Stub

    private class NetdTetheringStatsProvider extends ITetheringStatsProvider.Stub {
        @Override
        public NetworkStats getTetherStats() {
        public NetworkStats getTetherStats(int how) {
            // We only need to return per-UID stats. Per-device stats are already counted by
            // interface counters.
            if (how != STATS_PER_UID) {
                return new NetworkStats(SystemClock.elapsedRealtime(), 0);
            }

            final NativeDaemonEvent[] events;
            try {
                events = mConnector.executeForList("bandwidth", "gettetherstats");
@@ -1853,14 +1872,14 @@ public class NetworkManagementService extends INetworkManagementService.Stub
    }

    @Override
    public NetworkStats getNetworkStatsTethering() {
    public NetworkStats getNetworkStatsTethering(int how) {
        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);

        final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 1);
        synchronized (mTetheringStatsProviders) {
            for (ITetheringStatsProvider provider: mTetheringStatsProviders.keySet()) {
                try {
                    stats.combineAllValues(provider.getTetherStats());
                    stats.combineAllValues(provider.getTetherStats(how));
                } catch (RemoteException e) {
                    Log.e(TAG, "Problem reading tethering stats from " +
                            mTetheringStatsProviders.get(provider) + ": " + e);
+31 −5
Original line number Diff line number Diff line
@@ -17,7 +17,9 @@
package com.android.server.connectivity.tethering;

import static android.net.NetworkStats.SET_DEFAULT;
import static android.net.NetworkStats.STATS_PER_UID;
import static android.net.NetworkStats.TAG_NONE;
import static android.net.NetworkStats.UID_ALL;
import static android.net.TrafficStats.UID_TETHERING;
import static android.provider.Settings.Global.TETHER_OFFLOAD_DISABLED;

@@ -60,6 +62,8 @@ public class OffloadController {
    private final Handler mHandler;
    private final OffloadHardwareInterface mHwInterface;
    private final ContentResolver mContentResolver;
    private final INetworkManagementService mNms;
    private final ITetheringStatsProvider mStatsProvider;
    private final SharedLog mLog;
    private boolean mConfigInitialized;
    private boolean mControlInitialized;
@@ -89,13 +93,14 @@ public class OffloadController {
        mHandler = h;
        mHwInterface = hwi;
        mContentResolver = contentResolver;
        mNms = nms;
        mStatsProvider = new OffloadTetheringStatsProvider();
        mLog = log.forSubComponent(TAG);
        mExemptPrefixes = new HashSet<>();
        mLastLocalPrefixStrs = new HashSet<>();

        try {
            nms.registerTetheringStatsProvider(
                    new OffloadTetheringStatsProvider(), getClass().getSimpleName());
            mNms.registerTetheringStatsProvider(mStatsProvider, getClass().getSimpleName());
        } catch (RemoteException e) {
            mLog.e("Cannot register offload stats provider: " + e);
        }
@@ -150,7 +155,26 @@ public class OffloadController {
                    @Override
                    public void onStoppedLimitReached() {
                        mLog.log("onStoppedLimitReached");
                        // Poll for statistics and notify NetworkStats

                        // We cannot reliably determine on which interface the limit was reached,
                        // because the HAL interface does not specify it. We cannot just use the
                        // current upstream, because that might have changed since the time that
                        // the HAL queued the callback.
                        // TODO: rev the HAL so that it provides an interface name.

                        // Fetch current stats, so that when our notification reaches
                        // NetworkStatsService and triggers a poll, we will respond with
                        // current data (which will be above the limit that was reached).
                        // Note that if we just changed upstream, this is unnecessary but harmless.
                        // The stats for the previous upstream were already updated on this thread
                        // just after the upstream was changed, so they are also up-to-date.
                        updateStatsForCurrentUpstream();

                        try {
                            mNms.tetherLimitReached(mStatsProvider);
                        } catch (RemoteException e) {
                            mLog.e("Cannot report data limit reached: " + e);
                        }
                    }

                    @Override
@@ -180,16 +204,18 @@ public class OffloadController {

    private class OffloadTetheringStatsProvider extends ITetheringStatsProvider.Stub {
        @Override
        public NetworkStats getTetherStats() {
        public NetworkStats getTetherStats(int how) {
            NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 0);

            // We can't just post to mHandler because we are mostly (but not always) called by
            // NetworkStatsService#performPollLocked, which is (currently) on the same thread as us.
            mHandler.runWithScissors(() -> {
                // We have to report both per-interface and per-UID stats, because offloaded traffic
                // is not seen by kernel interface counters.
                NetworkStats.Entry entry = new NetworkStats.Entry();
                entry.set = SET_DEFAULT;
                entry.tag = TAG_NONE;
                entry.uid = UID_TETHERING;
                entry.uid = (how == STATS_PER_UID) ? UID_TETHERING : UID_ALL;

                updateStatsForCurrentUpstream();

Loading