blob: 6a826795160389c45c7dffac0f04e741a573df59 [file] [log] [blame]
Jeff Sharkey75279902011-05-24 18:39:45 -07001/*
Jeff Sharkeyd2a45872011-05-28 20:56:34 -07002 * Copyright (C) 2011 The Android Open Source Project
Jeff Sharkey75279902011-05-24 18:39:45 -07003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.net;
18
Jeff Sharkeya63ba592011-07-19 23:47:12 -070019import static android.Manifest.permission.ACCESS_NETWORK_STATE;
Jeff Sharkey63d27a92011-08-03 17:04:22 -070020import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
Jeff Sharkey75279902011-05-24 18:39:45 -070021import static android.Manifest.permission.DUMP;
Jeff Sharkey63d27a92011-08-03 17:04:22 -070022import static android.Manifest.permission.MODIFY_NETWORK_ACCOUNTING;
Jeff Sharkey21c9c452011-06-07 12:26:43 -070023import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY;
Jeff Sharkeyb09540f2011-06-19 01:08:12 -070024import static android.content.Intent.ACTION_SHUTDOWN;
25import static android.content.Intent.ACTION_UID_REMOVED;
26import static android.content.Intent.EXTRA_UID;
Jeff Sharkeycdd02c5d2011-09-16 01:52:49 -070027import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED;
Jeff Sharkey367d15a2011-09-22 14:59:51 -070028import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE;
Jeff Sharkey61ee0bb2011-05-29 22:50:42 -070029import static android.net.NetworkStats.IFACE_ALL;
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -070030import static android.net.NetworkStats.SET_ALL;
31import static android.net.NetworkStats.SET_DEFAULT;
32import static android.net.NetworkStats.SET_FOREGROUND;
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -070033import static android.net.NetworkStats.TAG_NONE;
Jeff Sharkey75279902011-05-24 18:39:45 -070034import static android.net.NetworkStats.UID_ALL;
Jeff Sharkey07b0dd92011-09-01 13:06:19 -070035import static android.net.NetworkTemplate.buildTemplateMobileAll;
36import static android.net.NetworkTemplate.buildTemplateWifi;
Jeff Sharkeyb09540f2011-06-19 01:08:12 -070037import static android.net.TrafficStats.UID_REMOVED;
Jeff Sharkey39ebc212011-06-11 17:25:42 -070038import static android.provider.Settings.Secure.NETSTATS_NETWORK_BUCKET_DURATION;
39import static android.provider.Settings.Secure.NETSTATS_NETWORK_MAX_HISTORY;
Jeff Sharkey61ee0bb2011-05-29 22:50:42 -070040import static android.provider.Settings.Secure.NETSTATS_PERSIST_THRESHOLD;
41import static android.provider.Settings.Secure.NETSTATS_POLL_INTERVAL;
Jeff Sharkeyd03fd3f2011-06-19 20:55:09 -070042import static android.provider.Settings.Secure.NETSTATS_TAG_MAX_HISTORY;
Jeff Sharkey39ebc212011-06-11 17:25:42 -070043import static android.provider.Settings.Secure.NETSTATS_UID_BUCKET_DURATION;
44import static android.provider.Settings.Secure.NETSTATS_UID_MAX_HISTORY;
Jeff Sharkey367d15a2011-09-22 14:59:51 -070045import static android.telephony.PhoneStateListener.LISTEN_DATA_CONNECTION_STATE;
46import static android.telephony.PhoneStateListener.LISTEN_NONE;
Jeff Sharkey61ee0bb2011-05-29 22:50:42 -070047import static android.text.format.DateUtils.DAY_IN_MILLIS;
48import static android.text.format.DateUtils.HOUR_IN_MILLIS;
49import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
Jeff Sharkey367d15a2011-09-22 14:59:51 -070050import static android.text.format.DateUtils.SECOND_IN_MILLIS;
Jeff Sharkeyd2a45872011-05-28 20:56:34 -070051import static com.android.internal.util.Preconditions.checkNotNull;
Jeff Sharkey8e9992a2011-08-23 18:37:23 -070052import static com.android.server.NetworkManagementService.LIMIT_GLOBAL_ALERT;
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -070053import static com.android.server.NetworkManagementSocketTagger.resetKernelUidStats;
54import static com.android.server.NetworkManagementSocketTagger.setKernelCounterSet;
Jeff Sharkey75279902011-05-24 18:39:45 -070055
56import android.app.AlarmManager;
57import android.app.IAlarmManager;
58import android.app.PendingIntent;
59import android.content.BroadcastReceiver;
Jeff Sharkey39ebc212011-06-11 17:25:42 -070060import android.content.ContentResolver;
Jeff Sharkey75279902011-05-24 18:39:45 -070061import android.content.Context;
62import android.content.Intent;
63import android.content.IntentFilter;
Jeff Sharkey61ee0bb2011-05-29 22:50:42 -070064import android.content.pm.ApplicationInfo;
Jeff Sharkey293779f2011-10-05 23:31:57 -070065import android.content.pm.PackageManager;
66import android.content.pm.PackageManager.NameNotFoundException;
Jeff Sharkeyd2a45872011-05-28 20:56:34 -070067import android.net.IConnectivityManager;
Jeff Sharkey8e9992a2011-08-23 18:37:23 -070068import android.net.INetworkManagementEventObserver;
Jeff Sharkey75279902011-05-24 18:39:45 -070069import android.net.INetworkStatsService;
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -070070import android.net.NetworkIdentity;
Jeff Sharkeyd2a45872011-05-28 20:56:34 -070071import android.net.NetworkInfo;
72import android.net.NetworkState;
Jeff Sharkey75279902011-05-24 18:39:45 -070073import android.net.NetworkStats;
Jeff Sharkey163e6442011-10-31 16:37:52 -070074import android.net.NetworkStats.NonMonotonicException;
Jeff Sharkey75279902011-05-24 18:39:45 -070075import android.net.NetworkStatsHistory;
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -070076import android.net.NetworkTemplate;
Jeff Sharkeya63ba592011-07-19 23:47:12 -070077import android.os.Binder;
Jeff Sharkey163e6442011-10-31 16:37:52 -070078import android.os.DropBoxManager;
Jeff Sharkey3f391352011-06-05 17:42:53 -070079import android.os.Environment;
Jeff Sharkey75279902011-05-24 18:39:45 -070080import android.os.Handler;
81import android.os.HandlerThread;
82import android.os.INetworkManagementService;
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -070083import android.os.Message;
Jeff Sharkey62489262011-07-17 12:53:28 -070084import android.os.PowerManager;
Jeff Sharkey75279902011-05-24 18:39:45 -070085import android.os.RemoteException;
86import android.os.SystemClock;
Jeff Sharkey61ee0bb2011-05-29 22:50:42 -070087import android.provider.Settings;
Jeff Sharkey367d15a2011-09-22 14:59:51 -070088import android.telephony.PhoneStateListener;
Jeff Sharkey75279902011-05-24 18:39:45 -070089import android.telephony.TelephonyManager;
Jeff Sharkey07b0dd92011-09-01 13:06:19 -070090import android.util.EventLog;
Jeff Sharkeyb3d59572011-09-07 17:20:27 -070091import android.util.Log;
Jeff Sharkey75279902011-05-24 18:39:45 -070092import android.util.NtpTrustedTime;
93import android.util.Slog;
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -070094import android.util.SparseIntArray;
Jeff Sharkey75279902011-05-24 18:39:45 -070095import android.util.TrustedTime;
96
Jeff Sharkey3f391352011-06-05 17:42:53 -070097import com.android.internal.os.AtomicFile;
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -070098import com.android.internal.util.Objects;
Jeff Sharkey07b0dd92011-09-01 13:06:19 -070099import com.android.server.EventLogTags;
Jeff Sharkeycdd02c5d2011-09-16 01:52:49 -0700100import com.android.server.connectivity.Tethering;
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700101import com.google.android.collect.Lists;
Jeff Sharkey75279902011-05-24 18:39:45 -0700102import com.google.android.collect.Maps;
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -0700103import com.google.android.collect.Sets;
Jeff Sharkey75279902011-05-24 18:39:45 -0700104
Jeff Sharkey4e814c32011-07-14 20:37:37 -0700105import java.io.BufferedInputStream;
106import java.io.BufferedOutputStream;
Jeff Sharkey3f391352011-06-05 17:42:53 -0700107import java.io.DataInputStream;
108import java.io.DataOutputStream;
109import java.io.File;
Jeff Sharkey75279902011-05-24 18:39:45 -0700110import java.io.FileDescriptor;
Jeff Sharkey3f391352011-06-05 17:42:53 -0700111import java.io.FileNotFoundException;
112import java.io.FileOutputStream;
113import java.io.IOException;
Jeff Sharkey75279902011-05-24 18:39:45 -0700114import java.io.PrintWriter;
Jeff Sharkey3f391352011-06-05 17:42:53 -0700115import java.net.ProtocolException;
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700116import java.util.ArrayList;
117import java.util.Collections;
Jeff Sharkey75279902011-05-24 18:39:45 -0700118import java.util.HashMap;
Jeff Sharkey61ee0bb2011-05-29 22:50:42 -0700119import java.util.HashSet;
Jeff Sharkey293779f2011-10-05 23:31:57 -0700120import java.util.Random;
Jeff Sharkey75279902011-05-24 18:39:45 -0700121
Jeff Sharkey3f391352011-06-05 17:42:53 -0700122import libcore.io.IoUtils;
123
Jeff Sharkey75279902011-05-24 18:39:45 -0700124/**
125 * Collect and persist detailed network statistics, and provide this data to
126 * other system services.
127 */
128public class NetworkStatsService extends INetworkStatsService.Stub {
Jeff Sharkey21c9c452011-06-07 12:26:43 -0700129 private static final String TAG = "NetworkStats";
Jeff Sharkey367d15a2011-09-22 14:59:51 -0700130 private static final boolean LOGD = false;
Jeff Sharkey39ebc212011-06-11 17:25:42 -0700131 private static final boolean LOGV = false;
Jeff Sharkey75279902011-05-24 18:39:45 -0700132
Jeff Sharkey3f391352011-06-05 17:42:53 -0700133 /** File header magic number: "ANET" */
134 private static final int FILE_MAGIC = 0x414E4554;
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -0700135 private static final int VERSION_NETWORK_INIT = 1;
136 private static final int VERSION_UID_INIT = 1;
137 private static final int VERSION_UID_WITH_IDENT = 2;
Jeff Sharkeyd03fd3f2011-06-19 20:55:09 -0700138 private static final int VERSION_UID_WITH_TAG = 3;
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700139 private static final int VERSION_UID_WITH_SET = 4;
140
Jeff Sharkey367d15a2011-09-22 14:59:51 -0700141 private static final int MSG_PERFORM_POLL = 1;
142 private static final int MSG_UPDATE_IFACES = 2;
Jeff Sharkeyb3d59572011-09-07 17:20:27 -0700143
144 /** Flags to control detail level of poll event. */
Jeff Sharkey905b5892011-09-30 15:19:49 -0700145 private static final int FLAG_PERSIST_NETWORK = 0x1;
146 private static final int FLAG_PERSIST_UID = 0x2;
Jeff Sharkeyb3d59572011-09-07 17:20:27 -0700147 private static final int FLAG_PERSIST_ALL = FLAG_PERSIST_NETWORK | FLAG_PERSIST_UID;
Jeff Sharkey1f0b13b2011-09-18 13:30:23 -0700148 private static final int FLAG_PERSIST_FORCE = 0x100;
Jeff Sharkey3f391352011-06-05 17:42:53 -0700149
Jeff Sharkey905b5892011-09-30 15:19:49 -0700150 /** Sample recent usage after each poll event. */
151 private static final boolean ENABLE_SAMPLE_AFTER_POLL = true;
152
Jeff Sharkey163e6442011-10-31 16:37:52 -0700153 private static final String TAG_NETSTATS_ERROR = "netstats_error";
154
Jeff Sharkey75279902011-05-24 18:39:45 -0700155 private final Context mContext;
156 private final INetworkManagementService mNetworkManager;
157 private final IAlarmManager mAlarmManager;
158 private final TrustedTime mTime;
Jeff Sharkey367d15a2011-09-22 14:59:51 -0700159 private final TelephonyManager mTeleManager;
Jeff Sharkey39ebc212011-06-11 17:25:42 -0700160 private final NetworkStatsSettings mSettings;
Jeff Sharkey75279902011-05-24 18:39:45 -0700161
Jeff Sharkey62489262011-07-17 12:53:28 -0700162 private final PowerManager.WakeLock mWakeLock;
163
Jeff Sharkeyd2a45872011-05-28 20:56:34 -0700164 private IConnectivityManager mConnManager;
Jeff Sharkey163e6442011-10-31 16:37:52 -0700165 private DropBoxManager mDropBox;
Jeff Sharkeyd2a45872011-05-28 20:56:34 -0700166
Jeff Sharkey3f391352011-06-05 17:42:53 -0700167 // @VisibleForTesting
168 public static final String ACTION_NETWORK_STATS_POLL =
Jeff Sharkey75279902011-05-24 18:39:45 -0700169 "com.android.server.action.NETWORK_STATS_POLL";
Jeff Sharkey497e4432011-06-14 17:27:29 -0700170 public static final String ACTION_NETWORK_STATS_UPDATED =
171 "com.android.server.action.NETWORK_STATS_UPDATED";
Jeff Sharkey75279902011-05-24 18:39:45 -0700172
173 private PendingIntent mPollIntent;
174
Jeff Sharkeyd03fd3f2011-06-19 20:55:09 -0700175 // TODO: trim empty history objects entirely
176
Jeff Sharkey75279902011-05-24 18:39:45 -0700177 private static final long KB_IN_BYTES = 1024;
Jeff Sharkey61ee0bb2011-05-29 22:50:42 -0700178 private static final long MB_IN_BYTES = 1024 * KB_IN_BYTES;
179 private static final long GB_IN_BYTES = 1024 * MB_IN_BYTES;
Jeff Sharkey75279902011-05-24 18:39:45 -0700180
Jeff Sharkey39ebc212011-06-11 17:25:42 -0700181 /**
182 * Settings that can be changed externally.
183 */
184 public interface NetworkStatsSettings {
185 public long getPollInterval();
186 public long getPersistThreshold();
187 public long getNetworkBucketDuration();
188 public long getNetworkMaxHistory();
189 public long getUidBucketDuration();
190 public long getUidMaxHistory();
Jeff Sharkeyd03fd3f2011-06-19 20:55:09 -0700191 public long getTagMaxHistory();
Jeff Sharkey39ebc212011-06-11 17:25:42 -0700192 public long getTimeCacheMaxAge();
193 }
Jeff Sharkey75279902011-05-24 18:39:45 -0700194
195 private final Object mStatsLock = new Object();
196
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -0700197 /** Set of currently active ifaces. */
198 private HashMap<String, NetworkIdentitySet> mActiveIfaces = Maps.newHashMap();
Jeff Sharkey905b5892011-09-30 15:19:49 -0700199 /** Set of historical {@code dev} stats for known networks. */
200 private HashMap<NetworkIdentitySet, NetworkStatsHistory> mNetworkDevStats = Maps.newHashMap();
201 /** Set of historical {@code xtables} stats for known networks. */
202 private HashMap<NetworkIdentitySet, NetworkStatsHistory> mNetworkXtStats = Maps.newHashMap();
203 /** Set of historical {@code xtables} stats for known UIDs. */
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700204 private HashMap<UidStatsKey, NetworkStatsHistory> mUidStats = Maps.newHashMap();
Jeff Sharkey61ee0bb2011-05-29 22:50:42 -0700205
Jeff Sharkeyc506ff62011-11-17 11:59:29 -0800206 /** Flag if {@link #mNetworkDevStats} have been loaded from disk. */
207 private boolean mNetworkStatsLoaded = false;
Jeff Sharkey39ebc212011-06-11 17:25:42 -0700208 /** Flag if {@link #mUidStats} have been loaded from disk. */
209 private boolean mUidStatsLoaded = false;
Jeff Sharkey61ee0bb2011-05-29 22:50:42 -0700210
Jeff Sharkey905b5892011-09-30 15:19:49 -0700211 private NetworkStats mLastPollNetworkDevSnapshot;
212 private NetworkStats mLastPollNetworkXtSnapshot;
Jeff Sharkey8e9992a2011-08-23 18:37:23 -0700213 private NetworkStats mLastPollUidSnapshot;
214 private NetworkStats mLastPollOperationsSnapshot;
Jeff Sharkey39ebc212011-06-11 17:25:42 -0700215
Jeff Sharkey905b5892011-09-30 15:19:49 -0700216 private NetworkStats mLastPersistNetworkDevSnapshot;
217 private NetworkStats mLastPersistNetworkXtSnapshot;
Jeff Sharkey8e9992a2011-08-23 18:37:23 -0700218 private NetworkStats mLastPersistUidSnapshot;
Jeff Sharkey75279902011-05-24 18:39:45 -0700219
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700220 /** Current counter sets for each UID. */
221 private SparseIntArray mActiveUidCounterSet = new SparseIntArray();
222
Jeff Sharkeya63ba592011-07-19 23:47:12 -0700223 /** Data layer operation counters for splicing into other structures. */
224 private NetworkStats mOperations = new NetworkStats(0L, 10);
Jeff Sharkeya63ba592011-07-19 23:47:12 -0700225
Jeff Sharkey75279902011-05-24 18:39:45 -0700226 private final HandlerThread mHandlerThread;
227 private final Handler mHandler;
228
Jeff Sharkey905b5892011-09-30 15:19:49 -0700229 private final AtomicFile mNetworkDevFile;
230 private final AtomicFile mNetworkXtFile;
Jeff Sharkey39ebc212011-06-11 17:25:42 -0700231 private final AtomicFile mUidFile;
Jeff Sharkey3f391352011-06-05 17:42:53 -0700232
Jeff Sharkey75279902011-05-24 18:39:45 -0700233 public NetworkStatsService(
234 Context context, INetworkManagementService networkManager, IAlarmManager alarmManager) {
Jeff Sharkey104344e2011-07-10 14:20:41 -0700235 this(context, networkManager, alarmManager, NtpTrustedTime.getInstance(context),
236 getSystemDir(), new DefaultNetworkStatsSettings(context));
Jeff Sharkey3f391352011-06-05 17:42:53 -0700237 }
238
239 private static File getSystemDir() {
240 return new File(Environment.getDataDirectory(), "system");
Jeff Sharkey75279902011-05-24 18:39:45 -0700241 }
242
243 public NetworkStatsService(Context context, INetworkManagementService networkManager,
Jeff Sharkey39ebc212011-06-11 17:25:42 -0700244 IAlarmManager alarmManager, TrustedTime time, File systemDir,
245 NetworkStatsSettings settings) {
Jeff Sharkey75279902011-05-24 18:39:45 -0700246 mContext = checkNotNull(context, "missing Context");
247 mNetworkManager = checkNotNull(networkManager, "missing INetworkManagementService");
248 mAlarmManager = checkNotNull(alarmManager, "missing IAlarmManager");
249 mTime = checkNotNull(time, "missing TrustedTime");
Jeff Sharkey367d15a2011-09-22 14:59:51 -0700250 mTeleManager = checkNotNull(TelephonyManager.getDefault(), "missing TelephonyManager");
Jeff Sharkey39ebc212011-06-11 17:25:42 -0700251 mSettings = checkNotNull(settings, "missing NetworkStatsSettings");
Jeff Sharkey75279902011-05-24 18:39:45 -0700252
Jeff Sharkey62489262011-07-17 12:53:28 -0700253 final PowerManager powerManager = (PowerManager) context.getSystemService(
254 Context.POWER_SERVICE);
255 mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
256
Jeff Sharkey75279902011-05-24 18:39:45 -0700257 mHandlerThread = new HandlerThread(TAG);
258 mHandlerThread.start();
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700259 mHandler = new Handler(mHandlerThread.getLooper(), mHandlerCallback);
Jeff Sharkey3f391352011-06-05 17:42:53 -0700260
Jeff Sharkey905b5892011-09-30 15:19:49 -0700261 mNetworkDevFile = new AtomicFile(new File(systemDir, "netstats.bin"));
262 mNetworkXtFile = new AtomicFile(new File(systemDir, "netstats_xt.bin"));
Jeff Sharkey39ebc212011-06-11 17:25:42 -0700263 mUidFile = new AtomicFile(new File(systemDir, "netstats_uid.bin"));
Jeff Sharkey75279902011-05-24 18:39:45 -0700264 }
265
Jeff Sharkey21c9c452011-06-07 12:26:43 -0700266 public void bindConnectivityManager(IConnectivityManager connManager) {
267 mConnManager = checkNotNull(connManager, "missing IConnectivityManager");
268 }
269
Jeff Sharkey75279902011-05-24 18:39:45 -0700270 public void systemReady() {
Jeff Sharkey418d12d2011-12-13 15:38:03 -0800271 if (!isBandwidthControlEnabled()) {
272 Slog.w(TAG, "bandwidth controls disabled, unable to track stats");
273 return;
274 }
275
Jeff Sharkey3f391352011-06-05 17:42:53 -0700276 synchronized (mStatsLock) {
Jeff Sharkey39ebc212011-06-11 17:25:42 -0700277 // read historical network stats from disk, since policy service
278 // might need them right away. we delay loading detailed UID stats
279 // until actually needed.
Jeff Sharkey905b5892011-09-30 15:19:49 -0700280 readNetworkDevStatsLocked();
281 readNetworkXtStatsLocked();
Jeff Sharkeyc506ff62011-11-17 11:59:29 -0800282 mNetworkStatsLoaded = true;
Jeff Sharkey3f391352011-06-05 17:42:53 -0700283 }
Jeff Sharkey75279902011-05-24 18:39:45 -0700284
Jeff Sharkey3359aca2011-11-08 18:08:48 -0800285 // bootstrap initial stats to prevent double-counting later
286 bootstrapStats();
287
Jeff Sharkey21c9c452011-06-07 12:26:43 -0700288 // watch for network interfaces to be claimed
Jeff Sharkey961e3042011-08-29 16:02:57 -0700289 final IntentFilter connFilter = new IntentFilter(CONNECTIVITY_ACTION_IMMEDIATE);
Jeff Sharkeyb09540f2011-06-19 01:08:12 -0700290 mContext.registerReceiver(mConnReceiver, connFilter, CONNECTIVITY_INTERNAL, mHandler);
Jeff Sharkey75279902011-05-24 18:39:45 -0700291
Jeff Sharkeycdd02c5d2011-09-16 01:52:49 -0700292 // watch for tethering changes
293 final IntentFilter tetherFilter = new IntentFilter(ACTION_TETHER_STATE_CHANGED);
294 mContext.registerReceiver(mTetherReceiver, tetherFilter, CONNECTIVITY_INTERNAL, mHandler);
295
Jeff Sharkey75279902011-05-24 18:39:45 -0700296 // listen for periodic polling events
297 final IntentFilter pollFilter = new IntentFilter(ACTION_NETWORK_STATS_POLL);
Jeff Sharkey21c9c452011-06-07 12:26:43 -0700298 mContext.registerReceiver(mPollReceiver, pollFilter, READ_NETWORK_USAGE_HISTORY, mHandler);
Jeff Sharkey75279902011-05-24 18:39:45 -0700299
Jeff Sharkeyb09540f2011-06-19 01:08:12 -0700300 // listen for uid removal to clean stats
301 final IntentFilter removedFilter = new IntentFilter(ACTION_UID_REMOVED);
302 mContext.registerReceiver(mRemovedReceiver, removedFilter, null, mHandler);
303
Jeff Sharkey75279902011-05-24 18:39:45 -0700304 // persist stats during clean shutdown
Jeff Sharkeyb09540f2011-06-19 01:08:12 -0700305 final IntentFilter shutdownFilter = new IntentFilter(ACTION_SHUTDOWN);
306 mContext.registerReceiver(mShutdownReceiver, shutdownFilter);
Jeff Sharkey75279902011-05-24 18:39:45 -0700307
308 try {
Jeff Sharkey8e9992a2011-08-23 18:37:23 -0700309 mNetworkManager.registerObserver(mAlertObserver);
Jeff Sharkey75279902011-05-24 18:39:45 -0700310 } catch (RemoteException e) {
Jeff Sharkeyb3d59572011-09-07 17:20:27 -0700311 // ignored; service lives in system_server
Jeff Sharkey75279902011-05-24 18:39:45 -0700312 }
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700313
Jeff Sharkey367d15a2011-09-22 14:59:51 -0700314 // watch for networkType changes that aren't broadcast through
315 // CONNECTIVITY_ACTION_IMMEDIATE above.
316 mTeleManager.listen(mPhoneListener, LISTEN_DATA_CONNECTION_STATE);
317
Jeff Sharkey8e9992a2011-08-23 18:37:23 -0700318 registerPollAlarmLocked();
319 registerGlobalAlert();
320
Jeff Sharkey163e6442011-10-31 16:37:52 -0700321 mDropBox = (DropBoxManager) mContext.getSystemService(Context.DROPBOX_SERVICE);
Jeff Sharkey75279902011-05-24 18:39:45 -0700322 }
323
Jeff Sharkey3f391352011-06-05 17:42:53 -0700324 private void shutdownLocked() {
Jeff Sharkeyb09540f2011-06-19 01:08:12 -0700325 mContext.unregisterReceiver(mConnReceiver);
Jeff Sharkey367d15a2011-09-22 14:59:51 -0700326 mContext.unregisterReceiver(mTetherReceiver);
Jeff Sharkey3f391352011-06-05 17:42:53 -0700327 mContext.unregisterReceiver(mPollReceiver);
Jeff Sharkeyb09540f2011-06-19 01:08:12 -0700328 mContext.unregisterReceiver(mRemovedReceiver);
Jeff Sharkey3f391352011-06-05 17:42:53 -0700329 mContext.unregisterReceiver(mShutdownReceiver);
330
Jeff Sharkey367d15a2011-09-22 14:59:51 -0700331 mTeleManager.listen(mPhoneListener, LISTEN_NONE);
332
Jeff Sharkeyc506ff62011-11-17 11:59:29 -0800333 if (mNetworkStatsLoaded) {
334 writeNetworkDevStatsLocked();
335 writeNetworkXtStatsLocked();
336 }
Jeff Sharkeyaf833932011-06-17 11:18:27 -0700337 if (mUidStatsLoaded) {
338 writeUidStatsLocked();
339 }
Jeff Sharkey905b5892011-09-30 15:19:49 -0700340 mNetworkDevStats.clear();
341 mNetworkXtStats.clear();
Jeff Sharkey39ebc212011-06-11 17:25:42 -0700342 mUidStats.clear();
Jeff Sharkeyc506ff62011-11-17 11:59:29 -0800343 mNetworkStatsLoaded = false;
Jeff Sharkey39ebc212011-06-11 17:25:42 -0700344 mUidStatsLoaded = false;
Jeff Sharkey3f391352011-06-05 17:42:53 -0700345 }
346
Jeff Sharkey75279902011-05-24 18:39:45 -0700347 /**
348 * Clear any existing {@link #ACTION_NETWORK_STATS_POLL} alarms, and
Jeff Sharkey39ebc212011-06-11 17:25:42 -0700349 * reschedule based on current {@link NetworkStatsSettings#getPollInterval()}.
Jeff Sharkey75279902011-05-24 18:39:45 -0700350 */
Jeff Sharkey8e9992a2011-08-23 18:37:23 -0700351 private void registerPollAlarmLocked() {
352 try {
353 if (mPollIntent != null) {
354 mAlarmManager.remove(mPollIntent);
355 }
356
357 mPollIntent = PendingIntent.getBroadcast(
358 mContext, 0, new Intent(ACTION_NETWORK_STATS_POLL), 0);
359
360 final long currentRealtime = SystemClock.elapsedRealtime();
361 mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME, currentRealtime,
362 mSettings.getPollInterval(), mPollIntent);
363 } catch (RemoteException e) {
Jeff Sharkeyb3d59572011-09-07 17:20:27 -0700364 // ignored; service lives in system_server
Jeff Sharkey75279902011-05-24 18:39:45 -0700365 }
Jeff Sharkey8e9992a2011-08-23 18:37:23 -0700366 }
Jeff Sharkey75279902011-05-24 18:39:45 -0700367
Jeff Sharkey8e9992a2011-08-23 18:37:23 -0700368 /**
369 * Register for a global alert that is delivered through
370 * {@link INetworkManagementEventObserver} once a threshold amount of data
371 * has been transferred.
372 */
373 private void registerGlobalAlert() {
374 try {
375 final long alertBytes = mSettings.getPersistThreshold();
376 mNetworkManager.setGlobalAlert(alertBytes);
377 } catch (IllegalStateException e) {
378 Slog.w(TAG, "problem registering for global alert: " + e);
379 } catch (RemoteException e) {
Jeff Sharkeyb3d59572011-09-07 17:20:27 -0700380 // ignored; service lives in system_server
Jeff Sharkey8e9992a2011-08-23 18:37:23 -0700381 }
Jeff Sharkey75279902011-05-24 18:39:45 -0700382 }
383
384 @Override
Jeff Sharkey63d27a92011-08-03 17:04:22 -0700385 public NetworkStatsHistory getHistoryForNetwork(NetworkTemplate template, int fields) {
Jeff Sharkey21c9c452011-06-07 12:26:43 -0700386 mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
Jeff Sharkey905b5892011-09-30 15:19:49 -0700387 return getHistoryForNetworkDev(template, fields);
388 }
Jeff Sharkeyd2a45872011-05-28 20:56:34 -0700389
Jeff Sharkey905b5892011-09-30 15:19:49 -0700390 private NetworkStatsHistory getHistoryForNetworkDev(NetworkTemplate template, int fields) {
391 return getHistoryForNetwork(template, fields, mNetworkDevStats);
392 }
393
394 private NetworkStatsHistory getHistoryForNetworkXt(NetworkTemplate template, int fields) {
395 return getHistoryForNetwork(template, fields, mNetworkXtStats);
396 }
397
398 private NetworkStatsHistory getHistoryForNetwork(NetworkTemplate template, int fields,
399 HashMap<NetworkIdentitySet, NetworkStatsHistory> source) {
Jeff Sharkeyd2a45872011-05-28 20:56:34 -0700400 synchronized (mStatsLock) {
401 // combine all interfaces that match template
Jeff Sharkey61ee0bb2011-05-29 22:50:42 -0700402 final NetworkStatsHistory combined = new NetworkStatsHistory(
Jeff Sharkey63d27a92011-08-03 17:04:22 -0700403 mSettings.getNetworkBucketDuration(), estimateNetworkBuckets(), fields);
Jeff Sharkey905b5892011-09-30 15:19:49 -0700404 for (NetworkIdentitySet ident : source.keySet()) {
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -0700405 if (templateMatches(template, ident)) {
Jeff Sharkey905b5892011-09-30 15:19:49 -0700406 final NetworkStatsHistory history = source.get(ident);
Jeff Sharkeyd03fd3f2011-06-19 20:55:09 -0700407 if (history != null) {
408 combined.recordEntireHistory(history);
409 }
Jeff Sharkeyd2a45872011-05-28 20:56:34 -0700410 }
411 }
412 return combined;
413 }
Jeff Sharkey75279902011-05-24 18:39:45 -0700414 }
415
416 @Override
Jeff Sharkey63d27a92011-08-03 17:04:22 -0700417 public NetworkStatsHistory getHistoryForUid(
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700418 NetworkTemplate template, int uid, int set, int tag, int fields) {
Jeff Sharkey21c9c452011-06-07 12:26:43 -0700419 mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
Jeff Sharkeyd2a45872011-05-28 20:56:34 -0700420
Jeff Sharkey39ebc212011-06-11 17:25:42 -0700421 synchronized (mStatsLock) {
Jeff Sharkey39ebc212011-06-11 17:25:42 -0700422 ensureUidStatsLoadedLocked();
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -0700423
424 // combine all interfaces that match template
425 final NetworkStatsHistory combined = new NetworkStatsHistory(
Jeff Sharkey63d27a92011-08-03 17:04:22 -0700426 mSettings.getUidBucketDuration(), estimateUidBuckets(), fields);
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700427 for (UidStatsKey key : mUidStats.keySet()) {
428 final boolean setMatches = set == SET_ALL || key.set == set;
429 if (templateMatches(template, key.ident) && key.uid == uid && setMatches
430 && key.tag == tag) {
431 final NetworkStatsHistory history = mUidStats.get(key);
432 combined.recordEntireHistory(history);
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -0700433 }
434 }
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700435
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -0700436 return combined;
Jeff Sharkey39ebc212011-06-11 17:25:42 -0700437 }
Jeff Sharkey75279902011-05-24 18:39:45 -0700438 }
439
Jeff Sharkeyd2a45872011-05-28 20:56:34 -0700440 @Override
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -0700441 public NetworkStats getSummaryForNetwork(NetworkTemplate template, long start, long end) {
Jeff Sharkey21c9c452011-06-07 12:26:43 -0700442 mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
Jeff Sharkey905b5892011-09-30 15:19:49 -0700443 return getSummaryForNetworkDev(template, start, end);
444 }
Jeff Sharkey21c9c452011-06-07 12:26:43 -0700445
Jeff Sharkey905b5892011-09-30 15:19:49 -0700446 private NetworkStats getSummaryForNetworkDev(NetworkTemplate template, long start, long end) {
447 return getSummaryForNetwork(template, start, end, mNetworkDevStats);
448 }
449
450 private NetworkStats getSummaryForNetworkXt(NetworkTemplate template, long start, long end) {
451 return getSummaryForNetwork(template, start, end, mNetworkXtStats);
452 }
453
454 private NetworkStats getSummaryForNetwork(NetworkTemplate template, long start, long end,
455 HashMap<NetworkIdentitySet, NetworkStatsHistory> source) {
Jeff Sharkey21c9c452011-06-07 12:26:43 -0700456 synchronized (mStatsLock) {
Jeff Sharkey434962e2011-07-12 20:20:56 -0700457 // use system clock to be externally consistent
458 final long now = System.currentTimeMillis();
459
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700460 final NetworkStats stats = new NetworkStats(end - start, 1);
461 final NetworkStats.Entry entry = new NetworkStats.Entry();
Jeff Sharkey434962e2011-07-12 20:20:56 -0700462 NetworkStatsHistory.Entry historyEntry = null;
Jeff Sharkey21c9c452011-06-07 12:26:43 -0700463
464 // combine total from all interfaces that match template
Jeff Sharkey905b5892011-09-30 15:19:49 -0700465 for (NetworkIdentitySet ident : source.keySet()) {
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -0700466 if (templateMatches(template, ident)) {
Jeff Sharkey905b5892011-09-30 15:19:49 -0700467 final NetworkStatsHistory history = source.get(ident);
Jeff Sharkey434962e2011-07-12 20:20:56 -0700468 historyEntry = history.getValues(start, end, now, historyEntry);
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700469
470 entry.iface = IFACE_ALL;
471 entry.uid = UID_ALL;
472 entry.tag = TAG_NONE;
Jeff Sharkey434962e2011-07-12 20:20:56 -0700473 entry.rxBytes = historyEntry.rxBytes;
Jeff Sharkey07b0dd92011-09-01 13:06:19 -0700474 entry.rxPackets = historyEntry.rxPackets;
Jeff Sharkey434962e2011-07-12 20:20:56 -0700475 entry.txBytes = historyEntry.txBytes;
Jeff Sharkey07b0dd92011-09-01 13:06:19 -0700476 entry.txPackets = historyEntry.txPackets;
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700477
478 stats.combineValues(entry);
Jeff Sharkey21c9c452011-06-07 12:26:43 -0700479 }
480 }
481
Jeff Sharkey4a971222011-06-11 22:16:55 -0700482 return stats;
Jeff Sharkey21c9c452011-06-07 12:26:43 -0700483 }
484 }
485
Jeff Sharkey684c54a2011-11-16 17:46:30 -0800486 private long getHistoryStartLocked(
487 NetworkTemplate template, HashMap<NetworkIdentitySet, NetworkStatsHistory> source) {
488 long start = Long.MAX_VALUE;
489 for (NetworkIdentitySet ident : source.keySet()) {
490 if (templateMatches(template, ident)) {
491 final NetworkStatsHistory history = source.get(ident);
492 start = Math.min(start, history.getStart());
493 }
494 }
495 return start;
496 }
497
Jeff Sharkey21c9c452011-06-07 12:26:43 -0700498 @Override
Jeff Sharkeyd03fd3f2011-06-19 20:55:09 -0700499 public NetworkStats getSummaryForAllUid(
500 NetworkTemplate template, long start, long end, boolean includeTags) {
Jeff Sharkey21c9c452011-06-07 12:26:43 -0700501 mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
Jeff Sharkeyd2a45872011-05-28 20:56:34 -0700502
Jeff Sharkey19862bf2011-06-02 17:38:22 -0700503 synchronized (mStatsLock) {
Jeff Sharkey39ebc212011-06-11 17:25:42 -0700504 ensureUidStatsLoadedLocked();
505
Jeff Sharkey434962e2011-07-12 20:20:56 -0700506 // use system clock to be externally consistent
507 final long now = System.currentTimeMillis();
508
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -0700509 final NetworkStats stats = new NetworkStats(end - start, 24);
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700510 final NetworkStats.Entry entry = new NetworkStats.Entry();
Jeff Sharkey434962e2011-07-12 20:20:56 -0700511 NetworkStatsHistory.Entry historyEntry = null;
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -0700512
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700513 for (UidStatsKey key : mUidStats.keySet()) {
514 if (templateMatches(template, key.ident)) {
515 // always include summary under TAG_NONE, and include
516 // other tags when requested.
517 if (key.tag == TAG_NONE || includeTags) {
518 final NetworkStatsHistory history = mUidStats.get(key);
519 historyEntry = history.getValues(start, end, now, historyEntry);
Jeff Sharkeyd03fd3f2011-06-19 20:55:09 -0700520
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700521 entry.iface = IFACE_ALL;
522 entry.uid = key.uid;
523 entry.set = key.set;
524 entry.tag = key.tag;
525 entry.rxBytes = historyEntry.rxBytes;
526 entry.rxPackets = historyEntry.rxPackets;
527 entry.txBytes = historyEntry.txBytes;
528 entry.txPackets = historyEntry.txPackets;
529 entry.operations = historyEntry.operations;
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700530
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700531 if (entry.rxBytes > 0 || entry.rxPackets > 0 || entry.txBytes > 0
532 || entry.txPackets > 0 || entry.operations > 0) {
533 stats.combineValues(entry);
Jeff Sharkeyd03fd3f2011-06-19 20:55:09 -0700534 }
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -0700535 }
536 }
Jeff Sharkey19862bf2011-06-02 17:38:22 -0700537 }
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -0700538
Jeff Sharkey4a971222011-06-11 22:16:55 -0700539 return stats;
Jeff Sharkey19862bf2011-06-02 17:38:22 -0700540 }
Jeff Sharkeyd2a45872011-05-28 20:56:34 -0700541 }
542
Jeff Sharkey350083e2011-06-29 10:45:16 -0700543 @Override
Jeff Sharkeya63ba592011-07-19 23:47:12 -0700544 public NetworkStats getDataLayerSnapshotForUid(int uid) throws RemoteException {
545 if (Binder.getCallingUid() != uid) {
546 mContext.enforceCallingOrSelfPermission(ACCESS_NETWORK_STATE, TAG);
547 }
548
549 // TODO: switch to data layer stats once kernel exports
550 // for now, read network layer stats and flatten across all ifaces
Jeff Sharkey4529bb62011-12-14 10:31:54 -0800551 final long token = Binder.clearCallingIdentity();
552 final NetworkStats networkLayer;
553 try {
554 networkLayer = mNetworkManager.getNetworkStatsUidDetail(uid);
555 } finally {
556 Binder.restoreCallingIdentity(token);
557 }
558
Jeff Sharkeya63ba592011-07-19 23:47:12 -0700559 final NetworkStats dataLayer = new NetworkStats(
560 networkLayer.getElapsedRealtime(), networkLayer.size());
561
562 NetworkStats.Entry entry = null;
563 for (int i = 0; i < networkLayer.size(); i++) {
564 entry = networkLayer.getValues(i, entry);
565 entry.iface = IFACE_ALL;
566 dataLayer.combineValues(entry);
567 }
568
569 // splice in operation counts
570 dataLayer.spliceOperationsFrom(mOperations);
571 return dataLayer;
572 }
573
574 @Override
575 public void incrementOperationCount(int uid, int tag, int operationCount) {
576 if (Binder.getCallingUid() != uid) {
577 mContext.enforceCallingOrSelfPermission(MODIFY_NETWORK_ACCOUNTING, TAG);
578 }
579
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700580 if (operationCount < 0) {
581 throw new IllegalArgumentException("operation count can only be incremented");
582 }
583 if (tag == TAG_NONE) {
584 throw new IllegalArgumentException("operation count must have specific tag");
585 }
586
Jeff Sharkeya63ba592011-07-19 23:47:12 -0700587 synchronized (mStatsLock) {
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700588 final int set = mActiveUidCounterSet.get(uid, SET_DEFAULT);
589 mOperations.combineValues(IFACE_ALL, uid, set, tag, 0L, 0L, 0L, 0L, operationCount);
590 mOperations.combineValues(IFACE_ALL, uid, set, TAG_NONE, 0L, 0L, 0L, 0L, operationCount);
591 }
592 }
593
594 @Override
595 public void setUidForeground(int uid, boolean uidForeground) {
596 mContext.enforceCallingOrSelfPermission(MODIFY_NETWORK_ACCOUNTING, TAG);
597
598 synchronized (mStatsLock) {
599 final int set = uidForeground ? SET_FOREGROUND : SET_DEFAULT;
600 final int oldSet = mActiveUidCounterSet.get(uid, SET_DEFAULT);
601 if (oldSet != set) {
602 mActiveUidCounterSet.put(uid, set);
603 setKernelCounterSet(uid, set);
604 }
Jeff Sharkeya63ba592011-07-19 23:47:12 -0700605 }
606 }
607
608 @Override
Jeff Sharkey350083e2011-06-29 10:45:16 -0700609 public void forceUpdate() {
610 mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
Jeff Sharkey1f0b13b2011-09-18 13:30:23 -0700611 performPoll(FLAG_PERSIST_ALL);
Jeff Sharkey350083e2011-06-29 10:45:16 -0700612 }
613
Jeff Sharkey75279902011-05-24 18:39:45 -0700614 /**
Jeff Sharkeyd2a45872011-05-28 20:56:34 -0700615 * Receiver that watches for {@link IConnectivityManager} to claim network
Jeff Sharkey75279902011-05-24 18:39:45 -0700616 * interfaces. Used to associate {@link TelephonyManager#getSubscriberId()}
617 * with mobile interfaces.
618 */
Jeff Sharkeyb09540f2011-06-19 01:08:12 -0700619 private BroadcastReceiver mConnReceiver = new BroadcastReceiver() {
Jeff Sharkey75279902011-05-24 18:39:45 -0700620 @Override
621 public void onReceive(Context context, Intent intent) {
Jeff Sharkeyd2a45872011-05-28 20:56:34 -0700622 // on background handler thread, and verified CONNECTIVITY_INTERNAL
623 // permission above.
Jeff Sharkey367d15a2011-09-22 14:59:51 -0700624 updateIfaces();
Jeff Sharkey75279902011-05-24 18:39:45 -0700625 }
626 };
627
Jeff Sharkeycdd02c5d2011-09-16 01:52:49 -0700628 /**
629 * Receiver that watches for {@link Tethering} to claim interface pairs.
630 */
631 private BroadcastReceiver mTetherReceiver = new BroadcastReceiver() {
632 @Override
633 public void onReceive(Context context, Intent intent) {
634 // on background handler thread, and verified CONNECTIVITY_INTERNAL
635 // permission above.
Jeff Sharkey1f0b13b2011-09-18 13:30:23 -0700636 performPoll(FLAG_PERSIST_NETWORK);
Jeff Sharkeycdd02c5d2011-09-16 01:52:49 -0700637 }
638 };
639
Jeff Sharkey75279902011-05-24 18:39:45 -0700640 private BroadcastReceiver mPollReceiver = new BroadcastReceiver() {
641 @Override
642 public void onReceive(Context context, Intent intent) {
Jeff Sharkeyd2a45872011-05-28 20:56:34 -0700643 // on background handler thread, and verified UPDATE_DEVICE_STATS
644 // permission above.
Jeff Sharkey1f0b13b2011-09-18 13:30:23 -0700645 performPoll(FLAG_PERSIST_ALL);
Jeff Sharkey8e9992a2011-08-23 18:37:23 -0700646
647 // verify that we're watching global alert
648 registerGlobalAlert();
Jeff Sharkey75279902011-05-24 18:39:45 -0700649 }
650 };
651
Jeff Sharkeyb09540f2011-06-19 01:08:12 -0700652 private BroadcastReceiver mRemovedReceiver = new BroadcastReceiver() {
653 @Override
654 public void onReceive(Context context, Intent intent) {
655 // on background handler thread, and UID_REMOVED is protected
656 // broadcast.
657 final int uid = intent.getIntExtra(EXTRA_UID, 0);
658 synchronized (mStatsLock) {
Jeff Sharkey62489262011-07-17 12:53:28 -0700659 mWakeLock.acquire();
660 try {
661 removeUidLocked(uid);
662 } finally {
663 mWakeLock.release();
664 }
Jeff Sharkeyb09540f2011-06-19 01:08:12 -0700665 }
666 }
667 };
668
Jeff Sharkey75279902011-05-24 18:39:45 -0700669 private BroadcastReceiver mShutdownReceiver = new BroadcastReceiver() {
670 @Override
671 public void onReceive(Context context, Intent intent) {
Jeff Sharkeyb09540f2011-06-19 01:08:12 -0700672 // SHUTDOWN is protected broadcast.
Jeff Sharkey75279902011-05-24 18:39:45 -0700673 synchronized (mStatsLock) {
Jeff Sharkey3f391352011-06-05 17:42:53 -0700674 shutdownLocked();
Jeff Sharkey75279902011-05-24 18:39:45 -0700675 }
676 }
677 };
678
Jeff Sharkeyd2a45872011-05-28 20:56:34 -0700679 /**
Jeff Sharkey8e9992a2011-08-23 18:37:23 -0700680 * Observer that watches for {@link INetworkManagementService} alerts.
681 */
682 private INetworkManagementEventObserver mAlertObserver = new NetworkAlertObserver() {
683 @Override
684 public void limitReached(String limitName, String iface) {
685 // only someone like NMS should be calling us
686 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
687
688 if (LIMIT_GLOBAL_ALERT.equals(limitName)) {
689 // kick off background poll to collect network stats; UID stats
690 // are handled during normal polling interval.
Jeff Sharkey1f0b13b2011-09-18 13:30:23 -0700691 final int flags = FLAG_PERSIST_NETWORK;
Jeff Sharkeyb3d59572011-09-07 17:20:27 -0700692 mHandler.obtainMessage(MSG_PERFORM_POLL, flags, 0).sendToTarget();
Jeff Sharkey8e9992a2011-08-23 18:37:23 -0700693
694 // re-arm global alert for next update
695 registerGlobalAlert();
696 }
697 }
698 };
699
Jeff Sharkey367d15a2011-09-22 14:59:51 -0700700 private int mLastPhoneState = TelephonyManager.DATA_UNKNOWN;
701 private int mLastPhoneNetworkType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
702
703 /**
704 * Receiver that watches for {@link TelephonyManager} changes, such as
705 * transitioning between network types.
706 */
707 private PhoneStateListener mPhoneListener = new PhoneStateListener() {
708 @Override
709 public void onDataConnectionStateChanged(int state, int networkType) {
710 final boolean stateChanged = state != mLastPhoneState;
711 final boolean networkTypeChanged = networkType != mLastPhoneNetworkType;
712
713 if (networkTypeChanged && !stateChanged) {
714 // networkType changed without a state change, which means we
715 // need to roll our own update. delay long enough for
716 // ConnectivityManager to process.
717 // TODO: add direct event to ConnectivityService instead of
718 // relying on this delay.
719 if (LOGV) Slog.v(TAG, "triggering delayed updateIfaces()");
720 mHandler.sendMessageDelayed(
721 mHandler.obtainMessage(MSG_UPDATE_IFACES), SECOND_IN_MILLIS);
722 }
723
724 mLastPhoneState = state;
725 mLastPhoneNetworkType = networkType;
726 }
727 };
728
729 private void updateIfaces() {
730 synchronized (mStatsLock) {
731 mWakeLock.acquire();
732 try {
733 updateIfacesLocked();
734 } finally {
735 mWakeLock.release();
736 }
737 }
738 }
739
Jeff Sharkey8e9992a2011-08-23 18:37:23 -0700740 /**
Jeff Sharkeyd2a45872011-05-28 20:56:34 -0700741 * Inspect all current {@link NetworkState} to derive mapping from {@code
742 * iface} to {@link NetworkStatsHistory}. When multiple {@link NetworkInfo}
743 * are active on a single {@code iface}, they are combined under a single
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -0700744 * {@link NetworkIdentitySet}.
Jeff Sharkeyd2a45872011-05-28 20:56:34 -0700745 */
746 private void updateIfacesLocked() {
Jeff Sharkey39ebc212011-06-11 17:25:42 -0700747 if (LOGV) Slog.v(TAG, "updateIfacesLocked()");
Jeff Sharkeyd2a45872011-05-28 20:56:34 -0700748
749 // take one last stats snapshot before updating iface mapping. this
750 // isn't perfect, since the kernel may already be counting traffic from
751 // the updated network.
Jeff Sharkeyb3d59572011-09-07 17:20:27 -0700752
Jeff Sharkey1f0b13b2011-09-18 13:30:23 -0700753 // poll, but only persist network stats to keep codepath fast. UID stats
754 // will be persisted during next alarm poll event.
755 performPollLocked(FLAG_PERSIST_NETWORK);
Jeff Sharkeyd2a45872011-05-28 20:56:34 -0700756
757 final NetworkState[] states;
758 try {
759 states = mConnManager.getAllNetworkState();
760 } catch (RemoteException e) {
Jeff Sharkeyb3d59572011-09-07 17:20:27 -0700761 // ignored; service lives in system_server
Jeff Sharkeyd2a45872011-05-28 20:56:34 -0700762 return;
763 }
764
765 // rebuild active interfaces based on connected networks
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -0700766 mActiveIfaces.clear();
Jeff Sharkeyd2a45872011-05-28 20:56:34 -0700767
768 for (NetworkState state : states) {
769 if (state.networkInfo.isConnected()) {
770 // collect networks under their parent interfaces
771 final String iface = state.linkProperties.getInterfaceName();
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -0700772
773 NetworkIdentitySet ident = mActiveIfaces.get(iface);
774 if (ident == null) {
775 ident = new NetworkIdentitySet();
776 mActiveIfaces.put(iface, ident);
777 }
778
Jeff Sharkeyd2a45872011-05-28 20:56:34 -0700779 ident.add(NetworkIdentity.buildNetworkIdentity(mContext, state));
780 }
781 }
782 }
783
Jeff Sharkey39ebc212011-06-11 17:25:42 -0700784 /**
Jeff Sharkey8e9992a2011-08-23 18:37:23 -0700785 * Bootstrap initial stats snapshot, usually during {@link #systemReady()}
786 * so we have baseline values without double-counting.
787 */
788 private void bootstrapStats() {
789 try {
Jeff Sharkey8e9992a2011-08-23 18:37:23 -0700790 mLastPollUidSnapshot = mNetworkManager.getNetworkStatsUidDetail(UID_ALL);
Jeff Sharkey905b5892011-09-30 15:19:49 -0700791 mLastPollNetworkDevSnapshot = mNetworkManager.getNetworkStatsSummary();
792 mLastPollNetworkXtSnapshot = computeNetworkXtSnapshotFromUid(mLastPollUidSnapshot);
Jeff Sharkey8e9992a2011-08-23 18:37:23 -0700793 mLastPollOperationsSnapshot = new NetworkStats(0L, 0);
794 } catch (IllegalStateException e) {
795 Slog.w(TAG, "problem reading network stats: " + e);
796 } catch (RemoteException e) {
Jeff Sharkeyb3d59572011-09-07 17:20:27 -0700797 // ignored; service lives in system_server
Jeff Sharkey8e9992a2011-08-23 18:37:23 -0700798 }
799 }
800
Jeff Sharkeyb3d59572011-09-07 17:20:27 -0700801 private void performPoll(int flags) {
Jeff Sharkey8e9992a2011-08-23 18:37:23 -0700802 synchronized (mStatsLock) {
803 mWakeLock.acquire();
Jeff Sharkey684c54a2011-11-16 17:46:30 -0800804
805 // try refreshing time source when stale
806 if (mTime.getCacheAge() > mSettings.getTimeCacheMaxAge()) {
807 mTime.forceRefresh();
808 }
809
Jeff Sharkey8e9992a2011-08-23 18:37:23 -0700810 try {
Jeff Sharkeyb3d59572011-09-07 17:20:27 -0700811 performPollLocked(flags);
Jeff Sharkey8e9992a2011-08-23 18:37:23 -0700812 } finally {
813 mWakeLock.release();
814 }
815 }
816 }
817
818 /**
Jeff Sharkey39ebc212011-06-11 17:25:42 -0700819 * Periodic poll operation, reading current statistics and recording into
820 * {@link NetworkStatsHistory}.
Jeff Sharkey39ebc212011-06-11 17:25:42 -0700821 */
Jeff Sharkeyb3d59572011-09-07 17:20:27 -0700822 private void performPollLocked(int flags) {
823 if (LOGV) Slog.v(TAG, "performPollLocked(flags=0x" + Integer.toHexString(flags) + ")");
Jeff Sharkey8e9992a2011-08-23 18:37:23 -0700824 final long startRealtime = SystemClock.elapsedRealtime();
Jeff Sharkey75279902011-05-24 18:39:45 -0700825
Jeff Sharkeyb3d59572011-09-07 17:20:27 -0700826 final boolean persistNetwork = (flags & FLAG_PERSIST_NETWORK) != 0;
827 final boolean persistUid = (flags & FLAG_PERSIST_UID) != 0;
Jeff Sharkey1f0b13b2011-09-18 13:30:23 -0700828 final boolean persistForce = (flags & FLAG_PERSIST_FORCE) != 0;
Jeff Sharkeyb3d59572011-09-07 17:20:27 -0700829
Jeff Sharkey75279902011-05-24 18:39:45 -0700830 // TODO: consider marking "untrusted" times in historical stats
831 final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis()
832 : System.currentTimeMillis();
Jeff Sharkeyb3d59572011-09-07 17:20:27 -0700833 final long threshold = mSettings.getPersistThreshold();
Jeff Sharkey75279902011-05-24 18:39:45 -0700834
Jeff Sharkey905b5892011-09-30 15:19:49 -0700835 final NetworkStats uidSnapshot;
836 final NetworkStats networkXtSnapshot;
837 final NetworkStats networkDevSnapshot;
Jeff Sharkey75279902011-05-24 18:39:45 -0700838 try {
Jeff Sharkey905b5892011-09-30 15:19:49 -0700839 // collect any tethering stats
Jeff Sharkeyd4ef8c8f2011-11-10 17:54:23 -0800840 final NetworkStats tetherSnapshot = getNetworkStatsTethering();
Jeff Sharkeycdd02c5d2011-09-16 01:52:49 -0700841
Jeff Sharkey905b5892011-09-30 15:19:49 -0700842 // record uid stats, folding in tethering stats
843 uidSnapshot = mNetworkManager.getNetworkStatsUidDetail(UID_ALL);
844 uidSnapshot.combineAllValues(tetherSnapshot);
Jeff Sharkey1f0b13b2011-09-18 13:30:23 -0700845 performUidPollLocked(uidSnapshot, currentTime);
Jeff Sharkeycdd02c5d2011-09-16 01:52:49 -0700846
Jeff Sharkey905b5892011-09-30 15:19:49 -0700847 // record dev network stats
848 networkDevSnapshot = mNetworkManager.getNetworkStatsSummary();
849 performNetworkDevPollLocked(networkDevSnapshot, currentTime);
Jeff Sharkey367d15a2011-09-22 14:59:51 -0700850
Jeff Sharkey905b5892011-09-30 15:19:49 -0700851 // record xt network stats
852 networkXtSnapshot = computeNetworkXtSnapshotFromUid(uidSnapshot);
853 performNetworkXtPollLocked(networkXtSnapshot, currentTime);
Jeff Sharkey367d15a2011-09-22 14:59:51 -0700854
Jeff Sharkeyb3d59572011-09-07 17:20:27 -0700855 } catch (IllegalStateException e) {
856 Log.wtf(TAG, "problem reading network stats", e);
Jeff Sharkey905b5892011-09-30 15:19:49 -0700857 return;
Jeff Sharkeyb3d59572011-09-07 17:20:27 -0700858 } catch (RemoteException e) {
859 // ignored; service lives in system_server
Jeff Sharkey905b5892011-09-30 15:19:49 -0700860 return;
861 }
862
863 // persist when enough network data has occurred
864 final long persistNetworkDevDelta = computeStatsDelta(
Jeff Sharkey3359aca2011-11-08 18:08:48 -0800865 mLastPersistNetworkDevSnapshot, networkDevSnapshot, true, "devp").getTotalBytes();
Jeff Sharkey905b5892011-09-30 15:19:49 -0700866 final long persistNetworkXtDelta = computeStatsDelta(
Jeff Sharkey3359aca2011-11-08 18:08:48 -0800867 mLastPersistNetworkXtSnapshot, networkXtSnapshot, true, "xtp").getTotalBytes();
Jeff Sharkey905b5892011-09-30 15:19:49 -0700868 final boolean networkOverThreshold = persistNetworkDevDelta > threshold
869 || persistNetworkXtDelta > threshold;
870 if (persistForce || (persistNetwork && networkOverThreshold)) {
871 writeNetworkDevStatsLocked();
872 writeNetworkXtStatsLocked();
873 mLastPersistNetworkDevSnapshot = networkDevSnapshot;
874 mLastPersistNetworkXtSnapshot = networkXtSnapshot;
875 }
876
877 // persist when enough uid data has occurred
Jeff Sharkey163e6442011-10-31 16:37:52 -0700878 final long persistUidDelta = computeStatsDelta(
Jeff Sharkey3359aca2011-11-08 18:08:48 -0800879 mLastPersistUidSnapshot, uidSnapshot, true, "uidp").getTotalBytes();
Jeff Sharkey905b5892011-09-30 15:19:49 -0700880 if (persistForce || (persistUid && persistUidDelta > threshold)) {
881 writeUidStatsLocked();
882 mLastPersistUidSnapshot = uidSnapshot;
Jeff Sharkey61ee0bb2011-05-29 22:50:42 -0700883 }
Jeff Sharkey497e4432011-06-14 17:27:29 -0700884
Jeff Sharkey8e9992a2011-08-23 18:37:23 -0700885 if (LOGV) {
886 final long duration = SystemClock.elapsedRealtime() - startRealtime;
887 Slog.v(TAG, "performPollLocked() took " + duration + "ms");
888 }
889
Jeff Sharkey905b5892011-09-30 15:19:49 -0700890 if (ENABLE_SAMPLE_AFTER_POLL) {
891 // sample stats after each full poll
892 performSample();
893 }
Jeff Sharkey07b0dd92011-09-01 13:06:19 -0700894
Jeff Sharkey497e4432011-06-14 17:27:29 -0700895 // finally, dispatch updated event to any listeners
896 final Intent updatedIntent = new Intent(ACTION_NETWORK_STATS_UPDATED);
897 updatedIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
898 mContext.sendBroadcast(updatedIntent, READ_NETWORK_USAGE_HISTORY);
Jeff Sharkey61ee0bb2011-05-29 22:50:42 -0700899 }
900
901 /**
Jeff Sharkey905b5892011-09-30 15:19:49 -0700902 * Update {@link #mNetworkDevStats} historical usage.
Jeff Sharkey61ee0bb2011-05-29 22:50:42 -0700903 */
Jeff Sharkey905b5892011-09-30 15:19:49 -0700904 private void performNetworkDevPollLocked(NetworkStats networkDevSnapshot, long currentTime) {
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -0700905 final HashSet<String> unknownIface = Sets.newHashSet();
Jeff Sharkeyd2a45872011-05-28 20:56:34 -0700906
Jeff Sharkey905b5892011-09-30 15:19:49 -0700907 final NetworkStats delta = computeStatsDelta(
Jeff Sharkey3359aca2011-11-08 18:08:48 -0800908 mLastPollNetworkDevSnapshot, networkDevSnapshot, false, "dev");
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700909 final long timeStart = currentTime - delta.getElapsedRealtime();
910
911 NetworkStats.Entry entry = null;
912 for (int i = 0; i < delta.size(); i++) {
913 entry = delta.getValues(i, entry);
914 final NetworkIdentitySet ident = mActiveIfaces.get(entry.iface);
Jeff Sharkeyd2a45872011-05-28 20:56:34 -0700915 if (ident == null) {
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700916 unknownIface.add(entry.iface);
Jeff Sharkey75279902011-05-24 18:39:45 -0700917 continue;
918 }
919
Jeff Sharkey905b5892011-09-30 15:19:49 -0700920 final NetworkStatsHistory history = findOrCreateNetworkDevStatsLocked(ident);
Jeff Sharkeya63ba592011-07-19 23:47:12 -0700921 history.recordData(timeStart, currentTime, entry);
Jeff Sharkeyd03fd3f2011-06-19 20:55:09 -0700922 }
923
Jeff Sharkey905b5892011-09-30 15:19:49 -0700924 mLastPollNetworkDevSnapshot = networkDevSnapshot;
Jeff Sharkey75279902011-05-24 18:39:45 -0700925
Jeff Sharkeyd2a45872011-05-28 20:56:34 -0700926 if (LOGD && unknownIface.size() > 0) {
Jeff Sharkey905b5892011-09-30 15:19:49 -0700927 Slog.w(TAG, "unknown dev interfaces " + unknownIface + ", ignoring those stats");
928 }
929 }
930
931 /**
932 * Update {@link #mNetworkXtStats} historical usage.
933 */
934 private void performNetworkXtPollLocked(NetworkStats networkXtSnapshot, long currentTime) {
935 final HashSet<String> unknownIface = Sets.newHashSet();
936
937 final NetworkStats delta = computeStatsDelta(
Jeff Sharkey3359aca2011-11-08 18:08:48 -0800938 mLastPollNetworkXtSnapshot, networkXtSnapshot, false, "xt");
Jeff Sharkey905b5892011-09-30 15:19:49 -0700939 final long timeStart = currentTime - delta.getElapsedRealtime();
940
941 NetworkStats.Entry entry = null;
942 for (int i = 0; i < delta.size(); i++) {
943 entry = delta.getValues(i, entry);
944 final NetworkIdentitySet ident = mActiveIfaces.get(entry.iface);
945 if (ident == null) {
946 unknownIface.add(entry.iface);
947 continue;
948 }
949
950 final NetworkStatsHistory history = findOrCreateNetworkXtStatsLocked(ident);
951 history.recordData(timeStart, currentTime, entry);
952 }
953
954 mLastPollNetworkXtSnapshot = networkXtSnapshot;
955
956 if (LOGD && unknownIface.size() > 0) {
957 Slog.w(TAG, "unknown xt interfaces " + unknownIface + ", ignoring those stats");
Jeff Sharkeyd2a45872011-05-28 20:56:34 -0700958 }
Jeff Sharkey75279902011-05-24 18:39:45 -0700959 }
960
Jeff Sharkey61ee0bb2011-05-29 22:50:42 -0700961 /**
Jeff Sharkey39ebc212011-06-11 17:25:42 -0700962 * Update {@link #mUidStats} historical usage.
Jeff Sharkey61ee0bb2011-05-29 22:50:42 -0700963 */
Jeff Sharkeyd03fd3f2011-06-19 20:55:09 -0700964 private void performUidPollLocked(NetworkStats uidSnapshot, long currentTime) {
Jeff Sharkey39ebc212011-06-11 17:25:42 -0700965 ensureUidStatsLoadedLocked();
966
Jeff Sharkey163e6442011-10-31 16:37:52 -0700967 final NetworkStats delta = computeStatsDelta(
Jeff Sharkey3359aca2011-11-08 18:08:48 -0800968 mLastPollUidSnapshot, uidSnapshot, false, "uid");
Jeff Sharkeya63ba592011-07-19 23:47:12 -0700969 final NetworkStats operationsDelta = computeStatsDelta(
Jeff Sharkey3359aca2011-11-08 18:08:48 -0800970 mLastPollOperationsSnapshot, mOperations, false, "uidop");
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700971 final long timeStart = currentTime - delta.getElapsedRealtime();
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -0700972
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700973 NetworkStats.Entry entry = null;
Jeff Sharkeya63ba592011-07-19 23:47:12 -0700974 NetworkStats.Entry operationsEntry = null;
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700975 for (int i = 0; i < delta.size(); i++) {
976 entry = delta.getValues(i, entry);
977 final NetworkIdentitySet ident = mActiveIfaces.get(entry.iface);
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -0700978 if (ident == null) {
Jeff Sharkeyb3d59572011-09-07 17:20:27 -0700979 if (entry.rxBytes > 0 || entry.rxPackets > 0 || entry.txBytes > 0
980 || entry.txPackets > 0) {
981 Log.w(TAG, "dropping UID delta from unknown iface: " + entry);
982 }
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -0700983 continue;
Jeff Sharkey39ebc212011-06-11 17:25:42 -0700984 }
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -0700985
Jeff Sharkeya63ba592011-07-19 23:47:12 -0700986 // splice in operation counts since last poll
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700987 final int j = operationsDelta.findIndex(IFACE_ALL, entry.uid, entry.set, entry.tag);
Jeff Sharkeya63ba592011-07-19 23:47:12 -0700988 if (j != -1) {
989 operationsEntry = operationsDelta.getValues(j, operationsEntry);
990 entry.operations = operationsEntry.operations;
991 }
992
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700993 final NetworkStatsHistory history = findOrCreateUidStatsLocked(
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700994 ident, entry.uid, entry.set, entry.tag);
Jeff Sharkeya63ba592011-07-19 23:47:12 -0700995 history.recordData(timeStart, currentTime, entry);
Jeff Sharkey61ee0bb2011-05-29 22:50:42 -0700996 }
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -0700997
Jeff Sharkey8e9992a2011-08-23 18:37:23 -0700998 mLastPollUidSnapshot = uidSnapshot;
Jeff Sharkey4abb1b82011-11-08 17:35:28 -0800999 mLastPollOperationsSnapshot = mOperations.clone();
Jeff Sharkey61ee0bb2011-05-29 22:50:42 -07001000 }
1001
Jeff Sharkeyb09540f2011-06-19 01:08:12 -07001002 /**
Jeff Sharkey07b0dd92011-09-01 13:06:19 -07001003 * Sample recent statistics summary into {@link EventLog}.
1004 */
1005 private void performSample() {
Jeff Sharkey1f0b13b2011-09-18 13:30:23 -07001006 final long largestBucketSize = Math.max(
1007 mSettings.getNetworkBucketDuration(), mSettings.getUidBucketDuration());
1008
1009 // take sample as atomic buckets
1010 final long now = mTime.hasCache() ? mTime.currentTimeMillis() : System.currentTimeMillis();
1011 final long end = now - (now % largestBucketSize) + largestBucketSize;
1012 final long start = end - largestBucketSize;
Jeff Sharkey07b0dd92011-09-01 13:06:19 -07001013
Jeff Sharkey905b5892011-09-30 15:19:49 -07001014 final long trustedTime = mTime.hasCache() ? mTime.currentTimeMillis() : -1;
Jeff Sharkey684c54a2011-11-16 17:46:30 -08001015 long devHistoryStart = Long.MAX_VALUE;
Jeff Sharkey905b5892011-09-30 15:19:49 -07001016
Jeff Sharkey07b0dd92011-09-01 13:06:19 -07001017 NetworkTemplate template = null;
Jeff Sharkey905b5892011-09-30 15:19:49 -07001018 NetworkStats.Entry devTotal = null;
1019 NetworkStats.Entry xtTotal = null;
Jeff Sharkey07b0dd92011-09-01 13:06:19 -07001020 NetworkStats.Entry uidTotal = null;
1021
1022 // collect mobile sample
1023 template = buildTemplateMobileAll(getActiveSubscriberId(mContext));
Jeff Sharkey905b5892011-09-30 15:19:49 -07001024 devTotal = getSummaryForNetworkDev(template, start, end).getTotal(devTotal);
Jeff Sharkey684c54a2011-11-16 17:46:30 -08001025 devHistoryStart = getHistoryStartLocked(template, mNetworkDevStats);
Jeff Sharkey905b5892011-09-30 15:19:49 -07001026 xtTotal = getSummaryForNetworkXt(template, start, end).getTotal(xtTotal);
Jeff Sharkey07b0dd92011-09-01 13:06:19 -07001027 uidTotal = getSummaryForAllUid(template, start, end, false).getTotal(uidTotal);
Jeff Sharkey684c54a2011-11-16 17:46:30 -08001028
Jeff Sharkey905b5892011-09-30 15:19:49 -07001029 EventLogTags.writeNetstatsMobileSample(
1030 devTotal.rxBytes, devTotal.rxPackets, devTotal.txBytes, devTotal.txPackets,
1031 xtTotal.rxBytes, xtTotal.rxPackets, xtTotal.txBytes, xtTotal.txPackets,
1032 uidTotal.rxBytes, uidTotal.rxPackets, uidTotal.txBytes, uidTotal.txPackets,
Jeff Sharkey684c54a2011-11-16 17:46:30 -08001033 trustedTime, devHistoryStart);
Jeff Sharkey07b0dd92011-09-01 13:06:19 -07001034
1035 // collect wifi sample
1036 template = buildTemplateWifi();
Jeff Sharkey905b5892011-09-30 15:19:49 -07001037 devTotal = getSummaryForNetworkDev(template, start, end).getTotal(devTotal);
Jeff Sharkey684c54a2011-11-16 17:46:30 -08001038 devHistoryStart = getHistoryStartLocked(template, mNetworkDevStats);
Jeff Sharkey905b5892011-09-30 15:19:49 -07001039 xtTotal = getSummaryForNetworkXt(template, start, end).getTotal(xtTotal);
Jeff Sharkey07b0dd92011-09-01 13:06:19 -07001040 uidTotal = getSummaryForAllUid(template, start, end, false).getTotal(uidTotal);
Jeff Sharkey905b5892011-09-30 15:19:49 -07001041 EventLogTags.writeNetstatsWifiSample(
1042 devTotal.rxBytes, devTotal.rxPackets, devTotal.txBytes, devTotal.txPackets,
1043 xtTotal.rxBytes, xtTotal.rxPackets, xtTotal.txBytes, xtTotal.txPackets,
1044 uidTotal.rxBytes, uidTotal.rxPackets, uidTotal.txBytes, uidTotal.txPackets,
Jeff Sharkey684c54a2011-11-16 17:46:30 -08001045 trustedTime, devHistoryStart);
Jeff Sharkey07b0dd92011-09-01 13:06:19 -07001046 }
1047
1048 /**
Jeff Sharkeyb09540f2011-06-19 01:08:12 -07001049 * Clean up {@link #mUidStats} after UID is removed.
1050 */
1051 private void removeUidLocked(int uid) {
1052 ensureUidStatsLoadedLocked();
1053
Jeff Sharkey163e6442011-10-31 16:37:52 -07001054 // perform one last poll before removing
1055 performPollLocked(FLAG_PERSIST_ALL);
1056
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -07001057 final ArrayList<UidStatsKey> knownKeys = Lists.newArrayList();
1058 knownKeys.addAll(mUidStats.keySet());
1059
Jeff Sharkeyb09540f2011-06-19 01:08:12 -07001060 // migrate all UID stats into special "removed" bucket
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -07001061 for (UidStatsKey key : knownKeys) {
1062 if (key.uid == uid) {
1063 // only migrate combined TAG_NONE history
1064 if (key.tag == TAG_NONE) {
1065 final NetworkStatsHistory uidHistory = mUidStats.get(key);
1066 final NetworkStatsHistory removedHistory = findOrCreateUidStatsLocked(
1067 key.ident, UID_REMOVED, SET_DEFAULT, TAG_NONE);
1068 removedHistory.recordEntireHistory(uidHistory);
Jeff Sharkeyd03fd3f2011-06-19 20:55:09 -07001069 }
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -07001070 mUidStats.remove(key);
Jeff Sharkeyb09540f2011-06-19 01:08:12 -07001071 }
1072 }
1073
Jeff Sharkey163e6442011-10-31 16:37:52 -07001074 // clear UID from current stats snapshot
Jeff Sharkeyd04ff112011-12-12 18:51:26 -08001075 if (mLastPollUidSnapshot != null) {
1076 mLastPollUidSnapshot = mLastPollUidSnapshot.withoutUid(uid);
1077 mLastPollNetworkXtSnapshot = computeNetworkXtSnapshotFromUid(mLastPollUidSnapshot);
1078 }
Jeff Sharkey163e6442011-10-31 16:37:52 -07001079
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -07001080 // clear kernel stats associated with UID
1081 resetKernelUidStats(uid);
Jeff Sharkeyb09540f2011-06-19 01:08:12 -07001082
1083 // since this was radical rewrite, push to disk
1084 writeUidStatsLocked();
1085 }
1086
Jeff Sharkey905b5892011-09-30 15:19:49 -07001087 private NetworkStatsHistory findOrCreateNetworkXtStatsLocked(NetworkIdentitySet ident) {
1088 return findOrCreateNetworkStatsLocked(ident, mNetworkXtStats);
1089 }
1090
1091 private NetworkStatsHistory findOrCreateNetworkDevStatsLocked(NetworkIdentitySet ident) {
1092 return findOrCreateNetworkStatsLocked(ident, mNetworkDevStats);
1093 }
1094
1095 private NetworkStatsHistory findOrCreateNetworkStatsLocked(
1096 NetworkIdentitySet ident, HashMap<NetworkIdentitySet, NetworkStatsHistory> source) {
1097 final NetworkStatsHistory existing = source.get(ident);
Jeff Sharkey39ebc212011-06-11 17:25:42 -07001098
1099 // update when no existing, or when bucket duration changed
Jeff Sharkeyd03fd3f2011-06-19 20:55:09 -07001100 final long bucketDuration = mSettings.getNetworkBucketDuration();
Jeff Sharkey39ebc212011-06-11 17:25:42 -07001101 NetworkStatsHistory updated = null;
1102 if (existing == null) {
Jeff Sharkey4a971222011-06-11 22:16:55 -07001103 updated = new NetworkStatsHistory(bucketDuration, 10);
Jeff Sharkeyd37948f2011-07-12 13:57:00 -07001104 } else if (existing.getBucketDuration() != bucketDuration) {
Jeff Sharkey4a971222011-06-11 22:16:55 -07001105 updated = new NetworkStatsHistory(
1106 bucketDuration, estimateResizeBuckets(existing, bucketDuration));
Jeff Sharkey39ebc212011-06-11 17:25:42 -07001107 updated.recordEntireHistory(existing);
Jeff Sharkey61ee0bb2011-05-29 22:50:42 -07001108 }
Jeff Sharkey39ebc212011-06-11 17:25:42 -07001109
1110 if (updated != null) {
Jeff Sharkey905b5892011-09-30 15:19:49 -07001111 source.put(ident, updated);
Jeff Sharkey39ebc212011-06-11 17:25:42 -07001112 return updated;
1113 } else {
1114 return existing;
1115 }
Jeff Sharkey61ee0bb2011-05-29 22:50:42 -07001116 }
1117
Jeff Sharkeyd03fd3f2011-06-19 20:55:09 -07001118 private NetworkStatsHistory findOrCreateUidStatsLocked(
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -07001119 NetworkIdentitySet ident, int uid, int set, int tag) {
Jeff Sharkeyb09540f2011-06-19 01:08:12 -07001120 ensureUidStatsLoadedLocked();
1121
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -07001122 final UidStatsKey key = new UidStatsKey(ident, uid, set, tag);
1123 final NetworkStatsHistory existing = mUidStats.get(key);
Jeff Sharkey39ebc212011-06-11 17:25:42 -07001124
1125 // update when no existing, or when bucket duration changed
Jeff Sharkeyd03fd3f2011-06-19 20:55:09 -07001126 final long bucketDuration = mSettings.getUidBucketDuration();
Jeff Sharkey39ebc212011-06-11 17:25:42 -07001127 NetworkStatsHistory updated = null;
1128 if (existing == null) {
Jeff Sharkey4a971222011-06-11 22:16:55 -07001129 updated = new NetworkStatsHistory(bucketDuration, 10);
Jeff Sharkeyd37948f2011-07-12 13:57:00 -07001130 } else if (existing.getBucketDuration() != bucketDuration) {
Jeff Sharkey4a971222011-06-11 22:16:55 -07001131 updated = new NetworkStatsHistory(
1132 bucketDuration, estimateResizeBuckets(existing, bucketDuration));
Jeff Sharkey39ebc212011-06-11 17:25:42 -07001133 updated.recordEntireHistory(existing);
Jeff Sharkey75279902011-05-24 18:39:45 -07001134 }
Jeff Sharkey39ebc212011-06-11 17:25:42 -07001135
1136 if (updated != null) {
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -07001137 mUidStats.put(key, updated);
Jeff Sharkey39ebc212011-06-11 17:25:42 -07001138 return updated;
1139 } else {
1140 return existing;
1141 }
Jeff Sharkey75279902011-05-24 18:39:45 -07001142 }
1143
Jeff Sharkey905b5892011-09-30 15:19:49 -07001144 private void readNetworkDevStatsLocked() {
1145 if (LOGV) Slog.v(TAG, "readNetworkDevStatsLocked()");
1146 readNetworkStats(mNetworkDevFile, mNetworkDevStats);
1147 }
Jeff Sharkey3f391352011-06-05 17:42:53 -07001148
Jeff Sharkey905b5892011-09-30 15:19:49 -07001149 private void readNetworkXtStatsLocked() {
1150 if (LOGV) Slog.v(TAG, "readNetworkXtStatsLocked()");
1151 readNetworkStats(mNetworkXtFile, mNetworkXtStats);
1152 }
1153
1154 private static void readNetworkStats(
1155 AtomicFile inputFile, HashMap<NetworkIdentitySet, NetworkStatsHistory> output) {
Jeff Sharkey3f391352011-06-05 17:42:53 -07001156 // clear any existing stats and read from disk
Jeff Sharkey905b5892011-09-30 15:19:49 -07001157 output.clear();
Jeff Sharkey3f391352011-06-05 17:42:53 -07001158
Jeff Sharkey4e814c32011-07-14 20:37:37 -07001159 DataInputStream in = null;
Jeff Sharkey3f391352011-06-05 17:42:53 -07001160 try {
Jeff Sharkey905b5892011-09-30 15:19:49 -07001161 in = new DataInputStream(new BufferedInputStream(inputFile.openRead()));
Jeff Sharkey3f391352011-06-05 17:42:53 -07001162
1163 // verify file magic header intact
1164 final int magic = in.readInt();
1165 if (magic != FILE_MAGIC) {
1166 throw new ProtocolException("unexpected magic: " + magic);
1167 }
1168
1169 final int version = in.readInt();
1170 switch (version) {
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001171 case VERSION_NETWORK_INIT: {
1172 // network := size *(NetworkIdentitySet NetworkStatsHistory)
Jeff Sharkey3f391352011-06-05 17:42:53 -07001173 final int size = in.readInt();
1174 for (int i = 0; i < size; i++) {
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001175 final NetworkIdentitySet ident = new NetworkIdentitySet(in);
Jeff Sharkey3f391352011-06-05 17:42:53 -07001176 final NetworkStatsHistory history = new NetworkStatsHistory(in);
Jeff Sharkey905b5892011-09-30 15:19:49 -07001177 output.put(ident, history);
Jeff Sharkey3f391352011-06-05 17:42:53 -07001178 }
1179 break;
1180 }
1181 default: {
1182 throw new ProtocolException("unexpected version: " + version);
1183 }
1184 }
1185 } catch (FileNotFoundException e) {
1186 // missing stats is okay, probably first boot
1187 } catch (IOException e) {
Jeff Sharkeyb3d59572011-09-07 17:20:27 -07001188 Log.wtf(TAG, "problem reading network stats", e);
Jeff Sharkey3f391352011-06-05 17:42:53 -07001189 } finally {
Jeff Sharkey4e814c32011-07-14 20:37:37 -07001190 IoUtils.closeQuietly(in);
Jeff Sharkey3f391352011-06-05 17:42:53 -07001191 }
Jeff Sharkey75279902011-05-24 18:39:45 -07001192 }
1193
Jeff Sharkey39ebc212011-06-11 17:25:42 -07001194 private void ensureUidStatsLoadedLocked() {
1195 if (!mUidStatsLoaded) {
1196 readUidStatsLocked();
1197 mUidStatsLoaded = true;
1198 }
1199 }
1200
1201 private void readUidStatsLocked() {
1202 if (LOGV) Slog.v(TAG, "readUidStatsLocked()");
1203
1204 // clear any existing stats and read from disk
1205 mUidStats.clear();
1206
Jeff Sharkey4e814c32011-07-14 20:37:37 -07001207 DataInputStream in = null;
Jeff Sharkey39ebc212011-06-11 17:25:42 -07001208 try {
Jeff Sharkey4e814c32011-07-14 20:37:37 -07001209 in = new DataInputStream(new BufferedInputStream(mUidFile.openRead()));
Jeff Sharkey39ebc212011-06-11 17:25:42 -07001210
1211 // verify file magic header intact
1212 final int magic = in.readInt();
1213 if (magic != FILE_MAGIC) {
1214 throw new ProtocolException("unexpected magic: " + magic);
1215 }
1216
1217 final int version = in.readInt();
1218 switch (version) {
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001219 case VERSION_UID_INIT: {
Jeff Sharkey39ebc212011-06-11 17:25:42 -07001220 // uid := size *(UID NetworkStatsHistory)
1221
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001222 // drop this data version, since we don't have a good
1223 // mapping into NetworkIdentitySet.
1224 break;
1225 }
1226 case VERSION_UID_WITH_IDENT: {
1227 // uid := size *(NetworkIdentitySet size *(UID NetworkStatsHistory))
Jeff Sharkeyd03fd3f2011-06-19 20:55:09 -07001228
1229 // drop this data version, since this version only existed
1230 // for a short time.
1231 break;
1232 }
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -07001233 case VERSION_UID_WITH_TAG:
1234 case VERSION_UID_WITH_SET: {
1235 // uid := size *(NetworkIdentitySet size *(uid set tag NetworkStatsHistory))
1236 final int identSize = in.readInt();
1237 for (int i = 0; i < identSize; i++) {
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001238 final NetworkIdentitySet ident = new NetworkIdentitySet(in);
Jeff Sharkey39ebc212011-06-11 17:25:42 -07001239
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -07001240 final int size = in.readInt();
1241 for (int j = 0; j < size; j++) {
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001242 final int uid = in.readInt();
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -07001243 final int set = (version >= VERSION_UID_WITH_SET) ? in.readInt()
1244 : SET_DEFAULT;
Jeff Sharkeyd03fd3f2011-06-19 20:55:09 -07001245 final int tag = in.readInt();
Jeff Sharkeyd03fd3f2011-06-19 20:55:09 -07001246
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -07001247 final UidStatsKey key = new UidStatsKey(ident, uid, set, tag);
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001248 final NetworkStatsHistory history = new NetworkStatsHistory(in);
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -07001249 mUidStats.put(key, history);
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001250 }
Jeff Sharkey39ebc212011-06-11 17:25:42 -07001251 }
1252 break;
1253 }
1254 default: {
1255 throw new ProtocolException("unexpected version: " + version);
1256 }
1257 }
1258 } catch (FileNotFoundException e) {
1259 // missing stats is okay, probably first boot
1260 } catch (IOException e) {
Jeff Sharkeyb3d59572011-09-07 17:20:27 -07001261 Log.wtf(TAG, "problem reading uid stats", e);
Jeff Sharkey39ebc212011-06-11 17:25:42 -07001262 } finally {
Jeff Sharkey4e814c32011-07-14 20:37:37 -07001263 IoUtils.closeQuietly(in);
Jeff Sharkey39ebc212011-06-11 17:25:42 -07001264 }
1265 }
1266
Jeff Sharkey905b5892011-09-30 15:19:49 -07001267 private void writeNetworkDevStatsLocked() {
1268 if (LOGV) Slog.v(TAG, "writeNetworkDevStatsLocked()");
1269 writeNetworkStats(mNetworkDevStats, mNetworkDevFile);
1270 }
Jeff Sharkey3f391352011-06-05 17:42:53 -07001271
Jeff Sharkey905b5892011-09-30 15:19:49 -07001272 private void writeNetworkXtStatsLocked() {
1273 if (LOGV) Slog.v(TAG, "writeNetworkXtStatsLocked()");
1274 writeNetworkStats(mNetworkXtStats, mNetworkXtFile);
1275 }
1276
1277 private void writeNetworkStats(
1278 HashMap<NetworkIdentitySet, NetworkStatsHistory> input, AtomicFile outputFile) {
Jeff Sharkeyd2a45872011-05-28 20:56:34 -07001279 // TODO: consider duplicating stats and releasing lock while writing
Jeff Sharkey3f391352011-06-05 17:42:53 -07001280
Jeff Sharkey1f0b13b2011-09-18 13:30:23 -07001281 // trim any history beyond max
1282 if (mTime.hasCache()) {
Jeff Sharkey684c54a2011-11-16 17:46:30 -08001283 final long systemCurrentTime = System.currentTimeMillis();
1284 final long trustedCurrentTime = mTime.currentTimeMillis();
1285
1286 final long currentTime = Math.min(systemCurrentTime, trustedCurrentTime);
Jeff Sharkey1f0b13b2011-09-18 13:30:23 -07001287 final long maxHistory = mSettings.getNetworkMaxHistory();
Jeff Sharkey684c54a2011-11-16 17:46:30 -08001288
Jeff Sharkey905b5892011-09-30 15:19:49 -07001289 for (NetworkStatsHistory history : input.values()) {
Jeff Sharkey684c54a2011-11-16 17:46:30 -08001290 final int beforeSize = history.size();
Jeff Sharkey1f0b13b2011-09-18 13:30:23 -07001291 history.removeBucketsBefore(currentTime - maxHistory);
Jeff Sharkey684c54a2011-11-16 17:46:30 -08001292 final int afterSize = history.size();
1293
1294 if (beforeSize > 24 && afterSize < beforeSize / 2) {
1295 // yikes, dropping more than half of significant history
1296 final StringBuilder builder = new StringBuilder();
1297 builder.append("yikes, dropping more than half of history").append('\n');
1298 builder.append("systemCurrentTime=").append(systemCurrentTime).append('\n');
1299 builder.append("trustedCurrentTime=").append(trustedCurrentTime).append('\n');
1300 builder.append("maxHistory=").append(maxHistory).append('\n');
1301 builder.append("beforeSize=").append(beforeSize).append('\n');
1302 builder.append("afterSize=").append(afterSize).append('\n');
1303 mDropBox.addText(TAG_NETSTATS_ERROR, builder.toString());
1304 }
Jeff Sharkey1f0b13b2011-09-18 13:30:23 -07001305 }
1306 }
1307
Jeff Sharkey3f391352011-06-05 17:42:53 -07001308 FileOutputStream fos = null;
1309 try {
Jeff Sharkey905b5892011-09-30 15:19:49 -07001310 fos = outputFile.startWrite();
Jeff Sharkey4e814c32011-07-14 20:37:37 -07001311 final DataOutputStream out = new DataOutputStream(new BufferedOutputStream(fos));
Jeff Sharkey3f391352011-06-05 17:42:53 -07001312
1313 out.writeInt(FILE_MAGIC);
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001314 out.writeInt(VERSION_NETWORK_INIT);
Jeff Sharkey3f391352011-06-05 17:42:53 -07001315
Jeff Sharkey905b5892011-09-30 15:19:49 -07001316 out.writeInt(input.size());
1317 for (NetworkIdentitySet ident : input.keySet()) {
1318 final NetworkStatsHistory history = input.get(ident);
Jeff Sharkey3f391352011-06-05 17:42:53 -07001319 ident.writeToStream(out);
1320 history.writeToStream(out);
1321 }
1322
Jeff Sharkey4e814c32011-07-14 20:37:37 -07001323 out.flush();
Jeff Sharkey905b5892011-09-30 15:19:49 -07001324 outputFile.finishWrite(fos);
Jeff Sharkey3f391352011-06-05 17:42:53 -07001325 } catch (IOException e) {
Jeff Sharkeyb3d59572011-09-07 17:20:27 -07001326 Log.wtf(TAG, "problem writing stats", e);
Jeff Sharkey3f391352011-06-05 17:42:53 -07001327 if (fos != null) {
Jeff Sharkey905b5892011-09-30 15:19:49 -07001328 outputFile.failWrite(fos);
Jeff Sharkey39ebc212011-06-11 17:25:42 -07001329 }
1330 }
1331 }
1332
1333 private void writeUidStatsLocked() {
1334 if (LOGV) Slog.v(TAG, "writeUidStatsLocked()");
1335
Jeff Sharkeyb09540f2011-06-19 01:08:12 -07001336 if (!mUidStatsLoaded) {
1337 Slog.w(TAG, "asked to write UID stats when not loaded; skipping");
1338 return;
1339 }
1340
Jeff Sharkey39ebc212011-06-11 17:25:42 -07001341 // TODO: consider duplicating stats and releasing lock while writing
1342
Jeff Sharkey1f0b13b2011-09-18 13:30:23 -07001343 // trim any history beyond max
1344 if (mTime.hasCache()) {
Jeff Sharkey7ee86582011-11-14 18:02:21 -08001345 final long currentTime = Math.min(
1346 System.currentTimeMillis(), mTime.currentTimeMillis());
Jeff Sharkey1f0b13b2011-09-18 13:30:23 -07001347 final long maxUidHistory = mSettings.getUidMaxHistory();
1348 final long maxTagHistory = mSettings.getTagMaxHistory();
1349 for (UidStatsKey key : mUidStats.keySet()) {
1350 final NetworkStatsHistory history = mUidStats.get(key);
1351
1352 // detailed tags are trimmed sooner than summary in TAG_NONE
1353 if (key.tag == TAG_NONE) {
1354 history.removeBucketsBefore(currentTime - maxUidHistory);
1355 } else {
1356 history.removeBucketsBefore(currentTime - maxTagHistory);
1357 }
1358 }
1359 }
1360
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -07001361 // build UidStatsKey lists grouped by ident
1362 final HashMap<NetworkIdentitySet, ArrayList<UidStatsKey>> keysByIdent = Maps.newHashMap();
1363 for (UidStatsKey key : mUidStats.keySet()) {
1364 ArrayList<UidStatsKey> keys = keysByIdent.get(key.ident);
1365 if (keys == null) {
1366 keys = Lists.newArrayList();
1367 keysByIdent.put(key.ident, keys);
1368 }
1369 keys.add(key);
1370 }
1371
Jeff Sharkey39ebc212011-06-11 17:25:42 -07001372 FileOutputStream fos = null;
1373 try {
1374 fos = mUidFile.startWrite();
Jeff Sharkey4e814c32011-07-14 20:37:37 -07001375 final DataOutputStream out = new DataOutputStream(new BufferedOutputStream(fos));
Jeff Sharkey39ebc212011-06-11 17:25:42 -07001376
1377 out.writeInt(FILE_MAGIC);
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -07001378 out.writeInt(VERSION_UID_WITH_SET);
Jeff Sharkey39ebc212011-06-11 17:25:42 -07001379
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -07001380 out.writeInt(keysByIdent.size());
1381 for (NetworkIdentitySet ident : keysByIdent.keySet()) {
1382 final ArrayList<UidStatsKey> keys = keysByIdent.get(ident);
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001383 ident.writeToStream(out);
Jeff Sharkey39ebc212011-06-11 17:25:42 -07001384
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -07001385 out.writeInt(keys.size());
1386 for (UidStatsKey key : keys) {
1387 final NetworkStatsHistory history = mUidStats.get(key);
1388 out.writeInt(key.uid);
1389 out.writeInt(key.set);
1390 out.writeInt(key.tag);
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001391 history.writeToStream(out);
1392 }
Jeff Sharkey39ebc212011-06-11 17:25:42 -07001393 }
1394
Jeff Sharkey4e814c32011-07-14 20:37:37 -07001395 out.flush();
Jeff Sharkey39ebc212011-06-11 17:25:42 -07001396 mUidFile.finishWrite(fos);
1397 } catch (IOException e) {
Jeff Sharkeyb3d59572011-09-07 17:20:27 -07001398 Log.wtf(TAG, "problem writing stats", e);
Jeff Sharkey39ebc212011-06-11 17:25:42 -07001399 if (fos != null) {
1400 mUidFile.failWrite(fos);
Jeff Sharkey3f391352011-06-05 17:42:53 -07001401 }
1402 }
Jeff Sharkey75279902011-05-24 18:39:45 -07001403 }
1404
1405 @Override
1406 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1407 mContext.enforceCallingOrSelfPermission(DUMP, TAG);
1408
Jeff Sharkey61ee0bb2011-05-29 22:50:42 -07001409 final HashSet<String> argSet = new HashSet<String>();
1410 for (String arg : args) {
1411 argSet.add(arg);
Jeff Sharkey75279902011-05-24 18:39:45 -07001412 }
1413
Jeff Sharkey350083e2011-06-29 10:45:16 -07001414 final boolean fullHistory = argSet.contains("full");
1415
Jeff Sharkey61ee0bb2011-05-29 22:50:42 -07001416 synchronized (mStatsLock) {
1417 // TODO: remove this testing code, since it corrupts stats
1418 if (argSet.contains("generate")) {
Jeff Sharkey293779f2011-10-05 23:31:57 -07001419 generateRandomLocked(args);
Jeff Sharkey61ee0bb2011-05-29 22:50:42 -07001420 pw.println("Generated stub stats");
1421 return;
1422 }
1423
Jeff Sharkey3f391352011-06-05 17:42:53 -07001424 if (argSet.contains("poll")) {
Jeff Sharkey1f0b13b2011-09-18 13:30:23 -07001425 performPollLocked(FLAG_PERSIST_ALL | FLAG_PERSIST_FORCE);
Jeff Sharkey3f391352011-06-05 17:42:53 -07001426 pw.println("Forced poll");
1427 return;
1428 }
1429
Jeff Sharkey61ee0bb2011-05-29 22:50:42 -07001430 pw.println("Active interfaces:");
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001431 for (String iface : mActiveIfaces.keySet()) {
1432 final NetworkIdentitySet ident = mActiveIfaces.get(iface);
Jeff Sharkey61ee0bb2011-05-29 22:50:42 -07001433 pw.print(" iface="); pw.print(iface);
1434 pw.print(" ident="); pw.println(ident.toString());
1435 }
1436
Jeff Sharkey905b5892011-09-30 15:19:49 -07001437 pw.println("Known historical dev stats:");
1438 for (NetworkIdentitySet ident : mNetworkDevStats.keySet()) {
1439 final NetworkStatsHistory history = mNetworkDevStats.get(ident);
1440 pw.print(" ident="); pw.println(ident.toString());
1441 history.dump(" ", pw, fullHistory);
1442 }
1443
1444 pw.println("Known historical xt stats:");
1445 for (NetworkIdentitySet ident : mNetworkXtStats.keySet()) {
1446 final NetworkStatsHistory history = mNetworkXtStats.get(ident);
Jeff Sharkey61ee0bb2011-05-29 22:50:42 -07001447 pw.print(" ident="); pw.println(ident.toString());
Jeff Sharkey350083e2011-06-29 10:45:16 -07001448 history.dump(" ", pw, fullHistory);
Jeff Sharkey61ee0bb2011-05-29 22:50:42 -07001449 }
1450
1451 if (argSet.contains("detail")) {
Jeff Sharkey39ebc212011-06-11 17:25:42 -07001452 // since explicitly requested with argument, we're okay to load
1453 // from disk if not already in memory.
1454 ensureUidStatsLoadedLocked();
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001455
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -07001456 final ArrayList<UidStatsKey> keys = Lists.newArrayList();
1457 keys.addAll(mUidStats.keySet());
1458 Collections.sort(keys);
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001459
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -07001460 pw.println("Detailed UID stats:");
1461 for (UidStatsKey key : keys) {
1462 pw.print(" ident="); pw.print(key.ident.toString());
1463 pw.print(" uid="); pw.print(key.uid);
1464 pw.print(" set="); pw.print(NetworkStats.setToString(key.set));
1465 pw.print(" tag="); pw.println(NetworkStats.tagToString(key.tag));
1466
1467 final NetworkStatsHistory history = mUidStats.get(key);
1468 history.dump(" ", pw, fullHistory);
Jeff Sharkey61ee0bb2011-05-29 22:50:42 -07001469 }
1470 }
1471 }
1472 }
1473
1474 /**
1475 * @deprecated only for temporary testing
1476 */
1477 @Deprecated
Jeff Sharkey293779f2011-10-05 23:31:57 -07001478 private void generateRandomLocked(String[] args) {
1479 final long totalBytes = Long.parseLong(args[1]);
1480 final long totalTime = Long.parseLong(args[2]);
1481
1482 final PackageManager pm = mContext.getPackageManager();
1483 final ArrayList<Integer> specialUidList = Lists.newArrayList();
1484 for (int i = 3; i < args.length; i++) {
1485 try {
1486 specialUidList.add(pm.getApplicationInfo(args[i], 0).uid);
1487 } catch (NameNotFoundException e) {
1488 throw new RuntimeException(e);
1489 }
1490 }
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001491
Jeff Sharkey293779f2011-10-05 23:31:57 -07001492 final HashSet<Integer> otherUidSet = Sets.newHashSet();
1493 for (ApplicationInfo info : pm.getInstalledApplications(0)) {
1494 if (pm.checkPermission(android.Manifest.permission.INTERNET, info.packageName)
1495 == PackageManager.PERMISSION_GRANTED && !specialUidList.contains(info.uid)) {
1496 otherUidSet.add(info.uid);
1497 }
1498 }
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001499
Jeff Sharkey293779f2011-10-05 23:31:57 -07001500 final ArrayList<Integer> otherUidList = new ArrayList<Integer>(otherUidSet);
1501
1502 final long end = System.currentTimeMillis();
1503 final long start = end - totalTime;
Jeff Sharkey61ee0bb2011-05-29 22:50:42 -07001504
Jeff Sharkey905b5892011-09-30 15:19:49 -07001505 mNetworkDevStats.clear();
1506 mNetworkXtStats.clear();
Jeff Sharkey39ebc212011-06-11 17:25:42 -07001507 mUidStats.clear();
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001508
Jeff Sharkey293779f2011-10-05 23:31:57 -07001509 final Random r = new Random();
1510 for (NetworkIdentitySet ident : mActiveIfaces.values()) {
1511 final NetworkStatsHistory devHistory = findOrCreateNetworkDevStatsLocked(ident);
1512 final NetworkStatsHistory xtHistory = findOrCreateNetworkXtStatsLocked(ident);
1513
1514 final ArrayList<Integer> uidList = new ArrayList<Integer>();
1515 uidList.addAll(specialUidList);
1516
1517 if (uidList.size() == 0) {
1518 Collections.shuffle(otherUidList);
1519 uidList.addAll(otherUidList);
1520 }
1521
1522 boolean first = true;
1523 long remainingBytes = totalBytes;
1524 for (int uid : uidList) {
1525 final NetworkStatsHistory defaultHistory = findOrCreateUidStatsLocked(
1526 ident, uid, SET_DEFAULT, TAG_NONE);
1527 final NetworkStatsHistory foregroundHistory = findOrCreateUidStatsLocked(
1528 ident, uid, SET_FOREGROUND, TAG_NONE);
1529
1530 final long uidBytes = totalBytes / uidList.size();
1531
1532 final float fractionDefault = r.nextFloat();
1533 final long defaultBytes = (long) (uidBytes * fractionDefault);
1534 final long foregroundBytes = (long) (uidBytes * (1 - fractionDefault));
1535
1536 defaultHistory.generateRandom(start, end, defaultBytes);
1537 foregroundHistory.generateRandom(start, end, foregroundBytes);
1538
1539 if (first) {
1540 final long bumpTime = (start + end) / 2;
1541 defaultHistory.recordData(
1542 bumpTime, bumpTime + DAY_IN_MILLIS, 200 * MB_IN_BYTES, 0);
1543 first = false;
1544 }
1545
1546 devHistory.recordEntireHistory(defaultHistory);
1547 devHistory.recordEntireHistory(foregroundHistory);
1548 xtHistory.recordEntireHistory(defaultHistory);
1549 xtHistory.recordEntireHistory(foregroundHistory);
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001550 }
Jeff Sharkey61ee0bb2011-05-29 22:50:42 -07001551 }
1552 }
1553
Jeff Sharkey75279902011-05-24 18:39:45 -07001554 /**
1555 * Return the delta between two {@link NetworkStats} snapshots, where {@code
1556 * before} can be {@code null}.
1557 */
Jeff Sharkey163e6442011-10-31 16:37:52 -07001558 private NetworkStats computeStatsDelta(
1559 NetworkStats before, NetworkStats current, boolean collectStale, String type) {
Jeff Sharkey75279902011-05-24 18:39:45 -07001560 if (before != null) {
Jeff Sharkey163e6442011-10-31 16:37:52 -07001561 try {
Jeff Sharkeyd4ef8c8f2011-11-10 17:54:23 -08001562 return current.subtract(before, false);
Jeff Sharkey163e6442011-10-31 16:37:52 -07001563 } catch (NonMonotonicException e) {
1564 Log.w(TAG, "found non-monotonic values; saving to dropbox");
1565
1566 // record error for debugging
1567 final StringBuilder builder = new StringBuilder();
Jeff Sharkey3359aca2011-11-08 18:08:48 -08001568 builder.append("found non-monotonic " + type + " values at left[" + e.leftIndex
Jeff Sharkey163e6442011-10-31 16:37:52 -07001569 + "] - right[" + e.rightIndex + "]\n");
1570 builder.append("left=").append(e.left).append('\n');
1571 builder.append("right=").append(e.right).append('\n');
1572 mDropBox.addText(TAG_NETSTATS_ERROR, builder.toString());
1573
Jeff Sharkeyd4ef8c8f2011-11-10 17:54:23 -08001574 try {
1575 // return clamped delta to help recover
1576 return current.subtract(before, true);
1577 } catch (NonMonotonicException e1) {
1578 Log.wtf(TAG, "found non-monotonic values; returning empty delta", e1);
1579 return new NetworkStats(0L, 10);
1580 }
Jeff Sharkey163e6442011-10-31 16:37:52 -07001581 }
Jeff Sharkey63d27a92011-08-03 17:04:22 -07001582 } else if (collectStale) {
1583 // caller is okay collecting stale stats for first call.
1584 return current;
Jeff Sharkey75279902011-05-24 18:39:45 -07001585 } else {
Jeff Sharkeya63ba592011-07-19 23:47:12 -07001586 // this is first snapshot; to prevent from double-counting we only
1587 // observe traffic occuring between known snapshots.
1588 return new NetworkStats(0L, 10);
Jeff Sharkey75279902011-05-24 18:39:45 -07001589 }
1590 }
1591
Jeff Sharkeyd4ef8c8f2011-11-10 17:54:23 -08001592 /**
1593 * Return snapshot of current tethering statistics. Will return empty
1594 * {@link NetworkStats} if any problems are encountered.
1595 */
1596 private NetworkStats getNetworkStatsTethering() throws RemoteException {
1597 try {
1598 final String[] tetheredIfacePairs = mConnManager.getTetheredIfacePairs();
1599 return mNetworkManager.getNetworkStatsTethering(tetheredIfacePairs);
1600 } catch (IllegalStateException e) {
1601 Log.wtf(TAG, "problem reading network stats", e);
1602 return new NetworkStats(0L, 10);
1603 }
1604 }
1605
Jeff Sharkey905b5892011-09-30 15:19:49 -07001606 private static NetworkStats computeNetworkXtSnapshotFromUid(NetworkStats uidSnapshot) {
1607 return uidSnapshot.groupedByIface();
1608 }
1609
Jeff Sharkey4a971222011-06-11 22:16:55 -07001610 private int estimateNetworkBuckets() {
1611 return (int) (mSettings.getNetworkMaxHistory() / mSettings.getNetworkBucketDuration());
1612 }
1613
1614 private int estimateUidBuckets() {
1615 return (int) (mSettings.getUidMaxHistory() / mSettings.getUidBucketDuration());
1616 }
1617
1618 private static int estimateResizeBuckets(NetworkStatsHistory existing, long newBucketDuration) {
Jeff Sharkeyd37948f2011-07-12 13:57:00 -07001619 return (int) (existing.size() * existing.getBucketDuration() / newBucketDuration);
Jeff Sharkey4a971222011-06-11 22:16:55 -07001620 }
1621
Jeff Sharkey39ebc212011-06-11 17:25:42 -07001622 /**
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001623 * Test if given {@link NetworkTemplate} matches any {@link NetworkIdentity}
1624 * in the given {@link NetworkIdentitySet}.
1625 */
1626 private static boolean templateMatches(NetworkTemplate template, NetworkIdentitySet identSet) {
1627 for (NetworkIdentity ident : identSet) {
1628 if (template.matches(ident)) {
1629 return true;
1630 }
1631 }
1632 return false;
1633 }
1634
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -07001635 private Handler.Callback mHandlerCallback = new Handler.Callback() {
1636 /** {@inheritDoc} */
1637 public boolean handleMessage(Message msg) {
1638 switch (msg.what) {
Jeff Sharkey8e9992a2011-08-23 18:37:23 -07001639 case MSG_PERFORM_POLL: {
Jeff Sharkeyb3d59572011-09-07 17:20:27 -07001640 final int flags = msg.arg1;
1641 performPoll(flags);
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -07001642 return true;
1643 }
Jeff Sharkey367d15a2011-09-22 14:59:51 -07001644 case MSG_UPDATE_IFACES: {
1645 updateIfaces();
1646 return true;
1647 }
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -07001648 default: {
1649 return false;
1650 }
1651 }
1652 }
1653 };
1654
Jeff Sharkey07b0dd92011-09-01 13:06:19 -07001655 private static String getActiveSubscriberId(Context context) {
1656 final TelephonyManager telephony = (TelephonyManager) context.getSystemService(
1657 Context.TELEPHONY_SERVICE);
1658 return telephony.getSubscriberId();
1659 }
1660
Jeff Sharkey418d12d2011-12-13 15:38:03 -08001661 private boolean isBandwidthControlEnabled() {
1662 try {
1663 return mNetworkManager.isBandwidthControlEnabled();
1664 } catch (RemoteException e) {
1665 // ignored; service lives in system_server
1666 return false;
1667 }
1668 }
1669
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -07001670 /**
1671 * Key uniquely identifying a {@link NetworkStatsHistory} for a UID.
1672 */
1673 private static class UidStatsKey implements Comparable<UidStatsKey> {
1674 public final NetworkIdentitySet ident;
1675 public final int uid;
1676 public final int set;
1677 public final int tag;
1678
1679 public UidStatsKey(NetworkIdentitySet ident, int uid, int set, int tag) {
1680 this.ident = ident;
1681 this.uid = uid;
1682 this.set = set;
1683 this.tag = tag;
1684 }
1685
1686 @Override
1687 public int hashCode() {
1688 return Objects.hashCode(ident, uid, set, tag);
1689 }
1690
1691 @Override
1692 public boolean equals(Object obj) {
1693 if (obj instanceof UidStatsKey) {
1694 final UidStatsKey key = (UidStatsKey) obj;
1695 return Objects.equal(ident, key.ident) && uid == key.uid && set == key.set
1696 && tag == key.tag;
1697 }
1698 return false;
1699 }
1700
1701 /** {@inheritDoc} */
1702 public int compareTo(UidStatsKey another) {
1703 return Integer.compare(uid, another.uid);
1704 }
1705 }
1706
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001707 /**
Jeff Sharkey39ebc212011-06-11 17:25:42 -07001708 * Default external settings that read from {@link Settings.Secure}.
1709 */
1710 private static class DefaultNetworkStatsSettings implements NetworkStatsSettings {
1711 private final ContentResolver mResolver;
1712
1713 public DefaultNetworkStatsSettings(Context context) {
1714 mResolver = checkNotNull(context.getContentResolver());
1715 // TODO: adjust these timings for production builds
1716 }
1717
1718 private long getSecureLong(String name, long def) {
1719 return Settings.Secure.getLong(mResolver, name, def);
1720 }
Jeff Sharkey991d1b12011-09-14 19:31:04 -07001721 private boolean getSecureBoolean(String name, boolean def) {
1722 final int defInt = def ? 1 : 0;
1723 return Settings.Secure.getInt(mResolver, name, defInt) != 0;
1724 }
Jeff Sharkey39ebc212011-06-11 17:25:42 -07001725
1726 public long getPollInterval() {
Jeff Sharkey8e9992a2011-08-23 18:37:23 -07001727 return getSecureLong(NETSTATS_POLL_INTERVAL, 30 * MINUTE_IN_MILLIS);
Jeff Sharkey39ebc212011-06-11 17:25:42 -07001728 }
1729 public long getPersistThreshold() {
Jeff Sharkeyb3d59572011-09-07 17:20:27 -07001730 return getSecureLong(NETSTATS_PERSIST_THRESHOLD, 2 * MB_IN_BYTES);
Jeff Sharkey39ebc212011-06-11 17:25:42 -07001731 }
1732 public long getNetworkBucketDuration() {
1733 return getSecureLong(NETSTATS_NETWORK_BUCKET_DURATION, HOUR_IN_MILLIS);
1734 }
1735 public long getNetworkMaxHistory() {
1736 return getSecureLong(NETSTATS_NETWORK_MAX_HISTORY, 90 * DAY_IN_MILLIS);
1737 }
1738 public long getUidBucketDuration() {
1739 return getSecureLong(NETSTATS_UID_BUCKET_DURATION, 2 * HOUR_IN_MILLIS);
1740 }
1741 public long getUidMaxHistory() {
1742 return getSecureLong(NETSTATS_UID_MAX_HISTORY, 90 * DAY_IN_MILLIS);
1743 }
Jeff Sharkeyd03fd3f2011-06-19 20:55:09 -07001744 public long getTagMaxHistory() {
1745 return getSecureLong(NETSTATS_TAG_MAX_HISTORY, 30 * DAY_IN_MILLIS);
1746 }
Jeff Sharkey39ebc212011-06-11 17:25:42 -07001747 public long getTimeCacheMaxAge() {
1748 return DAY_IN_MILLIS;
1749 }
1750 }
Jeff Sharkey75279902011-05-24 18:39:45 -07001751}