diff --git a/services/java/com/android/server/net/NetworkStatsRecorder.java b/services/java/com/android/server/net/NetworkStatsRecorder.java index 2ce7771135..c3ecf54951 100644 --- a/services/java/com/android/server/net/NetworkStatsRecorder.java +++ b/services/java/com/android/server/net/NetworkStatsRecorder.java @@ -26,6 +26,7 @@ import android.net.NetworkStats.NonMonotonicObserver; import android.net.NetworkStatsHistory; import android.net.NetworkTemplate; import android.net.TrafficStats; +import android.os.DropBoxManager; import android.util.Log; import android.util.MathUtils; import android.util.Slog; @@ -34,6 +35,7 @@ import com.android.internal.util.FileRotator; import com.android.internal.util.IndentingPrintWriter; import com.google.android.collect.Sets; +import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.File; import java.io.IOException; @@ -43,6 +45,8 @@ import java.lang.ref.WeakReference; import java.util.HashSet; import java.util.Map; +import libcore.io.IoUtils; + /** * Logic to record deltas between periodic {@link NetworkStats} snapshots into * {@link NetworkStatsHistory} that belong to {@link NetworkStatsCollection}. @@ -56,8 +60,14 @@ public class NetworkStatsRecorder { private static final boolean LOGD = false; private static final boolean LOGV = false; + private static final String TAG_NETSTATS_DUMP = "netstats_dump"; + + /** Dump before deleting in {@link #recoverFromWtf()}. */ + private static final boolean DUMP_BEFORE_DELETE = true; + private final FileRotator mRotator; private final NonMonotonicObserver mObserver; + private final DropBoxManager mDropBox; private final String mCookie; private final long mBucketDuration; @@ -74,9 +84,10 @@ public class NetworkStatsRecorder { private WeakReference mComplete; public NetworkStatsRecorder(FileRotator rotator, NonMonotonicObserver observer, - String cookie, long bucketDuration, boolean onlyTags) { + DropBoxManager dropBox, String cookie, long bucketDuration, boolean onlyTags) { mRotator = checkNotNull(rotator, "missing FileRotator"); mObserver = checkNotNull(observer, "missing NonMonotonicObserver"); + mDropBox = checkNotNull(dropBox, "missing DropBoxManager"); mCookie = cookie; mBucketDuration = bucketDuration; @@ -122,6 +133,7 @@ public class NetworkStatsRecorder { mComplete = new WeakReference(complete); } catch (IOException e) { Log.wtf(TAG, "problem completely reading network stats", e); + recoverFromWtf(); } } return complete; @@ -212,6 +224,7 @@ public class NetworkStatsRecorder { mPending.reset(); } catch (IOException e) { Log.wtf(TAG, "problem persisting pending stats", e); + recoverFromWtf(); } } } @@ -226,6 +239,7 @@ public class NetworkStatsRecorder { mRotator.rewriteAll(new RemoveUidRewriter(mBucketDuration, uid)); } catch (IOException e) { Log.wtf(TAG, "problem removing UID " + uid, e); + recoverFromWtf(); } // clear UID from current stats snapshot @@ -355,4 +369,25 @@ public class NetworkStatsRecorder { mSinceBoot.dump(pw); } } + + /** + * Recover from {@link FileRotator} failure by dumping state to + * {@link DropBoxManager} and deleting contents. + */ + private void recoverFromWtf() { + if (DUMP_BEFORE_DELETE) { + final ByteArrayOutputStream os = new ByteArrayOutputStream(); + try { + mRotator.dumpAll(os); + } catch (IOException e) { + // ignore partial contents + os.reset(); + } finally { + IoUtils.closeQuietly(os); + } + mDropBox.addData(TAG_NETSTATS_DUMP, os.toByteArray(), 0); + } + + mRotator.deleteAll(); + } } diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index 1a56b80d7e..e710b3389e 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -338,9 +338,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private NetworkStatsRecorder buildRecorder( String prefix, NetworkStatsSettings.Config config, boolean includeTags) { + final DropBoxManager dropBox = (DropBoxManager) mContext.getSystemService( + Context.DROPBOX_SERVICE); return new NetworkStatsRecorder(new FileRotator( mBaseDir, prefix, config.rotateAgeMillis, config.deleteAgeMillis), - mNonMonotonicObserver, prefix, config.bucketDuration, includeTags); + mNonMonotonicObserver, dropBox, prefix, config.bucketDuration, includeTags); } private void shutdownLocked() {