Initial netd binder interface.

In this change:

1. AIDL files for a new, android.net.INetd service, and
   corresponding implementation using generated code. For now the
   interface is just a prototype: it only has one trivial method.
2. Permission checking code to check for CONNECTIVITY_INTERNAL.
3. Add a Big Netd Lock and provide a wrapper that makes it easy
   to ensure that it is taken by every CommandListener command.

Bug: 27239233
Change-Id: I448d0ac233edd0e351a7fe7f13901fb6871683a2
diff --git a/server/Android.mk b/server/Android.mk
index b713b4f..dbbc5a1 100644
--- a/server/Android.mk
+++ b/server/Android.mk
@@ -16,6 +16,20 @@
 
 include $(CLEAR_VARS)
 
+LOCAL_CFLAGS := -Wall -Werror
+LOCAL_CLANG := true
+LOCAL_MODULE := libnetdaidl
+LOCAL_SHARED_LIBRARIES := \
+        libbinder \
+        libutils
+LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/binder
+LOCAL_SRC_FILES := binder/android/net/INetd.aidl
+
+include $(BUILD_SHARED_LIBRARY)
+
+
+include $(CLEAR_VARS)
+
 LOCAL_C_INCLUDES := \
         $(call include-path-for, libhardware_legacy)/hardware_legacy \
         bionic/libc/dns/include \
@@ -29,6 +43,7 @@
 LOCAL_INIT_RC := netd.rc
 
 LOCAL_SHARED_LIBRARIES := \
+        libbinder \
         libcrypto \
         libcutils \
         libdl \
@@ -36,6 +51,7 @@
         liblog \
         liblogwrap \
         libmdnssd \
+        libnetdaidl \
         libnetutils \
         libnl \
         libsysutils \
@@ -60,6 +76,7 @@
         NatController.cpp \
         NetdCommand.cpp \
         NetdConstants.cpp \
+        NetdNativeService.cpp \
         NetlinkHandler.cpp \
         NetlinkManager.cpp \
         Network.cpp \
diff --git a/server/CommandListener.cpp b/server/CommandListener.cpp
index af757c9..6f34752 100644
--- a/server/CommandListener.cpp
+++ b/server/CommandListener.cpp
@@ -171,20 +171,20 @@
 
 CommandListener::CommandListener() :
                  FrameworkListener("netd", true) {
-    registerCmd(new InterfaceCmd());
-    registerCmd(new IpFwdCmd());
-    registerCmd(new TetherCmd());
-    registerCmd(new NatCmd());
-    registerCmd(new ListTtysCmd());
-    registerCmd(new PppdCmd());
-    registerCmd(new SoftapCmd());
-    registerCmd(new BandwidthControlCmd());
-    registerCmd(new IdletimerControlCmd());
-    registerCmd(new ResolverCmd());
-    registerCmd(new FirewallCmd());
-    registerCmd(new ClatdCmd());
-    registerCmd(new NetworkCommand());
-    registerCmd(new StrictCmd());
+    registerLockingCmd(new InterfaceCmd());
+    registerLockingCmd(new IpFwdCmd());
+    registerLockingCmd(new TetherCmd());
+    registerLockingCmd(new NatCmd());
+    registerLockingCmd(new ListTtysCmd());
+    registerLockingCmd(new PppdCmd());
+    registerLockingCmd(new SoftapCmd());
+    registerLockingCmd(new BandwidthControlCmd());
+    registerLockingCmd(new IdletimerControlCmd());
+    registerLockingCmd(new ResolverCmd());
+    registerLockingCmd(new FirewallCmd());
+    registerLockingCmd(new ClatdCmd());
+    registerLockingCmd(new NetworkCommand());
+    registerLockingCmd(new StrictCmd());
 
     if (!sNetCtrl)
         sNetCtrl = new NetworkController();
diff --git a/server/CommandListener.h b/server/CommandListener.h
index 72f4da1..77fbb1e 100644
--- a/server/CommandListener.h
+++ b/server/CommandListener.h
@@ -18,8 +18,10 @@
 #define _COMMANDLISTENER_H__
 
 #include <sysutils/FrameworkListener.h>
+#include "utils/RWLock.h"
 
 #include "NetdCommand.h"
+#include "NetdConstants.h"
 #include "NetworkController.h"
 #include "TetherController.h"
 #include "NatController.h"
@@ -33,6 +35,22 @@
 #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 {
     static TetherController *sTetherCtrl;
     static NatController *sNatCtrl;
@@ -54,6 +72,10 @@
 
 private:
 
+    void registerLockingCmd(FrameworkCommand *cmd) {
+        registerCmd(new LockingFrameworkCommand(cmd));
+    }
+
     class SoftapCmd : public NetdCommand {
     public:
         SoftapCmd();
diff --git a/server/NetdConstants.h b/server/NetdConstants.h
index 296661d..5c3fde0 100644
--- a/server/NetdConstants.h
+++ b/server/NetdConstants.h
@@ -21,6 +21,8 @@
 #include <list>
 #include <stdarg.h>
 
+#include "utils/RWLock.h"
+
 const int PROTECT_MARK = 0x1;
 
 extern const char * const IPTABLES_PATH;
@@ -49,4 +51,18 @@
 
 const uid_t INVALID_UID = static_cast<uid_t>(-1);
 
-#endif
+namespace android {
+namespace net {
+
+/**
+ * This lock exists to make NetdNativeService RPCs (which come in on multiple Binder threads)
+ * coexist with the commands in CommandListener.cpp. These are presumed not thread-safe because
+ * CommandListener has only one user (NetworkManagementService), which is connected through a
+ * FrameworkListener that passes in commands one at a time.
+ */
+extern android::RWLock gBigNetdLock;
+
+}  // namespace net
+}  // namespace android
+
+#endif  // _NETD_CONSTANTS_H
diff --git a/server/NetdNativeService.cpp b/server/NetdNativeService.cpp
new file mode 100644
index 0000000..f4b5a10
--- /dev/null
+++ b/server/NetdNativeService.cpp
@@ -0,0 +1,73 @@
+/**
+ * Copyright (c) 2016, 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.
+ */
+
+#define LOG_TAG "Netd"
+
+#include <android-base/stringprintf.h>
+#include <cutils/log.h>
+#include <utils/Errors.h>
+
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include "android/net/BnNetd.h"
+
+#include "NetdConstants.h"
+#include "NetdNativeService.h"
+
+using android::base::StringPrintf;
+
+namespace android {
+namespace net {
+
+namespace {
+
+const char CONNECTIVITY_INTERNAL[] = "android.permission.CONNECTIVITY_INTERNAL";
+
+binder::Status checkPermission(const char *permission) {
+    pid_t pid;
+    uid_t uid;
+
+    if (checkCallingPermission(String16(permission), (int32_t *) &pid, (int32_t *) &uid)) {
+        return binder::Status::ok();
+    } else {
+        auto err = StringPrintf("UID %d / PID %d lacks permission %s", uid, pid, permission);
+        return binder::Status::fromExceptionCode(binder::Status::EX_SECURITY, String8(err.c_str()));
+    }
+}
+
+#define ENFORCE_PERMISSION(permission) {                    \
+    binder::Status status = checkPermission((permission));  \
+    if (!status.isOk()) {                                   \
+        return status;                                      \
+    }                                                       \
+}
+
+#define NETD_LOCKING_RPC(permission)               \
+    ENFORCE_PERMISSION(permission);                \
+    android::RWLock::AutoWLock lock(gBigNetdLock);
+
+}  // namespace
+
+
+binder::Status NetdNativeService::isAlive(bool *alive) {
+    NETD_LOCKING_RPC(CONNECTIVITY_INTERNAL);
+
+    *alive = true;
+    return binder::Status::ok();
+}
+
+}  // namespace net
+}  // namespace android
diff --git a/server/NetdNativeService.h b/server/NetdNativeService.h
new file mode 100644
index 0000000..6ca4432
--- /dev/null
+++ b/server/NetdNativeService.h
@@ -0,0 +1,36 @@
+/**
+ * Copyright (c) 2016, 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.
+ */
+
+#ifndef _NETD_NATIVE_SERVICE_H_
+#define _NETD_NATIVE_SERVICE_H_
+
+#include <binder/BinderService.h>
+
+#include "android/net/BnNetd.h"
+
+namespace android {
+namespace net {
+
+class NetdNativeService : public BinderService<NetdNativeService>, public BnNetd {
+  public:
+    static char const* getServiceName() { return "android.net.INetd"; }
+    binder::Status isAlive(bool *alive) override;
+};
+
+}  // namespace net
+}  // namespace android
+
+#endif  // _NETD_NATIVE_SERVICE_H_
diff --git a/server/binder/android/net/INetd.aidl b/server/binder/android/net/INetd.aidl
new file mode 100644
index 0000000..8242034
--- /dev/null
+++ b/server/binder/android/net/INetd.aidl
@@ -0,0 +1,22 @@
+/**
+ * Copyright (c) 2016, 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.net;
+
+/** {@hide} */
+interface INetd {
+    boolean isAlive();
+}
diff --git a/server/main.cpp b/server/main.cpp
index 5e189cc..2de0091 100644
--- a/server/main.cpp
+++ b/server/main.cpp
@@ -29,13 +29,27 @@
 #define LOG_TAG "Netd"
 
 #include "cutils/log.h"
+#include "utils/RWLock.h"
+
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
 
 #include "CommandListener.h"
+#include "NetdConstants.h"
+#include "NetdNativeService.h"
 #include "NetlinkManager.h"
 #include "DnsProxyListener.h"
 #include "MDnsSdListener.h"
 #include "FwmarkServer.h"
 
+using android::status_t;
+using android::sp;
+using android::IPCThreadState;
+using android::ProcessState;
+using android::defaultServiceManager;
+using android::net::NetdNativeService;
+
 static void blockSigpipe();
 static void remove_pid_file();
 static bool write_pid_file();
@@ -44,6 +58,10 @@
 const int PID_FILE_FLAGS = O_CREAT | O_TRUNC | O_WRONLY | O_NOFOLLOW | O_CLOEXEC;
 const mode_t PID_FILE_MODE = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;  // mode 0644, rw-r--r--
 
+
+android::RWLock android::net::gBigNetdLock;
+
+
 int main() {
 
     CommandListener *cl;
@@ -99,17 +117,15 @@
         exit(1);
     }
 
-    bool wrote_pid = write_pid_file();
+    write_pid_file();
 
-    while(1) {
-        sleep(30); // 30 sec
-        if (!wrote_pid) {
-            wrote_pid = write_pid_file();
-        }
-    }
+    IPCThreadState::self()->disableBackgroundScheduling(true);
+    NetdNativeService::publishAndJoinThreadPool();
 
     ALOGI("Netd exiting");
+
     remove_pid_file();
+
     exit(0);
 }