blob: a2e7e0cae96bb57dd5a3d191fc9b88aa5b77bfb0 [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
Jeff Davidson4ff3bcf2016-06-15 13:31:52 -070026import android.annotation.Nullable;
Jeff Sharkey63abc372012-01-11 18:38:16 -080027import android.net.NetworkStats;
28import android.net.NetworkStats.NonMonotonicObserver;
29import android.net.NetworkStatsHistory;
30import android.net.NetworkTemplate;
31import android.net.TrafficStats;
Jeff Sharkeyf4de2942017-08-29 15:32:13 -060032import android.os.Binder;
Jeff Sharkey6de357e2012-05-09 13:33:52 -070033import android.os.DropBoxManager;
Makoto Onukida65a522017-01-13 10:23:30 -080034import android.service.NetworkStatsRecorderProto;
Jeff Sharkey63abc372012-01-11 18:38:16 -080035import android.util.Log;
Jeff Sharkeyac3fcb12012-05-02 18:11:52 -070036import android.util.MathUtils;
Jeff Sharkey63abc372012-01-11 18:38:16 -080037import android.util.Slog;
Makoto Onukida65a522017-01-13 10:23:30 -080038import android.util.proto.ProtoOutputStream;
Jeff Sharkey63abc372012-01-11 18:38:16 -080039
Wenchao Tongf5ea3402015-03-04 13:26:38 -080040import com.android.internal.net.VpnInfo;
Jeff Sharkey63abc372012-01-11 18:38:16 -080041import com.android.internal.util.FileRotator;
42import com.android.internal.util.IndentingPrintWriter;
Jeff Sharkeyf4de2942017-08-29 15:32:13 -060043
44import libcore.io.IoUtils;
45
Jeff Sharkey63abc372012-01-11 18:38:16 -080046import com.google.android.collect.Sets;
47
Jeff Sharkey6de357e2012-05-09 13:33:52 -070048import java.io.ByteArrayOutputStream;
Jeff Sharkey63abc372012-01-11 18:38:16 -080049import java.io.DataOutputStream;
50import java.io.File;
51import java.io.IOException;
52import java.io.InputStream;
53import java.io.OutputStream;
Jeff Sharkey55a442e2014-11-18 18:22:21 -080054import java.io.PrintWriter;
Jeff Sharkey63abc372012-01-11 18:38:16 -080055import java.lang.ref.WeakReference;
Jeff Sharkeydaa57e82012-09-19 14:10:39 -070056import java.util.Arrays;
Jeff Sharkey63abc372012-01-11 18:38:16 -080057import java.util.HashSet;
58import java.util.Map;
59
60/**
61 * Logic to record deltas between periodic {@link NetworkStats} snapshots into
62 * {@link NetworkStatsHistory} that belong to {@link NetworkStatsCollection}.
63 * Keeps pending changes in memory until they pass a specific threshold, in
Antonio Cansadocd42acd2016-02-17 13:03:38 -080064 * bytes. Uses {@link FileRotator} for persistence logic if present.
Jeff Sharkey63abc372012-01-11 18:38:16 -080065 * <p>
66 * Not inherently thread safe.
67 */
68public class NetworkStatsRecorder {
69 private static final String TAG = "NetworkStatsRecorder";
Jeff Sharkeye7bb71d2012-02-28 15:13:08 -080070 private static final boolean LOGD = false;
Jeff Sharkey1f8ea2d2012-02-07 12:05:43 -080071 private static final boolean LOGV = false;
Jeff Sharkey63abc372012-01-11 18:38:16 -080072
Jeff Sharkey6de357e2012-05-09 13:33:52 -070073 private static final String TAG_NETSTATS_DUMP = "netstats_dump";
74
75 /** Dump before deleting in {@link #recoverFromWtf()}. */
76 private static final boolean DUMP_BEFORE_DELETE = true;
77
Jeff Sharkey63abc372012-01-11 18:38:16 -080078 private final FileRotator mRotator;
79 private final NonMonotonicObserver<String> mObserver;
Jeff Sharkey6de357e2012-05-09 13:33:52 -070080 private final DropBoxManager mDropBox;
Jeff Sharkey63abc372012-01-11 18:38:16 -080081 private final String mCookie;
82
83 private final long mBucketDuration;
Jeff Sharkey63abc372012-01-11 18:38:16 -080084 private final boolean mOnlyTags;
85
Jeff Sharkeyac3fcb12012-05-02 18:11:52 -070086 private long mPersistThresholdBytes = 2 * MB_IN_BYTES;
Jeff Sharkey63abc372012-01-11 18:38:16 -080087 private NetworkStats mLastSnapshot;
88
89 private final NetworkStatsCollection mPending;
90 private final NetworkStatsCollection mSinceBoot;
91
92 private final CombiningRewriter mPendingRewriter;
93
94 private WeakReference<NetworkStatsCollection> mComplete;
95
Antonio Cansadocd42acd2016-02-17 13:03:38 -080096 /**
97 * Non-persisted recorder, with only one bucket. Used by {@link NetworkStatsObservers}.
98 */
99 public NetworkStatsRecorder() {
100 mRotator = null;
101 mObserver = null;
102 mDropBox = null;
103 mCookie = null;
104
105 // set the bucket big enough to have all data in one bucket, but allow some
106 // slack to avoid overflow
107 mBucketDuration = YEAR_IN_MILLIS;
108 mOnlyTags = false;
109
110 mPending = null;
111 mSinceBoot = new NetworkStatsCollection(mBucketDuration);
112
113 mPendingRewriter = null;
114 }
115
116 /**
117 * Persisted recorder.
118 */
Jeff Sharkey63abc372012-01-11 18:38:16 -0800119 public NetworkStatsRecorder(FileRotator rotator, NonMonotonicObserver<String> observer,
Jeff Sharkey6de357e2012-05-09 13:33:52 -0700120 DropBoxManager dropBox, String cookie, long bucketDuration, boolean onlyTags) {
Jeff Sharkey63abc372012-01-11 18:38:16 -0800121 mRotator = checkNotNull(rotator, "missing FileRotator");
122 mObserver = checkNotNull(observer, "missing NonMonotonicObserver");
Jeff Sharkey6de357e2012-05-09 13:33:52 -0700123 mDropBox = checkNotNull(dropBox, "missing DropBoxManager");
Jeff Sharkey63abc372012-01-11 18:38:16 -0800124 mCookie = cookie;
125
126 mBucketDuration = bucketDuration;
Jeff Sharkey63abc372012-01-11 18:38:16 -0800127 mOnlyTags = onlyTags;
128
129 mPending = new NetworkStatsCollection(bucketDuration);
130 mSinceBoot = new NetworkStatsCollection(bucketDuration);
131
132 mPendingRewriter = new CombiningRewriter(mPending);
133 }
134
Jeff Sharkeyac3fcb12012-05-02 18:11:52 -0700135 public void setPersistThreshold(long thresholdBytes) {
136 if (LOGV) Slog.v(TAG, "setPersistThreshold() with " + thresholdBytes);
137 mPersistThresholdBytes = MathUtils.constrain(
138 thresholdBytes, 1 * KB_IN_BYTES, 100 * MB_IN_BYTES);
139 }
140
Jeff Sharkey63abc372012-01-11 18:38:16 -0800141 public void resetLocked() {
142 mLastSnapshot = null;
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800143 if (mPending != null) {
144 mPending.reset();
145 }
146 if (mSinceBoot != null) {
147 mSinceBoot.reset();
148 }
149 if (mComplete != null) {
150 mComplete.clear();
151 }
Jeff Sharkey63abc372012-01-11 18:38:16 -0800152 }
153
154 public NetworkStats.Entry getTotalSinceBootLocked(NetworkTemplate template) {
Jeff Davidson1efb1332015-12-09 18:04:50 -0800155 return mSinceBoot.getSummary(template, Long.MIN_VALUE, Long.MAX_VALUE,
Jeff Sharkeyf4de2942017-08-29 15:32:13 -0600156 NetworkStatsAccess.Level.DEVICE, Binder.getCallingUid()).getTotal(null);
Jeff Sharkey63abc372012-01-11 18:38:16 -0800157 }
158
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800159 public NetworkStatsCollection getSinceBoot() {
160 return mSinceBoot;
161 }
162
Jeff Sharkey63abc372012-01-11 18:38:16 -0800163 /**
164 * Load complete history represented by {@link FileRotator}. Caches
165 * internally as a {@link WeakReference}, and updated with future
166 * {@link #recordSnapshotLocked(NetworkStats, Map, long)} snapshots as long
167 * as reference is valid.
168 */
169 public NetworkStatsCollection getOrLoadCompleteLocked() {
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800170 checkNotNull(mRotator, "missing FileRotator");
Jeff Sharkey55a442e2014-11-18 18:22:21 -0800171 NetworkStatsCollection res = mComplete != null ? mComplete.get() : null;
172 if (res == null) {
173 res = loadLocked(Long.MIN_VALUE, Long.MAX_VALUE);
174 mComplete = new WeakReference<NetworkStatsCollection>(res);
Jeff Sharkey63abc372012-01-11 18:38:16 -0800175 }
Jeff Sharkey55a442e2014-11-18 18:22:21 -0800176 return res;
177 }
178
179 public NetworkStatsCollection getOrLoadPartialLocked(long start, long end) {
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800180 checkNotNull(mRotator, "missing FileRotator");
Jeff Sharkey55a442e2014-11-18 18:22:21 -0800181 NetworkStatsCollection res = mComplete != null ? mComplete.get() : null;
182 if (res == null) {
183 res = loadLocked(start, end);
184 }
185 return res;
186 }
187
188 private NetworkStatsCollection loadLocked(long start, long end) {
189 if (LOGD) Slog.d(TAG, "loadLocked() reading from disk for " + mCookie);
190 final NetworkStatsCollection res = new NetworkStatsCollection(mBucketDuration);
191 try {
192 mRotator.readMatching(res, start, end);
193 res.recordCollection(mPending);
194 } catch (IOException e) {
195 Log.wtf(TAG, "problem completely reading network stats", e);
196 recoverFromWtf();
197 } catch (OutOfMemoryError e) {
198 Log.wtf(TAG, "problem completely reading network stats", e);
199 recoverFromWtf();
200 }
201 return res;
Jeff Sharkey63abc372012-01-11 18:38:16 -0800202 }
203
204 /**
205 * Record any delta that occurred since last {@link NetworkStats} snapshot,
206 * using the given {@link Map} to identify network interfaces. First
207 * snapshot is considered bootstrap, and is not counted as delta.
Jeff Davidson4ff3bcf2016-06-15 13:31:52 -0700208 *
209 * @param vpnArray Optional info about the currently active VPN, if any. This is used to
210 * redistribute traffic from the VPN app to the underlying responsible apps.
211 * This should always be set to null if the provided snapshot is aggregated
212 * across all UIDs (e.g. contains UID_ALL buckets), regardless of VPN state.
Jeff Sharkey63abc372012-01-11 18:38:16 -0800213 */
214 public void recordSnapshotLocked(NetworkStats snapshot,
Jeff Davidson4ff3bcf2016-06-15 13:31:52 -0700215 Map<String, NetworkIdentitySet> ifaceIdent, @Nullable VpnInfo[] vpnArray,
Wenchao Tongf5ea3402015-03-04 13:26:38 -0800216 long currentTimeMillis) {
Jeff Sharkey63abc372012-01-11 18:38:16 -0800217 final HashSet<String> unknownIfaces = Sets.newHashSet();
218
Jeff Sharkeye8914c32012-05-01 16:26:09 -0700219 // skip recording when snapshot missing
220 if (snapshot == null) return;
221
Jeff Sharkey63abc372012-01-11 18:38:16 -0800222 // assume first snapshot is bootstrap and don't record
223 if (mLastSnapshot == null) {
224 mLastSnapshot = snapshot;
225 return;
226 }
227
228 final NetworkStatsCollection complete = mComplete != null ? mComplete.get() : null;
229
230 final NetworkStats delta = NetworkStats.subtract(
231 snapshot, mLastSnapshot, mObserver, mCookie);
232 final long end = currentTimeMillis;
233 final long start = end - delta.getElapsedRealtime();
234
Wenchao Tongf5ea3402015-03-04 13:26:38 -0800235 if (vpnArray != null) {
236 for (VpnInfo info : vpnArray) {
237 delta.migrateTun(info.ownerUid, info.vpnIface, info.primaryUnderlyingIface);
238 }
239 }
240
Jeff Sharkey63abc372012-01-11 18:38:16 -0800241 NetworkStats.Entry entry = null;
242 for (int i = 0; i < delta.size(); i++) {
243 entry = delta.getValues(i, entry);
Jeff Sharkeyb5a97e62018-05-22 11:35:29 -0600244
245 // As a last-ditch sanity check, report any negative values and
246 // clamp them so recording below doesn't croak.
247 if (entry.isNegative()) {
248 if (mObserver != null) {
249 mObserver.foundNonMonotonic(delta, i, mCookie);
250 }
251 entry.rxBytes = Math.max(entry.rxBytes, 0);
252 entry.rxPackets = Math.max(entry.rxPackets, 0);
253 entry.txBytes = Math.max(entry.txBytes, 0);
254 entry.txPackets = Math.max(entry.txPackets, 0);
255 entry.operations = Math.max(entry.operations, 0);
256 }
257
Jeff Sharkey63abc372012-01-11 18:38:16 -0800258 final NetworkIdentitySet ident = ifaceIdent.get(entry.iface);
259 if (ident == null) {
260 unknownIfaces.add(entry.iface);
261 continue;
262 }
263
Jeff Sharkeyac3fcb12012-05-02 18:11:52 -0700264 // skip when no delta occurred
Jeff Sharkey63abc372012-01-11 18:38:16 -0800265 if (entry.isEmpty()) continue;
266
267 // only record tag data when requested
268 if ((entry.tag == TAG_NONE) != mOnlyTags) {
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800269 if (mPending != null) {
270 mPending.recordData(ident, entry.uid, entry.set, entry.tag, start, end, entry);
271 }
Jeff Sharkey63abc372012-01-11 18:38:16 -0800272
273 // also record against boot stats when present
274 if (mSinceBoot != null) {
275 mSinceBoot.recordData(ident, entry.uid, entry.set, entry.tag, start, end, entry);
276 }
277
278 // also record against complete dataset when present
279 if (complete != null) {
280 complete.recordData(ident, entry.uid, entry.set, entry.tag, start, end, entry);
281 }
282 }
283 }
284
285 mLastSnapshot = snapshot;
286
Jeff Sharkey1f8ea2d2012-02-07 12:05:43 -0800287 if (LOGV && unknownIfaces.size() > 0) {
Jeff Sharkey63abc372012-01-11 18:38:16 -0800288 Slog.w(TAG, "unknown interfaces " + unknownIfaces + ", ignoring those stats");
289 }
290 }
291
292 /**
293 * Consider persisting any pending deltas, if they are beyond
294 * {@link #mPersistThresholdBytes}.
295 */
296 public void maybePersistLocked(long currentTimeMillis) {
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800297 checkNotNull(mRotator, "missing FileRotator");
Jeff Sharkey63abc372012-01-11 18:38:16 -0800298 final long pendingBytes = mPending.getTotalBytes();
299 if (pendingBytes >= mPersistThresholdBytes) {
300 forcePersistLocked(currentTimeMillis);
301 } else {
302 mRotator.maybeRotate(currentTimeMillis);
303 }
304 }
305
306 /**
307 * Force persisting any pending deltas.
308 */
309 public void forcePersistLocked(long currentTimeMillis) {
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800310 checkNotNull(mRotator, "missing FileRotator");
Jeff Sharkey63abc372012-01-11 18:38:16 -0800311 if (mPending.isDirty()) {
312 if (LOGD) Slog.d(TAG, "forcePersistLocked() writing for " + mCookie);
313 try {
314 mRotator.rewriteActive(mPendingRewriter, currentTimeMillis);
315 mRotator.maybeRotate(currentTimeMillis);
316 mPending.reset();
317 } catch (IOException e) {
318 Log.wtf(TAG, "problem persisting pending stats", e);
Jeff Sharkey6de357e2012-05-09 13:33:52 -0700319 recoverFromWtf();
Jeff Sharkeye4984be2013-09-10 21:03:27 -0700320 } catch (OutOfMemoryError e) {
321 Log.wtf(TAG, "problem persisting pending stats", e);
322 recoverFromWtf();
Jeff Sharkey63abc372012-01-11 18:38:16 -0800323 }
324 }
325 }
326
327 /**
328 * Remove the given UID from all {@link FileRotator} history, migrating it
329 * to {@link TrafficStats#UID_REMOVED}.
330 */
Jeff Sharkeydaa57e82012-09-19 14:10:39 -0700331 public void removeUidsLocked(int[] uids) {
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800332 if (mRotator != null) {
333 try {
334 // Rewrite all persisted data to migrate UID stats
335 mRotator.rewriteAll(new RemoveUidRewriter(mBucketDuration, uids));
336 } catch (IOException e) {
337 Log.wtf(TAG, "problem removing UIDs " + Arrays.toString(uids), e);
338 recoverFromWtf();
339 } catch (OutOfMemoryError e) {
340 Log.wtf(TAG, "problem removing UIDs " + Arrays.toString(uids), e);
341 recoverFromWtf();
342 }
Jeff Sharkey63abc372012-01-11 18:38:16 -0800343 }
344
Jeff Sharkeydaa57e82012-09-19 14:10:39 -0700345 // Remove any pending stats
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800346 if (mPending != null) {
347 mPending.removeUids(uids);
348 }
349 if (mSinceBoot != null) {
350 mSinceBoot.removeUids(uids);
351 }
Jeff Sharkeydaa57e82012-09-19 14:10:39 -0700352
353 // Clear UID from current stats snapshot
Jeff Sharkey63abc372012-01-11 18:38:16 -0800354 if (mLastSnapshot != null) {
junyulai8b8684a2018-10-29 22:26:22 +0800355 mLastSnapshot.removeUids(uids);
Jeff Sharkey63abc372012-01-11 18:38:16 -0800356 }
Jeff Sharkeyb52e3e52012-04-06 11:12:08 -0700357
358 final NetworkStatsCollection complete = mComplete != null ? mComplete.get() : null;
359 if (complete != null) {
Jeff Sharkeydaa57e82012-09-19 14:10:39 -0700360 complete.removeUids(uids);
Jeff Sharkeyb52e3e52012-04-06 11:12:08 -0700361 }
Jeff Sharkey63abc372012-01-11 18:38:16 -0800362 }
363
364 /**
365 * Rewriter that will combine current {@link NetworkStatsCollection} values
366 * with anything read from disk, and write combined set to disk. Clears the
367 * original {@link NetworkStatsCollection} when finished writing.
368 */
369 private static class CombiningRewriter implements FileRotator.Rewriter {
370 private final NetworkStatsCollection mCollection;
371
372 public CombiningRewriter(NetworkStatsCollection collection) {
373 mCollection = checkNotNull(collection, "missing NetworkStatsCollection");
374 }
375
Jeff Sharkeybfdd6802012-04-09 10:49:19 -0700376 @Override
Jeff Sharkey63abc372012-01-11 18:38:16 -0800377 public void reset() {
378 // ignored
379 }
380
Jeff Sharkeybfdd6802012-04-09 10:49:19 -0700381 @Override
Jeff Sharkey63abc372012-01-11 18:38:16 -0800382 public void read(InputStream in) throws IOException {
383 mCollection.read(in);
384 }
385
Jeff Sharkeybfdd6802012-04-09 10:49:19 -0700386 @Override
Jeff Sharkey63abc372012-01-11 18:38:16 -0800387 public boolean shouldWrite() {
388 return true;
389 }
390
Jeff Sharkeybfdd6802012-04-09 10:49:19 -0700391 @Override
Jeff Sharkey63abc372012-01-11 18:38:16 -0800392 public void write(OutputStream out) throws IOException {
393 mCollection.write(new DataOutputStream(out));
394 mCollection.reset();
395 }
396 }
397
398 /**
399 * Rewriter that will remove any {@link NetworkStatsHistory} attributed to
400 * the requested UID, only writing data back when modified.
401 */
402 public static class RemoveUidRewriter implements FileRotator.Rewriter {
403 private final NetworkStatsCollection mTemp;
Jeff Sharkeydaa57e82012-09-19 14:10:39 -0700404 private final int[] mUids;
Jeff Sharkey63abc372012-01-11 18:38:16 -0800405
Jeff Sharkeydaa57e82012-09-19 14:10:39 -0700406 public RemoveUidRewriter(long bucketDuration, int[] uids) {
Jeff Sharkey63abc372012-01-11 18:38:16 -0800407 mTemp = new NetworkStatsCollection(bucketDuration);
Jeff Sharkeydaa57e82012-09-19 14:10:39 -0700408 mUids = uids;
Jeff Sharkey63abc372012-01-11 18:38:16 -0800409 }
410
Jeff Sharkeybfdd6802012-04-09 10:49:19 -0700411 @Override
Jeff Sharkey63abc372012-01-11 18:38:16 -0800412 public void reset() {
413 mTemp.reset();
414 }
415
Jeff Sharkeybfdd6802012-04-09 10:49:19 -0700416 @Override
Jeff Sharkey63abc372012-01-11 18:38:16 -0800417 public void read(InputStream in) throws IOException {
418 mTemp.read(in);
419 mTemp.clearDirty();
Jeff Sharkeydaa57e82012-09-19 14:10:39 -0700420 mTemp.removeUids(mUids);
Jeff Sharkey63abc372012-01-11 18:38:16 -0800421 }
422
Jeff Sharkeybfdd6802012-04-09 10:49:19 -0700423 @Override
Jeff Sharkey63abc372012-01-11 18:38:16 -0800424 public boolean shouldWrite() {
425 return mTemp.isDirty();
426 }
427
Jeff Sharkeybfdd6802012-04-09 10:49:19 -0700428 @Override
Jeff Sharkey63abc372012-01-11 18:38:16 -0800429 public void write(OutputStream out) throws IOException {
430 mTemp.write(new DataOutputStream(out));
431 }
432 }
433
434 public void importLegacyNetworkLocked(File file) throws IOException {
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800435 checkNotNull(mRotator, "missing FileRotator");
436
Jeff Sharkey63abc372012-01-11 18:38:16 -0800437 // legacy file still exists; start empty to avoid double importing
438 mRotator.deleteAll();
439
440 final NetworkStatsCollection collection = new NetworkStatsCollection(mBucketDuration);
441 collection.readLegacyNetwork(file);
442
443 final long startMillis = collection.getStartMillis();
444 final long endMillis = collection.getEndMillis();
445
446 if (!collection.isEmpty()) {
447 // process legacy data, creating active file at starting time, then
448 // using end time to possibly trigger rotation.
449 mRotator.rewriteActive(new CombiningRewriter(collection), startMillis);
450 mRotator.maybeRotate(endMillis);
451 }
452 }
453
454 public void importLegacyUidLocked(File file) throws IOException {
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800455 checkNotNull(mRotator, "missing FileRotator");
456
Jeff Sharkey63abc372012-01-11 18:38:16 -0800457 // legacy file still exists; start empty to avoid double importing
458 mRotator.deleteAll();
459
460 final NetworkStatsCollection collection = new NetworkStatsCollection(mBucketDuration);
461 collection.readLegacyUid(file, mOnlyTags);
462
463 final long startMillis = collection.getStartMillis();
464 final long endMillis = collection.getEndMillis();
465
466 if (!collection.isEmpty()) {
467 // process legacy data, creating active file at starting time, then
468 // using end time to possibly trigger rotation.
469 mRotator.rewriteActive(new CombiningRewriter(collection), startMillis);
470 mRotator.maybeRotate(endMillis);
471 }
472 }
473
474 public void dumpLocked(IndentingPrintWriter pw, boolean fullHistory) {
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800475 if (mPending != null) {
476 pw.print("Pending bytes: "); pw.println(mPending.getTotalBytes());
477 }
Jeff Sharkey63abc372012-01-11 18:38:16 -0800478 if (fullHistory) {
479 pw.println("Complete history:");
480 getOrLoadCompleteLocked().dump(pw);
481 } else {
482 pw.println("History since boot:");
483 mSinceBoot.dump(pw);
484 }
485 }
Jeff Sharkey6de357e2012-05-09 13:33:52 -0700486
Makoto Onukida65a522017-01-13 10:23:30 -0800487 public void writeToProtoLocked(ProtoOutputStream proto, long tag) {
488 final long start = proto.start(tag);
489 if (mPending != null) {
490 proto.write(NetworkStatsRecorderProto.PENDING_TOTAL_BYTES, mPending.getTotalBytes());
491 }
492 getOrLoadCompleteLocked().writeToProto(proto, NetworkStatsRecorderProto.COMPLETE_HISTORY);
493 proto.end(start);
494 }
495
Jeff Sharkey55a442e2014-11-18 18:22:21 -0800496 public void dumpCheckin(PrintWriter pw, long start, long end) {
497 // Only load and dump stats from the requested window
498 getOrLoadPartialLocked(start, end).dumpCheckin(pw, start, end);
499 }
500
Jeff Sharkey6de357e2012-05-09 13:33:52 -0700501 /**
502 * Recover from {@link FileRotator} failure by dumping state to
503 * {@link DropBoxManager} and deleting contents.
504 */
505 private void recoverFromWtf() {
506 if (DUMP_BEFORE_DELETE) {
507 final ByteArrayOutputStream os = new ByteArrayOutputStream();
508 try {
509 mRotator.dumpAll(os);
510 } catch (IOException e) {
511 // ignore partial contents
512 os.reset();
513 } finally {
514 IoUtils.closeQuietly(os);
515 }
516 mDropBox.addData(TAG_NETSTATS_DUMP, os.toByteArray(), 0);
517 }
518
519 mRotator.deleteAll();
520 }
Jeff Sharkey63abc372012-01-11 18:38:16 -0800521}