blob: 06ec341d9e4681fd611d0d9e73596b39b1c7caad [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 Sharkeyf4de2942017-08-29 15:32:13 -060023
Jeff Sharkey63abc372012-01-11 18:38:16 -080024import static com.android.internal.util.Preconditions.checkNotNull;
25
26import android.net.NetworkStats;
27import android.net.NetworkStats.NonMonotonicObserver;
28import android.net.NetworkStatsHistory;
29import android.net.NetworkTemplate;
30import android.net.TrafficStats;
Jeff Sharkeyf4de2942017-08-29 15:32:13 -060031import android.os.Binder;
Jeff Sharkey6de357e2012-05-09 13:33:52 -070032import android.os.DropBoxManager;
Makoto Onukida65a522017-01-13 10:23:30 -080033import android.service.NetworkStatsRecorderProto;
Jeff Sharkey63abc372012-01-11 18:38:16 -080034import android.util.Log;
Jeff Sharkeyac3fcb12012-05-02 18:11:52 -070035import android.util.MathUtils;
Jeff Sharkey63abc372012-01-11 18:38:16 -080036import android.util.Slog;
Makoto Onukida65a522017-01-13 10:23:30 -080037import android.util.proto.ProtoOutputStream;
Jeff Sharkey63abc372012-01-11 18:38:16 -080038
39import com.android.internal.util.FileRotator;
40import com.android.internal.util.IndentingPrintWriter;
Jeff Sharkeyf4de2942017-08-29 15:32:13 -060041
Varun Anandd8220c22019-06-10 22:44:57 +000042import com.google.android.collect.Sets;
43
Benedict Wonga84d9fa2019-06-12 17:46:15 +000044import libcore.io.IoUtils;
45
Jeff Sharkey6de357e2012-05-09 13:33:52 -070046import java.io.ByteArrayOutputStream;
Jeff Sharkey63abc372012-01-11 18:38:16 -080047import java.io.DataOutputStream;
48import java.io.File;
49import java.io.IOException;
50import java.io.InputStream;
51import java.io.OutputStream;
Jeff Sharkey55a442e2014-11-18 18:22:21 -080052import java.io.PrintWriter;
Jeff Sharkey63abc372012-01-11 18:38:16 -080053import java.lang.ref.WeakReference;
Jeff Sharkeydaa57e82012-09-19 14:10:39 -070054import java.util.Arrays;
Jeff Sharkey63abc372012-01-11 18:38:16 -080055import java.util.HashSet;
56import java.util.Map;
57
58/**
59 * Logic to record deltas between periodic {@link NetworkStats} snapshots into
60 * {@link NetworkStatsHistory} that belong to {@link NetworkStatsCollection}.
61 * Keeps pending changes in memory until they pass a specific threshold, in
Antonio Cansadocd42acd2016-02-17 13:03:38 -080062 * bytes. Uses {@link FileRotator} for persistence logic if present.
Jeff Sharkey63abc372012-01-11 18:38:16 -080063 * <p>
64 * Not inherently thread safe.
65 */
66public class NetworkStatsRecorder {
67 private static final String TAG = "NetworkStatsRecorder";
Jeff Sharkeye7bb71d2012-02-28 15:13:08 -080068 private static final boolean LOGD = false;
Jeff Sharkey1f8ea2d2012-02-07 12:05:43 -080069 private static final boolean LOGV = false;
Jeff Sharkey63abc372012-01-11 18:38:16 -080070
Jeff Sharkey6de357e2012-05-09 13:33:52 -070071 private static final String TAG_NETSTATS_DUMP = "netstats_dump";
72
73 /** Dump before deleting in {@link #recoverFromWtf()}. */
74 private static final boolean DUMP_BEFORE_DELETE = true;
75
Jeff Sharkey63abc372012-01-11 18:38:16 -080076 private final FileRotator mRotator;
77 private final NonMonotonicObserver<String> mObserver;
Jeff Sharkey6de357e2012-05-09 13:33:52 -070078 private final DropBoxManager mDropBox;
Jeff Sharkey63abc372012-01-11 18:38:16 -080079 private final String mCookie;
80
81 private final long mBucketDuration;
Jeff Sharkey63abc372012-01-11 18:38:16 -080082 private final boolean mOnlyTags;
83
Jeff Sharkeyac3fcb12012-05-02 18:11:52 -070084 private long mPersistThresholdBytes = 2 * MB_IN_BYTES;
Jeff Sharkey63abc372012-01-11 18:38:16 -080085 private NetworkStats mLastSnapshot;
86
87 private final NetworkStatsCollection mPending;
88 private final NetworkStatsCollection mSinceBoot;
89
90 private final CombiningRewriter mPendingRewriter;
91
92 private WeakReference<NetworkStatsCollection> mComplete;
93
Antonio Cansadocd42acd2016-02-17 13:03:38 -080094 /**
95 * Non-persisted recorder, with only one bucket. Used by {@link NetworkStatsObservers}.
96 */
97 public NetworkStatsRecorder() {
98 mRotator = null;
99 mObserver = null;
100 mDropBox = null;
101 mCookie = null;
102
103 // set the bucket big enough to have all data in one bucket, but allow some
104 // slack to avoid overflow
105 mBucketDuration = YEAR_IN_MILLIS;
106 mOnlyTags = false;
107
108 mPending = null;
109 mSinceBoot = new NetworkStatsCollection(mBucketDuration);
110
111 mPendingRewriter = null;
112 }
113
114 /**
115 * Persisted recorder.
116 */
Jeff Sharkey63abc372012-01-11 18:38:16 -0800117 public NetworkStatsRecorder(FileRotator rotator, NonMonotonicObserver<String> observer,
Jeff Sharkey6de357e2012-05-09 13:33:52 -0700118 DropBoxManager dropBox, String cookie, long bucketDuration, boolean onlyTags) {
Jeff Sharkey63abc372012-01-11 18:38:16 -0800119 mRotator = checkNotNull(rotator, "missing FileRotator");
120 mObserver = checkNotNull(observer, "missing NonMonotonicObserver");
Jeff Sharkey6de357e2012-05-09 13:33:52 -0700121 mDropBox = checkNotNull(dropBox, "missing DropBoxManager");
Jeff Sharkey63abc372012-01-11 18:38:16 -0800122 mCookie = cookie;
123
124 mBucketDuration = bucketDuration;
Jeff Sharkey63abc372012-01-11 18:38:16 -0800125 mOnlyTags = onlyTags;
126
127 mPending = new NetworkStatsCollection(bucketDuration);
128 mSinceBoot = new NetworkStatsCollection(bucketDuration);
129
130 mPendingRewriter = new CombiningRewriter(mPending);
131 }
132
Jeff Sharkeyac3fcb12012-05-02 18:11:52 -0700133 public void setPersistThreshold(long thresholdBytes) {
134 if (LOGV) Slog.v(TAG, "setPersistThreshold() with " + thresholdBytes);
135 mPersistThresholdBytes = MathUtils.constrain(
136 thresholdBytes, 1 * KB_IN_BYTES, 100 * MB_IN_BYTES);
137 }
138
Jeff Sharkey63abc372012-01-11 18:38:16 -0800139 public void resetLocked() {
140 mLastSnapshot = null;
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800141 if (mPending != null) {
142 mPending.reset();
143 }
144 if (mSinceBoot != null) {
145 mSinceBoot.reset();
146 }
147 if (mComplete != null) {
148 mComplete.clear();
149 }
Jeff Sharkey63abc372012-01-11 18:38:16 -0800150 }
151
152 public NetworkStats.Entry getTotalSinceBootLocked(NetworkTemplate template) {
Jeff Davidson1efb1332015-12-09 18:04:50 -0800153 return mSinceBoot.getSummary(template, Long.MIN_VALUE, Long.MAX_VALUE,
Jeff Sharkeyf4de2942017-08-29 15:32:13 -0600154 NetworkStatsAccess.Level.DEVICE, Binder.getCallingUid()).getTotal(null);
Jeff Sharkey63abc372012-01-11 18:38:16 -0800155 }
156
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800157 public NetworkStatsCollection getSinceBoot() {
158 return mSinceBoot;
159 }
160
Jeff Sharkey63abc372012-01-11 18:38:16 -0800161 /**
162 * Load complete history represented by {@link FileRotator}. Caches
163 * internally as a {@link WeakReference}, and updated with future
164 * {@link #recordSnapshotLocked(NetworkStats, Map, long)} snapshots as long
165 * as reference is valid.
166 */
167 public NetworkStatsCollection getOrLoadCompleteLocked() {
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800168 checkNotNull(mRotator, "missing FileRotator");
Jeff Sharkey55a442e2014-11-18 18:22:21 -0800169 NetworkStatsCollection res = mComplete != null ? mComplete.get() : null;
170 if (res == null) {
171 res = loadLocked(Long.MIN_VALUE, Long.MAX_VALUE);
172 mComplete = new WeakReference<NetworkStatsCollection>(res);
Jeff Sharkey63abc372012-01-11 18:38:16 -0800173 }
Jeff Sharkey55a442e2014-11-18 18:22:21 -0800174 return res;
175 }
176
177 public NetworkStatsCollection getOrLoadPartialLocked(long start, long end) {
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800178 checkNotNull(mRotator, "missing FileRotator");
Jeff Sharkey55a442e2014-11-18 18:22:21 -0800179 NetworkStatsCollection res = mComplete != null ? mComplete.get() : null;
180 if (res == null) {
181 res = loadLocked(start, end);
182 }
183 return res;
184 }
185
186 private NetworkStatsCollection loadLocked(long start, long end) {
187 if (LOGD) Slog.d(TAG, "loadLocked() reading from disk for " + mCookie);
188 final NetworkStatsCollection res = new NetworkStatsCollection(mBucketDuration);
189 try {
190 mRotator.readMatching(res, start, end);
191 res.recordCollection(mPending);
192 } catch (IOException e) {
193 Log.wtf(TAG, "problem completely reading network stats", e);
194 recoverFromWtf();
195 } catch (OutOfMemoryError e) {
196 Log.wtf(TAG, "problem completely reading network stats", e);
197 recoverFromWtf();
198 }
199 return res;
Jeff Sharkey63abc372012-01-11 18:38:16 -0800200 }
201
202 /**
Benedict Wong833603c2019-06-13 10:54:38 -0700203 * Record any delta that occurred since last {@link NetworkStats} snapshot, using the given
204 * {@link Map} to identify network interfaces. First snapshot is considered bootstrap, and is
205 * not counted as delta.
Jeff Sharkey63abc372012-01-11 18:38:16 -0800206 */
207 public void recordSnapshotLocked(NetworkStats snapshot,
Benedict Wong833603c2019-06-13 10:54:38 -0700208 Map<String, NetworkIdentitySet> ifaceIdent, long currentTimeMillis) {
Jeff Sharkey63abc372012-01-11 18:38:16 -0800209 final HashSet<String> unknownIfaces = Sets.newHashSet();
210
Jeff Sharkeye8914c32012-05-01 16:26:09 -0700211 // skip recording when snapshot missing
212 if (snapshot == null) return;
213
Jeff Sharkey63abc372012-01-11 18:38:16 -0800214 // assume first snapshot is bootstrap and don't record
215 if (mLastSnapshot == null) {
216 mLastSnapshot = snapshot;
217 return;
218 }
219
220 final NetworkStatsCollection complete = mComplete != null ? mComplete.get() : null;
221
222 final NetworkStats delta = NetworkStats.subtract(
223 snapshot, mLastSnapshot, mObserver, mCookie);
224 final long end = currentTimeMillis;
225 final long start = end - delta.getElapsedRealtime();
226
227 NetworkStats.Entry entry = null;
228 for (int i = 0; i < delta.size(); i++) {
229 entry = delta.getValues(i, entry);
Jeff Sharkeyb5a97e62018-05-22 11:35:29 -0600230
231 // As a last-ditch sanity check, report any negative values and
232 // clamp them so recording below doesn't croak.
233 if (entry.isNegative()) {
234 if (mObserver != null) {
235 mObserver.foundNonMonotonic(delta, i, mCookie);
236 }
237 entry.rxBytes = Math.max(entry.rxBytes, 0);
238 entry.rxPackets = Math.max(entry.rxPackets, 0);
239 entry.txBytes = Math.max(entry.txBytes, 0);
240 entry.txPackets = Math.max(entry.txPackets, 0);
241 entry.operations = Math.max(entry.operations, 0);
242 }
243
Jeff Sharkey63abc372012-01-11 18:38:16 -0800244 final NetworkIdentitySet ident = ifaceIdent.get(entry.iface);
245 if (ident == null) {
246 unknownIfaces.add(entry.iface);
247 continue;
248 }
249
Jeff Sharkeyac3fcb12012-05-02 18:11:52 -0700250 // skip when no delta occurred
Jeff Sharkey63abc372012-01-11 18:38:16 -0800251 if (entry.isEmpty()) continue;
252
253 // only record tag data when requested
254 if ((entry.tag == TAG_NONE) != mOnlyTags) {
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800255 if (mPending != null) {
256 mPending.recordData(ident, entry.uid, entry.set, entry.tag, start, end, entry);
257 }
Jeff Sharkey63abc372012-01-11 18:38:16 -0800258
259 // also record against boot stats when present
260 if (mSinceBoot != null) {
261 mSinceBoot.recordData(ident, entry.uid, entry.set, entry.tag, start, end, entry);
262 }
263
264 // also record against complete dataset when present
265 if (complete != null) {
266 complete.recordData(ident, entry.uid, entry.set, entry.tag, start, end, entry);
267 }
268 }
269 }
270
271 mLastSnapshot = snapshot;
272
Jeff Sharkey1f8ea2d2012-02-07 12:05:43 -0800273 if (LOGV && unknownIfaces.size() > 0) {
Jeff Sharkey63abc372012-01-11 18:38:16 -0800274 Slog.w(TAG, "unknown interfaces " + unknownIfaces + ", ignoring those stats");
275 }
276 }
277
278 /**
279 * Consider persisting any pending deltas, if they are beyond
280 * {@link #mPersistThresholdBytes}.
281 */
282 public void maybePersistLocked(long currentTimeMillis) {
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800283 checkNotNull(mRotator, "missing FileRotator");
Jeff Sharkey63abc372012-01-11 18:38:16 -0800284 final long pendingBytes = mPending.getTotalBytes();
285 if (pendingBytes >= mPersistThresholdBytes) {
286 forcePersistLocked(currentTimeMillis);
287 } else {
288 mRotator.maybeRotate(currentTimeMillis);
289 }
290 }
291
292 /**
293 * Force persisting any pending deltas.
294 */
295 public void forcePersistLocked(long currentTimeMillis) {
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800296 checkNotNull(mRotator, "missing FileRotator");
Jeff Sharkey63abc372012-01-11 18:38:16 -0800297 if (mPending.isDirty()) {
298 if (LOGD) Slog.d(TAG, "forcePersistLocked() writing for " + mCookie);
299 try {
300 mRotator.rewriteActive(mPendingRewriter, currentTimeMillis);
301 mRotator.maybeRotate(currentTimeMillis);
302 mPending.reset();
303 } catch (IOException e) {
304 Log.wtf(TAG, "problem persisting pending stats", e);
Jeff Sharkey6de357e2012-05-09 13:33:52 -0700305 recoverFromWtf();
Jeff Sharkeye4984be2013-09-10 21:03:27 -0700306 } catch (OutOfMemoryError e) {
307 Log.wtf(TAG, "problem persisting pending stats", e);
308 recoverFromWtf();
Jeff Sharkey63abc372012-01-11 18:38:16 -0800309 }
310 }
311 }
312
313 /**
314 * Remove the given UID from all {@link FileRotator} history, migrating it
315 * to {@link TrafficStats#UID_REMOVED}.
316 */
Jeff Sharkeydaa57e82012-09-19 14:10:39 -0700317 public void removeUidsLocked(int[] uids) {
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800318 if (mRotator != null) {
319 try {
320 // Rewrite all persisted data to migrate UID stats
321 mRotator.rewriteAll(new RemoveUidRewriter(mBucketDuration, uids));
322 } catch (IOException e) {
323 Log.wtf(TAG, "problem removing UIDs " + Arrays.toString(uids), e);
324 recoverFromWtf();
325 } catch (OutOfMemoryError e) {
326 Log.wtf(TAG, "problem removing UIDs " + Arrays.toString(uids), e);
327 recoverFromWtf();
328 }
Jeff Sharkey63abc372012-01-11 18:38:16 -0800329 }
330
Jeff Sharkeydaa57e82012-09-19 14:10:39 -0700331 // Remove any pending stats
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800332 if (mPending != null) {
333 mPending.removeUids(uids);
334 }
335 if (mSinceBoot != null) {
336 mSinceBoot.removeUids(uids);
337 }
Jeff Sharkeydaa57e82012-09-19 14:10:39 -0700338
339 // Clear UID from current stats snapshot
Jeff Sharkey63abc372012-01-11 18:38:16 -0800340 if (mLastSnapshot != null) {
junyulai8b8684a2018-10-29 22:26:22 +0800341 mLastSnapshot.removeUids(uids);
Jeff Sharkey63abc372012-01-11 18:38:16 -0800342 }
Jeff Sharkeyb52e3e52012-04-06 11:12:08 -0700343
344 final NetworkStatsCollection complete = mComplete != null ? mComplete.get() : null;
345 if (complete != null) {
Jeff Sharkeydaa57e82012-09-19 14:10:39 -0700346 complete.removeUids(uids);
Jeff Sharkeyb52e3e52012-04-06 11:12:08 -0700347 }
Jeff Sharkey63abc372012-01-11 18:38:16 -0800348 }
349
350 /**
351 * Rewriter that will combine current {@link NetworkStatsCollection} values
352 * with anything read from disk, and write combined set to disk. Clears the
353 * original {@link NetworkStatsCollection} when finished writing.
354 */
355 private static class CombiningRewriter implements FileRotator.Rewriter {
356 private final NetworkStatsCollection mCollection;
357
358 public CombiningRewriter(NetworkStatsCollection collection) {
359 mCollection = checkNotNull(collection, "missing NetworkStatsCollection");
360 }
361
Jeff Sharkeybfdd6802012-04-09 10:49:19 -0700362 @Override
Jeff Sharkey63abc372012-01-11 18:38:16 -0800363 public void reset() {
364 // ignored
365 }
366
Jeff Sharkeybfdd6802012-04-09 10:49:19 -0700367 @Override
Jeff Sharkey63abc372012-01-11 18:38:16 -0800368 public void read(InputStream in) throws IOException {
369 mCollection.read(in);
370 }
371
Jeff Sharkeybfdd6802012-04-09 10:49:19 -0700372 @Override
Jeff Sharkey63abc372012-01-11 18:38:16 -0800373 public boolean shouldWrite() {
374 return true;
375 }
376
Jeff Sharkeybfdd6802012-04-09 10:49:19 -0700377 @Override
Jeff Sharkey63abc372012-01-11 18:38:16 -0800378 public void write(OutputStream out) throws IOException {
379 mCollection.write(new DataOutputStream(out));
380 mCollection.reset();
381 }
382 }
383
384 /**
385 * Rewriter that will remove any {@link NetworkStatsHistory} attributed to
386 * the requested UID, only writing data back when modified.
387 */
388 public static class RemoveUidRewriter implements FileRotator.Rewriter {
389 private final NetworkStatsCollection mTemp;
Jeff Sharkeydaa57e82012-09-19 14:10:39 -0700390 private final int[] mUids;
Jeff Sharkey63abc372012-01-11 18:38:16 -0800391
Jeff Sharkeydaa57e82012-09-19 14:10:39 -0700392 public RemoveUidRewriter(long bucketDuration, int[] uids) {
Jeff Sharkey63abc372012-01-11 18:38:16 -0800393 mTemp = new NetworkStatsCollection(bucketDuration);
Jeff Sharkeydaa57e82012-09-19 14:10:39 -0700394 mUids = uids;
Jeff Sharkey63abc372012-01-11 18:38:16 -0800395 }
396
Jeff Sharkeybfdd6802012-04-09 10:49:19 -0700397 @Override
Jeff Sharkey63abc372012-01-11 18:38:16 -0800398 public void reset() {
399 mTemp.reset();
400 }
401
Jeff Sharkeybfdd6802012-04-09 10:49:19 -0700402 @Override
Jeff Sharkey63abc372012-01-11 18:38:16 -0800403 public void read(InputStream in) throws IOException {
404 mTemp.read(in);
405 mTemp.clearDirty();
Jeff Sharkeydaa57e82012-09-19 14:10:39 -0700406 mTemp.removeUids(mUids);
Jeff Sharkey63abc372012-01-11 18:38:16 -0800407 }
408
Jeff Sharkeybfdd6802012-04-09 10:49:19 -0700409 @Override
Jeff Sharkey63abc372012-01-11 18:38:16 -0800410 public boolean shouldWrite() {
411 return mTemp.isDirty();
412 }
413
Jeff Sharkeybfdd6802012-04-09 10:49:19 -0700414 @Override
Jeff Sharkey63abc372012-01-11 18:38:16 -0800415 public void write(OutputStream out) throws IOException {
416 mTemp.write(new DataOutputStream(out));
417 }
418 }
419
420 public void importLegacyNetworkLocked(File file) throws IOException {
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800421 checkNotNull(mRotator, "missing FileRotator");
422
Jeff Sharkey63abc372012-01-11 18:38:16 -0800423 // legacy file still exists; start empty to avoid double importing
424 mRotator.deleteAll();
425
426 final NetworkStatsCollection collection = new NetworkStatsCollection(mBucketDuration);
427 collection.readLegacyNetwork(file);
428
429 final long startMillis = collection.getStartMillis();
430 final long endMillis = collection.getEndMillis();
431
432 if (!collection.isEmpty()) {
433 // process legacy data, creating active file at starting time, then
434 // using end time to possibly trigger rotation.
435 mRotator.rewriteActive(new CombiningRewriter(collection), startMillis);
436 mRotator.maybeRotate(endMillis);
437 }
438 }
439
440 public void importLegacyUidLocked(File file) throws IOException {
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800441 checkNotNull(mRotator, "missing FileRotator");
442
Jeff Sharkey63abc372012-01-11 18:38:16 -0800443 // legacy file still exists; start empty to avoid double importing
444 mRotator.deleteAll();
445
446 final NetworkStatsCollection collection = new NetworkStatsCollection(mBucketDuration);
447 collection.readLegacyUid(file, mOnlyTags);
448
449 final long startMillis = collection.getStartMillis();
450 final long endMillis = collection.getEndMillis();
451
452 if (!collection.isEmpty()) {
453 // process legacy data, creating active file at starting time, then
454 // using end time to possibly trigger rotation.
455 mRotator.rewriteActive(new CombiningRewriter(collection), startMillis);
456 mRotator.maybeRotate(endMillis);
457 }
458 }
459
460 public void dumpLocked(IndentingPrintWriter pw, boolean fullHistory) {
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800461 if (mPending != null) {
462 pw.print("Pending bytes: "); pw.println(mPending.getTotalBytes());
463 }
Jeff Sharkey63abc372012-01-11 18:38:16 -0800464 if (fullHistory) {
465 pw.println("Complete history:");
466 getOrLoadCompleteLocked().dump(pw);
467 } else {
468 pw.println("History since boot:");
469 mSinceBoot.dump(pw);
470 }
471 }
Jeff Sharkey6de357e2012-05-09 13:33:52 -0700472
Makoto Onukida65a522017-01-13 10:23:30 -0800473 public void writeToProtoLocked(ProtoOutputStream proto, long tag) {
474 final long start = proto.start(tag);
475 if (mPending != null) {
476 proto.write(NetworkStatsRecorderProto.PENDING_TOTAL_BYTES, mPending.getTotalBytes());
477 }
478 getOrLoadCompleteLocked().writeToProto(proto, NetworkStatsRecorderProto.COMPLETE_HISTORY);
479 proto.end(start);
480 }
481
Jeff Sharkey55a442e2014-11-18 18:22:21 -0800482 public void dumpCheckin(PrintWriter pw, long start, long end) {
483 // Only load and dump stats from the requested window
484 getOrLoadPartialLocked(start, end).dumpCheckin(pw, start, end);
485 }
486
Jeff Sharkey6de357e2012-05-09 13:33:52 -0700487 /**
488 * Recover from {@link FileRotator} failure by dumping state to
489 * {@link DropBoxManager} and deleting contents.
490 */
491 private void recoverFromWtf() {
492 if (DUMP_BEFORE_DELETE) {
493 final ByteArrayOutputStream os = new ByteArrayOutputStream();
494 try {
495 mRotator.dumpAll(os);
496 } catch (IOException e) {
497 // ignore partial contents
498 os.reset();
499 } finally {
500 IoUtils.closeQuietly(os);
501 }
502 mDropBox.addData(TAG_NETSTATS_DUMP, os.toByteArray(), 0);
503 }
504
505 mRotator.deleteAll();
506 }
Jeff Sharkey63abc372012-01-11 18:38:16 -0800507}