summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/net/NetworkStatsHistory.java5
-rw-r--r--services/java/com/android/server/ConnectivityService.java7
-rw-r--r--services/java/com/android/server/SystemServer.java3
-rw-r--r--services/java/com/android/server/connectivity/Tethering.java17
-rw-r--r--services/java/com/android/server/net/NetworkStatsService.java99
-rw-r--r--services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java1
6 files changed, 102 insertions, 30 deletions
diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java
index a5cdf70325ee..a6635bee205a 100644
--- a/core/java/android/net/NetworkStatsHistory.java
+++ b/core/java/android/net/NetworkStatsHistory.java
@@ -270,6 +270,11 @@ public class NetworkStatsHistory implements Parcelable {
|| entry.operations < 0) {
throw new IllegalArgumentException("tried recording negative data");
}
+ if (entry.rxBytes == 0 && entry.rxPackets == 0 && entry.txBytes == 0 && entry.txPackets == 0
+ && entry.operations == 0) {
+ // nothing to record; skip
+ return;
+ }
// create any buckets needed by this range
ensureBuckets(start, end);
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 327450a6f500..991b7da6796a 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -35,6 +35,7 @@ import android.net.EthernetDataTracker;
import android.net.IConnectivityManager;
import android.net.INetworkPolicyListener;
import android.net.INetworkPolicyManager;
+import android.net.INetworkStatsService;
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.LinkProperties.CompareResult;
@@ -306,8 +307,8 @@ public class ConnectivityService extends IConnectivityManager.Stub {
// the set of network types that can only be enabled by system/sig apps
List mProtectedNetworks;
- public ConnectivityService(
- Context context, INetworkManagementService netd, INetworkPolicyManager policyManager) {
+ public ConnectivityService(Context context, INetworkManagementService netd,
+ INetworkStatsService statsService, INetworkPolicyManager policyManager) {
if (DBG) log("ConnectivityService starting up");
HandlerThread handlerThread = new HandlerThread("ConnectivityServiceThread");
@@ -496,7 +497,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
INetworkManagementService nmService = INetworkManagementService.Stub.asInterface(b);
- mTethering = new Tethering(mContext, nmService, mHandler.getLooper());
+ mTethering = new Tethering(mContext, nmService, statsService, mHandler.getLooper());
mTetheringConfigValid = ((mTethering.getTetherableUsbRegexs().length != 0 ||
mTethering.getTetherableWifiRegexs().length != 0 ||
mTethering.getTetherableBluetoothRegexs().length != 0) &&
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 977dd6f5d54f..72d19171048b 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -364,7 +364,8 @@ class ServerThread extends Thread {
try {
Slog.i(TAG, "Connectivity Service");
- connectivity = new ConnectivityService(context, networkManagement, networkPolicy);
+ connectivity = new ConnectivityService(
+ context, networkManagement, networkStats, networkPolicy);
ServiceManager.addService(Context.CONNECTIVITY_SERVICE, connectivity);
networkStats.bindConnectivityManager(connectivity);
networkPolicy.bindConnectivityManager(connectivity);
diff --git a/services/java/com/android/server/connectivity/Tethering.java b/services/java/com/android/server/connectivity/Tethering.java
index 10f6d2ccdc5f..6b9c08852124 100644
--- a/services/java/com/android/server/connectivity/Tethering.java
+++ b/services/java/com/android/server/connectivity/Tethering.java
@@ -29,6 +29,7 @@ import android.hardware.usb.UsbManager;
import android.net.ConnectivityManager;
import android.net.IConnectivityManager;
import android.net.INetworkManagementEventObserver;
+import android.net.INetworkStatsService;
import android.net.InterfaceConfiguration;
import android.net.LinkAddress;
import android.net.LinkProperties;
@@ -88,7 +89,8 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
// upstream type list and the DUN_REQUIRED secure-setting
private int mPreferredUpstreamMobileApn = ConnectivityManager.TYPE_NONE;
- private INetworkManagementService mNMService;
+ private final INetworkManagementService mNMService;
+ private final INetworkStatsService mStatsService;
private Looper mLooper;
private HandlerThread mThread;
@@ -124,9 +126,11 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
private boolean mUsbTetherRequested; // true if USB tethering should be started
// when RNDIS is enabled
- public Tethering(Context context, INetworkManagementService nmService, Looper looper) {
+ public Tethering(Context context, INetworkManagementService nmService,
+ INetworkStatsService statsService, Looper looper) {
mContext = context;
mNMService = nmService;
+ mStatsService = statsService;
mLooper = looper;
mIfaces = new HashMap<String, TetherInterfaceSM>();
@@ -913,6 +917,9 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
case CMD_INTERFACE_DOWN:
if (mMyUpstreamIfaceName != null) {
try {
+ // about to tear down NAT; gather remaining statistics
+ mStatsService.forceUpdate();
+
mNMService.disableNat(mIfaceName, mMyUpstreamIfaceName);
mMyUpstreamIfaceName = null;
} catch (Exception e) {
@@ -957,6 +964,9 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
}
if (mMyUpstreamIfaceName != null) {
try {
+ // about to tear down NAT; gather remaining statistics
+ mStatsService.forceUpdate();
+
mNMService.disableNat(mIfaceName, mMyUpstreamIfaceName);
mMyUpstreamIfaceName = null;
} catch (Exception e) {
@@ -995,6 +1005,9 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
case CMD_TETHER_MODE_DEAD:
if (mMyUpstreamIfaceName != null) {
try {
+ // about to tear down NAT; gather remaining statistics
+ mStatsService.forceUpdate();
+
mNMService.disableNat(mIfaceName, mMyUpstreamIfaceName);
mMyUpstreamIfaceName = null;
} catch (Exception e) {
diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java
index bc65205cbe10..aa46795b4fb9 100644
--- a/services/java/com/android/server/net/NetworkStatsService.java
+++ b/services/java/com/android/server/net/NetworkStatsService.java
@@ -24,8 +24,8 @@ import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY;
import static android.content.Intent.ACTION_SHUTDOWN;
import static android.content.Intent.ACTION_UID_REMOVED;
import static android.content.Intent.EXTRA_UID;
-import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE;
import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED;
+import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE;
import static android.net.NetworkStats.IFACE_ALL;
import static android.net.NetworkStats.SET_ALL;
import static android.net.NetworkStats.SET_DEFAULT;
@@ -43,9 +43,12 @@ import static android.provider.Settings.Secure.NETSTATS_POLL_INTERVAL;
import static android.provider.Settings.Secure.NETSTATS_TAG_MAX_HISTORY;
import static android.provider.Settings.Secure.NETSTATS_UID_BUCKET_DURATION;
import static android.provider.Settings.Secure.NETSTATS_UID_MAX_HISTORY;
+import static android.telephony.PhoneStateListener.LISTEN_DATA_CONNECTION_STATE;
+import static android.telephony.PhoneStateListener.LISTEN_NONE;
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;
+import static android.text.format.DateUtils.SECOND_IN_MILLIS;
import static com.android.internal.util.Preconditions.checkNotNull;
import static com.android.server.NetworkManagementService.LIMIT_GLOBAL_ALERT;
import static com.android.server.NetworkManagementSocketTagger.resetKernelUidStats;
@@ -80,6 +83,7 @@ import android.os.PowerManager;
import android.os.RemoteException;
import android.os.SystemClock;
import android.provider.Settings;
+import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.util.EventLog;
import android.util.Log;
@@ -121,7 +125,7 @@ import libcore.io.IoUtils;
*/
public class NetworkStatsService extends INetworkStatsService.Stub {
private static final String TAG = "NetworkStats";
- private static final boolean LOGD = true;
+ private static final boolean LOGD = false;
private static final boolean LOGV = false;
/** File header magic number: "ANET" */
@@ -132,7 +136,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
private static final int VERSION_UID_WITH_TAG = 3;
private static final int VERSION_UID_WITH_SET = 4;
- private static final int MSG_PERFORM_POLL = 0x1;
+ private static final int MSG_PERFORM_POLL = 1;
+ private static final int MSG_UPDATE_IFACES = 2;
/** Flags to control detail level of poll event. */
private static final int FLAG_PERSIST_NETWORK = 0x10;
@@ -144,6 +149,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
private final INetworkManagementService mNetworkManager;
private final IAlarmManager mAlarmManager;
private final TrustedTime mTime;
+ private final TelephonyManager mTeleManager;
private final NetworkStatsSettings mSettings;
private final PowerManager.WakeLock mWakeLock;
@@ -227,6 +233,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
mNetworkManager = checkNotNull(networkManager, "missing INetworkManagementService");
mAlarmManager = checkNotNull(alarmManager, "missing IAlarmManager");
mTime = checkNotNull(time, "missing TrustedTime");
+ mTeleManager = checkNotNull(TelephonyManager.getDefault(), "missing TelephonyManager");
mSettings = checkNotNull(settings, "missing NetworkStatsSettings");
final PowerManager powerManager = (PowerManager) context.getSystemService(
@@ -279,6 +286,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
// ignored; service lives in system_server
}
+ // watch for networkType changes that aren't broadcast through
+ // CONNECTIVITY_ACTION_IMMEDIATE above.
+ mTeleManager.listen(mPhoneListener, LISTEN_DATA_CONNECTION_STATE);
+
registerPollAlarmLocked();
registerGlobalAlert();
@@ -288,10 +299,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
private void shutdownLocked() {
mContext.unregisterReceiver(mConnReceiver);
+ mContext.unregisterReceiver(mTetherReceiver);
mContext.unregisterReceiver(mPollReceiver);
mContext.unregisterReceiver(mRemovedReceiver);
mContext.unregisterReceiver(mShutdownReceiver);
+ mTeleManager.listen(mPhoneListener, LISTEN_NONE);
+
writeNetworkStatsLocked();
if (mUidStatsLoaded) {
writeUidStatsLocked();
@@ -535,14 +549,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
public void onReceive(Context context, Intent intent) {
// on background handler thread, and verified CONNECTIVITY_INTERNAL
// permission above.
- synchronized (mStatsLock) {
- mWakeLock.acquire();
- try {
- updateIfacesLocked();
- } finally {
- mWakeLock.release();
- }
- }
+ updateIfaces();
}
};
@@ -619,6 +626,46 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
}
};
+ private int mLastPhoneState = TelephonyManager.DATA_UNKNOWN;
+ private int mLastPhoneNetworkType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
+
+ /**
+ * Receiver that watches for {@link TelephonyManager} changes, such as
+ * transitioning between network types.
+ */
+ private PhoneStateListener mPhoneListener = new PhoneStateListener() {
+ @Override
+ public void onDataConnectionStateChanged(int state, int networkType) {
+ final boolean stateChanged = state != mLastPhoneState;
+ final boolean networkTypeChanged = networkType != mLastPhoneNetworkType;
+
+ if (networkTypeChanged && !stateChanged) {
+ // networkType changed without a state change, which means we
+ // need to roll our own update. delay long enough for
+ // ConnectivityManager to process.
+ // TODO: add direct event to ConnectivityService instead of
+ // relying on this delay.
+ if (LOGV) Slog.v(TAG, "triggering delayed updateIfaces()");
+ mHandler.sendMessageDelayed(
+ mHandler.obtainMessage(MSG_UPDATE_IFACES), SECOND_IN_MILLIS);
+ }
+
+ mLastPhoneState = state;
+ mLastPhoneNetworkType = networkType;
+ }
+ };
+
+ private void updateIfaces() {
+ synchronized (mStatsLock) {
+ mWakeLock.acquire();
+ try {
+ updateIfacesLocked();
+ } finally {
+ mWakeLock.release();
+ }
+ }
+ }
+
/**
* Inspect all current {@link NetworkState} to derive mapping from {@code
* iface} to {@link NetworkStatsHistory}. When multiple {@link NetworkInfo}
@@ -713,19 +760,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
final long threshold = mSettings.getPersistThreshold();
try {
- // record network stats
- final NetworkStats networkSnapshot = mNetworkManager.getNetworkStatsSummary();
- performNetworkPollLocked(networkSnapshot, currentTime);
-
- // persist when enough network data has occurred
- final NetworkStats persistNetworkDelta = computeStatsDelta(
- mLastPersistNetworkSnapshot, networkSnapshot, true);
- final boolean networkPastThreshold = persistNetworkDelta.getTotalBytes() > threshold;
- if (persistForce || (persistNetwork && networkPastThreshold)) {
- writeNetworkStatsLocked();
- mLastPersistNetworkSnapshot = networkSnapshot;
- }
-
// record tethering stats; persisted during normal UID cycle below
final String[] ifacePairs = mConnManager.getTetheredIfacePairs();
final NetworkStats tetherSnapshot = mNetworkManager.getNetworkStatsTethering(
@@ -744,6 +778,19 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
writeUidStatsLocked();
mLastPersistUidSnapshot = uidSnapshot;
}
+
+ // record network stats
+ final NetworkStats networkSnapshot = mNetworkManager.getNetworkStatsSummary();
+ performNetworkPollLocked(networkSnapshot, currentTime);
+
+ // persist when enough network data has occurred
+ final NetworkStats persistNetworkDelta = computeStatsDelta(
+ mLastPersistNetworkSnapshot, networkSnapshot, true);
+ final boolean networkPastThreshold = persistNetworkDelta.getTotalBytes() > threshold;
+ if (persistForce || (persistNetwork && networkPastThreshold)) {
+ writeNetworkStatsLocked();
+ mLastPersistNetworkSnapshot = networkSnapshot;
+ }
} catch (IllegalStateException e) {
Log.wtf(TAG, "problem reading network stats", e);
} catch (RemoteException e) {
@@ -1356,6 +1403,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
performPoll(flags);
return true;
}
+ case MSG_UPDATE_IFACES: {
+ updateIfaces();
+ return true;
+ }
default: {
return false;
}
diff --git a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
index 99ae027f4b16..2ead254af18c 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
@@ -776,6 +776,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase {
private void expectNetworkStatsPoll() throws Exception {
mNetManager.setGlobalAlert(anyLong());
expectLastCall().anyTimes();
+ expect(mConnManager.getTetheredIfacePairs()).andReturn(null).anyTimes();
}
private void assertStatsFilesExist(boolean exist) {