Add NativeDaemonConnector users to watchdog.

To catch instances where NativeDaemonConnector hangs while executing
commands, add users to system_server watchdog.  Also moved qtaguid
enabler to separate thread to prevent blocking systemReady().

Bug: 5145437
Change-Id: I4c6c1dc09864a1c05f9486a31faa1b366548e911
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index 7f61c635..fd03201 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -89,7 +89,8 @@
  * @hide - Applications should use android.os.storage.StorageManager
  * to access the MountService.
  */
-class MountService extends IMountService.Stub implements INativeDaemonConnectorCallbacks {
+class MountService extends IMountService.Stub
+        implements INativeDaemonConnectorCallbacks, Watchdog.Monitor {
 
     private static final boolean LOCAL_LOGD = false;
     private static final boolean DEBUG_UNMOUNT = false;
@@ -474,7 +475,8 @@
                             // it is not safe to call vold with mVolumeStates locked
                             // so we make a copy of the paths and states and process them
                             // outside the lock
-                            String[] paths, states;
+                            String[] paths;
+                            String[] states;
                             int count;
                             synchronized (mVolumeStates) {
                                 Set<String> keys = mVolumeStates.keySet();
@@ -1179,6 +1181,9 @@
         mReady = false;
         Thread thread = new Thread(mConnector, VOLD_TAG);
         thread.start();
+
+        // Add ourself to the Watchdog monitors.
+        Watchdog.getInstance().addMonitor(this);
     }
 
     /**
@@ -2379,5 +2384,11 @@
             }
         }
     }
-}
 
+    /** {@inheritDoc} */
+    public void monitor() {
+        if (mConnector != null) {
+            mConnector.monitor();
+        }
+    }
+}
diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/java/com/android/server/NativeDaemonConnector.java
index fed554c..43d938c 100644
--- a/services/java/com/android/server/NativeDaemonConnector.java
+++ b/services/java/com/android/server/NativeDaemonConnector.java
@@ -16,24 +16,18 @@
 
 package com.android.server;
 
-import android.net.LocalSocketAddress;
 import android.net.LocalSocket;
-import android.os.Environment;
+import android.net.LocalSocketAddress;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Message;
 import android.os.SystemClock;
-import android.os.SystemProperties;
 import android.util.Slog;
 
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.net.Socket;
-
-import java.util.List;
 import java.util.ArrayList;
-import java.util.ListIterator;
 import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.LinkedBlockingQueue;
 
@@ -42,7 +36,7 @@
  * daemon which uses the libsysutils FrameworkListener
  * protocol.
  */
-final class NativeDaemonConnector implements Runnable, Handler.Callback {
+final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdog.Monitor {
     private static final boolean LOCAL_LOGD = false;
 
     private BlockingQueue<String> mResponseQueue;
@@ -52,6 +46,9 @@
     private INativeDaemonConnectorCallbacks mCallbacks;
     private Handler               mCallbackHandler;
 
+    /** Lock held whenever communicating with native daemon. */
+    private Object mDaemonLock = new Object();
+
     private final int BUFFER_SIZE = 4096;
 
     class ResponseCode {
@@ -177,7 +174,7 @@
             Slog.e(TAG, "Communications error", ex);
             throw ex;
         } finally {
-            synchronized (this) {
+            synchronized (mDaemonLock) {
                 if (mOutputStream != null) {
                     try {
                         mOutputStream.close();
@@ -198,9 +195,8 @@
         }
     }
 
-    private void sendCommand(String command)
-            throws NativeDaemonConnectorException  {
-        sendCommand(command, null);
+    private void sendCommandLocked(String command) throws NativeDaemonConnectorException {
+        sendCommandLocked(command, null);
     }
 
     /**
@@ -209,25 +205,23 @@
      * @param command  The command to send to the daemon
      * @param argument The argument to send with the command (or null)
      */
-    private void sendCommand(String command, String argument)
-            throws NativeDaemonConnectorException  {
-        synchronized (this) {
-            if (LOCAL_LOGD) Slog.d(TAG, String.format("SND -> {%s} {%s}", command, argument));
-            if (mOutputStream == null) {
-                Slog.e(TAG, "No connection to daemon", new IllegalStateException());
-                throw new NativeDaemonConnectorException("No output stream!");
-            } else {
-                StringBuilder builder = new StringBuilder(command);
-                if (argument != null) {
-                    builder.append(argument);
-                }
-                builder.append('\0');
+    private void sendCommandLocked(String command, String argument)
+            throws NativeDaemonConnectorException {
+        if (LOCAL_LOGD) Slog.d(TAG, String.format("SND -> {%s} {%s}", command, argument));
+        if (mOutputStream == null) {
+            Slog.e(TAG, "No connection to daemon", new IllegalStateException());
+            throw new NativeDaemonConnectorException("No output stream!");
+        } else {
+            StringBuilder builder = new StringBuilder(command);
+            if (argument != null) {
+                builder.append(argument);
+            }
+            builder.append('\0');
 
-                try {
-                    mOutputStream.write(builder.toString().getBytes());
-                } catch (IOException ex) {
-                    Slog.e(TAG, "IOException in sendCommand", ex);
-                }
+            try {
+                mOutputStream.write(builder.toString().getBytes());
+            } catch (IOException ex) {
+                Slog.e(TAG, "IOException in sendCommand", ex);
             }
         }
     }
@@ -235,10 +229,15 @@
     /**
      * Issue a command to the native daemon and return the responses
      */
-    public synchronized ArrayList<String> doCommand(String cmd)
-            throws NativeDaemonConnectorException  {
+    public ArrayList<String> doCommand(String cmd) throws NativeDaemonConnectorException {
+        synchronized (mDaemonLock) {
+            return doCommandLocked(cmd);
+        }
+    }
+
+    private ArrayList<String> doCommandLocked(String cmd) throws NativeDaemonConnectorException {
         mResponseQueue.clear();
-        sendCommand(cmd);
+        sendCommandLocked(cmd);
 
         ArrayList<String> response = new ArrayList<String>();
         boolean complete = false;
@@ -278,7 +277,7 @@
         return response;
     }
 
-    /*
+    /**
      * Issues a list command and returns the cooked list
      */
     public String[] doListCommand(String cmd, int expectedResponseCode)
@@ -317,4 +316,9 @@
         }
         throw new NativeDaemonConnectorException("Got an empty response");
     }
+
+    /** {@inheritDoc} */
+    public void monitor() {
+        synchronized (mDaemonLock) { }
+    }
 }
diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java
index cb5e968..abb780b 100644
--- a/services/java/com/android/server/NetworkManagementService.java
+++ b/services/java/com/android/server/NetworkManagementService.java
@@ -68,7 +68,7 @@
 /**
  * @hide
  */
-class NetworkManagementService extends INetworkManagementService.Stub {
+class NetworkManagementService extends INetworkManagementService.Stub implements Watchdog.Monitor {
     private static final String TAG = "NetworkManagementService";
     private static final boolean DBG = false;
     private static final String NETD_TAG = "NetdConnector";
@@ -139,7 +139,7 @@
     /** Set of UIDs with active reject rules. */
     private SparseBooleanArray mUidRejectOnQuota = new SparseBooleanArray();
 
-    private boolean mBandwidthControlEnabled;
+    private volatile boolean mBandwidthControlEnabled;
 
     /**
      * Constructs a new NetworkManagementService instance
@@ -162,6 +162,9 @@
         mConnector = new NativeDaemonConnector(
                 new NetdCallbackReceiver(), "netd", 10, NETD_TAG);
         mThread = new Thread(mConnector, NETD_TAG);
+
+        // Add ourself to the Watchdog monitors.
+        Watchdog.getInstance().addMonitor(this);
     }
 
     public static NetworkManagementService create(Context context) throws InterruptedException {
@@ -185,14 +188,12 @@
     }
 
     public void systemReady() {
-
         // only enable bandwidth control when support exists, and requested by
         // system setting.
         final boolean hasKernelSupport = new File("/proc/net/xt_qtaguid/ctrl").exists();
         final boolean shouldEnable =
                 Settings.Secure.getInt(mContext.getContentResolver(), NETSTATS_ENABLED, 1) != 0;
 
-        mBandwidthControlEnabled = false;
         if (hasKernelSupport && shouldEnable) {
             Slog.d(TAG, "enabling bandwidth control");
             try {
@@ -288,7 +289,7 @@
     /**
      * Let us know the daemon is connected
      */
-    protected void onConnected() {
+    protected void onDaemonConnected() {
         if (DBG) Slog.d(TAG, "onConnected");
         mConnectedSignal.countDown();
     }
@@ -299,13 +300,12 @@
     //
 
     class NetdCallbackReceiver implements INativeDaemonConnectorCallbacks {
+        /** {@inheritDoc} */
         public void onDaemonConnected() {
-            NetworkManagementService.this.onConnected();
-            new Thread() {
-                public void run() {
-                }
-            }.start();
+            NetworkManagementService.this.onDaemonConnected();
         }
+
+        /** {@inheritDoc} */
         public boolean onEvent(int code, String raw, String[] cooked) {
             switch (code) {
             case NetdResponseCode.InterfaceChange:
@@ -1520,4 +1520,11 @@
                     "Error communicating with native daemon to flush interface " + iface, e);
         }
     }
+
+    /** {@inheritDoc} */
+    public void monitor() {
+        if (mConnector != null) {
+            mConnector.monitor();
+        }
+    }
 }