blob: 090a0762a4b5e5734d05eb43c096b988fa8d18d2 [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
Jeff Davidson4ff3bcf2016-06-15 13:31:52 -070025import android.annotation.Nullable;
Jeff Sharkey63abc372012-01-11 18:38:16 -080026import android.net.NetworkStats;
27import android.net.NetworkStats.NonMonotonicObserver;
28import android.net.NetworkStatsHistory;
29import android.net.NetworkTemplate;
30import android.net.TrafficStats;
Jeff Sharkey6de357e2012-05-09 13:33:52 -070031import android.os.DropBoxManager;
Jeff Sharkey63abc372012-01-11 18:38:16 -080032import android.util.Log;
Jeff Sharkeyac3fcb12012-05-02 18:11:52 -070033import android.util.MathUtils;
Jeff Sharkey63abc372012-01-11 18:38:16 -080034import android.util.Slog;
35
Wenchao Tongf5ea3402015-03-04 13:26:38 -080036import com.android.internal.net.VpnInfo;
Jeff Sharkey63abc372012-01-11 18:38:16 -080037import com.android.internal.util.FileRotator;
38import com.android.internal.util.IndentingPrintWriter;
39import com.google.android.collect.Sets;
40
Jeff Sharkey6de357e2012-05-09 13:33:52 -070041import java.io.ByteArrayOutputStream;
Jeff Sharkey63abc372012-01-11 18:38:16 -080042import java.io.DataOutputStream;
43import java.io.File;
44import java.io.IOException;
45import java.io.InputStream;
46import java.io.OutputStream;
Jeff Sharkey55a442e2014-11-18 18:22:21 -080047import java.io.PrintWriter;
Jeff Sharkey63abc372012-01-11 18:38:16 -080048import java.lang.ref.WeakReference;
Jeff Sharkeydaa57e82012-09-19 14:10:39 -070049import java.util.Arrays;
Jeff Sharkey63abc372012-01-11 18:38:16 -080050import java.util.HashSet;
51import java.util.Map;
52
Jeff Sharkey6de357e2012-05-09 13:33:52 -070053import libcore.io.IoUtils;
54
Jeff Sharkey63abc372012-01-11 18:38:16 -080055/**
56 * Logic to record deltas between periodic {@link NetworkStats} snapshots into
57 * {@link NetworkStatsHistory} that belong to {@link NetworkStatsCollection}.
58 * Keeps pending changes in memory until they pass a specific threshold, in
Antonio Cansadocd42acd2016-02-17 13:03:38 -080059 * bytes. Uses {@link FileRotator} for persistence logic if present.
Jeff Sharkey63abc372012-01-11 18:38:16 -080060 * <p>
61 * Not inherently thread safe.
62 */
63public class NetworkStatsRecorder {
64 private static final String TAG = "NetworkStatsRecorder";
Jeff Sharkeye7bb71d2012-02-28 15:13:08 -080065 private static final boolean LOGD = false;
Jeff Sharkey1f8ea2d2012-02-07 12:05:43 -080066 private static final boolean LOGV = false;
Jeff Sharkey63abc372012-01-11 18:38:16 -080067
Jeff Sharkey6de357e2012-05-09 13:33:52 -070068 private static final String TAG_NETSTATS_DUMP = "netstats_dump";
69
70 /** Dump before deleting in {@link #recoverFromWtf()}. */
71 private static final boolean DUMP_BEFORE_DELETE = true;
72
Jeff Sharkey63abc372012-01-11 18:38:16 -080073 private final FileRotator mRotator;
74 private final NonMonotonicObserver<String> mObserver;
Jeff Sharkey6de357e2012-05-09 13:33:52 -070075 private final DropBoxManager mDropBox;
Jeff Sharkey63abc372012-01-11 18:38:16 -080076 private final String mCookie;
77
78 private final long mBucketDuration;
Jeff Sharkey63abc372012-01-11 18:38:16 -080079 private final boolean mOnlyTags;
80
Jeff Sharkeyac3fcb12012-05-02 18:11:52 -070081 private long mPersistThresholdBytes = 2 * MB_IN_BYTES;
Jeff Sharkey63abc372012-01-11 18:38:16 -080082 private NetworkStats mLastSnapshot;
83
84 private final NetworkStatsCollection mPending;
85 private final NetworkStatsCollection mSinceBoot;
86
87 private final CombiningRewriter mPendingRewriter;
88
89 private WeakReference<NetworkStatsCollection> mComplete;
90
Antonio Cansadocd42acd2016-02-17 13:03:38 -080091 /**
92 * Non-persisted recorder, with only one bucket. Used by {@link NetworkStatsObservers}.
93 */
94 public NetworkStatsRecorder() {
95 mRotator = null;
96 mObserver = null;
97 mDropBox = null;
98 mCookie = null;
99
100 // set the bucket big enough to have all data in one bucket, but allow some
101 // slack to avoid overflow
102 mBucketDuration = YEAR_IN_MILLIS;
103 mOnlyTags = false;
104
105 mPending = null;
106 mSinceBoot = new NetworkStatsCollection(mBucketDuration);
107
108 mPendingRewriter = null;
109 }
110
111 /**
112 * Persisted recorder.
113 */
Jeff Sharkey63abc372012-01-11 18:38:16 -0800114 public NetworkStatsRecorder(FileRotator rotator, NonMonotonicObserver<String> observer,
Jeff Sharkey6de357e2012-05-09 13:33:52 -0700115 DropBoxManager dropBox, String cookie, long bucketDuration, boolean onlyTags) {
Jeff Sharkey63abc372012-01-11 18:38:16 -0800116 mRotator = checkNotNull(rotator, "missing FileRotator");
117 mObserver = checkNotNull(observer, "missing NonMonotonicObserver");
Jeff Sharkey6de357e2012-05-09 13:33:52 -0700118 mDropBox = checkNotNull(dropBox, "missing DropBoxManager");
Jeff Sharkey63abc372012-01-11 18:38:16 -0800119 mCookie = cookie;
120
121 mBucketDuration = bucketDuration;
Jeff Sharkey63abc372012-01-11 18:38:16 -0800122 mOnlyTags = onlyTags;
123
124 mPending = new NetworkStatsCollection(bucketDuration);
125 mSinceBoot = new NetworkStatsCollection(bucketDuration);
126
127 mPendingRewriter = new CombiningRewriter(mPending);
128 }
129
Jeff Sharkeyac3fcb12012-05-02 18:11:52 -0700130 public void setPersistThreshold(long thresholdBytes) {
131 if (LOGV) Slog.v(TAG, "setPersistThreshold() with " + thresholdBytes);
132 mPersistThresholdBytes = MathUtils.constrain(
133 thresholdBytes, 1 * KB_IN_BYTES, 100 * MB_IN_BYTES);
134 }
135
Jeff Sharkey63abc372012-01-11 18:38:16 -0800136 public void resetLocked() {
137 mLastSnapshot = null;
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800138 if (mPending != null) {
139 mPending.reset();
140 }
141 if (mSinceBoot != null) {
142 mSinceBoot.reset();
143 }
144 if (mComplete != null) {
145 mComplete.clear();
146 }
Jeff Sharkey63abc372012-01-11 18:38:16 -0800147 }
148
149 public NetworkStats.Entry getTotalSinceBootLocked(NetworkTemplate template) {
Jeff Davidson1efb1332015-12-09 18:04:50 -0800150 return mSinceBoot.getSummary(template, Long.MIN_VALUE, Long.MAX_VALUE,
151 NetworkStatsAccess.Level.DEVICE).getTotal(null);
Jeff Sharkey63abc372012-01-11 18:38:16 -0800152 }
153
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800154 public NetworkStatsCollection getSinceBoot() {
155 return mSinceBoot;
156 }
157
Jeff Sharkey63abc372012-01-11 18:38:16 -0800158 /**
159 * Load complete history represented by {@link FileRotator}. Caches
160 * internally as a {@link WeakReference}, and updated with future
161 * {@link #recordSnapshotLocked(NetworkStats, Map, long)} snapshots as long
162 * as reference is valid.
163 */
164 public NetworkStatsCollection getOrLoadCompleteLocked() {
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800165 checkNotNull(mRotator, "missing FileRotator");
Jeff Sharkey55a442e2014-11-18 18:22:21 -0800166 NetworkStatsCollection res = mComplete != null ? mComplete.get() : null;
167 if (res == null) {
168 res = loadLocked(Long.MIN_VALUE, Long.MAX_VALUE);
169 mComplete = new WeakReference<NetworkStatsCollection>(res);
Jeff Sharkey63abc372012-01-11 18:38:16 -0800170 }
Jeff Sharkey55a442e2014-11-18 18:22:21 -0800171 return res;
172 }
173
174 public NetworkStatsCollection getOrLoadPartialLocked(long start, long end) {
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800175 checkNotNull(mRotator, "missing FileRotator");
Jeff Sharkey55a442e2014-11-18 18:22:21 -0800176 NetworkStatsCollection res = mComplete != null ? mComplete.get() : null;
177 if (res == null) {
178 res = loadLocked(start, end);
179 }
180 return res;
181 }
182
183 private NetworkStatsCollection loadLocked(long start, long end) {
184 if (LOGD) Slog.d(TAG, "loadLocked() reading from disk for " + mCookie);
185 final NetworkStatsCollection res = new NetworkStatsCollection(mBucketDuration);
186 try {
187 mRotator.readMatching(res, start, end);
188 res.recordCollection(mPending);
189 } catch (IOException e) {
190 Log.wtf(TAG, "problem completely reading network stats", e);
191 recoverFromWtf();
192 } catch (OutOfMemoryError e) {
193 Log.wtf(TAG, "problem completely reading network stats", e);
194 recoverFromWtf();
195 }
196 return res;
Jeff Sharkey63abc372012-01-11 18:38:16 -0800197 }
198
199 /**
200 * Record any delta that occurred since last {@link NetworkStats} snapshot,
201 * using the given {@link Map} to identify network interfaces. First
202 * snapshot is considered bootstrap, and is not counted as delta.
Jeff Davidson4ff3bcf2016-06-15 13:31:52 -0700203 *
204 * @param vpnArray Optional info about the currently active VPN, if any. This is used to
205 * redistribute traffic from the VPN app to the underlying responsible apps.
206 * This should always be set to null if the provided snapshot is aggregated
207 * across all UIDs (e.g. contains UID_ALL buckets), regardless of VPN state.
Jeff Sharkey63abc372012-01-11 18:38:16 -0800208 */
209 public void recordSnapshotLocked(NetworkStats snapshot,
Jeff Davidson4ff3bcf2016-06-15 13:31:52 -0700210 Map<String, NetworkIdentitySet> ifaceIdent, @Nullable VpnInfo[] vpnArray,
Wenchao Tongf5ea3402015-03-04 13:26:38 -0800211 long currentTimeMillis) {
Jeff Sharkey63abc372012-01-11 18:38:16 -0800212 final HashSet<String> unknownIfaces = Sets.newHashSet();
213
Jeff Sharkeye8914c32012-05-01 16:26:09 -0700214 // skip recording when snapshot missing
215 if (snapshot == null) return;
216
Jeff Sharkey63abc372012-01-11 18:38:16 -0800217 // assume first snapshot is bootstrap and don't record
218 if (mLastSnapshot == null) {
219 mLastSnapshot = snapshot;
220 return;
221 }
222
223 final NetworkStatsCollection complete = mComplete != null ? mComplete.get() : null;
224
225 final NetworkStats delta = NetworkStats.subtract(
226 snapshot, mLastSnapshot, mObserver, mCookie);
227 final long end = currentTimeMillis;
228 final long start = end - delta.getElapsedRealtime();
229
Wenchao Tongf5ea3402015-03-04 13:26:38 -0800230 if (vpnArray != null) {
231 for (VpnInfo info : vpnArray) {
232 delta.migrateTun(info.ownerUid, info.vpnIface, info.primaryUnderlyingIface);
233 }
234 }
235
Jeff Sharkey63abc372012-01-11 18:38:16 -0800236 NetworkStats.Entry entry = null;
237 for (int i = 0; i < delta.size(); i++) {
238 entry = delta.getValues(i, entry);
239 final NetworkIdentitySet ident = ifaceIdent.get(entry.iface);
240 if (ident == null) {
241 unknownIfaces.add(entry.iface);
242 continue;
243 }
244
Jeff Sharkeyac3fcb12012-05-02 18:11:52 -0700245 // skip when no delta occurred
Jeff Sharkey63abc372012-01-11 18:38:16 -0800246 if (entry.isEmpty()) continue;
247
248 // only record tag data when requested
249 if ((entry.tag == TAG_NONE) != mOnlyTags) {
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800250 if (mPending != null) {
251 mPending.recordData(ident, entry.uid, entry.set, entry.tag, start, end, entry);
252 }
Jeff Sharkey63abc372012-01-11 18:38:16 -0800253
254 // also record against boot stats when present
255 if (mSinceBoot != null) {
256 mSinceBoot.recordData(ident, entry.uid, entry.set, entry.tag, start, end, entry);
257 }
258
259 // also record against complete dataset when present
260 if (complete != null) {
261 complete.recordData(ident, entry.uid, entry.set, entry.tag, start, end, entry);
262 }
263 }
264 }
265
266 mLastSnapshot = snapshot;
267
Jeff Sharkey1f8ea2d2012-02-07 12:05:43 -0800268 if (LOGV && unknownIfaces.size() > 0) {
Jeff Sharkey63abc372012-01-11 18:38:16 -0800269 Slog.w(TAG, "unknown interfaces " + unknownIfaces + ", ignoring those stats");
270 }
271 }
272
273 /**
274 * Consider persisting any pending deltas, if they are beyond
275 * {@link #mPersistThresholdBytes}.
276 */
277 public void maybePersistLocked(long currentTimeMillis) {
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800278 checkNotNull(mRotator, "missing FileRotator");
Jeff Sharkey63abc372012-01-11 18:38:16 -0800279 final long pendingBytes = mPending.getTotalBytes();
280 if (pendingBytes >= mPersistThresholdBytes) {
281 forcePersistLocked(currentTimeMillis);
282 } else {
283 mRotator.maybeRotate(currentTimeMillis);
284 }
285 }
286
287 /**
288 * Force persisting any pending deltas.
289 */
290 public void forcePersistLocked(long currentTimeMillis) {
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800291 checkNotNull(mRotator, "missing FileRotator");
Jeff Sharkey63abc372012-01-11 18:38:16 -0800292 if (mPending.isDirty()) {
293 if (LOGD) Slog.d(TAG, "forcePersistLocked() writing for " + mCookie);
294 try {
295 mRotator.rewriteActive(mPendingRewriter, currentTimeMillis);
296 mRotator.maybeRotate(currentTimeMillis);
297 mPending.reset();
298 } catch (IOException e) {
299 Log.wtf(TAG, "problem persisting pending stats", e);
Jeff Sharkey6de357e2012-05-09 13:33:52 -0700300 recoverFromWtf();
Jeff Sharkeye4984be2013-09-10 21:03:27 -0700301 } catch (OutOfMemoryError e) {
302 Log.wtf(TAG, "problem persisting pending stats", e);
303 recoverFromWtf();
Jeff Sharkey63abc372012-01-11 18:38:16 -0800304 }
305 }
306 }
307
308 /**
309 * Remove the given UID from all {@link FileRotator} history, migrating it
310 * to {@link TrafficStats#UID_REMOVED}.
311 */
Jeff Sharkeydaa57e82012-09-19 14:10:39 -0700312 public void removeUidsLocked(int[] uids) {
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800313 if (mRotator != null) {
314 try {
315 // Rewrite all persisted data to migrate UID stats
316 mRotator.rewriteAll(new RemoveUidRewriter(mBucketDuration, uids));
317 } catch (IOException e) {
318 Log.wtf(TAG, "problem removing UIDs " + Arrays.toString(uids), e);
319 recoverFromWtf();
320 } catch (OutOfMemoryError e) {
321 Log.wtf(TAG, "problem removing UIDs " + Arrays.toString(uids), e);
322 recoverFromWtf();
323 }
Jeff Sharkey63abc372012-01-11 18:38:16 -0800324 }
325
Jeff Sharkeydaa57e82012-09-19 14:10:39 -0700326 // Remove any pending stats
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800327 if (mPending != null) {
328 mPending.removeUids(uids);
329 }
330 if (mSinceBoot != null) {
331 mSinceBoot.removeUids(uids);
332 }
Jeff Sharkeydaa57e82012-09-19 14:10:39 -0700333
334 // Clear UID from current stats snapshot
Jeff Sharkey63abc372012-01-11 18:38:16 -0800335 if (mLastSnapshot != null) {
Jeff Sharkeydaa57e82012-09-19 14:10:39 -0700336 mLastSnapshot = mLastSnapshot.withoutUids(uids);
Jeff Sharkey63abc372012-01-11 18:38:16 -0800337 }
Jeff Sharkeyb52e3e52012-04-06 11:12:08 -0700338
339 final NetworkStatsCollection complete = mComplete != null ? mComplete.get() : null;
340 if (complete != null) {
Jeff Sharkeydaa57e82012-09-19 14:10:39 -0700341 complete.removeUids(uids);
Jeff Sharkeyb52e3e52012-04-06 11:12:08 -0700342 }
Jeff Sharkey63abc372012-01-11 18:38:16 -0800343 }
344
345 /**
346 * Rewriter that will combine current {@link NetworkStatsCollection} values
347 * with anything read from disk, and write combined set to disk. Clears the
348 * original {@link NetworkStatsCollection} when finished writing.
349 */
350 private static class CombiningRewriter implements FileRotator.Rewriter {
351 private final NetworkStatsCollection mCollection;
352
353 public CombiningRewriter(NetworkStatsCollection collection) {
354 mCollection = checkNotNull(collection, "missing NetworkStatsCollection");
355 }
356
Jeff Sharkeybfdd6802012-04-09 10:49:19 -0700357 @Override
Jeff Sharkey63abc372012-01-11 18:38:16 -0800358 public void reset() {
359 // ignored
360 }
361
Jeff Sharkeybfdd6802012-04-09 10:49:19 -0700362 @Override
Jeff Sharkey63abc372012-01-11 18:38:16 -0800363 public void read(InputStream in) throws IOException {
364 mCollection.read(in);
365 }
366
Jeff Sharkeybfdd6802012-04-09 10:49:19 -0700367 @Override
Jeff Sharkey63abc372012-01-11 18:38:16 -0800368 public boolean shouldWrite() {
369 return true;
370 }
371
Jeff Sharkeybfdd6802012-04-09 10:49:19 -0700372 @Override
Jeff Sharkey63abc372012-01-11 18:38:16 -0800373 public void write(OutputStream out) throws IOException {
374 mCollection.write(new DataOutputStream(out));
375 mCollection.reset();
376 }
377 }
378
379 /**
380 * Rewriter that will remove any {@link NetworkStatsHistory} attributed to
381 * the requested UID, only writing data back when modified.
382 */
383 public static class RemoveUidRewriter implements FileRotator.Rewriter {
384 private final NetworkStatsCollection mTemp;
Jeff Sharkeydaa57e82012-09-19 14:10:39 -0700385 private final int[] mUids;
Jeff Sharkey63abc372012-01-11 18:38:16 -0800386
Jeff Sharkeydaa57e82012-09-19 14:10:39 -0700387 public RemoveUidRewriter(long bucketDuration, int[] uids) {
Jeff Sharkey63abc372012-01-11 18:38:16 -0800388 mTemp = new NetworkStatsCollection(bucketDuration);
Jeff Sharkeydaa57e82012-09-19 14:10:39 -0700389 mUids = uids;
Jeff Sharkey63abc372012-01-11 18:38:16 -0800390 }
391
Jeff Sharkeybfdd6802012-04-09 10:49:19 -0700392 @Override
Jeff Sharkey63abc372012-01-11 18:38:16 -0800393 public void reset() {
394 mTemp.reset();
395 }
396
Jeff Sharkeybfdd6802012-04-09 10:49:19 -0700397 @Override
Jeff Sharkey63abc372012-01-11 18:38:16 -0800398 public void read(InputStream in) throws IOException {
399 mTemp.read(in);
400 mTemp.clearDirty();
Jeff Sharkeydaa57e82012-09-19 14:10:39 -0700401 mTemp.removeUids(mUids);
Jeff Sharkey63abc372012-01-11 18:38:16 -0800402 }
403
Jeff Sharkeybfdd6802012-04-09 10:49:19 -0700404 @Override
Jeff Sharkey63abc372012-01-11 18:38:16 -0800405 public boolean shouldWrite() {
406 return mTemp.isDirty();
407 }
408
Jeff Sharkeybfdd6802012-04-09 10:49:19 -0700409 @Override
Jeff Sharkey63abc372012-01-11 18:38:16 -0800410 public void write(OutputStream out) throws IOException {
411 mTemp.write(new DataOutputStream(out));
412 }
413 }
414
415 public void importLegacyNetworkLocked(File file) throws IOException {
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800416 checkNotNull(mRotator, "missing FileRotator");
417
Jeff Sharkey63abc372012-01-11 18:38:16 -0800418 // legacy file still exists; start empty to avoid double importing
419 mRotator.deleteAll();
420
421 final NetworkStatsCollection collection = new NetworkStatsCollection(mBucketDuration);
422 collection.readLegacyNetwork(file);
423
424 final long startMillis = collection.getStartMillis();
425 final long endMillis = collection.getEndMillis();
426
427 if (!collection.isEmpty()) {
428 // process legacy data, creating active file at starting time, then
429 // using end time to possibly trigger rotation.
430 mRotator.rewriteActive(new CombiningRewriter(collection), startMillis);
431 mRotator.maybeRotate(endMillis);
432 }
433 }
434
435 public void importLegacyUidLocked(File file) throws IOException {
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800436 checkNotNull(mRotator, "missing FileRotator");
437
Jeff Sharkey63abc372012-01-11 18:38:16 -0800438 // legacy file still exists; start empty to avoid double importing
439 mRotator.deleteAll();
440
441 final NetworkStatsCollection collection = new NetworkStatsCollection(mBucketDuration);
442 collection.readLegacyUid(file, mOnlyTags);
443
444 final long startMillis = collection.getStartMillis();
445 final long endMillis = collection.getEndMillis();
446
447 if (!collection.isEmpty()) {
448 // process legacy data, creating active file at starting time, then
449 // using end time to possibly trigger rotation.
450 mRotator.rewriteActive(new CombiningRewriter(collection), startMillis);
451 mRotator.maybeRotate(endMillis);
452 }
453 }
454
455 public void dumpLocked(IndentingPrintWriter pw, boolean fullHistory) {
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800456 if (mPending != null) {
457 pw.print("Pending bytes: "); pw.println(mPending.getTotalBytes());
458 }
Jeff Sharkey63abc372012-01-11 18:38:16 -0800459 if (fullHistory) {
460 pw.println("Complete history:");
461 getOrLoadCompleteLocked().dump(pw);
462 } else {
463 pw.println("History since boot:");
464 mSinceBoot.dump(pw);
465 }
466 }
Jeff Sharkey6de357e2012-05-09 13:33:52 -0700467
Jeff Sharkey55a442e2014-11-18 18:22:21 -0800468 public void dumpCheckin(PrintWriter pw, long start, long end) {
469 // Only load and dump stats from the requested window
470 getOrLoadPartialLocked(start, end).dumpCheckin(pw, start, end);
471 }
472
Jeff Sharkey6de357e2012-05-09 13:33:52 -0700473 /**
474 * Recover from {@link FileRotator} failure by dumping state to
475 * {@link DropBoxManager} and deleting contents.
476 */
477 private void recoverFromWtf() {
478 if (DUMP_BEFORE_DELETE) {
479 final ByteArrayOutputStream os = new ByteArrayOutputStream();
480 try {
481 mRotator.dumpAll(os);
482 } catch (IOException e) {
483 // ignore partial contents
484 os.reset();
485 } finally {
486 IoUtils.closeQuietly(os);
487 }
488 mDropBox.addData(TAG_NETSTATS_DUMP, os.toByteArray(), 0);
489 }
490
491 mRotator.deleteAll();
492 }
Jeff Sharkey63abc372012-01-11 18:38:16 -0800493}