Implement INetd.aidl getProcSysNet().

Also: a few "tidy-inspired" changes.

Test: as follows
    - built, flashed, booted
    - system/netd/tests/runtest.sh passes
Bug: 32163131
Change-Id: Icaa164af3c3d0d03af1ec083dfcbe856ac51529f
diff --git a/server/InterfaceController.cpp b/server/InterfaceController.cpp
index 34b8004..4c35085 100644
--- a/server/InterfaceController.cpp
+++ b/server/InterfaceController.cpp
@@ -26,6 +26,7 @@
 #include <android-base/file.h>
 #include <android-base/properties.h>
 #include <android-base/stringprintf.h>
+#include <android-base/strings.h>
 #include <log/log.h>
 #include <logwrap/logwrap.h>
 #include <netutils/ifc.h>
@@ -40,17 +41,18 @@
 
 using android::base::ReadFileToString;
 using android::base::StringPrintf;
+using android::base::Trim;
 using android::base::WriteStringToFile;
 using android::net::INetd;
 using android::net::RouteController;
 using android::netdutils::isOk;
-using android::netdutils::Status;
-using android::netdutils::StatusOr;
 using android::netdutils::makeSlice;
 using android::netdutils::sSyscalls;
-using android::netdutils::status::ok;
+using android::netdutils::Status;
 using android::netdutils::statusFromErrno;
+using android::netdutils::StatusOr;
 using android::netdutils::toString;
+using android::netdutils::status::ok;
 
 namespace {
 
@@ -380,7 +382,11 @@
     if (path.empty()) {
         return -errno;
     }
-    return ReadFileToString(path, value) ? 0 : -errno;
+    if (ReadFileToString(path, value)) {
+        *value = Trim(*value);
+        return 0;
+    }
+    return -errno;
 }
 
 int InterfaceController::setParameter(
diff --git a/server/InterfaceController.h b/server/InterfaceController.h
index 58505a6..45ff878 100644
--- a/server/InterfaceController.h
+++ b/server/InterfaceController.h
@@ -47,6 +47,9 @@
 
     // Read and write values in files of the form:
     //     /proc/sys/net/<family>/<which>/<interface>/<parameter>
+    //
+    // NOTE: getParameter() trims whitespace so the caller does not need extra
+    // code to crop trailing newlines, for example.
     static int getParameter(
             const char *family, const char *which, const char *interface, const char *parameter,
             std::string *value);
diff --git a/server/NetdNativeService.cpp b/server/NetdNativeService.cpp
index c0ca209..cb974ea 100644
--- a/server/NetdNativeService.cpp
+++ b/server/NetdNativeService.cpp
@@ -17,6 +17,7 @@
 #define LOG_TAG "Netd"
 
 #include <set>
+#include <tuple>
 #include <vector>
 
 #include <android-base/stringprintf.h>
@@ -444,25 +445,25 @@
     return binder::Status::ok();
 }
 
-binder::Status NetdNativeService::setProcSysNet(
-        int32_t family, int32_t which, const std::string &ifname, const std::string &parameter,
-        const std::string &value) {
-    ENFORCE_PERMISSION(CONNECTIVITY_INTERNAL);
+namespace {
 
-    const char *familyStr;
-    switch (family) {
+std::tuple<binder::Status, const char*, const char*> getPathComponents(int32_t ipversion,
+                                                                       int32_t category) {
+    const char* ipversionStr = nullptr;
+    switch (ipversion) {
         case INetd::IPV4:
-            familyStr = "ipv4";
+            ipversionStr = "ipv4";
             break;
         case INetd::IPV6:
-            familyStr = "ipv6";
+            ipversionStr = "ipv6";
             break;
         default:
-            return binder::Status::fromServiceSpecificError(EAFNOSUPPORT, String8("Bad family"));
+            return {binder::Status::fromServiceSpecificError(EAFNOSUPPORT, "Bad IP version"),
+                    nullptr, nullptr};
     }
 
-    const char *whichStr;
-    switch (which) {
+    const char* whichStr = nullptr;
+    switch (category) {
         case INetd::CONF:
             whichStr = "conf";
             break;
@@ -470,17 +471,58 @@
             whichStr = "neigh";
             break;
         default:
-            return binder::Status::fromServiceSpecificError(EINVAL, String8("Bad category"));
+            return {binder::Status::fromServiceSpecificError(EINVAL, "Bad category"), nullptr,
+                    nullptr};
     }
 
-    const int err = InterfaceController::setParameter(
-            familyStr, whichStr, ifname.c_str(), parameter.c_str(),
-            value.c_str());
-    if (err != 0) {
-        return binder::Status::fromServiceSpecificError(-err,
-                String8::format("ResolverController error: %s", strerror(-err)));
+    return {binder::Status::ok(), ipversionStr, whichStr};
+}
+
+}  // namespace
+
+binder::Status NetdNativeService::getProcSysNet(int32_t ipversion, int32_t which,
+                                                const std::string& ifname,
+                                                const std::string& parameter, std::string* value) {
+    ENFORCE_PERMISSION(NETWORK_STACK);
+    auto entry = gLog.newEntry().prettyFunction(__PRETTY_FUNCTION__)
+                         .args(ipversion, which, ifname, parameter);
+
+    const auto pathParts = getPathComponents(ipversion, which);
+    const auto& pathStatus = std::get<0>(pathParts);
+    if (!pathStatus.isOk()) {
+        gLog.log(entry.returns(pathStatus.exceptionCode()).withAutomaticDuration());
+        return pathStatus;
     }
-    return binder::Status::ok();
+
+    const int err = InterfaceController::getParameter(std::get<1>(pathParts),
+                                                      std::get<2>(pathParts), ifname.c_str(),
+                                                      parameter.c_str(), value);
+    entry.returns(err);
+    if (err == 0) entry.returns(*value);
+    gLog.log(entry.withAutomaticDuration());
+    return statusFromErrcode(err);
+}
+
+binder::Status NetdNativeService::setProcSysNet(int32_t ipversion, int32_t which,
+                                                const std::string& ifname,
+                                                const std::string& parameter,
+                                                const std::string& value) {
+    ENFORCE_PERMISSION(NETWORK_STACK);
+    auto entry = gLog.newEntry().prettyFunction(__PRETTY_FUNCTION__)
+                         .args(ipversion, which, ifname, parameter, value);
+
+    const auto pathParts = getPathComponents(ipversion, which);
+    const auto& pathStatus = std::get<0>(pathParts);
+    if (!pathStatus.isOk()) {
+        gLog.log(entry.returns(pathStatus.exceptionCode()).withAutomaticDuration());
+        return pathStatus;
+    }
+
+    const int err = InterfaceController::setParameter(std::get<1>(pathParts),
+                                                      std::get<2>(pathParts), ifname.c_str(),
+                                                      parameter.c_str(), value.c_str());
+    gLog.log(entry.returns(err).withAutomaticDuration());
+    return statusFromErrcode(err);
 }
 
 binder::Status NetdNativeService::getMetricsReportingLevel(int *reportingLevel) {
diff --git a/server/NetdNativeService.h b/server/NetdNativeService.h
index b34e363..c8b85f0 100644
--- a/server/NetdNativeService.h
+++ b/server/NetdNativeService.h
@@ -93,9 +93,10 @@
     binder::Status interfaceDelAddress(const std::string &ifName,
             const std::string &addrString, int prefixLength) override;
 
-    binder::Status setProcSysNet(
-            int32_t family, int32_t which, const std::string &ifname, const std::string &parameter,
-            const std::string &value) override;
+    binder::Status getProcSysNet(int32_t ipversion, int32_t which, const std::string& ifname,
+                                 const std::string& parameter, std::string* value) override;
+    binder::Status setProcSysNet(int32_t ipversion, int32_t which, const std::string& ifname,
+                                 const std::string& parameter, const std::string& value) override;
 
     // Metrics reporting level set / get (internal use only).
     binder::Status getMetricsReportingLevel(int *reportingLevel) override;
diff --git a/server/binder/android/net/INetd.aidl b/server/binder/android/net/INetd.aidl
index 3ed4f8c..5e42770 100644
--- a/server/binder/android/net/INetd.aidl
+++ b/server/binder/android/net/INetd.aidl
@@ -291,20 +291,24 @@
     /**
      * Set and get /proc/sys/net interface configuration parameters.
      *
-     * @param family One of IPV4/IPV6 integers, indicating the desired address family directory.
+     * @param ipversion One of IPV4/IPV6 integers, indicating the desired IP version directory.
      * @param which One of CONF/NEIGH integers, indicating the desired parameter category directory.
      * @param ifname The interface name portion of the path; may also be "all" or "default".
      * @param parameter The parameter name portion of the path.
      * @param value The value string to be written into the assembled path.
+     *
+     * @throws ServiceSpecificException in case of failure, with an error code corresponding to the
+     *         unix errno.
      */
 
     const int IPV4  = 4;
     const int IPV6  = 6;
     const int CONF  = 1;
     const int NEIGH = 2;
-    void setProcSysNet(int family, int which, in @utf8InCpp String ifname,
+    @utf8InCpp String getProcSysNet(int ipversion, int which, in @utf8InCpp String ifname,
+            in @utf8InCpp String parameter);
+    void setProcSysNet(int ipversion, int which, in @utf8InCpp String ifname,
             in @utf8InCpp String parameter, in @utf8InCpp String value);
-    // TODO: add corresponding getProcSysNet().
 
     /**
      * Get/Set metrics reporting level.