blob: 80309e19eb428fc7403982bcab74dee395f7fe84 [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;
Makoto Onukida65a522017-01-13 10:23:30 -080032import android.service.NetworkStatsRecorderProto;
Jeff Sharkey63abc372012-01-11 18:38:16 -080033import android.util.Log;
Jeff Sharkeyac3fcb12012-05-02 18:11:52 -070034import android.util.MathUtils;
Jeff Sharkey63abc372012-01-11 18:38:16 -080035import android.util.Slog;
Makoto Onukida65a522017-01-13 10:23:30 -080036import android.util.proto.ProtoOutputStream;
Jeff Sharkey63abc372012-01-11 18:38:16 -080037
Wenchao Tongf5ea3402015-03-04 13:26:38 -080038import com.android.internal.net.VpnInfo;
Jeff Sharkey63abc372012-01-11 18:38:16 -080039import com.android.internal.util.FileRotator;
40import com.android.internal.util.IndentingPrintWriter;
41import com.google.android.collect.Sets;
42
Jeff Sharkey6de357e2012-05-09 13:33:52 -070043import java.io.ByteArrayOutputStream;
Jeff Sharkey63abc372012-01-11 18:38:16 -080044import java.io.DataOutputStream;
45import java.io.File;
46import java.io.IOException;
47import java.io.InputStream;
48import java.io.OutputStream;
Jeff Sharkey55a442e2014-11-18 18:22:21 -080049import java.io.PrintWriter;
Jeff Sharkey63abc372012-01-11 18:38:16 -080050import java.lang.ref.WeakReference;
Jeff Sharkeydaa57e82012-09-19 14:10:39 -070051import java.util.Arrays;
Jeff Sharkey63abc372012-01-11 18:38:16 -080052import java.util.HashSet;
53import java.util.Map;
54
Jeff Sharkey6de357e2012-05-09 13:33:52 -070055import libcore.io.IoUtils;
56
Jeff Sharkey63abc372012-01-11 18:38:16 -080057/**
58 * Logic to record deltas between periodic {@link NetworkStats} snapshots into
59 * {@link NetworkStatsHistory} that belong to {@link NetworkStatsCollection}.
60 * Keeps pending changes in memory until they pass a specific threshold, in
Antonio Cansadocd42acd2016-02-17 13:03:38 -080061 * bytes. Uses {@link FileRotator} for persistence logic if present.
Jeff Sharkey63abc372012-01-11 18:38:16 -080062 * <p>
63 * Not inherently thread safe.
64 */
65public class NetworkStatsRecorder {
66 private static final String TAG = "NetworkStatsRecorder";
Jeff Sharkeye7bb71d2012-02-28 15:13:08 -080067 private static final boolean LOGD = false;
Jeff Sharkey1f8ea2d2012-02-07 12:05:43 -080068 private static final boolean LOGV = false;
Jeff Sharkey63abc372012-01-11 18:38:16 -080069
Jeff Sharkey6de357e2012-05-09 13:33:52 -070070 private static final String TAG_NETSTATS_DUMP = "netstats_dump";
71
72 /** Dump before deleting in {@link #recoverFromWtf()}. */
73 private static final boolean DUMP_BEFORE_DELETE = true;
74
Jeff Sharkey63abc372012-01-11 18:38:16 -080075 private final FileRotator mRotator;
76 private final NonMonotonicObserver<String> mObserver;
Jeff Sharkey6de357e2012-05-09 13:33:52 -070077 private final DropBoxManager mDropBox;
Jeff Sharkey63abc372012-01-11 18:38:16 -080078 private final String mCookie;
79
80 private final long mBucketDuration;
Jeff Sharkey63abc372012-01-11 18:38:16 -080081 private final boolean mOnlyTags;
82
Jeff Sharkeyac3fcb12012-05-02 18:11:52 -070083 private long mPersistThresholdBytes = 2 * MB_IN_BYTES;
Jeff Sharkey63abc372012-01-11 18:38:16 -080084 private NetworkStats mLastSnapshot;
85
86 private final NetworkStatsCollection mPending;
87 private final NetworkStatsCollection mSinceBoot;
88
89 private final CombiningRewriter mPendingRewriter;
90
91 private WeakReference<NetworkStatsCollection> mComplete;
92
Antonio Cansadocd42acd2016-02-17 13:03:38 -080093 /**
94 * Non-persisted recorder, with only one bucket. Used by {@link NetworkStatsObservers}.
95 */
96 public NetworkStatsRecorder() {
97 mRotator = null;
98 mObserver = null;
99 mDropBox = null;
100 mCookie = null;
101
102 // set the bucket big enough to have all data in one bucket, but allow some
103 // slack to avoid overflow
104 mBucketDuration = YEAR_IN_MILLIS;
105 mOnlyTags = false;
106
107 mPending = null;
108 mSinceBoot = new NetworkStatsCollection(mBucketDuration);
109
110 mPendingRewriter = null;
111 }
112
113 /**
114 * Persisted recorder.
115 */
Jeff Sharkey63abc372012-01-11 18:38:16 -0800116 public NetworkStatsRecorder(FileRotator rotator, NonMonotonicObserver<String> observer,
Jeff Sharkey6de357e2012-05-09 13:33:52 -0700117 DropBoxManager dropBox, String cookie, long bucketDuration, boolean onlyTags) {
Jeff Sharkey63abc372012-01-11 18:38:16 -0800118 mRotator = checkNotNull(rotator, "missing FileRotator");
119 mObserver = checkNotNull(observer, "missing NonMonotonicObserver");
Jeff Sharkey6de357e2012-05-09 13:33:52 -0700120 mDropBox = checkNotNull(dropBox, "missing DropBoxManager");
Jeff Sharkey63abc372012-01-11 18:38:16 -0800121 mCookie = cookie;
122
123 mBucketDuration = bucketDuration;
Jeff Sharkey63abc372012-01-11 18:38:16 -0800124 mOnlyTags = onlyTags;
125
126 mPending = new NetworkStatsCollection(bucketDuration);
127 mSinceBoot = new NetworkStatsCollection(bucketDuration);
128
129 mPendingRewriter = new CombiningRewriter(mPending);
130 }
131
Jeff Sharkeyac3fcb12012-05-02 18:11:52 -0700132 public void setPersistThreshold(long thresholdBytes) {
133 if (LOGV) Slog.v(TAG, "setPersistThreshold() with " + thresholdBytes);
134 mPersistThresholdBytes = MathUtils.constrain(
135 thresholdBytes, 1 * KB_IN_BYTES, 100 * MB_IN_BYTES);
136 }
137
Jeff Sharkey63abc372012-01-11 18:38:16 -0800138 public void resetLocked() {
139 mLastSnapshot = null;
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800140 if (mPending != null) {
141 mPending.reset();
142 }
143 if (mSinceBoot != null) {
144 mSinceBoot.reset();
145 }
146 if (mComplete != null) {
147 mComplete.clear();
148 }
Jeff Sharkey63abc372012-01-11 18:38:16 -0800149 }
150
151 public NetworkStats.Entry getTotalSinceBootLocked(NetworkTemplate template) {
Jeff Davidson1efb1332015-12-09 18:04:50 -0800152 return mSinceBoot.getSummary(template, Long.MIN_VALUE, Long.MAX_VALUE,
153 NetworkStatsAccess.Level.DEVICE).getTotal(null);
Jeff Sharkey63abc372012-01-11 18:38:16 -0800154 }
155
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800156 public NetworkStatsCollection getSinceBoot() {
157 return mSinceBoot;
158 }
159
Jeff Sharkey63abc372012-01-11 18:38:16 -0800160 /**
161 * Load complete history represented by {@link FileRotator}. Caches
162 * internally as a {@link WeakReference}, and updated with future
163 * {@link #recordSnapshotLocked(NetworkStats, Map, long)} snapshots as long
164 * as reference is valid.
165 */
166 public NetworkStatsCollection getOrLoadCompleteLocked() {
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800167 checkNotNull(mRotator, "missing FileRotator");
Jeff Sharkey55a442e2014-11-18 18:22:21 -0800168 NetworkStatsCollection res = mComplete != null ? mComplete.get() : null;
169 if (res == null) {
170 res = loadLocked(Long.MIN_VALUE, Long.MAX_VALUE);
171 mComplete = new WeakReference<NetworkStatsCollection>(res);
Jeff Sharkey63abc372012-01-11 18:38:16 -0800172 }
Jeff Sharkey55a442e2014-11-18 18:22:21 -0800173 return res;
174 }
175
176 public NetworkStatsCollection getOrLoadPartialLocked(long start, long end) {
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800177 checkNotNull(mRotator, "missing FileRotator");
Jeff Sharkey55a442e2014-11-18 18:22:21 -0800178 NetworkStatsCollection res = mComplete != null ? mComplete.get() : null;
179 if (res == null) {
180 res = loadLocked(start, end);
181 }
182 return res;
183 }
184
185 private NetworkStatsCollection loadLocked(long start, long end) {
186 if (LOGD) Slog.d(TAG, "loadLocked() reading from disk for " + mCookie);
187 final NetworkStatsCollection res = new NetworkStatsCollection(mBucketDuration);
188 try {
189 mRotator.readMatching(res, start, end);
190 res.recordCollection(mPending);
191 } catch (IOException e) {
192 Log.wtf(TAG, "problem completely reading network stats", e);
193 recoverFromWtf();
194 } catch (OutOfMemoryError e) {
195 Log.wtf(TAG, "problem completely reading network stats", e);
196 recoverFromWtf();
197 }
198 return res;
Jeff Sharkey63abc372012-01-11 18:38:16 -0800199 }
200
201 /**
202 * Record any delta that occurred since last {@link NetworkStats} snapshot,
203 * using the given {@link Map} to identify network interfaces. First
204 * snapshot is considered bootstrap, and is not counted as delta.
Jeff Davidson4ff3bcf2016-06-15 13:31:52 -0700205 *
206 * @param vpnArray Optional info about the currently active VPN, if any. This is used to
207 * redistribute traffic from the VPN app to the underlying responsible apps.
208 * This should always be set to null if the provided snapshot is aggregated
209 * across all UIDs (e.g. contains UID_ALL buckets), regardless of VPN state.
Jeff Sharkey63abc372012-01-11 18:38:16 -0800210 */
211 public void recordSnapshotLocked(NetworkStats snapshot,
Jeff Davidson4ff3bcf2016-06-15 13:31:52 -0700212 Map<String, NetworkIdentitySet> ifaceIdent, @Nullable VpnInfo[] vpnArray,
Wenchao Tongf5ea3402015-03-04 13:26:38 -0800213 long currentTimeMillis) {
Jeff Sharkey63abc372012-01-11 18:38:16 -0800214 final HashSet<String> unknownIfaces = Sets.newHashSet();
215
Jeff Sharkeye8914c32012-05-01 16:26:09 -0700216 // skip recording when snapshot missing
217 if (snapshot == null) return;
218
Jeff Sharkey63abc372012-01-11 18:38:16 -0800219 // assume first snapshot is bootstrap and don't record
220 if (mLastSnapshot == null) {
221 mLastSnapshot = snapshot;
222 return;
223 }
224
225 final NetworkStatsCollection complete = mComplete != null ? mComplete.get() : null;
226
227 final NetworkStats delta = NetworkStats.subtract(
228 snapshot, mLastSnapshot, mObserver, mCookie);
229 final long end = currentTimeMillis;
230 final long start = end - delta.getElapsedRealtime();
231
Wenchao Tongf5ea3402015-03-04 13:26:38 -0800232 if (vpnArray != null) {
233 for (VpnInfo info : vpnArray) {
234 delta.migrateTun(info.ownerUid, info.vpnIface, info.primaryUnderlyingIface);
235 }
236 }
237
Jeff Sharkey63abc372012-01-11 18:38:16 -0800238 NetworkStats.Entry entry = null;
239 for (int i = 0; i < delta.size(); i++) {
240 entry = delta.getValues(i, entry);
241 final NetworkIdentitySet ident = ifaceIdent.get(entry.iface);
242 if (ident == null) {
243 unknownIfaces.add(entry.iface);
244 continue;
245 }
246
Jeff Sharkeyac3fcb12012-05-02 18:11:52 -0700247 // skip when no delta occurred
Jeff Sharkey63abc372012-01-11 18:38:16 -0800248 if (entry.isEmpty()) continue;
249
250 // only record tag data when requested
251 if ((entry.tag == TAG_NONE) != mOnlyTags) {
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800252 if (mPending != null) {
253 mPending.recordData(ident, entry.uid, entry.set, entry.tag, start, end, entry);
254 }
Jeff Sharkey63abc372012-01-11 18:38:16 -0800255
256 // also record against boot stats when present
257 if (mSinceBoot != null) {
258 mSinceBoot.recordData(ident, entry.uid, entry.set, entry.tag, start, end, entry);
259 }
260
261 // also record against complete dataset when present
262 if (complete != null) {
263 complete.recordData(ident, entry.uid, entry.set, entry.tag, start, end, entry);
264 }
265 }
266 }
267
268 mLastSnapshot = snapshot;
269
Jeff Sharkey1f8ea2d2012-02-07 12:05:43 -0800270 if (LOGV && unknownIfaces.size() > 0) {
Jeff Sharkey63abc372012-01-11 18:38:16 -0800271 Slog.w(TAG, "unknown interfaces " + unknownIfaces + ", ignoring those stats");
272 }
273 }
274
275 /**
276 * Consider persisting any pending deltas, if they are beyond
277 * {@link #mPersistThresholdBytes}.
278 */
279 public void maybePersistLocked(long currentTimeMillis) {
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800280 checkNotNull(mRotator, "missing FileRotator");
Jeff Sharkey63abc372012-01-11 18:38:16 -0800281 final long pendingBytes = mPending.getTotalBytes();
282 if (pendingBytes >= mPersistThresholdBytes) {
283 forcePersistLocked(currentTimeMillis);
284 } else {
285 mRotator.maybeRotate(currentTimeMillis);
286 }
287 }
288
289 /**
290 * Force persisting any pending deltas.
291 */
292 public void forcePersistLocked(long currentTimeMillis) {
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800293 checkNotNull(mRotator, "missing FileRotator");
Jeff Sharkey63abc372012-01-11 18:38:16 -0800294 if (mPending.isDirty()) {
295 if (LOGD) Slog.d(TAG, "forcePersistLocked() writing for " + mCookie);
296 try {
297 mRotator.rewriteActive(mPendingRewriter, currentTimeMillis);
298 mRotator.maybeRotate(currentTimeMillis);
299 mPending.reset();
300 } catch (IOException e) {
301 Log.wtf(TAG, "problem persisting pending stats", e);
Jeff Sharkey6de357e2012-05-09 13:33:52 -0700302 recoverFromWtf();
Jeff Sharkeye4984be2013-09-10 21:03:27 -0700303 } catch (OutOfMemoryError e) {
304 Log.wtf(TAG, "problem persisting pending stats", e);
305 recoverFromWtf();
Jeff Sharkey63abc372012-01-11 18:38:16 -0800306 }
307 }
308 }
309
310 /**
311 * Remove the given UID from all {@link FileRotator} history, migrating it
312 * to {@link TrafficStats#UID_REMOVED}.
313 */
Jeff Sharkeydaa57e82012-09-19 14:10:39 -0700314 public void removeUidsLocked(int[] uids) {
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800315 if (mRotator != null) {
316 try {
317 // Rewrite all persisted data to migrate UID stats
318 mRotator.rewriteAll(new RemoveUidRewriter(mBucketDuration, uids));
319 } catch (IOException e) {
320 Log.wtf(TAG, "problem removing UIDs " + Arrays.toString(uids), e);
321 recoverFromWtf();
322 } catch (OutOfMemoryError e) {
323 Log.wtf(TAG, "problem removing UIDs " + Arrays.toString(uids), e);
324 recoverFromWtf();
325 }
Jeff Sharkey63abc372012-01-11 18:38:16 -0800326 }
327
Jeff Sharkeydaa57e82012-09-19 14:10:39 -0700328 // Remove any pending stats
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800329 if (mPending != null) {
330 mPending.removeUids(uids);
331 }
332 if (mSinceBoot != null) {
333 mSinceBoot.removeUids(uids);
334 }
Jeff Sharkeydaa57e82012-09-19 14:10:39 -0700335
336 // Clear UID from current stats snapshot
Jeff Sharkey63abc372012-01-11 18:38:16 -0800337 if (mLastSnapshot != null) {
Jeff Sharkeydaa57e82012-09-19 14:10:39 -0700338 mLastSnapshot = mLastSnapshot.withoutUids(uids);
Jeff Sharkey63abc372012-01-11 18:38:16 -0800339 }
Jeff Sharkeyb52e3e52012-04-06 11:12:08 -0700340
341 final NetworkStatsCollection complete = mComplete != null ? mComplete.get() : null;
342 if (complete != null) {
Jeff Sharkeydaa57e82012-09-19 14:10:39 -0700343 complete.removeUids(uids);
Jeff Sharkeyb52e3e52012-04-06 11:12:08 -0700344 }
Jeff Sharkey63abc372012-01-11 18:38:16 -0800345 }
346
347 /**
348 * Rewriter that will combine current {@link NetworkStatsCollection} values
349 * with anything read from disk, and write combined set to disk. Clears the
350 * original {@link NetworkStatsCollection} when finished writing.
351 */
352 private static class CombiningRewriter implements FileRotator.Rewriter {
353 private final NetworkStatsCollection mCollection;
354
355 public CombiningRewriter(NetworkStatsCollection collection) {
356 mCollection = checkNotNull(collection, "missing NetworkStatsCollection");
357 }
358
Jeff Sharkeybfdd6802012-04-09 10:49:19 -0700359 @Override
Jeff Sharkey63abc372012-01-11 18:38:16 -0800360 public void reset() {
361 // ignored
362 }
363
Jeff Sharkeybfdd6802012-04-09 10:49:19 -0700364 @Override
Jeff Sharkey63abc372012-01-11 18:38:16 -0800365 public void read(InputStream in) throws IOException {
366 mCollection.read(in);
367 }
368
Jeff Sharkeybfdd6802012-04-09 10:49:19 -0700369 @Override
Jeff Sharkey63abc372012-01-11 18:38:16 -0800370 public boolean shouldWrite() {
371 return true;
372 }
373
Jeff Sharkeybfdd6802012-04-09 10:49:19 -0700374 @Override
Jeff Sharkey63abc372012-01-11 18:38:16 -0800375 public void write(OutputStream out) throws IOException {
376 mCollection.write(new DataOutputStream(out));
377 mCollection.reset();
378 }
379 }
380
381 /**
382 * Rewriter that will remove any {@link NetworkStatsHistory} attributed to
383 * the requested UID, only writing data back when modified.
384 */
385 public static class RemoveUidRewriter implements FileRotator.Rewriter {
386 private final NetworkStatsCollection mTemp;
Jeff Sharkeydaa57e82012-09-19 14:10:39 -0700387 private final int[] mUids;
Jeff Sharkey63abc372012-01-11 18:38:16 -0800388
Jeff Sharkeydaa57e82012-09-19 14:10:39 -0700389 public RemoveUidRewriter(long bucketDuration, int[] uids) {
Jeff Sharkey63abc372012-01-11 18:38:16 -0800390 mTemp = new NetworkStatsCollection(bucketDuration);
Jeff Sharkeydaa57e82012-09-19 14:10:39 -0700391 mUids = uids;
Jeff Sharkey63abc372012-01-11 18:38:16 -0800392 }
393
Jeff Sharkeybfdd6802012-04-09 10:49:19 -0700394 @Override
Jeff Sharkey63abc372012-01-11 18:38:16 -0800395 public void reset() {
396 mTemp.reset();
397 }
398
Jeff Sharkeybfdd6802012-04-09 10:49:19 -0700399 @Override
Jeff Sharkey63abc372012-01-11 18:38:16 -0800400 public void read(InputStream in) throws IOException {
401 mTemp.read(in);
402 mTemp.clearDirty();
Jeff Sharkeydaa57e82012-09-19 14:10:39 -0700403 mTemp.removeUids(mUids);
Jeff Sharkey63abc372012-01-11 18:38:16 -0800404 }
405
Jeff Sharkeybfdd6802012-04-09 10:49:19 -0700406 @Override
Jeff Sharkey63abc372012-01-11 18:38:16 -0800407 public boolean shouldWrite() {
408 return mTemp.isDirty();
409 }
410
Jeff Sharkeybfdd6802012-04-09 10:49:19 -0700411 @Override
Jeff Sharkey63abc372012-01-11 18:38:16 -0800412 public void write(OutputStream out) throws IOException {
413 mTemp.write(new DataOutputStream(out));
414 }
415 }
416
417 public void importLegacyNetworkLocked(File file) throws IOException {
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800418 checkNotNull(mRotator, "missing FileRotator");
419
Jeff Sharkey63abc372012-01-11 18:38:16 -0800420 // legacy file still exists; start empty to avoid double importing
421 mRotator.deleteAll();
422
423 final NetworkStatsCollection collection = new NetworkStatsCollection(mBucketDuration);
424 collection.readLegacyNetwork(file);
425
426 final long startMillis = collection.getStartMillis();
427 final long endMillis = collection.getEndMillis();
428
429 if (!collection.isEmpty()) {
430 // process legacy data, creating active file at starting time, then
431 // using end time to possibly trigger rotation.
432 mRotator.rewriteActive(new CombiningRewriter(collection), startMillis);
433 mRotator.maybeRotate(endMillis);
434 }
435 }
436
437 public void importLegacyUidLocked(File file) throws IOException {
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800438 checkNotNull(mRotator, "missing FileRotator");
439
Jeff Sharkey63abc372012-01-11 18:38:16 -0800440 // legacy file still exists; start empty to avoid double importing
441 mRotator.deleteAll();
442
443 final NetworkStatsCollection collection = new NetworkStatsCollection(mBucketDuration);
444 collection.readLegacyUid(file, mOnlyTags);
445
446 final long startMillis = collection.getStartMillis();
447 final long endMillis = collection.getEndMillis();
448
449 if (!collection.isEmpty()) {
450 // process legacy data, creating active file at starting time, then
451 // using end time to possibly trigger rotation.
452 mRotator.rewriteActive(new CombiningRewriter(collection), startMillis);
453 mRotator.maybeRotate(endMillis);
454 }
455 }
456
457 public void dumpLocked(IndentingPrintWriter pw, boolean fullHistory) {
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800458 if (mPending != null) {
459 pw.print("Pending bytes: "); pw.println(mPending.getTotalBytes());
460 }
Jeff Sharkey63abc372012-01-11 18:38:16 -0800461 if (fullHistory) {
462 pw.println("Complete history:");
463 getOrLoadCompleteLocked().dump(pw);
464 } else {
465 pw.println("History since boot:");
466 mSinceBoot.dump(pw);
467 }
468 }
Jeff Sharkey6de357e2012-05-09 13:33:52 -0700469
Makoto Onukida65a522017-01-13 10:23:30 -0800470 public void writeToProtoLocked(ProtoOutputStream proto, long tag) {
471 final long start = proto.start(tag);
472 if (mPending != null) {
473 proto.write(NetworkStatsRecorderProto.PENDING_TOTAL_BYTES, mPending.getTotalBytes());
474 }
475 getOrLoadCompleteLocked().writeToProto(proto, NetworkStatsRecorderProto.COMPLETE_HISTORY);
476 proto.end(start);
477 }
478
Jeff Sharkey55a442e2014-11-18 18:22:21 -0800479 public void dumpCheckin(PrintWriter pw, long start, long end) {
480 // Only load and dump stats from the requested window
481 getOrLoadPartialLocked(start, end).dumpCheckin(pw, start, end);
482 }
483
Jeff Sharkey6de357e2012-05-09 13:33:52 -0700484 /**
485 * Recover from {@link FileRotator} failure by dumping state to
486 * {@link DropBoxManager} and deleting contents.
487 */
488 private void recoverFromWtf() {
489 if (DUMP_BEFORE_DELETE) {
490 final ByteArrayOutputStream os = new ByteArrayOutputStream();
491 try {
492 mRotator.dumpAll(os);
493 } catch (IOException e) {
494 // ignore partial contents
495 os.reset();
496 } finally {
497 IoUtils.closeQuietly(os);
498 }
499 mDropBox.addData(TAG_NETSTATS_DUMP, os.toByteArray(), 0);
500 }
501
502 mRotator.deleteAll();
503 }
Jeff Sharkey63abc372012-01-11 18:38:16 -0800504}