blob: 04dc917ec3abc4380de2094decaec90c11df9624 [file] [log] [blame]
Jeff Sharkey63abc372012-01-11 18:38:16 -08001/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
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
19import static android.net.NetworkStats.TAG_NONE;
Jeff Sharkeyac3fcb12012-05-02 18:11:52 -070020import static android.net.TrafficStats.KB_IN_BYTES;
21import static android.net.TrafficStats.MB_IN_BYTES;
Antonio Cansadocd42acd2016-02-17 13:03:38 -080022import static android.text.format.DateUtils.YEAR_IN_MILLIS;
Jeff Sharkey63abc372012-01-11 18:38:16 -080023import static com.android.internal.util.Preconditions.checkNotNull;
24
25import android.net.NetworkStats;
26import android.net.NetworkStats.NonMonotonicObserver;
27import android.net.NetworkStatsHistory;
28import android.net.NetworkTemplate;
29import android.net.TrafficStats;
Jeff Sharkey6de357e2012-05-09 13:33:52 -070030import android.os.DropBoxManager;
Jeff Sharkey63abc372012-01-11 18:38:16 -080031import android.util.Log;
Jeff Sharkeyac3fcb12012-05-02 18:11:52 -070032import android.util.MathUtils;
Jeff Sharkey63abc372012-01-11 18:38:16 -080033import android.util.Slog;
34
Wenchao Tongf5ea3402015-03-04 13:26:38 -080035import com.android.internal.net.VpnInfo;
Jeff Sharkey63abc372012-01-11 18:38:16 -080036import com.android.internal.util.FileRotator;
37import com.android.internal.util.IndentingPrintWriter;
38import com.google.android.collect.Sets;
39
Jeff Sharkey6de357e2012-05-09 13:33:52 -070040import java.io.ByteArrayOutputStream;
Jeff Sharkey63abc372012-01-11 18:38:16 -080041import java.io.DataOutputStream;
42import java.io.File;
43import java.io.IOException;
44import java.io.InputStream;
45import java.io.OutputStream;
Jeff Sharkey55a442e2014-11-18 18:22:21 -080046import java.io.PrintWriter;
Jeff Sharkey63abc372012-01-11 18:38:16 -080047import java.lang.ref.WeakReference;
Jeff Sharkeydaa57e82012-09-19 14:10:39 -070048import java.util.Arrays;
Jeff Sharkey63abc372012-01-11 18:38:16 -080049import java.util.HashSet;
50import java.util.Map;
51
Jeff Sharkey6de357e2012-05-09 13:33:52 -070052import libcore.io.IoUtils;
53
Jeff Sharkey63abc372012-01-11 18:38:16 -080054/**
55 * Logic to record deltas between periodic {@link NetworkStats} snapshots into
56 * {@link NetworkStatsHistory} that belong to {@link NetworkStatsCollection}.
57 * Keeps pending changes in memory until they pass a specific threshold, in
Antonio Cansadocd42acd2016-02-17 13:03:38 -080058 * bytes. Uses {@link FileRotator} for persistence logic if present.
Jeff Sharkey63abc372012-01-11 18:38:16 -080059 * <p>
60 * Not inherently thread safe.
61 */
62public class NetworkStatsRecorder {
63 private static final String TAG = "NetworkStatsRecorder";
Jeff Sharkeye7bb71d2012-02-28 15:13:08 -080064 private static final boolean LOGD = false;
Jeff Sharkey1f8ea2d2012-02-07 12:05:43 -080065 private static final boolean LOGV = false;
Jeff Sharkey63abc372012-01-11 18:38:16 -080066
Jeff Sharkey6de357e2012-05-09 13:33:52 -070067 private static final String TAG_NETSTATS_DUMP = "netstats_dump";
68
69 /** Dump before deleting in {@link #recoverFromWtf()}. */
70 private static final boolean DUMP_BEFORE_DELETE = true;
71
Jeff Sharkey63abc372012-01-11 18:38:16 -080072 private final FileRotator mRotator;
73 private final NonMonotonicObserver<String> mObserver;
Jeff Sharkey6de357e2012-05-09 13:33:52 -070074 private final DropBoxManager mDropBox;
Jeff Sharkey63abc372012-01-11 18:38:16 -080075 private final String mCookie;
76
77 private final long mBucketDuration;
Jeff Sharkey63abc372012-01-11 18:38:16 -080078 private final boolean mOnlyTags;
79
Jeff Sharkeyac3fcb12012-05-02 18:11:52 -070080 private long mPersistThresholdBytes = 2 * MB_IN_BYTES;
Jeff Sharkey63abc372012-01-11 18:38:16 -080081 private NetworkStats mLastSnapshot;
82
83 private final NetworkStatsCollection mPending;
84 private final NetworkStatsCollection mSinceBoot;
85
86 private final CombiningRewriter mPendingRewriter;
87
88 private WeakReference<NetworkStatsCollection> mComplete;
89
Antonio Cansadocd42acd2016-02-17 13:03:38 -080090 /**
91 * Non-persisted recorder, with only one bucket. Used by {@link NetworkStatsObservers}.
92 */
93 public NetworkStatsRecorder() {
94 mRotator = null;
95 mObserver = null;
96 mDropBox = null;
97 mCookie = null;
98
99 // set the bucket big enough to have all data in one bucket, but allow some
100 // slack to avoid overflow
101 mBucketDuration = YEAR_IN_MILLIS;
102 mOnlyTags = false;
103
104 mPending = null;
105 mSinceBoot = new NetworkStatsCollection(mBucketDuration);
106
107 mPendingRewriter = null;
108 }
109
110 /**
111 * Persisted recorder.
112 */
Jeff Sharkey63abc372012-01-11 18:38:16 -0800113 public NetworkStatsRecorder(FileRotator rotator, NonMonotonicObserver<String> observer,
Jeff Sharkey6de357e2012-05-09 13:33:52 -0700114 DropBoxManager dropBox, String cookie, long bucketDuration, boolean onlyTags) {
Jeff Sharkey63abc372012-01-11 18:38:16 -0800115 mRotator = checkNotNull(rotator, "missing FileRotator");
116 mObserver = checkNotNull(observer, "missing NonMonotonicObserver");
Jeff Sharkey6de357e2012-05-09 13:33:52 -0700117 mDropBox = checkNotNull(dropBox, "missing DropBoxManager");
Jeff Sharkey63abc372012-01-11 18:38:16 -0800118 mCookie = cookie;
119
120 mBucketDuration = bucketDuration;
Jeff Sharkey63abc372012-01-11 18:38:16 -0800121 mOnlyTags = onlyTags;
122
123 mPending = new NetworkStatsCollection(bucketDuration);
124 mSinceBoot = new NetworkStatsCollection(bucketDuration);
125
126 mPendingRewriter = new CombiningRewriter(mPending);
127 }
128
Jeff Sharkeyac3fcb12012-05-02 18:11:52 -0700129 public void setPersistThreshold(long thresholdBytes) {
130 if (LOGV) Slog.v(TAG, "setPersistThreshold() with " + thresholdBytes);
131 mPersistThresholdBytes = MathUtils.constrain(
132 thresholdBytes, 1 * KB_IN_BYTES, 100 * MB_IN_BYTES);
133 }
134
Jeff Sharkey63abc372012-01-11 18:38:16 -0800135 public void resetLocked() {
136 mLastSnapshot = null;
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800137 if (mPending != null) {
138 mPending.reset();
139 }
140 if (mSinceBoot != null) {
141 mSinceBoot.reset();
142 }
143 if (mComplete != null) {
144 mComplete.clear();
145 }
Jeff Sharkey63abc372012-01-11 18:38:16 -0800146 }
147
148 public NetworkStats.Entry getTotalSinceBootLocked(NetworkTemplate template) {
Jeff Davidson1efb1332015-12-09 18:04:50 -0800149 return mSinceBoot.getSummary(template, Long.MIN_VALUE, Long.MAX_VALUE,
150 NetworkStatsAccess.Level.DEVICE).getTotal(null);
Jeff Sharkey63abc372012-01-11 18:38:16 -0800151 }
152
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800153 public NetworkStatsCollection getSinceBoot() {
154 return mSinceBoot;
155 }
156
Jeff Sharkey63abc372012-01-11 18:38:16 -0800157 /**
158 * Load complete history represented by {@link FileRotator}. Caches
159 * internally as a {@link WeakReference}, and updated with future
160 * {@link #recordSnapshotLocked(NetworkStats, Map, long)} snapshots as long
161 * as reference is valid.
162 */
163 public NetworkStatsCollection getOrLoadCompleteLocked() {
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800164 checkNotNull(mRotator, "missing FileRotator");
Jeff Sharkey55a442e2014-11-18 18:22:21 -0800165 NetworkStatsCollection res = mComplete != null ? mComplete.get() : null;
166 if (res == null) {
167 res = loadLocked(Long.MIN_VALUE, Long.MAX_VALUE);
168 mComplete = new WeakReference<NetworkStatsCollection>(res);
Jeff Sharkey63abc372012-01-11 18:38:16 -0800169 }
Jeff Sharkey55a442e2014-11-18 18:22:21 -0800170 return res;
171 }
172
173 public NetworkStatsCollection getOrLoadPartialLocked(long start, long end) {
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800174 checkNotNull(mRotator, "missing FileRotator");
Jeff Sharkey55a442e2014-11-18 18:22:21 -0800175 NetworkStatsCollection res = mComplete != null ? mComplete.get() : null;
176 if (res == null) {
177 res = loadLocked(start, end);
178 }
179 return res;
180 }
181
182 private NetworkStatsCollection loadLocked(long start, long end) {
183 if (LOGD) Slog.d(TAG, "loadLocked() reading from disk for " + mCookie);
184 final NetworkStatsCollection res = new NetworkStatsCollection(mBucketDuration);
185 try {
186 mRotator.readMatching(res, start, end);
187 res.recordCollection(mPending);
188 } catch (IOException e) {
189 Log.wtf(TAG, "problem completely reading network stats", e);
190 recoverFromWtf();
191 } catch (OutOfMemoryError e) {
192 Log.wtf(TAG, "problem completely reading network stats", e);
193 recoverFromWtf();
194 }
195 return res;
Jeff Sharkey63abc372012-01-11 18:38:16 -0800196 }
197
198 /**
199 * Record any delta that occurred since last {@link NetworkStats} snapshot,
200 * using the given {@link Map} to identify network interfaces. First
201 * snapshot is considered bootstrap, and is not counted as delta.
202 */
203 public void recordSnapshotLocked(NetworkStats snapshot,
Wenchao Tongf5ea3402015-03-04 13:26:38 -0800204 Map<String, NetworkIdentitySet> ifaceIdent, VpnInfo[] vpnArray,
205 long currentTimeMillis) {
Jeff Sharkey63abc372012-01-11 18:38:16 -0800206 final HashSet<String> unknownIfaces = Sets.newHashSet();
207
Jeff Sharkeye8914c32012-05-01 16:26:09 -0700208 // skip recording when snapshot missing
209 if (snapshot == null) return;
210
Jeff Sharkey63abc372012-01-11 18:38:16 -0800211 // assume first snapshot is bootstrap and don't record
212 if (mLastSnapshot == null) {
213 mLastSnapshot = snapshot;
214 return;
215 }
216
217 final NetworkStatsCollection complete = mComplete != null ? mComplete.get() : null;
218
219 final NetworkStats delta = NetworkStats.subtract(
220 snapshot, mLastSnapshot, mObserver, mCookie);
221 final long end = currentTimeMillis;
222 final long start = end - delta.getElapsedRealtime();
223
Wenchao Tongf5ea3402015-03-04 13:26:38 -0800224 if (vpnArray != null) {
225 for (VpnInfo info : vpnArray) {
226 delta.migrateTun(info.ownerUid, info.vpnIface, info.primaryUnderlyingIface);
227 }
228 }
229
Jeff Sharkey63abc372012-01-11 18:38:16 -0800230 NetworkStats.Entry entry = null;
231 for (int i = 0; i < delta.size(); i++) {
232 entry = delta.getValues(i, entry);
233 final NetworkIdentitySet ident = ifaceIdent.get(entry.iface);
234 if (ident == null) {
235 unknownIfaces.add(entry.iface);
236 continue;
237 }
238
Jeff Sharkeyac3fcb12012-05-02 18:11:52 -0700239 // skip when no delta occurred
Jeff Sharkey63abc372012-01-11 18:38:16 -0800240 if (entry.isEmpty()) continue;
241
242 // only record tag data when requested
243 if ((entry.tag == TAG_NONE) != mOnlyTags) {
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800244 if (mPending != null) {
245 mPending.recordData(ident, entry.uid, entry.set, entry.tag, start, end, entry);
246 }
Jeff Sharkey63abc372012-01-11 18:38:16 -0800247
248 // also record against boot stats when present
249 if (mSinceBoot != null) {
250 mSinceBoot.recordData(ident, entry.uid, entry.set, entry.tag, start, end, entry);
251 }
252
253 // also record against complete dataset when present
254 if (complete != null) {
255 complete.recordData(ident, entry.uid, entry.set, entry.tag, start, end, entry);
256 }
257 }
258 }
259
260 mLastSnapshot = snapshot;
261
Jeff Sharkey1f8ea2d2012-02-07 12:05:43 -0800262 if (LOGV && unknownIfaces.size() > 0) {
Jeff Sharkey63abc372012-01-11 18:38:16 -0800263 Slog.w(TAG, "unknown interfaces " + unknownIfaces + ", ignoring those stats");
264 }
265 }
266
267 /**
268 * Consider persisting any pending deltas, if they are beyond
269 * {@link #mPersistThresholdBytes}.
270 */
271 public void maybePersistLocked(long currentTimeMillis) {
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800272 checkNotNull(mRotator, "missing FileRotator");
Jeff Sharkey63abc372012-01-11 18:38:16 -0800273 final long pendingBytes = mPending.getTotalBytes();
274 if (pendingBytes >= mPersistThresholdBytes) {
275 forcePersistLocked(currentTimeMillis);
276 } else {
277 mRotator.maybeRotate(currentTimeMillis);
278 }
279 }
280
281 /**
282 * Force persisting any pending deltas.
283 */
284 public void forcePersistLocked(long currentTimeMillis) {
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800285 checkNotNull(mRotator, "missing FileRotator");
Jeff Sharkey63abc372012-01-11 18:38:16 -0800286 if (mPending.isDirty()) {
287 if (LOGD) Slog.d(TAG, "forcePersistLocked() writing for " + mCookie);
288 try {
289 mRotator.rewriteActive(mPendingRewriter, currentTimeMillis);
290 mRotator.maybeRotate(currentTimeMillis);
291 mPending.reset();
292 } catch (IOException e) {
293 Log.wtf(TAG, "problem persisting pending stats", e);
Jeff Sharkey6de357e2012-05-09 13:33:52 -0700294 recoverFromWtf();
Jeff Sharkeye4984be2013-09-10 21:03:27 -0700295 } catch (OutOfMemoryError e) {
296 Log.wtf(TAG, "problem persisting pending stats", e);
297 recoverFromWtf();
Jeff Sharkey63abc372012-01-11 18:38:16 -0800298 }
299 }
300 }
301
302 /**
303 * Remove the given UID from all {@link FileRotator} history, migrating it
304 * to {@link TrafficStats#UID_REMOVED}.
305 */
Jeff Sharkeydaa57e82012-09-19 14:10:39 -0700306 public void removeUidsLocked(int[] uids) {
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800307 if (mRotator != null) {
308 try {
309 // Rewrite all persisted data to migrate UID stats
310 mRotator.rewriteAll(new RemoveUidRewriter(mBucketDuration, uids));
311 } catch (IOException e) {
312 Log.wtf(TAG, "problem removing UIDs " + Arrays.toString(uids), e);
313 recoverFromWtf();
314 } catch (OutOfMemoryError e) {
315 Log.wtf(TAG, "problem removing UIDs " + Arrays.toString(uids), e);
316 recoverFromWtf();
317 }
Jeff Sharkey63abc372012-01-11 18:38:16 -0800318 }
319
Jeff Sharkeydaa57e82012-09-19 14:10:39 -0700320 // Remove any pending stats
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800321 if (mPending != null) {
322 mPending.removeUids(uids);
323 }
324 if (mSinceBoot != null) {
325 mSinceBoot.removeUids(uids);
326 }
Jeff Sharkeydaa57e82012-09-19 14:10:39 -0700327
328 // Clear UID from current stats snapshot
Jeff Sharkey63abc372012-01-11 18:38:16 -0800329 if (mLastSnapshot != null) {
Jeff Sharkeydaa57e82012-09-19 14:10:39 -0700330 mLastSnapshot = mLastSnapshot.withoutUids(uids);
Jeff Sharkey63abc372012-01-11 18:38:16 -0800331 }
Jeff Sharkeyb52e3e52012-04-06 11:12:08 -0700332
333 final NetworkStatsCollection complete = mComplete != null ? mComplete.get() : null;
334 if (complete != null) {
Jeff Sharkeydaa57e82012-09-19 14:10:39 -0700335 complete.removeUids(uids);
Jeff Sharkeyb52e3e52012-04-06 11:12:08 -0700336 }
Jeff Sharkey63abc372012-01-11 18:38:16 -0800337 }
338
339 /**
340 * Rewriter that will combine current {@link NetworkStatsCollection} values
341 * with anything read from disk, and write combined set to disk. Clears the
342 * original {@link NetworkStatsCollection} when finished writing.
343 */
344 private static class CombiningRewriter implements FileRotator.Rewriter {
345 private final NetworkStatsCollection mCollection;
346
347 public CombiningRewriter(NetworkStatsCollection collection) {
348 mCollection = checkNotNull(collection, "missing NetworkStatsCollection");
349 }
350
Jeff Sharkeybfdd6802012-04-09 10:49:19 -0700351 @Override
Jeff Sharkey63abc372012-01-11 18:38:16 -0800352 public void reset() {
353 // ignored
354 }
355
Jeff Sharkeybfdd6802012-04-09 10:49:19 -0700356 @Override
Jeff Sharkey63abc372012-01-11 18:38:16 -0800357 public void read(InputStream in) throws IOException {
358 mCollection.read(in);
359 }
360
Jeff Sharkeybfdd6802012-04-09 10:49:19 -0700361 @Override
Jeff Sharkey63abc372012-01-11 18:38:16 -0800362 public boolean shouldWrite() {
363 return true;
364 }
365
Jeff Sharkeybfdd6802012-04-09 10:49:19 -0700366 @Override
Jeff Sharkey63abc372012-01-11 18:38:16 -0800367 public void write(OutputStream out) throws IOException {
368 mCollection.write(new DataOutputStream(out));
369 mCollection.reset();
370 }
371 }
372
373 /**
374 * Rewriter that will remove any {@link NetworkStatsHistory} attributed to
375 * the requested UID, only writing data back when modified.
376 */
377 public static class RemoveUidRewriter implements FileRotator.Rewriter {
378 private final NetworkStatsCollection mTemp;
Jeff Sharkeydaa57e82012-09-19 14:10:39 -0700379 private final int[] mUids;
Jeff Sharkey63abc372012-01-11 18:38:16 -0800380
Jeff Sharkeydaa57e82012-09-19 14:10:39 -0700381 public RemoveUidRewriter(long bucketDuration, int[] uids) {
Jeff Sharkey63abc372012-01-11 18:38:16 -0800382 mTemp = new NetworkStatsCollection(bucketDuration);
Jeff Sharkeydaa57e82012-09-19 14:10:39 -0700383 mUids = uids;
Jeff Sharkey63abc372012-01-11 18:38:16 -0800384 }
385
Jeff Sharkeybfdd6802012-04-09 10:49:19 -0700386 @Override
Jeff Sharkey63abc372012-01-11 18:38:16 -0800387 public void reset() {
388 mTemp.reset();
389 }
390
Jeff Sharkeybfdd6802012-04-09 10:49:19 -0700391 @Override
Jeff Sharkey63abc372012-01-11 18:38:16 -0800392 public void read(InputStream in) throws IOException {
393 mTemp.read(in);
394 mTemp.clearDirty();
Jeff Sharkeydaa57e82012-09-19 14:10:39 -0700395 mTemp.removeUids(mUids);
Jeff Sharkey63abc372012-01-11 18:38:16 -0800396 }
397
Jeff Sharkeybfdd6802012-04-09 10:49:19 -0700398 @Override
Jeff Sharkey63abc372012-01-11 18:38:16 -0800399 public boolean shouldWrite() {
400 return mTemp.isDirty();
401 }
402
Jeff Sharkeybfdd6802012-04-09 10:49:19 -0700403 @Override
Jeff Sharkey63abc372012-01-11 18:38:16 -0800404 public void write(OutputStream out) throws IOException {
405 mTemp.write(new DataOutputStream(out));
406 }
407 }
408
409 public void importLegacyNetworkLocked(File file) throws IOException {
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800410 checkNotNull(mRotator, "missing FileRotator");
411
Jeff Sharkey63abc372012-01-11 18:38:16 -0800412 // legacy file still exists; start empty to avoid double importing
413 mRotator.deleteAll();
414
415 final NetworkStatsCollection collection = new NetworkStatsCollection(mBucketDuration);
416 collection.readLegacyNetwork(file);
417
418 final long startMillis = collection.getStartMillis();
419 final long endMillis = collection.getEndMillis();
420
421 if (!collection.isEmpty()) {
422 // process legacy data, creating active file at starting time, then
423 // using end time to possibly trigger rotation.
424 mRotator.rewriteActive(new CombiningRewriter(collection), startMillis);
425 mRotator.maybeRotate(endMillis);
426 }
427 }
428
429 public void importLegacyUidLocked(File file) throws IOException {
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800430 checkNotNull(mRotator, "missing FileRotator");
431
Jeff Sharkey63abc372012-01-11 18:38:16 -0800432 // legacy file still exists; start empty to avoid double importing
433 mRotator.deleteAll();
434
435 final NetworkStatsCollection collection = new NetworkStatsCollection(mBucketDuration);
436 collection.readLegacyUid(file, mOnlyTags);
437
438 final long startMillis = collection.getStartMillis();
439 final long endMillis = collection.getEndMillis();
440
441 if (!collection.isEmpty()) {
442 // process legacy data, creating active file at starting time, then
443 // using end time to possibly trigger rotation.
444 mRotator.rewriteActive(new CombiningRewriter(collection), startMillis);
445 mRotator.maybeRotate(endMillis);
446 }
447 }
448
449 public void dumpLocked(IndentingPrintWriter pw, boolean fullHistory) {
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800450 if (mPending != null) {
451 pw.print("Pending bytes: "); pw.println(mPending.getTotalBytes());
452 }
Jeff Sharkey63abc372012-01-11 18:38:16 -0800453 if (fullHistory) {
454 pw.println("Complete history:");
455 getOrLoadCompleteLocked().dump(pw);
456 } else {
457 pw.println("History since boot:");
458 mSinceBoot.dump(pw);
459 }
460 }
Jeff Sharkey6de357e2012-05-09 13:33:52 -0700461
Jeff Sharkey55a442e2014-11-18 18:22:21 -0800462 public void dumpCheckin(PrintWriter pw, long start, long end) {
463 // Only load and dump stats from the requested window
464 getOrLoadPartialLocked(start, end).dumpCheckin(pw, start, end);
465 }
466
Jeff Sharkey6de357e2012-05-09 13:33:52 -0700467 /**
468 * Recover from {@link FileRotator} failure by dumping state to
469 * {@link DropBoxManager} and deleting contents.
470 */
471 private void recoverFromWtf() {
472 if (DUMP_BEFORE_DELETE) {
473 final ByteArrayOutputStream os = new ByteArrayOutputStream();
474 try {
475 mRotator.dumpAll(os);
476 } catch (IOException e) {
477 // ignore partial contents
478 os.reset();
479 } finally {
480 IoUtils.closeQuietly(os);
481 }
482 mDropBox.addData(TAG_NETSTATS_DUMP, os.toByteArray(), 0);
483 }
484
485 mRotator.deleteAll();
486 }
Jeff Sharkey63abc372012-01-11 18:38:16 -0800487}