Add an RPC to replace a UID firewall rule.

Also add a binder_test that exercises binder RPCs to the real
netd service running on the device

Bug: 21725996
Bug: 27239233
Change-Id: Ic83d81605021a0578d6cd32f889290be61d76125
diff --git a/server/NetdConstants.cpp b/server/NetdConstants.cpp
index c86538b..7bd4316 100644
--- a/server/NetdConstants.cpp
+++ b/server/NetdConstants.cpp
@@ -34,6 +34,8 @@
 const char * const OEM_SCRIPT_PATH = "/system/bin/oem-iptables-init.sh";
 const char * const IPTABLES_PATH = "/system/bin/iptables";
 const char * const IP6TABLES_PATH = "/system/bin/ip6tables";
+const char * const IPTABLES_RESTORE_PATH = "/system/bin/iptables-restore";
+const char * const IP6TABLES_RESTORE_PATH = "/system/bin/ip6tables-restore";
 const char * const TC_PATH = "/system/bin/tc";
 const char * const IP_PATH = "/system/bin/ip";
 const char * const ADD = "add";
@@ -117,6 +119,43 @@
     return res;
 }
 
+static int execIptablesRestoreCommand(const char *cmd, const std::string& commands) {
+    const char *argv[] = {
+        cmd,
+        "--noflush",  // Don't flush the whole table.
+        "-w",         // Wait instead of failing if the lock is held.
+    };
+    AndroidForkExecvpOption opt[1] = {
+        {
+            .opt_type = FORK_EXECVP_OPTION_INPUT,
+            .opt_input.input = reinterpret_cast<const uint8_t*>(commands.c_str()),
+            .opt_input.input_len = commands.size(),
+        }
+    };
+
+    int status = 0;
+    int res = android_fork_execvp_ext(
+            ARRAY_SIZE(argv), (char**)argv, &status, false /* ignore_int_quit */, LOG_NONE,
+            false /* abbreviated */, NULL /* file_path */, opt, ARRAY_SIZE(opt));
+    if (res || status) {
+        ALOGE("%s failed with res=%d, status=%d", argv[0], res, status);
+        return -1;
+    }
+
+    return 0;
+}
+
+int execIptablesRestore(IptablesTarget target, const std::string& commands) {
+    int res = 0;
+    if (target == V4 || target == V4V6) {
+        res |= execIptablesRestoreCommand(IPTABLES_RESTORE_PATH, commands);
+    }
+    if (target == V6 || target == V4V6) {
+        res |= execIptablesRestoreCommand(IP6TABLES_RESTORE_PATH, commands);
+    }
+    return res;
+}
+
 /*
  * Check an interface name for plausibility. This should e.g. help against
  * directory traversal.