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

Commit b3d56ed3 authored by Junyu Lai's avatar Junyu Lai Committed by Android (Google) Code Review
Browse files

Merge changes If330e853,Ie2d229be,Ic6b2f10f

* changes:
  [SM05] Enable record mobile network stats by collapsed rat type
  [SM04] Support fetching data with NetworkTemplate with subType
  [SM02] Support record mobile network stats by collapsed rat type
parents de1ad310 2d4fa2c0
Loading
Loading
Loading
Loading
+8 −9
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Build;
import android.service.NetworkIdentityProto;
import android.telephony.Annotation.NetworkType;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;

@@ -42,12 +43,9 @@ public class NetworkIdentity implements Comparable<NetworkIdentity> {
    /**
     * When enabled, combine all {@link #mSubType} together under
     * {@link #SUBTYPE_COMBINED}.
     *
     * @deprecated we no longer offer to collect statistics on a per-subtype
     *             basis; this is always disabled.
     */
    @Deprecated
    public static final boolean COMBINE_SUBTYPE_ENABLED = true;
    // TODO: make this flag configurable through settings. See http://b/146415925
    public static final boolean COMBINE_SUBTYPE_ENABLED = false;

    public static final int SUBTYPE_COMBINED = -1;

@@ -187,13 +185,14 @@ public class NetworkIdentity implements Comparable<NetworkIdentity> {
    }

    /**
     * Build a {@link NetworkIdentity} from the given {@link NetworkState},
     * assuming that any mobile networks are using the current IMSI.
     * Build a {@link NetworkIdentity} from the given {@link NetworkState} and {@code subType},
     * assuming that any mobile networks are using the current IMSI. The subType if applicable,
     * should be set as one of the TelephonyManager.NETWORK_TYPE_* constants, or
     * {@link android.telephony.TelephonyManager#NETWORK_TYPE_UNKNOWN} if not.
     */
    public static NetworkIdentity buildNetworkIdentity(Context context, NetworkState state,
            boolean defaultNetwork) {
            boolean defaultNetwork, @NetworkType int subType) {
        final int type = state.networkInfo.getType();
        final int subType = state.networkInfo.getSubtype();

        String subscriberId = null;
        String networkId = null;
+92 −8
Original line number Diff line number Diff line
@@ -34,9 +34,13 @@ import static android.net.NetworkStats.ROAMING_NO;
import static android.net.NetworkStats.ROAMING_YES;
import static android.net.wifi.WifiInfo.sanitizeSsid;

import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Parcel;
import android.os.Parcelable;
import android.telephony.Annotation.NetworkType;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.BackupUtils;
import android.util.Log;

@@ -73,6 +77,14 @@ public class NetworkTemplate implements Parcelable {
    public static final int MATCH_BLUETOOTH = 8;
    public static final int MATCH_PROXY = 9;

    /**
     * Include all network types when filtering. This is meant to merge in with the
     * {@code TelephonyManager.NETWORK_TYPE_*} constants, and thus needs to stay in sync.
     *
     * @hide
     */
    public static final int NETWORK_TYPE_ALL = -1;

    private static boolean isKnownMatchRule(final int rule) {
        switch (rule) {
            case MATCH_MOBILE:
@@ -117,7 +129,22 @@ public class NetworkTemplate implements Parcelable {
    }

    /**
     * Template to match {@link ConnectivityManager#TYPE_MOBILE} networks,
     * Template to match cellular networks with the given IMSI and {@code ratType}.
     * Use {@link #NETWORK_TYPE_ALL} to include all network types when filtering.
     * See {@code TelephonyManager.NETWORK_TYPE_*}.
     */
    public static NetworkTemplate buildTemplateMobileWithRatType(@Nullable String subscriberId,
            @NetworkType int ratType) {
        if (TextUtils.isEmpty(subscriberId)) {
            return new NetworkTemplate(MATCH_MOBILE_WILDCARD, null, null, null,
                    METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType);
        }
        return new NetworkTemplate(MATCH_MOBILE, subscriberId, new String[]{subscriberId}, null,
                METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType);
    }

    /**
     * Template to match metered {@link ConnectivityManager#TYPE_MOBILE} networks,
     * regardless of IMSI.
     */
    @UnsupportedAppUsage
@@ -126,7 +153,7 @@ public class NetworkTemplate implements Parcelable {
    }

    /**
     * Template to match all {@link ConnectivityManager#TYPE_WIFI} networks,
     * Template to match all metered {@link ConnectivityManager#TYPE_WIFI} networks,
     * regardless of SSID.
     */
    @UnsupportedAppUsage
@@ -192,6 +219,7 @@ public class NetworkTemplate implements Parcelable {
    private final int mMetered;
    private final int mRoaming;
    private final int mDefaultNetwork;
    private final int mSubType;

    @UnsupportedAppUsage
    public NetworkTemplate(int matchRule, String subscriberId, String networkId) {
@@ -201,11 +229,11 @@ public class NetworkTemplate implements Parcelable {
    public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds,
            String networkId) {
        this(matchRule, subscriberId, matchSubscriberIds, networkId, METERED_ALL, ROAMING_ALL,
                DEFAULT_NETWORK_ALL);
                DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL);
    }

    public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds,
            String networkId, int metered, int roaming, int defaultNetwork) {
            String networkId, int metered, int roaming, int defaultNetwork, int subType) {
        mMatchRule = matchRule;
        mSubscriberId = subscriberId;
        mMatchSubscriberIds = matchSubscriberIds;
@@ -213,6 +241,7 @@ public class NetworkTemplate implements Parcelable {
        mMetered = metered;
        mRoaming = roaming;
        mDefaultNetwork = defaultNetwork;
        mSubType = subType;

        if (!isKnownMatchRule(matchRule)) {
            Log.e(TAG, "Unknown network template rule " + matchRule
@@ -228,6 +257,7 @@ public class NetworkTemplate implements Parcelable {
        mMetered = in.readInt();
        mRoaming = in.readInt();
        mDefaultNetwork = in.readInt();
        mSubType = in.readInt();
    }

    @Override
@@ -239,6 +269,7 @@ public class NetworkTemplate implements Parcelable {
        dest.writeInt(mMetered);
        dest.writeInt(mRoaming);
        dest.writeInt(mDefaultNetwork);
        dest.writeInt(mSubType);
    }

    @Override
@@ -271,13 +302,16 @@ public class NetworkTemplate implements Parcelable {
            builder.append(", defaultNetwork=").append(NetworkStats.defaultNetworkToString(
                    mDefaultNetwork));
        }
        if (mSubType != NETWORK_TYPE_ALL) {
            builder.append(", subType=").append(mSubType);
        }
        return builder.toString();
    }

    @Override
    public int hashCode() {
        return Objects.hash(mMatchRule, mSubscriberId, mNetworkId, mMetered, mRoaming,
                mDefaultNetwork);
                mDefaultNetwork, mSubType);
    }

    @Override
@@ -289,7 +323,8 @@ public class NetworkTemplate implements Parcelable {
                    && Objects.equals(mNetworkId, other.mNetworkId)
                    && mMetered == other.mMetered
                    && mRoaming == other.mRoaming
                    && mDefaultNetwork == other.mDefaultNetwork;
                    && mDefaultNetwork == other.mDefaultNetwork
                    && mSubType == other.mSubType;
        }
        return false;
    }
@@ -376,6 +411,11 @@ public class NetworkTemplate implements Parcelable {
            || (mDefaultNetwork == DEFAULT_NETWORK_NO && !ident.mDefaultNetwork);
    }

    private boolean matchesCollapsedRatType(NetworkIdentity ident) {
        return mSubType == NETWORK_TYPE_ALL
                || getCollapsedRatType(mSubType) == getCollapsedRatType(ident.mSubType);
    }

    public boolean matchesSubscriberId(String subscriberId) {
        return ArrayUtils.contains(mMatchSubscriberIds, subscriberId);
    }
@@ -388,9 +428,52 @@ public class NetworkTemplate implements Parcelable {
            // TODO: consider matching against WiMAX subscriber identity
            return true;
        } else {
            // Only metered mobile network would be matched regardless of metered filter.
            // This is used to exclude non-metered APNs, e.g. IMS. See ag/908650.
            // TODO: Respect metered filter and remove mMetered condition.
            return (sForceAllNetworkTypes || (ident.mType == TYPE_MOBILE && ident.mMetered))
                    && !ArrayUtils.isEmpty(mMatchSubscriberIds)
                    && ArrayUtils.contains(mMatchSubscriberIds, ident.mSubscriberId);
                    && ArrayUtils.contains(mMatchSubscriberIds, ident.mSubscriberId)
                    && matchesCollapsedRatType(ident);
        }
    }

    /**
     * Get a Radio Access Technology(RAT) type that is representative of a group of RAT types.
     * The mapping is corresponding to {@code TelephonyManager#NETWORK_CLASS_BIT_MASK_*}.
     *
     * @param ratType An integer defined in {@code TelephonyManager#NETWORK_TYPE_*}.
     */
    // TODO: 1. Consider move this to TelephonyManager if used by other modules.
    //       2. Consider make this configurable.
    //       3. Use TelephonyManager APIs when available.
    public static int getCollapsedRatType(int ratType) {
        switch (ratType) {
            case TelephonyManager.NETWORK_TYPE_GPRS:
            case TelephonyManager.NETWORK_TYPE_GSM:
            case TelephonyManager.NETWORK_TYPE_EDGE:
            case TelephonyManager.NETWORK_TYPE_IDEN:
            case TelephonyManager.NETWORK_TYPE_CDMA:
            case TelephonyManager.NETWORK_TYPE_1xRTT:
                return TelephonyManager.NETWORK_TYPE_GSM;
            case TelephonyManager.NETWORK_TYPE_EVDO_0:
            case TelephonyManager.NETWORK_TYPE_EVDO_A:
            case TelephonyManager.NETWORK_TYPE_EVDO_B:
            case TelephonyManager.NETWORK_TYPE_EHRPD:
            case TelephonyManager.NETWORK_TYPE_UMTS:
            case TelephonyManager.NETWORK_TYPE_HSDPA:
            case TelephonyManager.NETWORK_TYPE_HSUPA:
            case TelephonyManager.NETWORK_TYPE_HSPA:
            case TelephonyManager.NETWORK_TYPE_HSPAP:
            case TelephonyManager.NETWORK_TYPE_TD_SCDMA:
                return TelephonyManager.NETWORK_TYPE_UMTS;
            case TelephonyManager.NETWORK_TYPE_LTE:
            case TelephonyManager.NETWORK_TYPE_IWLAN:
                return TelephonyManager.NETWORK_TYPE_LTE;
            case TelephonyManager.NETWORK_TYPE_NR:
                return TelephonyManager.NETWORK_TYPE_NR;
            default:
                return TelephonyManager.NETWORK_TYPE_UNKNOWN;
        }
    }

@@ -421,7 +504,8 @@ public class NetworkTemplate implements Parcelable {
        if (ident.mType == TYPE_WIMAX) {
            return true;
        } else {
            return sForceAllNetworkTypes || (ident.mType == TYPE_MOBILE && ident.mMetered);
            return (sForceAllNetworkTypes || (ident.mType == TYPE_MOBILE && ident.mMetered))
                    && matchesCollapsedRatType(ident);
        }
    }

+2 −1
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkPolicy.LIMIT_DISABLED;
import static android.net.NetworkPolicy.WARNING_DISABLED;
import static android.net.NetworkTemplate.NETWORK_TYPE_ALL;
import static android.provider.Settings.Global.NETWORK_DEFAULT_DAILY_MULTIPATH_QUOTA_BYTES;
import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;

@@ -220,7 +221,7 @@ public class MultipathPolicyTracker {
            mNetworkTemplate = new NetworkTemplate(
                    NetworkTemplate.MATCH_MOBILE, subscriberId, new String[] { subscriberId },
                    null, NetworkStats.METERED_ALL, NetworkStats.ROAMING_ALL,
                    NetworkStats.DEFAULT_NETWORK_NO);
                    NetworkStats.DEFAULT_NETWORK_NO, NETWORK_TYPE_ALL);
            mUsageCallback = new UsageCallback() {
                @Override
                public void onThresholdReached(int networkType, String subscriberId) {
+4 −1
Original line number Diff line number Diff line
@@ -1868,8 +1868,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
                mNetIdToSubId.put(state.network.netId, parseSubId(state));
            }
            if (state.networkInfo != null && state.networkInfo.isConnected()) {
                // Policies matched by NPMS only match by subscriber ID or by ssid. Thus subtype
                // in the object created here is never used and its value doesn't matter, so use
                // NETWORK_TYPE_UNKNOWN.
                final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, state,
                        true);
                        true, TelephonyManager.NETWORK_TYPE_UNKNOWN /* subType */);
                identified.put(state, ident);
            }
        }
+87 −2
Original line number Diff line number Diff line
@@ -27,6 +27,8 @@ import static android.content.Intent.EXTRA_UID;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED;
import static android.net.ConnectivityManager.isNetworkTypeMobile;
import static android.net.NetworkIdentity.COMBINE_SUBTYPE_ENABLED;
import static android.net.NetworkIdentity.SUBTYPE_COMBINED;
import static android.net.NetworkStack.checkNetworkStackPermission;
import static android.net.NetworkStats.DEFAULT_NETWORK_ALL;
import static android.net.NetworkStats.IFACE_ALL;
@@ -45,6 +47,7 @@ import static android.net.NetworkStats.UID_ALL;
import static android.net.NetworkStatsHistory.FIELD_ALL;
import static android.net.NetworkTemplate.buildTemplateMobileWildcard;
import static android.net.NetworkTemplate.buildTemplateWifiWildcard;
import static android.net.NetworkTemplate.getCollapsedRatType;
import static android.net.TrafficStats.KB_IN_BYTES;
import static android.net.TrafficStats.MB_IN_BYTES;
import static android.os.Trace.TRACE_TAG_NETWORK;
@@ -64,6 +67,9 @@ import static android.provider.Settings.Global.NETSTATS_UID_TAG_BUCKET_DURATION;
import static android.provider.Settings.Global.NETSTATS_UID_TAG_DELETE_AGE;
import static android.provider.Settings.Global.NETSTATS_UID_TAG_PERSIST_BYTES;
import static android.provider.Settings.Global.NETSTATS_UID_TAG_ROTATE_AGE;
import static android.telephony.PhoneStateListener.LISTEN_NONE;
import static android.telephony.PhoneStateListener.LISTEN_SERVICE_STATE;
import static android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN;
import static android.text.format.DateUtils.DAY_IN_MILLIS;
import static android.text.format.DateUtils.HOUR_IN_MILLIS;
import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
@@ -109,6 +115,7 @@ import android.os.Binder;
import android.os.DropBoxManager;
import android.os.Environment;
import android.os.Handler;
import android.os.HandlerExecutor;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.INetworkManagementService;
@@ -125,6 +132,8 @@ import android.provider.Settings;
import android.provider.Settings.Global;
import android.service.NetworkInterfaceProto;
import android.service.NetworkStatsServiceDumpProto;
import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
import android.telephony.SubscriptionPlan;
import android.telephony.TelephonyManager;
import android.text.format.DateUtils;
@@ -157,6 +166,7 @@ import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.Executor;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

@@ -173,6 +183,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
    private static final int MSG_PERFORM_POLL = 1;
    // Perform polling, persist network, and register the global alert again.
    private static final int MSG_PERFORM_POLL_REGISTER_ALERT = 2;
    private static final int MSG_UPDATE_IFACES = 3;

    /** Flags to control detail level of poll event. */
    private static final int FLAG_PERSIST_NETWORK = 0x1;
@@ -280,6 +291,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
    @GuardedBy("mStatsLock")
    private Network[] mDefaultNetworks = new Network[0];

    /** Last states of all networks sent from ConnectivityService. */
    @GuardedBy("mStatsLock")
    @Nullable
    private NetworkState[] mLastNetworkStates = null;

    private final DropBoxNonMonotonicObserver mNonMonotonicObserver =
            new DropBoxNonMonotonicObserver();

@@ -355,6 +371,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
                    performPoll(FLAG_PERSIST_ALL);
                    break;
                }
                case MSG_UPDATE_IFACES: {
                    // If no cached states, ignore.
                    if (mLastNetworkStates == null) break;
                    updateIfaces(mDefaultNetworks, mLastNetworkStates, mActiveIface);
                    break;
                }
                case MSG_PERFORM_POLL_REGISTER_ALERT: {
                    performPoll(FLAG_PERSIST_NETWORK);
                    registerGlobalAlert();
@@ -407,6 +429,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
        final HandlerThread handlerThread = mDeps.makeHandlerThread();
        handlerThread.start();
        mHandler = new NetworkStatsHandler(handlerThread.getLooper());
        mPhoneListener = new NetworkTypeListener(new HandlerExecutor(mHandler));
    }

    /**
@@ -486,6 +509,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
        mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME, currentRealtime,
                mSettings.getPollInterval(), pollIntent);

        // TODO: listen to changes from all subscriptions.
        // watch for networkType changes
        if (!COMBINE_SUBTYPE_ENABLED) {
            mTeleManager.listen(mPhoneListener, LISTEN_SERVICE_STATE);
        }

        registerGlobalAlert();
    }

@@ -506,6 +535,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
        mContext.unregisterReceiver(mUserReceiver);
        mContext.unregisterReceiver(mShutdownReceiver);

        if (!COMBINE_SUBTYPE_ENABLED) {
            mTeleManager.listen(mPhoneListener, LISTEN_NONE);
        }

        final long currentTime = mClock.millis();

        // persist any pending stats
@@ -1156,6 +1189,38 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
        }
    };

    /**
     * Receiver that watches for {@link TelephonyManager} changes, such as
     * transitioning between Radio Access Technology(RAT) types.
     */
    @NonNull
    private final NetworkTypeListener mPhoneListener;

    class NetworkTypeListener extends PhoneStateListener {
        private volatile int mLastCollapsedRatType = NETWORK_TYPE_UNKNOWN;

        NetworkTypeListener(@NonNull Executor executor) {
            super(executor);
        }

        @Override
        public void onServiceStateChanged(@NonNull ServiceState ss) {
            final int networkType = ss.getDataNetworkType();
            final int collapsedRatType = getCollapsedRatType(networkType);
            if (collapsedRatType == mLastCollapsedRatType) return;

            if (LOGD) {
                Log.d(TAG, "subtype changed for mobile: "
                        + mLastCollapsedRatType + " -> " + collapsedRatType);
            }
            // Protect service from frequently updating. Remove pending messages if any.
            mHandler.removeMessages(MSG_UPDATE_IFACES);
            mLastCollapsedRatType = collapsedRatType;
            mHandler.sendMessageDelayed(
                    mHandler.obtainMessage(MSG_UPDATE_IFACES), mSettings.getPollDelay());
        }
    }

    private void updateIfaces(
            Network[] defaultNetworks,
            NetworkState[] networkStates,
@@ -1177,7 +1242,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
     * they are combined under a single {@link NetworkIdentitySet}.
     */
    @GuardedBy("mStatsLock")
    private void updateIfacesLocked(Network[] defaultNetworks, NetworkState[] states) {
    private void updateIfacesLocked(@Nullable Network[] defaultNetworks,
            @NonNull NetworkState[] states) {
        if (!mSystemReady) return;
        if (LOGV) Slog.v(TAG, "updateIfacesLocked()");

@@ -1197,13 +1263,16 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
            mDefaultNetworks = defaultNetworks;
        }

        mLastNetworkStates = states;

        final ArraySet<String> mobileIfaces = new ArraySet<>();
        for (NetworkState state : states) {
            if (state.networkInfo.isConnected()) {
                final boolean isMobile = isNetworkTypeMobile(state.networkInfo.getType());
                final boolean isDefault = ArrayUtils.contains(mDefaultNetworks, state.network);
                final int subType = getSubTypeForState(state);
                final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, state,
                        isDefault);
                        isDefault, subType);

                // Traffic occurring on the base interface is always counted for
                // both total usage and UID details.
@@ -1264,6 +1333,22 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
        mMobileIfaces = mobileIfaces.toArray(new String[mobileIfaces.size()]);
    }

    /**
     * If combine subtype is not enabled. For networks with {@code TRANSPORT_CELLULAR}, get
     * subType that obtained through {@link PhoneStateListener}. Otherwise, return 0 given that
     * other networks with different transport types do not actually fill this value.
     */
    private int getSubTypeForState(@NonNull NetworkState state) {
        if (COMBINE_SUBTYPE_ENABLED) return SUBTYPE_COMBINED;

        if (!state.networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
            return 0;
        }

        // TODO: return different subType for different subscriptions.
        return mPhoneListener.mLastCollapsedRatType;
    }

    private static <K> NetworkIdentitySet findOrCreateNetworkIdentitySet(
            ArrayMap<K, NetworkIdentitySet> map, K key) {
        NetworkIdentitySet ident = map.get(key);
Loading