Allow finer-grained locking, and use it in FirewallCmd.

FirewallController is stateless and FirewallCmd does not access
any other controllers, so it is safe not to take the big netd
lock.

Bug: 27239233
Change-Id: I246696c4b17fa005c7d6b38ecd627747aa608831
diff --git a/server/CommandListener.cpp b/server/CommandListener.cpp
index 6e03563..1a291b1 100644
--- a/server/CommandListener.cpp
+++ b/server/CommandListener.cpp
@@ -82,6 +82,24 @@
     return strtoul(arg, NULL, 0);
 }
 
+class LockingFrameworkCommand : public FrameworkCommand {
+public:
+    LockingFrameworkCommand(FrameworkCommand *wrappedCmd, android::RWLock& lock) :
+            FrameworkCommand(wrappedCmd->getCommand()),
+            mWrappedCmd(wrappedCmd),
+            mLock(lock) {}
+
+    int runCommand(SocketClient *c, int argc, char **argv) {
+        android::RWLock::AutoWLock lock(mLock);
+        return mWrappedCmd->runCommand(c, argc, argv);
+    }
+
+private:
+    FrameworkCommand *mWrappedCmd;
+    android::RWLock& mLock;
+};
+
+
 }  // namespace
 
 /**
@@ -159,6 +177,10 @@
     } while (*(++childChain) != NULL);
 }
 
+void CommandListener::registerLockingCmd(FrameworkCommand *cmd, android::RWLock& lock) {
+    registerCmd(new LockingFrameworkCommand(cmd, lock));
+}
+
 CommandListener::CommandListener() :
                  FrameworkListener("netd", true) {
     registerLockingCmd(new InterfaceCmd());
@@ -171,7 +193,7 @@
     registerLockingCmd(new BandwidthControlCmd());
     registerLockingCmd(new IdletimerControlCmd());
     registerLockingCmd(new ResolverCmd());
-    registerLockingCmd(new FirewallCmd());
+    registerLockingCmd(new FirewallCmd(), gCtls->firewallCtrl.lock);
     registerLockingCmd(new ClatdCmd());
     registerLockingCmd(new NetworkCommand());
     registerLockingCmd(new StrictCmd());
diff --git a/server/CommandListener.h b/server/CommandListener.h
index 2e29246..56323d6 100644
--- a/server/CommandListener.h
+++ b/server/CommandListener.h
@@ -35,29 +35,15 @@
 #include "ClatdController.h"
 #include "StrictController.h"
 
-class LockingFrameworkCommand : public FrameworkCommand {
-public:
-    LockingFrameworkCommand(FrameworkCommand *wrappedCmd) :
-            FrameworkCommand(wrappedCmd->getCommand()),
-            mWrappedCmd(wrappedCmd) {}
-
-    int runCommand(SocketClient *c, int argc, char **argv) {
-        android::RWLock::AutoWLock lock(android::net::gBigNetdLock);
-        return mWrappedCmd->runCommand(c, argc, argv);
-    }
-
-private:
-    FrameworkCommand *mWrappedCmd;
-};
-
 class CommandListener : public FrameworkListener {
 public:
     CommandListener();
     virtual ~CommandListener() {}
 
 private:
+    void registerLockingCmd(FrameworkCommand *cmd, android::RWLock& lock);
     void registerLockingCmd(FrameworkCommand *cmd) {
-        registerCmd(new LockingFrameworkCommand(cmd));
+        registerLockingCmd(cmd, android::net::gBigNetdLock);
     }
 
     class SoftapCmd : public NetdCommand {
diff --git a/server/Controllers.h b/server/Controllers.h
index e608981..5634800 100644
--- a/server/Controllers.h
+++ b/server/Controllers.h
@@ -18,6 +18,7 @@
 #define _CONTROLLERS_H__
 
 #include <sysutils/FrameworkListener.h>
+
 #include "NetworkController.h"
 #include "TetherController.h"
 #include "NatController.h"
diff --git a/server/FirewallController.h b/server/FirewallController.h
index 34a8b9c..d3ef777 100644
--- a/server/FirewallController.h
+++ b/server/FirewallController.h
@@ -19,6 +19,8 @@
 
 #include <string>
 
+#include <utils/RWLock.h>
+
 enum FirewallRule { DENY, ALLOW };
 
 // WHITELIST means the firewall denies all by default, uids must be explicitly ALLOWed
@@ -34,6 +36,10 @@
 /*
  * Simple firewall that drops all packets except those matching explicitly
  * defined ALLOW rules.
+ *
+ * Methods in this class must be called when holding a write lock on |lock|, and may not call
+ * any other controller without explicitly managing that controller's lock. There are currently
+ * no such methods.
  */
 class FirewallController {
 public:
@@ -67,6 +73,8 @@
 
     static const char* ICMPV6_TYPES[];
 
+    android::RWLock lock;
+
 private:
     FirewallType mFirewallType;
     int attachChain(const char*, const char*);