Move TrafficStats iface counters to xt_qtaguid.

Use xt_qtaguid iface_stat_all counters, which are monotonic during
a single boot.

Track all ifaces associated with mobile networks since boot, and
move TrafficStats to using these ifaces.  This will include usage of
networks omitted from config_data_usage_network_types, specifically
on devices that recycle network interfaces across APNs.

Split wildcard template matching, and move NetworkStatsService to
use mobile wildcard when logging stats.

Bug: 5324515
Change-Id: I2211c374c05d1b598cc647f2f873630538955ffe
diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl
index b4f6367..08d4c6c 100644
--- a/core/java/android/net/INetworkStatsService.aidl
+++ b/core/java/android/net/INetworkStatsService.aidl
@@ -32,6 +32,9 @@
 
     /** Return data layer snapshot of UID network usage. */
     NetworkStats getDataLayerSnapshotForUid(int uid);
+    /** Return set of any ifaces associated with mobile networks since boot. */
+    String[] getMobileIfaces();
+
     /** Increment data layer count of operations performed for UID and tag. */
     void incrementOperationCount(int uid, int tag, int operationCount);
 
diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java
index 50432a1..39a4d7b 100644
--- a/core/java/android/net/NetworkTemplate.java
+++ b/core/java/android/net/NetworkTemplate.java
@@ -48,6 +48,8 @@
     public static final int MATCH_MOBILE_4G = 3;
     public static final int MATCH_WIFI = 4;
     public static final int MATCH_ETHERNET = 5;
+    public static final int MATCH_MOBILE_WILDCARD = 6;
+    public static final int MATCH_WIFI_WILDCARD = 7;
 
     /**
      * Set of {@link NetworkInfo#getType()} that reflect data usage.
@@ -86,11 +88,19 @@
     }
 
     /**
+     * Template to match {@link ConnectivityManager#TYPE_MOBILE} networks,
+     * regardless of IMSI.
+     */
+    public static NetworkTemplate buildTemplateMobileWildcard() {
+        return new NetworkTemplate(MATCH_MOBILE_WILDCARD, null, null);
+    }
+
+    /**
      * Template to match all {@link ConnectivityManager#TYPE_WIFI} networks,
      * regardless of SSID.
      */
     public static NetworkTemplate buildTemplateWifiWildcard() {
-        return new NetworkTemplate(MATCH_WIFI, null, null);
+        return new NetworkTemplate(MATCH_WIFI_WILDCARD, null, null);
     }
 
     @Deprecated
@@ -198,6 +208,10 @@
                 return matchesWifi(ident);
             case MATCH_ETHERNET:
                 return matchesEthernet(ident);
+            case MATCH_MOBILE_WILDCARD:
+                return matchesMobileWildcard(ident);
+            case MATCH_WIFI_WILDCARD:
+                return matchesWifiWildcard(ident);
             default:
                 throw new IllegalArgumentException("unknown network template");
         }
@@ -257,13 +271,7 @@
     private boolean matchesWifi(NetworkIdentity ident) {
         switch (ident.mType) {
             case TYPE_WIFI:
-                if (mNetworkId == null) {
-                    return true;
-                } else {
-                    return Objects.equal(mNetworkId, ident.mNetworkId);
-                }
-            case TYPE_WIFI_P2P:
-                return mNetworkId == null;
+                return Objects.equal(mNetworkId, ident.mNetworkId);
             default:
                 return false;
         }
@@ -279,6 +287,24 @@
         return false;
     }
 
+    private boolean matchesMobileWildcard(NetworkIdentity ident) {
+        if (ident.mType == TYPE_WIMAX) {
+            return true;
+        } else {
+            return contains(DATA_USAGE_NETWORK_TYPES, ident.mType);
+        }
+    }
+
+    private boolean matchesWifiWildcard(NetworkIdentity ident) {
+        switch (ident.mType) {
+            case TYPE_WIFI:
+            case TYPE_WIFI_P2P:
+                return true;
+            default:
+                return false;
+        }
+    }
+
     private static String getMatchRuleName(int matchRule) {
         switch (matchRule) {
             case MATCH_MOBILE_3G_LOWER:
@@ -291,6 +317,10 @@
                 return "WIFI";
             case MATCH_ETHERNET:
                 return "ETHERNET";
+            case MATCH_MOBILE_WILDCARD:
+                return "MOBILE_WILDCARD";
+            case MATCH_WIFI_WILDCARD:
+                return "WIFI_WILDCARD";
             default:
                 return "UNKNOWN";
         }
diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java
index ee3e165..e437d2e 100644
--- a/core/java/android/net/TrafficStats.java
+++ b/core/java/android/net/TrafficStats.java
@@ -88,6 +88,16 @@
      */
     public static final int TAG_SYSTEM_BACKUP = 0xFFFFFF03;
 
+    private static INetworkStatsService sStatsService;
+
+    private synchronized static INetworkStatsService getStatsService() {
+        if (sStatsService == null) {
+            sStatsService = INetworkStatsService.Stub.asInterface(
+                    ServiceManager.getService(Context.NETWORK_STATS_SERVICE));
+        }
+        return sStatsService;
+    }
+
     /**
      * Snapshot of {@link NetworkStats} when the currently active profiling
      * session started, or {@code null} if no session active.
@@ -228,11 +238,9 @@
      * @param operationCount Number of operations to increment count by.
      */
     public static void incrementOperationCount(int tag, int operationCount) {
-        final INetworkStatsService statsService = INetworkStatsService.Stub.asInterface(
-                ServiceManager.getService(Context.NETWORK_STATS_SERVICE));
         final int uid = android.os.Process.myUid();
         try {
-            statsService.incrementOperationCount(uid, tag, operationCount);
+            getStatsService().incrementOperationCount(uid, tag, operationCount);
         } catch (RemoteException e) {
             throw new RuntimeException(e);
         }
@@ -257,7 +265,13 @@
      * @return number of packets.  If the statistics are not supported by this device,
      * {@link #UNSUPPORTED} will be returned.
      */
-    public static native long getMobileTxPackets();
+    public static long getMobileTxPackets() {
+        long total = 0;
+        for (String iface : getMobileIfaces()) {
+            total += getTxPackets(iface);
+        }
+        return total;
+    }
 
     /**
      * Get the total number of packets received through the mobile interface.
@@ -265,7 +279,13 @@
      * @return number of packets.  If the statistics are not supported by this device,
      * {@link #UNSUPPORTED} will be returned.
      */
-    public static native long getMobileRxPackets();
+    public static long getMobileRxPackets() {
+        long total = 0;
+        for (String iface : getMobileIfaces()) {
+            total += getRxPackets(iface);
+        }
+        return total;
+    }
 
     /**
      * Get the total number of bytes transmitted through the mobile interface.
@@ -273,7 +293,13 @@
      * @return number of bytes.  If the statistics are not supported by this device,
      * {@link #UNSUPPORTED} will be returned.
      */
-      public static native long getMobileTxBytes();
+    public static long getMobileTxBytes() {
+        long total = 0;
+        for (String iface : getMobileIfaces()) {
+            total += getTxBytes(iface);
+        }
+        return total;
+    }
 
     /**
      * Get the total number of bytes received through the mobile interface.
@@ -281,7 +307,13 @@
      * @return number of bytes.  If the statistics are not supported by this device,
      * {@link #UNSUPPORTED} will be returned.
      */
-    public static native long getMobileRxBytes();
+    public static long getMobileRxBytes() {
+        long total = 0;
+        for (String iface : getMobileIfaces()) {
+            total += getRxBytes(iface);
+        }
+        return total;
+    }
 
     /**
      * Get the total number of packets transmitted through the specified interface.
@@ -290,7 +322,9 @@
      * {@link #UNSUPPORTED} will be returned.
      * @hide
      */
-    public static native long getTxPackets(String iface);
+    public static long getTxPackets(String iface) {
+        return nativeGetIfaceStat(iface, TYPE_TX_PACKETS);
+    }
 
     /**
      * Get the total number of packets received through the specified interface.
@@ -299,7 +333,9 @@
      * {@link #UNSUPPORTED} will be returned.
      * @hide
      */
-    public static native long getRxPackets(String iface);
+    public static long getRxPackets(String iface) {
+        return nativeGetIfaceStat(iface, TYPE_RX_PACKETS);
+    }
 
     /**
      * Get the total number of bytes transmitted through the specified interface.
@@ -308,7 +344,9 @@
      * {@link #UNSUPPORTED} will be returned.
      * @hide
      */
-    public static native long getTxBytes(String iface);
+    public static long getTxBytes(String iface) {
+        return nativeGetIfaceStat(iface, TYPE_TX_BYTES);
+    }
 
     /**
      * Get the total number of bytes received through the specified interface.
@@ -317,8 +355,9 @@
      * {@link #UNSUPPORTED} will be returned.
      * @hide
      */
-    public static native long getRxBytes(String iface);
-
+    public static long getRxBytes(String iface) {
+        return nativeGetIfaceStat(iface, TYPE_RX_BYTES);
+    }
 
     /**
      * Get the total number of packets sent through all network interfaces.
@@ -326,7 +365,9 @@
      * @return the number of packets.  If the statistics are not supported by this device,
      * {@link #UNSUPPORTED} will be returned.
      */
-    public static native long getTotalTxPackets();
+    public static long getTotalTxPackets() {
+        return nativeGetTotalStat(TYPE_TX_PACKETS);
+    }
 
     /**
      * Get the total number of packets received through all network interfaces.
@@ -334,7 +375,9 @@
      * @return number of packets.  If the statistics are not supported by this device,
      * {@link #UNSUPPORTED} will be returned.
      */
-    public static native long getTotalRxPackets();
+    public static long getTotalRxPackets() {
+        return nativeGetTotalStat(TYPE_RX_PACKETS);
+    }
 
     /**
      * Get the total number of bytes sent through all network interfaces.
@@ -342,7 +385,9 @@
      * @return number of bytes.  If the statistics are not supported by this device,
      * {@link #UNSUPPORTED} will be returned.
      */
-    public static native long getTotalTxBytes();
+    public static long getTotalTxBytes() {
+        return nativeGetTotalStat(TYPE_TX_BYTES);
+    }
 
     /**
      * Get the total number of bytes received through all network interfaces.
@@ -350,7 +395,9 @@
      * @return number of bytes.  If the statistics are not supported by this device,
      * {@link #UNSUPPORTED} will be returned.
      */
-    public static native long getTotalRxBytes();
+    public static long getTotalRxBytes() {
+        return nativeGetTotalStat(TYPE_RX_BYTES);
+    }
 
     /**
      * Get the number of bytes sent through the network for this UID.
@@ -483,7 +530,6 @@
      */
     public static native long getUidTcpRxSegments(int uid);
 
-
     /**
      * Get the number of UDP packets sent for this UID.
      * Includes DNS requests.
@@ -515,13 +561,33 @@
      * special permission.
      */
     private static NetworkStats getDataLayerSnapshotForUid(Context context) {
-        final INetworkStatsService statsService = INetworkStatsService.Stub.asInterface(
-                ServiceManager.getService(Context.NETWORK_STATS_SERVICE));
         final int uid = android.os.Process.myUid();
         try {
-            return statsService.getDataLayerSnapshotForUid(uid);
+            return getStatsService().getDataLayerSnapshotForUid(uid);
         } catch (RemoteException e) {
             throw new RuntimeException(e);
         }
     }
+
+    /**
+     * Return set of any ifaces associated with mobile networks since boot.
+     * Interfaces are never removed from this list, so counters should always be
+     * monotonic.
+     */
+    private static String[] getMobileIfaces() {
+        try {
+            return getStatsService().getMobileIfaces();
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    // NOTE: keep these in sync with android_net_TrafficStats.cpp
+    private static final int TYPE_RX_BYTES = 0;
+    private static final int TYPE_RX_PACKETS = 1;
+    private static final int TYPE_TX_BYTES = 2;
+    private static final int TYPE_TX_PACKETS = 3;
+
+    private static native long nativeGetTotalStat(int type);
+    private static native long nativeGetIfaceStat(String iface, int type);
 }
diff --git a/core/jni/android_net_TrafficStats.cpp b/core/jni/android_net_TrafficStats.cpp
index 0ab659b..325fe26 100644
--- a/core/jni/android_net_TrafficStats.cpp
+++ b/core/jni/android_net_TrafficStats.cpp
@@ -31,6 +31,9 @@
 
 namespace android {
 
+static const uint64_t VALUE_UNKNOWN = -1;
+static const char* IFACE_STAT_ALL = "/proc/net/xt_qtaguid/iface_stat_all";
+
 enum Tx_Rx {
     TX,
     RX
@@ -42,6 +45,21 @@
     TCP_AND_UDP
 };
 
+// NOTE: keep these in sync with TrafficStats.java
+enum IfaceStatType {
+    RX_BYTES = 0,
+    RX_PACKETS = 1,
+    TX_BYTES = 2,
+    TX_PACKETS = 3
+};
+
+struct IfaceStat {
+    uint64_t rxBytes;
+    uint64_t rxPackets;
+    uint64_t txBytes;
+    uint64_t txPackets;
+};
+
 // Returns an ASCII decimal number read from the specified file, -1 on error.
 static jlong readNumber(char const* filename) {
     char buf[80];
@@ -63,130 +81,82 @@
     return atoll(buf);
 }
 
-static const char* mobile_iface_list[] = {
-    "rmnet0",
-    "rmnet1",
-    "rmnet2",
-    "rmnet3",
-    "cdma_rmnet4",
-    "ppp0",
-    0
-};
+static int parseIfaceStat(const char* iface, struct IfaceStat* stat) {
+    FILE *fp = fopen(IFACE_STAT_ALL, "r");
+    if (!fp) {
+        return errno;
+    }
 
-static jlong getAll(const char** iface_list, const char* what) {
+    char buffer[256];
+    char cur_iface[32];
+    int active;
+    uint64_t rxBytes, rxPackets, txBytes, txPackets, devRxBytes, devRxPackets, devTxBytes,
+            devTxPackets;
 
-    char filename[80];
-    int idx = 0;
-    bool supported = false;
-    jlong total = 0;
-    while (iface_list[idx] != 0) {
-
-        snprintf(filename, sizeof(filename), "/sys/class/net/%s/statistics/%s",
-                 iface_list[idx], what);
-        jlong number = readNumber(filename);
-        if (number >= 0) {
-            supported = true;
-            total += number;
+    while (fgets(buffer, 256, fp) != NULL) {
+        if (sscanf(buffer, "%31s %d %llu %llu %llu %llu %llu %llu %llu %llu", cur_iface, &active,
+                   &rxBytes, &rxPackets, &txBytes, &txPackets, &devRxBytes, &devRxPackets,
+                   &devTxBytes, &devTxPackets) != 10) {
+            continue;
         }
-        idx++;
-    }
-    if (supported) return total;
 
-    return -1;
-}
+        if (!iface || !strcmp(iface, cur_iface)) {
+            stat->rxBytes += rxBytes;
+            stat->rxPackets += rxPackets;
+            stat->txBytes += txBytes;
+            stat->txPackets += txPackets;
 
-// Returns the sum of numbers from the specified path under /sys/class/net/*,
-// -1 if no such file exists.
-static jlong readTotal(char const* suffix) {
-    char filename[PATH_MAX] = "/sys/class/net/";
-    DIR *dir = opendir(filename);
-    if (dir == NULL) {
-        ALOGE("Can't list %s: %s", filename, strerror(errno));
-        return -1;
-    }
-
-    int len = strlen(filename);
-    jlong total = -1;
-    while (struct dirent *entry = readdir(dir)) {
-        // Skip ., .., and localhost interfaces.
-        if (entry->d_name[0] != '.' && strncmp(entry->d_name, "lo", 2) != 0) {
-            strlcpy(filename + len, entry->d_name, sizeof(filename) - len);
-            strlcat(filename, suffix, sizeof(filename));
-            jlong num = readNumber(filename);
-            if (num >= 0) total = total < 0 ? num : total + num;
+            if (active) {
+                stat->rxBytes += devRxBytes;
+                stat->rxPackets += devRxPackets;
+                stat->txBytes += devTxBytes;
+                stat->txPackets += devTxPackets;
+            }
         }
     }
 
-    closedir(dir);
-    return total;
+    fclose(fp);
+    return 0;
 }
 
-// Mobile stats get accessed a lot more often than total stats.
-// Note the individual files can come and go at runtime, so we check
-// each file every time (rather than caching which ones exist).
+static uint64_t getIfaceStatType(const char* iface, IfaceStatType type) {
+    struct IfaceStat stat;
+    memset(&stat, 0, sizeof(IfaceStat));
 
-static jlong getMobileTxPackets(JNIEnv* env, jobject clazz) {
-    return getAll(mobile_iface_list, "tx_packets");
-}
-
-static jlong getMobileRxPackets(JNIEnv* env, jobject clazz) {
-    return getAll(mobile_iface_list, "rx_packets");
-}
-
-static jlong getMobileTxBytes(JNIEnv* env, jobject clazz) {
-    return getAll(mobile_iface_list, "tx_bytes");
-}
-
-static jlong getMobileRxBytes(JNIEnv* env, jobject clazz) {
-    return getAll(mobile_iface_list, "rx_bytes");
-}
-
-static jlong getData(JNIEnv* env, const char* what, jstring javaInterface) {
-    ScopedUtfChars interface(env, javaInterface);
-    if (interface.c_str() == NULL) {
-        return -1;
+    if (parseIfaceStat(iface, &stat)) {
+        return VALUE_UNKNOWN;
     }
 
-    char filename[80];
-    snprintf(filename, sizeof(filename), "/sys/class/net/%s/statistics/%s", interface.c_str(), what);
-    return readNumber(filename);
+    switch (type) {
+        case RX_BYTES:
+            return stat.rxBytes;
+        case RX_PACKETS:
+            return stat.rxPackets;
+        case TX_BYTES:
+            return stat.txBytes;
+        case TX_PACKETS:
+            return stat.txPackets;
+        default:
+            return VALUE_UNKNOWN;
+    }
 }
 
-static jlong getTxPackets(JNIEnv* env, jobject clazz, jstring interface) {
-    return getData(env, "tx_packets", interface);
+static jlong getTotalStat(JNIEnv* env, jclass clazz, jint type) {
+    return getIfaceStatType(NULL, (IfaceStatType) type);
 }
 
-static jlong getRxPackets(JNIEnv* env, jobject clazz, jstring interface) {
-    return getData(env, "rx_packets", interface);
+static jlong getIfaceStat(JNIEnv* env, jclass clazz, jstring iface, jint type) {
+    struct IfaceStat stat;
+    const char* ifaceChars = env->GetStringUTFChars(iface, NULL);
+    if (ifaceChars) {
+        uint64_t stat = getIfaceStatType(ifaceChars, (IfaceStatType) type);
+        env->ReleaseStringUTFChars(iface, ifaceChars);
+        return stat;
+    } else {
+        return VALUE_UNKNOWN;
+    }
 }
 
-static jlong getTxBytes(JNIEnv* env, jobject clazz, jstring interface) {
-    return getData(env, "tx_bytes", interface);
-}
-
-static jlong getRxBytes(JNIEnv* env, jobject clazz, jstring interface) {
-    return getData(env, "rx_bytes", interface);
-}
-
-
-// Total stats are read less often, so we're willing to put up
-// with listing the directory and concatenating filenames.
-
-static jlong getTotalTxPackets(JNIEnv* env, jobject clazz) {
-    return readTotal("/statistics/tx_packets");
-}
-
-static jlong getTotalRxPackets(JNIEnv* env, jobject clazz) {
-    return readTotal("/statistics/rx_packets");
-}
-
-static jlong getTotalTxBytes(JNIEnv* env, jobject clazz) {
-    return readTotal("/statistics/tx_bytes");
-}
-
-static jlong getTotalRxBytes(JNIEnv* env, jobject clazz) {
-    return readTotal("/statistics/rx_bytes");
-}
 
 // Per-UID stats require reading from a constructed filename.
 
@@ -323,18 +293,8 @@
 }
 
 static JNINativeMethod gMethods[] = {
-    {"getMobileTxPackets", "()J", (void*) getMobileTxPackets},
-    {"getMobileRxPackets", "()J", (void*) getMobileRxPackets},
-    {"getMobileTxBytes", "()J", (void*) getMobileTxBytes},
-    {"getMobileRxBytes", "()J", (void*) getMobileRxBytes},
-    {"getTxPackets", "(Ljava/lang/String;)J", (void*) getTxPackets},
-    {"getRxPackets", "(Ljava/lang/String;)J", (void*) getRxPackets},
-    {"getTxBytes", "(Ljava/lang/String;)J", (void*) getTxBytes},
-    {"getRxBytes", "(Ljava/lang/String;)J", (void*) getRxBytes},
-    {"getTotalTxPackets", "()J", (void*) getTotalTxPackets},
-    {"getTotalRxPackets", "()J", (void*) getTotalRxPackets},
-    {"getTotalTxBytes", "()J", (void*) getTotalTxBytes},
-    {"getTotalRxBytes", "()J", (void*) getTotalRxBytes},
+    {"nativeGetTotalStat", "(I)J", (void*) getTotalStat},
+    {"nativeGetIfaceStat", "(Ljava/lang/String;I)J", (void*) getIfaceStat},
 
     /* Per-UID Stats */
     {"getUidTxBytes", "(I)J", (void*) getUidTxBytes},
diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java
index 4382a03..2a67e02 100644
--- a/services/java/com/android/server/net/NetworkStatsService.java
+++ b/services/java/com/android/server/net/NetworkStatsService.java
@@ -26,6 +26,7 @@
 import static android.content.Intent.EXTRA_UID;
 import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED;
 import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE;
+import static android.net.ConnectivityManager.isNetworkTypeMobile;
 import static android.net.NetworkIdentity.COMBINE_SUBTYPE_ENABLED;
 import static android.net.NetworkStats.IFACE_ALL;
 import static android.net.NetworkStats.SET_ALL;
@@ -33,7 +34,7 @@
 import static android.net.NetworkStats.SET_FOREGROUND;
 import static android.net.NetworkStats.TAG_NONE;
 import static android.net.NetworkStats.UID_ALL;
-import static android.net.NetworkTemplate.buildTemplateMobileAll;
+import static android.net.NetworkTemplate.buildTemplateMobileWildcard;
 import static android.net.NetworkTemplate.buildTemplateWifiWildcard;
 import static android.net.TrafficStats.MB_IN_BYTES;
 import static android.provider.Settings.Secure.NETSTATS_DEV_BUCKET_DURATION;
@@ -54,6 +55,8 @@
 import static android.text.format.DateUtils.HOUR_IN_MILLIS;
 import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
 import static android.text.format.DateUtils.SECOND_IN_MILLIS;
+import static com.android.internal.util.ArrayUtils.appendElement;
+import static com.android.internal.util.ArrayUtils.contains;
 import static com.android.internal.util.Preconditions.checkNotNull;
 import static com.android.server.NetworkManagementService.LIMIT_GLOBAL_ALERT;
 import static com.android.server.NetworkManagementSocketTagger.resetKernelUidStats;
@@ -194,6 +197,8 @@
     private HashMap<String, NetworkIdentitySet> mActiveIfaces = Maps.newHashMap();
     /** Current default active iface. */
     private String mActiveIface;
+    /** Set of any ifaces associated with mobile networks since boot. */
+    private String[] mMobileIfaces = new String[0];
 
     private final DropBoxNonMonotonicObserver mNonMonotonicObserver =
             new DropBoxNonMonotonicObserver();
@@ -517,6 +522,11 @@
     }
 
     @Override
+    public String[] getMobileIfaces() {
+        return mMobileIfaces;
+    }
+
+    @Override
     public void incrementOperationCount(int uid, int tag, int operationCount) {
         if (Binder.getCallingUid() != uid) {
             mContext.enforceCallingOrSelfPermission(MODIFY_NETWORK_ACCOUNTING, TAG);
@@ -735,6 +745,13 @@
                 }
 
                 ident.add(NetworkIdentity.buildNetworkIdentity(mContext, state));
+
+                // remember any ifaces associated with mobile networks
+                if (isNetworkTypeMobile(state.networkInfo.getType())) {
+                    if (!contains(mMobileIfaces, iface)) {
+                        mMobileIfaces = appendElement(String.class, mMobileIfaces, iface);
+                    }
+                }
             }
         }
     }
@@ -861,7 +878,7 @@
         NetworkStats.Entry uidTotal;
 
         // collect mobile sample
-        template = buildTemplateMobileAll(getActiveSubscriberId(mContext));
+        template = buildTemplateMobileWildcard();
         devTotal = mDevRecorder.getTotalSinceBootLocked(template);
         xtTotal = new NetworkStats.Entry();
         uidTotal = mUidRecorder.getTotalSinceBootLocked(template);
@@ -1022,12 +1039,6 @@
         }
     };
 
-    private static String getActiveSubscriberId(Context context) {
-        final TelephonyManager telephony = (TelephonyManager) context.getSystemService(
-                Context.TELEPHONY_SERVICE);
-        return telephony.getSubscriberId();
-    }
-
     private boolean isBandwidthControlEnabled() {
         try {
             return mNetworkManager.isBandwidthControlEnabled();