Revert "New protocol for property_service"

This reverts commit dee4bd236b706e229d4eb579613f4de3095ee33a.
Bug: http://b/33926793
Bug: http://b/34670529

Change-Id: Ife3a5a471ee29cb12c2c41efef885ba40b8970e6
(cherry picked from commit 70c4ecf2b562ec643c270d65e0585fe8506d064c)
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 9146d56..72fcb5b 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -27,7 +27,6 @@
 #include <sys/poll.h>
 
 #include <memory>
-#include <vector>
 
 #include <cutils/misc.h>
 #include <cutils/sockets.h>
@@ -49,7 +48,6 @@
 
 #include <fs_mgr.h>
 #include <android-base/file.h>
-#include <android-base/strings.h>
 #include "bootimg.h"
 
 #include "property_service.h"
@@ -72,30 +70,30 @@
     }
 }
 
-static bool check_mac_perms(const std::string& name, char* sctx, struct ucred* cr) {
-
-    if (!sctx) {
-      return false;
-    }
-
-    if (!sehandle_prop) {
-      return false;
-    }
-
-    char* tctx = nullptr;
-    if (selabel_lookup(sehandle_prop, &tctx, name.c_str(), 1) != 0) {
-      return false;
-    }
-
+static int check_mac_perms(const char *name, char *sctx, struct ucred *cr)
+{
+    char *tctx = NULL;
+    int result = 0;
     property_audit_data audit_data;
 
-    audit_data.name = name.c_str();
+    if (!sctx)
+        goto err;
+
+    if (!sehandle_prop)
+        goto err;
+
+    if (selabel_lookup(sehandle_prop, &tctx, name, 1) != 0)
+        goto err;
+
+    audit_data.name = name;
     audit_data.cr = cr;
 
-    bool has_access = (selinux_check_access(sctx, tctx, "property_service", "set", &audit_data) == 0);
+    if (selinux_check_access(sctx, tctx, "property_service", "set", reinterpret_cast<void*>(&audit_data)) == 0)
+        result = 1;
 
     freecon(tctx);
-    return has_access;
+ err:
+    return result;
 }
 
 static int check_control_mac_perms(const char *name, char *sctx, struct ucred *cr)
@@ -144,9 +142,11 @@
     }
 }
 
-bool is_legal_property_name(const std::string& name) {
+bool is_legal_property_name(const std::string &name)
+{
     size_t namelen = name.size();
 
+    if (namelen >= PROP_NAME_MAX) return false;
     if (namelen < 1) return false;
     if (name[0] == '.') return false;
     if (name[namelen - 1] == '.') return false;
@@ -169,218 +169,58 @@
     return true;
 }
 
-uint32_t property_set(const std::string& name, const std::string& value) {
-    size_t valuelen = value.size();
+int property_set(const char* name, const char* value) {
+    size_t valuelen = strlen(value);
 
     if (!is_legal_property_name(name)) {
         LOG(ERROR) << "property_set(\"" << name << "\", \"" << value << "\") failed: bad name";
-        return PROP_ERROR_INVALID_NAME;
+        return -1;
     }
-
     if (valuelen >= PROP_VALUE_MAX) {
         LOG(ERROR) << "property_set(\"" << name << "\", \"" << value << "\") failed: "
                    << "value too long";
-        return PROP_ERROR_INVALID_VALUE;
+        return -1;
     }
 
-    if (name == "selinux.restorecon_recursive" && valuelen > 0) {
-        if (restorecon(value.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE) != 0) {
+    if (strcmp("selinux.restorecon_recursive", name) == 0 && valuelen > 0) {
+        if (restorecon(value, SELINUX_ANDROID_RESTORECON_RECURSE) != 0) {
             LOG(ERROR) << "Failed to restorecon_recursive " << value;
         }
     }
 
-    prop_info* pi = (prop_info*) __system_property_find(name.c_str());
+    prop_info* pi = (prop_info*) __system_property_find(name);
     if (pi != nullptr) {
         // ro.* properties are actually "write-once".
-        if (android::base::StartsWith(name, "ro.")) {
+        if (!strncmp(name, "ro.", 3)) {
             LOG(ERROR) << "property_set(\"" << name << "\", \"" << value << "\") failed: "
                        << "property already set";
-            return PROP_ERROR_READ_ONLY_PROPERTY;
+            return -1;
         }
 
-        __system_property_update(pi, value.c_str(), valuelen);
+        __system_property_update(pi, value, valuelen);
     } else {
-        int rc = __system_property_add(name.c_str(), name.size(), value.c_str(), valuelen);
+        int rc = __system_property_add(name, strlen(name), value, valuelen);
         if (rc < 0) {
             LOG(ERROR) << "property_set(\"" << name << "\", \"" << value << "\") failed: "
                        << "__system_property_add failed";
-            return PROP_ERROR_SET_FAILED;
+            return rc;
         }
     }
 
     // Don't write properties to disk until after we have read all default
     // properties to prevent them from being overwritten by default values.
-    if (persistent_properties_loaded && android::base::StartsWith(name, "persist.")) {
-        write_persistent_property(name.c_str(), value.c_str());
+    if (persistent_properties_loaded && strncmp("persist.", name, strlen("persist.")) == 0) {
+        write_persistent_property(name, value);
     }
-    property_changed(name.c_str(), value.c_str());
-    return PROP_SUCCESS;
+    property_changed(name, value);
+    return 0;
 }
 
-class SocketConnection {
- public:
-  SocketConnection(int socket, const struct ucred& cred)
-      : socket_(socket), cred_(cred) {}
-
-  ~SocketConnection() {
-    close(socket_);
-  }
-
-  bool RecvUint32(uint32_t* value, uint32_t* timeout_ms) {
-    return RecvFully(value, sizeof(*value), timeout_ms);
-  }
-
-  bool RecvChars(char* chars, size_t size, uint32_t* timeout_ms) {
-    return RecvFully(chars, size, timeout_ms);
-  }
-
-  bool RecvString(std::string* value, uint32_t* timeout_ms) {
-    uint32_t len = 0;
-    if (!RecvUint32(&len, timeout_ms)) {
-      return false;
-    }
-
-    if (len == 0) {
-      *value = "";
-      return true;
-    }
-
-    std::vector<char> chars(len);
-    if (!RecvChars(&chars[0], len, timeout_ms)) {
-      return false;
-    }
-
-    *value = std::string(&chars[0], len);
-    return true;
-  }
-
-  bool SendUint32(uint32_t value) {
-    int result = TEMP_FAILURE_RETRY(send(socket_, &value, sizeof(value), 0));
-    return result == sizeof(value);
-  }
-
-  int socket() {
-    return socket_;
-  }
-
-  const struct ucred& cred() {
-    return cred_;
-  }
-
- private:
-  bool PollIn(uint32_t* timeout_ms) {
-    /* Default 2 sec timeout for caller to send data. */
-    struct pollfd ufds[1];
-    ufds[0].fd = socket_;
-    ufds[0].events = POLLIN;
-    ufds[0].revents = 0;
-    while (timeout_ms > 0) {
-      Timer timer;
-      int nr = poll(ufds, 1, *timeout_ms);
-      uint64_t millis = timer.duration_ns()/1000000;
-      *timeout_ms = (millis > *timeout_ms) ? 0 : *timeout_ms - millis;
-
-      if (nr > 0) {
-        return true;
-      }
-
-      if (nr == 0) {
-        // Timeout
-        break;
-      }
-
-      if (nr < 0 && errno != EINTR) {
-        PLOG(ERROR) << "sys_prop: error waiting for uid " << cred_.uid << " to send property message";
-        return false;
-      } else { // errno == EINTR
-        // Timer rounds milliseconds down in case of EINTR we want it to be rounded up
-        // to avoid slowing init down by causing EINTR with under millisecond timeout.
-        if (*timeout_ms > 0) {
-          --(*timeout_ms);
-        }
-      }
-    }
-
-    LOG(ERROR) << "sys_prop: timeout waiting for uid " << cred_.uid << " to send property message.";
-    return false;
-  }
-
-  bool RecvFully(void* data_ptr, size_t size, uint32_t* timeout_ms) {
-    size_t bytes_left = size;
-    char* data = static_cast<char*>(data_ptr);
-    while (*timeout_ms > 0 && bytes_left > 0) {
-      if (!PollIn(timeout_ms)) {
-        return false;
-      }
-
-      int result = TEMP_FAILURE_RETRY(recv(socket_, data, bytes_left, MSG_DONTWAIT));
-      if (result <= 0) {
-        return false;
-      }
-
-      bytes_left -= result;
-      data += result;
-    }
-
-    return bytes_left == 0;
-  }
-
-  int socket_;
-  struct ucred cred_;
-
-  DISALLOW_IMPLICIT_CONSTRUCTORS(SocketConnection);
-};
-
-static void handle_property_set(SocketConnection& socket,
-                                const std::string& name,
-                                const std::string& value,
-                                bool legacy_protocol) {
-  const char* cmd_name = legacy_protocol ? "PROP_MSG_SETPROP" : "PROP_MSG_SETPROP2";
-  if (!is_legal_property_name(name)) {
-    LOG(ERROR) << "sys_prop(" << cmd_name << "): illegal property name \"" << name << "\"";
-    socket.SendUint32(PROP_ERROR_INVALID_NAME);
-    return;
-  }
-
-  struct ucred cr = socket.cred();
-  char* source_ctx = nullptr;
-  getpeercon(socket.socket(), &source_ctx);
-
-  if (android::base::StartsWith(name, "ctl.")) {
-    if (check_control_mac_perms(value.c_str(), source_ctx, &cr)) {
-      handle_control_message(name.c_str() + 4, value.c_str());
-      if (!legacy_protocol) {
-        socket.SendUint32(PROP_SUCCESS);
-      }
-    } else {
-      LOG(ERROR) << "sys_prop(" << cmd_name << "): Unable to " << (name.c_str() + 4)
-                 << " service ctl [" << value << "]"
-                 << " uid:" << cr.uid
-                 << " gid:" << cr.gid
-                 << " pid:" << cr.pid;
-      if (!legacy_protocol) {
-        socket.SendUint32(PROP_ERROR_HANDLE_CONTROL_MESSAGE);
-      }
-    }
-  } else {
-    if (check_mac_perms(name, source_ctx, &cr)) {
-      uint32_t result = property_set(name, value);
-      if (!legacy_protocol) {
-        socket.SendUint32(result);
-      }
-    } else {
-      LOG(ERROR) << "sys_prop(" << cmd_name << "): permission denied uid:" << cr.uid << " name:" << name;
-      if (!legacy_protocol) {
-        socket.SendUint32(PROP_ERROR_PERMISSION_DENIED);
-      }
-    }
-  }
-
-  freecon(source_ctx);
-}
-
-static void handle_property_set_fd() {
-    static constexpr uint32_t kDefaultSocketTimeout = 2000; /* ms */
+static void handle_property_set_fd()
+{
+    prop_msg msg;
+    int r;
+    char * source_ctx = NULL;
 
     int s = accept(property_set_fd, nullptr, nullptr);
     if (s == -1) {
@@ -396,50 +236,72 @@
         return;
     }
 
-    SocketConnection socket(s, cr);
-    uint32_t timeout_ms = kDefaultSocketTimeout;
-
-    uint32_t cmd = 0;
-
-    if (!socket.RecvUint32(&cmd, &timeout_ms)) {
-        PLOG(ERROR) << "sys_prop: error while reading command from the socket";
-        socket.SendUint32(PROP_ERROR_READ_CMD);
+    static constexpr int timeout_ms = 2 * 1000;  /* Default 2 sec timeout for caller to send property. */
+    struct pollfd ufds[1];
+    ufds[0].fd = s;
+    ufds[0].events = POLLIN;
+    ufds[0].revents = 0;
+    int nr = TEMP_FAILURE_RETRY(poll(ufds, 1, timeout_ms));
+    if (nr == 0) {
+        LOG(ERROR) << "sys_prop: timeout waiting for uid " << cr.uid << " to send property message.";
+        close(s);
+        return;
+    } else if (nr < 0) {
+        PLOG(ERROR) << "sys_prop: error waiting for uid " << cr.uid << " to send property message";
+        close(s);
         return;
     }
 
-    switch(cmd) {
-    case PROP_MSG_SETPROP: {
-        char prop_name[PROP_NAME_MAX];
-        char prop_value[PROP_VALUE_MAX];
+    r = TEMP_FAILURE_RETRY(recv(s, &msg, sizeof(msg), MSG_DONTWAIT));
+    if(r != sizeof(prop_msg)) {
+        PLOG(ERROR) << "sys_prop: mis-match msg size received: " << r << " expected: " << sizeof(prop_msg);
+        close(s);
+        return;
+    }
 
-        if (!socket.RecvChars(prop_name, PROP_NAME_MAX, &timeout_ms) ||
-            !socket.RecvChars(prop_value, PROP_VALUE_MAX, &timeout_ms)) {
-          PLOG(ERROR) << "sys_prop(PROP_MSG_SETPROP): error while reading name/value from the socket";
-          return;
+    switch(msg.cmd) {
+    case PROP_MSG_SETPROP:
+        msg.name[PROP_NAME_MAX-1] = 0;
+        msg.value[PROP_VALUE_MAX-1] = 0;
+
+        if (!is_legal_property_name(msg.name)) {
+            LOG(ERROR) << "sys_prop: illegal property name \"" << msg.name << "\"";
+            close(s);
+            return;
         }
 
-        prop_name[PROP_NAME_MAX-1] = 0;
-        prop_value[PROP_VALUE_MAX-1] = 0;
+        getpeercon(s, &source_ctx);
 
-        handle_property_set(socket, prop_value, prop_value, true);
-        break;
-      }
+        if(memcmp(msg.name,"ctl.",4) == 0) {
+            // Keep the old close-socket-early behavior when handling
+            // ctl.* properties.
+            close(s);
+            if (check_control_mac_perms(msg.value, source_ctx, &cr)) {
+                handle_control_message((char*) msg.name + 4, (char*) msg.value);
+            } else {
+                LOG(ERROR) << "sys_prop: Unable to " << (msg.name + 4)
+                           << " service ctl [" << msg.value << "]"
+                           << " uid:" << cr.uid
+                           << " gid:" << cr.gid
+                           << " pid:" << cr.pid;
+            }
+        } else {
+            if (check_mac_perms(msg.name, source_ctx, &cr)) {
+                property_set((char*) msg.name, (char*) msg.value);
+            } else {
+                LOG(ERROR) << "sys_prop: permission denied uid:" << cr.uid << " name:" << msg.name;
+            }
 
-    case PROP_MSG_SETPROP2: {
-        std::string name;
-        std::string value;
-        if (!socket.RecvString(&name, &timeout_ms) ||
-            !socket.RecvString(&value, &timeout_ms)) {
-          PLOG(ERROR) << "sys_prop(PROP_MSG_SETPROP2): error while reading name/value from the socket";
-          socket.SendUint32(PROP_ERROR_READ_DATA);
-          return;
+            // Note: bionic's property client code assumes that the
+            // property server will not close the socket until *AFTER*
+            // the property is written to memory.
+            close(s);
         }
-
-        handle_property_set(socket, name, value, false);
+        freecon(source_ctx);
         break;
-      }
+
     default:
-        socket.SendUint32(PROP_ERROR_INVALID_CMD);
+        close(s);
         break;
     }
 }
@@ -648,8 +510,6 @@
 }
 
 void start_property_service() {
-    property_set("ro.property_service.version", "2");
-
     property_set_fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
                                     0666, 0, 0, NULL);
     if (property_set_fd == -1) {
diff --git a/init/property_service.h b/init/property_service.h
index 5d59473..e3a2acb 100644
--- a/init/property_service.h
+++ b/init/property_service.h
@@ -27,14 +27,14 @@
     const char* name;
 };
 
-void property_init(void);
-void property_load_boot_defaults(void);
-void load_persist_props(void);
-void load_system_props(void);
-void start_property_service(void);
+extern void property_init(void);
+extern void property_load_boot_defaults(void);
+extern void load_persist_props(void);
+extern void load_system_props(void);
+extern void start_property_service(void);
 std::string property_get(const char* name);
-uint32_t property_set(const std::string& name, const std::string& value);
-bool is_legal_property_name(const std::string& name);
+extern int property_set(const char *name, const char *value);
+extern bool is_legal_property_name(const std::string &name);
 
 
 #endif  /* _INIT_PROPERTY_H */