Log netd traffic nicely.

Create a LocalLog class for logging within a service for dumping in dumps.
Use it in the NativeDaemonConnector so we can get some insight into what
is happening in these lockups.

bug:5864209
Change-Id: I68ddc58847f3c8de613be9528570f8c3157d8274
diff --git a/core/java/android/util/LocalLog.java b/core/java/android/util/LocalLog.java
new file mode 100644
index 0000000..641d1b4
--- /dev/null
+++ b/core/java/android/util/LocalLog.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util;
+
+import android.text.format.Time;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.Iterator;
+import java.util.LinkedList;
+
+/**
+ * @hide
+ */
+public final class LocalLog {
+
+    private LinkedList<String> mLog;
+    private int mMaxLines;
+    private Time mNow;
+
+    public LocalLog(int maxLines) {
+        mLog = new LinkedList<String>();
+        mMaxLines = maxLines;
+        mNow = new Time();
+    }
+
+    public synchronized void log(String msg) {
+        if (mMaxLines > 0) {
+            mNow.setToNow();
+            mLog.add(mNow.format("%H:%M:%S") + " - " + msg);
+            while (mLog.size() > mMaxLines) mLog.remove();
+        }
+    }
+
+    public synchronized void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        Iterator<String> itr = mLog.listIterator(0);
+        while (itr.hasNext()) {
+            pw.println(itr.next());
+        }
+    }
+}
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index a32e9f5..366160b 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -1169,7 +1169,7 @@
          * amount of containers we'd ever expect to have. This keeps an
          * "asec list" from blocking a thread repeatedly.
          */
-        mConnector = new NativeDaemonConnector(this, "vold", MAX_CONTAINERS * 2, VOLD_TAG);
+        mConnector = new NativeDaemonConnector(this, "vold", MAX_CONTAINERS * 2, VOLD_TAG, 25);
         mReady = false;
         Thread thread = new Thread(mConnector, VOLD_TAG);
         thread.start();
@@ -2429,6 +2429,10 @@
                 pw.println(v.toString());
             }
         }
+
+        pw.println();
+        pw.println("  mConnection:");
+        mConnector.dump(fd, pw, args);
     }
 
     /** {@inheritDoc} */
diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/java/com/android/server/NativeDaemonConnector.java
index cc2bcd9..f475dd6 100644
--- a/services/java/com/android/server/NativeDaemonConnector.java
+++ b/services/java/com/android/server/NativeDaemonConnector.java
@@ -22,14 +22,17 @@
 import android.os.HandlerThread;
 import android.os.Message;
 import android.os.SystemClock;
+import android.util.LocalLog;
 import android.util.Slog;
 
 import com.google.android.collect.Lists;
 
+import java.nio.charset.Charsets;
+import java.io.FileDescriptor;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.nio.charset.Charsets;
+import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.LinkedBlockingQueue;
@@ -45,6 +48,7 @@
 
     private String mSocket;
     private OutputStream mOutputStream;
+    private LocalLog mLocalLog;
 
     private final BlockingQueue<NativeDaemonEvent> mResponseQueue;
 
@@ -57,11 +61,12 @@
     private final int BUFFER_SIZE = 4096;
 
     NativeDaemonConnector(INativeDaemonConnectorCallbacks callbacks, String socket,
-            int responseQueueSize, String logTag) {
+            int responseQueueSize, String logTag, int maxLogSize) {
         mCallbacks = callbacks;
         mSocket = socket;
         mResponseQueue = new LinkedBlockingQueue<NativeDaemonEvent>(responseQueueSize);
         TAG = logTag != null ? logTag : "NativeDaemonConnector";
+        mLocalLog = new LocalLog(maxLogSize);
     }
 
     @Override
@@ -125,7 +130,7 @@
                     if (buffer[i] == 0) {
                         final String rawEvent = new String(
                                 buffer, start, i - start, Charsets.UTF_8);
-                        if (LOGD) Slog.d(TAG, "RCV <- " + rawEvent);
+                        log("RCV <- {" + rawEvent + "}");
 
                         try {
                             final NativeDaemonEvent event = NativeDaemonEvent.parseRawEvent(
@@ -208,7 +213,7 @@
         }
 
         final String unterminated = builder.toString();
-        if (LOGD) Slog.d(TAG, "SND -> " + unterminated);
+        log("SND -> {" + unterminated + "}");
 
         builder.append('\0');
 
@@ -432,4 +437,13 @@
     public void monitor() {
         synchronized (mDaemonLock) { }
     }
+
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        mLocalLog.dump(fd, pw, args);
+    }
+
+    private void log(String logstring) {
+        if (LOGD) Slog.d(TAG, logstring);
+        mLocalLog.log(logstring);
+    }
 }
diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java
index c1d8a13..7bb7938 100644
--- a/services/java/com/android/server/NetworkManagementService.java
+++ b/services/java/com/android/server/NetworkManagementService.java
@@ -163,7 +163,7 @@
         }
 
         mConnector = new NativeDaemonConnector(
-                new NetdCallbackReceiver(), "netd", 10, NETD_TAG);
+                new NetdCallbackReceiver(), "netd", 10, NETD_TAG, 50);
         mThread = new Thread(mConnector, NETD_TAG);
 
         // Add ourself to the Watchdog monitors.
@@ -1265,6 +1265,10 @@
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         mContext.enforceCallingOrSelfPermission(DUMP, TAG);
 
+        pw.println("NetworkManagementService NativeDaemonConnector Log:");
+        mConnector.dump(fd, pw, args);
+        pw.println();
+
         pw.print("Bandwidth control enabled: "); pw.println(mBandwidthControlEnabled);
 
         synchronized (mQuotaLock) {