release-request-b6ab0986-e497-499a-b55d-25aa156be8cf-for-git_oc-dr1-release-4233813 snap-temp-L73000000087867826

Change-Id: I505f25b56ecab193ae8f6741a067b48d950d7bf1
diff --git a/server/Android.mk b/server/Android.mk
index c8ba20f..ba4c3a7 100644
--- a/server/Android.mk
+++ b/server/Android.mk
@@ -63,9 +63,12 @@
 LOCAL_INIT_RC := netd.rc
 
 LOCAL_SHARED_LIBRARIES := \
+        android.system.net.netd@1.0 \
         libbinder \
         libcutils \
         libdl \
+        libhidlbase \
+        libhidltransport \
         liblog \
         liblogwrap \
         libmdnssd \
@@ -97,6 +100,7 @@
         NatController.cpp \
         NetdCommand.cpp \
         NetdConstants.cpp \
+        NetdHwService.cpp \
         NetdNativeService.cpp \
         NetlinkHandler.cpp \
         NetlinkManager.cpp \
diff --git a/server/CommandListener.cpp b/server/CommandListener.cpp
index 5b9fa8a..d191c05 100644
--- a/server/CommandListener.cpp
+++ b/server/CommandListener.cpp
@@ -69,6 +69,12 @@
             return NetworkController::MIN_OEM_ID + n;
         }
         return NETID_UNSET;
+    } else if (!strncmp(arg, "handle", 6)) {
+        unsigned n = netHandleToNetId((net_handle_t)strtoull(arg + 6, NULL, 10));
+        if (NetworkController::MIN_OEM_ID <= n && n <= NetworkController::MAX_OEM_ID) {
+            return n;
+        }
+        return NETID_UNSET;
     }
     // strtoul() returns 0 on errors, which is fine because 0 is an invalid netId.
     return strtoul(arg, NULL, 0);
diff --git a/server/NetdHwService.cpp b/server/NetdHwService.cpp
new file mode 100644
index 0000000..6fb6700
--- /dev/null
+++ b/server/NetdHwService.cpp
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#include <binder/IPCThreadState.h>
+#include <hidl/HidlTransportSupport.h>
+#include <hwbinder/IPCThreadState.h>
+#include "Controllers.h"
+#include "Fwmark.h"
+#include "NetdHwService.h"
+
+using android::hardware::configureRpcThreadpool;
+using android::hardware::IPCThreadState;
+using android::hardware::Void;
+
+namespace android {
+namespace net {
+
+/**
+ * This lock exists to make NetdHwService RPCs (which come in on multiple HwBinder 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;
+
+static INetd::StatusCode toHalStatus(int ret) {
+    switch(ret) {
+        case 0:
+            return INetd::StatusCode::OK;
+        case -EINVAL:
+            return INetd::StatusCode::INVALID_ARGUMENTS;
+        case -EEXIST:
+            return INetd::StatusCode::ALREADY_EXISTS;
+        case -ENONET:
+            return INetd::StatusCode::NO_NETWORK;
+        case -EPERM:
+            return INetd::StatusCode::PERMISSION_DENIED;
+        default:
+            ALOGE("HAL service error=%d", ret);
+            return INetd::StatusCode::UNKNOWN_ERROR;
+    }
+}
+
+// Minimal service start.
+status_t NetdHwService::start() {
+    IPCThreadState::self()->disableBackgroundScheduling(true);
+    // Usage of this HAL is anticipated to be thin; one thread should suffice.
+    configureRpcThreadpool(1, false /* callerWillNotJoin */);
+    // Register hardware service with ServiceManager.
+    return INetd::registerAsService();
+}
+
+Return<void> NetdHwService::createOemNetwork(createOemNetwork_cb _hidl_cb) {
+    unsigned netId;
+    Permission permission = PERMISSION_SYSTEM;
+
+    android::RWLock::AutoWLock _lock(gBigNetdLock);
+    int ret = gCtls->netCtrl.createPhysicalOemNetwork(permission, &netId);
+
+    Fwmark fwmark;
+    fwmark.netId = netId;
+    fwmark.explicitlySelected = true;
+    fwmark.protectedFromVpn = true;
+    fwmark.permission = PERMISSION_SYSTEM;
+    _hidl_cb(netIdToNetHandle(netId), fwmark.intValue, toHalStatus(ret));
+
+    return Void();
+}
+
+Return<INetd::StatusCode> NetdHwService::destroyOemNetwork(uint64_t netHandle) {
+    unsigned netId = netHandleToNetId(netHandle);
+    if ((netId < NetworkController::MIN_OEM_ID) ||
+            (netId > NetworkController::MAX_OEM_ID)) {
+        return INetd::StatusCode::INVALID_ARGUMENTS;
+    }
+
+    android::RWLock::AutoWLock _lock(gBigNetdLock);
+
+    return toHalStatus(gCtls->netCtrl.destroyNetwork(netId));
+}
+
+}  // namespace net
+}  // namespace android
diff --git a/server/NetdHwService.h b/server/NetdHwService.h
new file mode 100644
index 0000000..f938dd6
--- /dev/null
+++ b/server/NetdHwService.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2017 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 ANDROID_NET_HW_SERVICE_H
+#define ANDROID_NET_HW_SERVICE_H
+
+#include <android/system/net/netd/1.0/INetd.h>
+
+using android::hardware::Return;
+using android::system::net::netd::V1_0::INetd;
+
+namespace android {
+namespace net {
+
+class NetdHwService : public INetd {
+public:
+    status_t start();
+    Return<void> createOemNetwork(createOemNetwork_cb _hidl_cb) override;
+    Return<INetd::StatusCode> destroyOemNetwork(uint64_t netHandle) override;
+};
+
+}  // namespace net
+}  // namespace android
+
+#endif  // ANDROID_NET_HW_SERVICE_H
+
diff --git a/server/NetworkController.cpp b/server/NetworkController.cpp
index b90976b..ecb4cee 100644
--- a/server/NetworkController.cpp
+++ b/server/NetworkController.cpp
@@ -321,14 +321,14 @@
     return network && network->getType() == Network::VIRTUAL;
 }
 
-int NetworkController::createPhysicalNetwork(unsigned netId, Permission permission) {
+int NetworkController::createPhysicalNetworkLocked(unsigned netId, Permission permission) {
     if (!((MIN_NET_ID <= netId && netId <= MAX_NET_ID) ||
           (MIN_OEM_ID <= netId && netId <= MAX_OEM_ID))) {
         ALOGE("invalid netId %u", netId);
         return -EINVAL;
     }
 
-    if (isValidNetwork(netId)) {
+    if (isValidNetworkLocked(netId)) {
         ALOGE("duplicate netId %u", netId);
         return -EEXIST;
     }
@@ -340,11 +340,41 @@
         return ret;
     }
 
-    android::RWLock::AutoWLock lock(mRWLock);
     mNetworks[netId] = physicalNetwork;
     return 0;
 }
 
+int NetworkController::createPhysicalNetwork(unsigned netId, Permission permission) {
+    android::RWLock::AutoWLock lock(mRWLock);
+    return createPhysicalNetworkLocked(netId, permission);
+}
+
+int NetworkController::createPhysicalOemNetwork(Permission permission, unsigned *pNetId) {
+    if (pNetId == NULL) {
+        return -EINVAL;
+    }
+
+    android::RWLock::AutoWLock lock(mRWLock);
+    for (*pNetId = MIN_OEM_ID; *pNetId <= MAX_OEM_ID; (*pNetId)++) {
+        if (!isValidNetworkLocked(*pNetId)) {
+            break;
+        }
+    }
+
+    if (*pNetId > MAX_OEM_ID) {
+        ALOGE("No free network ID");
+        *pNetId = 0;
+        return -ENONET;
+    }
+
+    int ret = createPhysicalNetworkLocked(*pNetId, permission);
+    if (ret) {
+        *pNetId = 0;
+    }
+
+    return ret;
+}
+
 int NetworkController::createVirtualNetwork(unsigned netId, bool hasDns, bool secure) {
     if (!(MIN_NET_ID <= netId && netId <= MAX_NET_ID)) {
         ALOGE("invalid netId %u", netId);
@@ -564,9 +594,13 @@
     dw.decIndent();
 }
 
+bool NetworkController::isValidNetworkLocked(unsigned netId) const {
+    return getNetworkLocked(netId);
+}
+
 bool NetworkController::isValidNetwork(unsigned netId) const {
     android::RWLock::AutoRLock lock(mRWLock);
-    return getNetworkLocked(netId);
+    return isValidNetworkLocked(netId);
 }
 
 Network* NetworkController::getNetworkLocked(unsigned netId) const {
diff --git a/server/NetworkController.h b/server/NetworkController.h
index d5451ee..ceb538e 100644
--- a/server/NetworkController.h
+++ b/server/NetworkController.h
@@ -17,6 +17,7 @@
 #ifndef NETD_SERVER_NETWORK_CONTROLLER_H
 #define NETD_SERVER_NETWORK_CONTROLLER_H
 
+#include <android/multinetwork.h>
 #include "NetdConstants.h"
 #include "Permission.h"
 
@@ -33,6 +34,36 @@
 namespace android {
 namespace net {
 
+// Utility to convert from netId to net_handle_t. Doing this here as opposed to exporting
+// from net.c as it may have NDK implications. Besides no conversion available in net.c for
+// obtaining handle given netId.
+// TODO: Use getnetidfromhandle() in net.c.
+static inline unsigned netHandleToNetId(net_handle_t fromNetHandle) {
+    const uint32_t k32BitMask = 0xffffffff;
+    // This value MUST be kept in sync with the corresponding value in
+    // the android.net.Network#getNetworkHandle() implementation.
+    const uint32_t kHandleMagic = 0xfacade;
+
+    // Check for minimum acceptable version of the API in the low bits.
+    if (fromNetHandle != NETWORK_UNSPECIFIED &&
+        (fromNetHandle & k32BitMask) != kHandleMagic) {
+        return 0;
+    }
+
+    return ((fromNetHandle >> (CHAR_BIT * sizeof(k32BitMask))) & k32BitMask);
+}
+
+// Utility to convert from nethandle to netid, keep in sync with getNetworkHandle
+// in Network.java.
+static inline net_handle_t netIdToNetHandle(unsigned fromNetId) {
+    const net_handle_t HANDLE_MAGIC = 0xfacade;
+
+    if (!fromNetId) {
+        return NETWORK_UNSPECIFIED;
+    }
+    return (((net_handle_t)fromNetId << 32) | HANDLE_MAGIC);
+}
+
 class DumpWriter;
 class Network;
 class UidRanges;
@@ -67,6 +98,7 @@
     bool isVirtualNetwork(unsigned netId) const;
 
     int createPhysicalNetwork(unsigned netId, Permission permission) WARN_UNUSED_RESULT;
+    int createPhysicalOemNetwork(Permission permission, unsigned *netId) WARN_UNUSED_RESULT;
     int createVirtualNetwork(unsigned netId, bool hasDns, bool secure) WARN_UNUSED_RESULT;
     int destroyNetwork(unsigned netId) WARN_UNUSED_RESULT;
 
@@ -100,10 +132,12 @@
 
 private:
     bool isValidNetwork(unsigned netId) const;
+    bool isValidNetworkLocked(unsigned netId) const;
     Network* getNetworkLocked(unsigned netId) const;
     VirtualNetwork* getVirtualNetworkForUserLocked(uid_t uid) const;
     Permission getPermissionForUserLocked(uid_t uid) const;
     int checkUserNetworkAccessLocked(uid_t uid, unsigned netId) const;
+    int createPhysicalNetworkLocked(unsigned netId, Permission permission) WARN_UNUSED_RESULT;
 
     int modifyRoute(unsigned netId, const char* interface, const char* destination,
                     const char* nexthop, bool add, bool legacy, uid_t uid) WARN_UNUSED_RESULT;
diff --git a/server/main.cpp b/server/main.cpp
index 27596f7..176d321 100644
--- a/server/main.cpp
+++ b/server/main.cpp
@@ -42,6 +42,7 @@
 #include "MDnsSdListener.h"
 #include "NFLogListener.h"
 #include "NetdConstants.h"
+#include "NetdHwService.h"
 #include "NetdNativeService.h"
 #include "NetlinkManager.h"
 #include "Stopwatch.h"
@@ -54,6 +55,7 @@
 using android::net::CommandListener;
 using android::net::DnsProxyListener;
 using android::net::FwmarkServer;
+using android::net::NetdHwService;
 using android::net::NetdNativeService;
 using android::net::NetlinkManager;
 using android::net::NFLogListener;
@@ -150,6 +152,15 @@
 
     write_pid_file();
 
+    // Now that netd is ready to process commands, advertise service
+    // availability for HAL clients.
+    NetdHwService mHwSvc;
+    if ((ret = mHwSvc.start()) != android::OK) {
+        ALOGE("Unable to start NetdHwService: %d", ret);
+        exit(1);
+    }
+    ALOGI("Registering NetdHwService: %.1fms", subTime.getTimeAndReset());
+
     ALOGI("Netd started in %dms", static_cast<int>(s.timeTaken()));
 
     IPCThreadState::self()->joinThreadPool();