Revert "init: handle property service callbacks asynchronously"

This is apparently causing problems with reboot.

This reverts commit d2dab830d3ec260ccd982d147d4eb0ef74071261.

Bug: 150863651
Test: build
Merged-In: Ib8a4835cdc8358a54c7acdebc5c95038963a0419
Change-Id: Ib8a4835cdc8358a54c7acdebc5c95038963a0419
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 319a241..730bf6d 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -92,10 +92,8 @@
 static bool persistent_properties_loaded = false;
 
 static int property_set_fd = -1;
-static int from_init_socket = -1;
 static int init_socket = -1;
 static bool accept_messages = false;
-static std::thread property_service_thread;
 
 static PropertyInfoAreaFile property_info_area;
 
@@ -149,6 +147,17 @@
     return has_access;
 }
 
+static void SendPropertyChanged(const std::string& name, const std::string& value) {
+    auto property_msg = PropertyMessage{};
+    auto* changed_message = property_msg.mutable_changed_message();
+    changed_message->set_name(name);
+    changed_message->set_value(value);
+
+    if (auto result = SendMessage(init_socket, property_msg); !result.ok()) {
+        LOG(ERROR) << "Failed to send property changed message: " << result.error();
+    }
+}
+
 static uint32_t PropertySet(const std::string& name, const std::string& value, std::string* error) {
     size_t valuelen = value.size();
 
@@ -187,137 +196,47 @@
     // If init hasn't started its main loop, then it won't be handling property changed messages
     // anyway, so there's no need to try to send them.
     if (accept_messages) {
-        PropertyChanged(name, value);
+        SendPropertyChanged(name, value);
     }
     return PROP_SUCCESS;
 }
 
-template <typename T>
-class SingleThreadExecutor {
+class AsyncRestorecon {
   public:
-    virtual ~SingleThreadExecutor() {}
-
-    template <typename F = T>
-    void Run(F&& item) {
+    void TriggerRestorecon(const std::string& path) {
         auto guard = std::lock_guard{mutex_};
-        items_.emplace(std::forward<F>(item));
+        paths_.emplace(path);
 
-        if (thread_state_ == ThreadState::kRunning || thread_state_ == ThreadState::kStopped) {
-            return;
-        }
-
-        if (thread_state_ == ThreadState::kPendingJoin) {
-            thread_.join();
-        }
-
-        StartThread();
-    }
-
-    void StopAndJoin() {
-        auto lock = std::unique_lock{mutex_};
-        if (thread_state_ == ThreadState::kPendingJoin) {
-            thread_.join();
-        } else if (thread_state_ == ThreadState::kRunning) {
-            thread_state_ = ThreadState::kStopped;
-            lock.unlock();
-            thread_.join();
-            lock.lock();
-        }
-
-        thread_state_ = ThreadState::kStopped;
-    }
-
-    void Restart() {
-        auto guard = std::lock_guard{mutex_};
-        if (items_.empty()) {
-            thread_state_ = ThreadState::kNotStarted;
-        } else {
-            StartThread();
-        }
-    }
-
-    void MaybeJoin() {
-        auto guard = std::lock_guard{mutex_};
-        if (thread_state_ == ThreadState::kPendingJoin) {
-            thread_.join();
-            thread_state_ = ThreadState::kNotStarted;
+        if (!thread_started_) {
+            thread_started_ = true;
+            std::thread{&AsyncRestorecon::ThreadFunction, this}.detach();
         }
     }
 
   private:
-    virtual void Execute(T&& item) = 0;
-
-    void StartThread() {
-        thread_state_ = ThreadState::kRunning;
-        auto thread = std::thread{&SingleThreadExecutor::ThreadFunction, this};
-        std::swap(thread_, thread);
-    }
-
     void ThreadFunction() {
         auto lock = std::unique_lock{mutex_};
 
-        while (!items_.empty()) {
-            auto item = items_.front();
-            items_.pop();
+        while (!paths_.empty()) {
+            auto path = paths_.front();
+            paths_.pop();
 
             lock.unlock();
-            Execute(std::move(item));
+            if (selinux_android_restorecon(path.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE) != 0) {
+                LOG(ERROR) << "Asynchronous restorecon of '" << path << "' failed'";
+            }
+            android::base::SetProperty(kRestoreconProperty, path);
             lock.lock();
         }
 
-        if (thread_state_ != ThreadState::kStopped) {
-            thread_state_ = ThreadState::kPendingJoin;
-        }
+        thread_started_ = false;
     }
 
     std::mutex mutex_;
-    std::queue<T> items_;
-    enum class ThreadState {
-        kNotStarted,  // Initial state when starting the program or when restarting with no items to
-                      // process.
-        kRunning,     // The thread is running and is in a state that it will process new items if
-                      // are run.
-        kPendingJoin,  // The thread has run to completion and is pending join().  A new thread must
-                       // be launched for new items to be processed.
-        kStopped,  // This executor has stopped and will not process more items until Restart() is
-                   // called.  Currently pending items will be processed and the thread will be
-                   // joined.
-    };
-    ThreadState thread_state_ = ThreadState::kNotStarted;
-    std::thread thread_;
+    std::queue<std::string> paths_;
+    bool thread_started_ = false;
 };
 
-class RestoreconThread : public SingleThreadExecutor<std::string> {
-    virtual void Execute(std::string&& path) override {
-        if (selinux_android_restorecon(path.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE) != 0) {
-            LOG(ERROR) << "Asynchronous restorecon of '" << path << "' failed'";
-        }
-        android::base::SetProperty(kRestoreconProperty, path);
-    }
-};
-
-struct ControlMessageInfo {
-    std::string message;
-    std::string name;
-    pid_t pid;
-    int fd;
-};
-
-class ControlMessageThread : public SingleThreadExecutor<ControlMessageInfo> {
-    virtual void Execute(ControlMessageInfo&& info) override {
-        bool success = HandleControlMessage(info.message, info.name, info.pid);
-
-        uint32_t response = success ? PROP_SUCCESS : PROP_ERROR_HANDLE_CONTROL_MESSAGE;
-        if (info.fd != -1) {
-            TEMP_FAILURE_RETRY(send(info.fd, &response, sizeof(response), 0));
-            close(info.fd);
-        }
-    }
-};
-
-static RestoreconThread restorecon_thread;
-static ControlMessageThread control_message_thread;
-
 class SocketConnection {
   public:
     SocketConnection(int socket, const ucred& cred) : socket_(socket), cred_(cred) {}
@@ -459,17 +378,29 @@
         return PROP_ERROR_HANDLE_CONTROL_MESSAGE;
     }
 
-    // We must release the fd before spawning the thread, otherwise there will be a race with the
-    // thread. If the thread calls close() before this function calls Release(), then fdsan will see
-    // the wrong tag and abort().
+    auto property_msg = PropertyMessage{};
+    auto* control_message = property_msg.mutable_control_message();
+    control_message->set_msg(msg);
+    control_message->set_name(name);
+    control_message->set_pid(pid);
+
+    // We must release the fd before sending it to init, otherwise there will be a race with init.
+    // If init calls close() before Release(), then fdsan will see the wrong tag and abort().
     int fd = -1;
     if (socket != nullptr && SelinuxGetVendorAndroidVersion() > __ANDROID_API_Q__) {
         fd = socket->Release();
+        control_message->set_fd(fd);
     }
 
-    // Handling a control message likely calls SetProperty, which we must synchronously handle,
-    // therefore we must fork a thread to handle it.
-    control_message_thread.Run({msg, name, pid, fd});
+    if (auto result = SendMessage(init_socket, property_msg); !result.ok()) {
+        // We've already released the fd above, so if we fail to send the message to init, we need
+        // to manually free it here.
+        if (fd != -1) {
+            close(fd);
+        }
+        *error = "Failed to send control message: " + result.error().message();
+        return PROP_ERROR_HANDLE_CONTROL_MESSAGE;
+    }
 
     return PROP_SUCCESS;
 }
@@ -571,7 +502,8 @@
     // We use a thread to do this restorecon operation to prevent holding up init, as it may take
     // a long time to complete.
     if (name == kRestoreconProperty && cr.pid != 1 && !value.empty()) {
-        restorecon_thread.Run(value);
+        static AsyncRestorecon async_restorecon;
+        async_restorecon.TriggerRestorecon(value);
         return PROP_SUCCESS;
     }
 
@@ -1152,8 +1084,6 @@
     PropertyLoadBootDefaults();
 }
 
-static bool pause_property_service = false;
-
 static void HandleInitSocket() {
     auto message = ReadMessage(init_socket);
     if (!message.ok()) {
@@ -1188,10 +1118,6 @@
             accept_messages = true;
             break;
         }
-        case InitMessage::kPausePropertyService: {
-            pause_property_service = true;
-            break;
-        }
         default:
             LOG(ERROR) << "Unknown message type from init: " << init_message.msg_case();
     }
@@ -1212,7 +1138,7 @@
         LOG(FATAL) << result.error();
     }
 
-    while (!pause_property_service) {
+    while (true) {
         auto pending_functions = epoll.Wait(std::nullopt);
         if (!pending_functions.ok()) {
             LOG(ERROR) << pending_functions.error();
@@ -1221,34 +1147,9 @@
                 (*function)();
             }
         }
-        control_message_thread.MaybeJoin();
-        restorecon_thread.MaybeJoin();
     }
 }
 
-void SendStopPropertyServiceMessage() {
-    auto init_message = InitMessage{};
-    init_message.set_pause_property_service(true);
-    if (auto result = SendMessage(from_init_socket, init_message); !result.ok()) {
-        LOG(ERROR) << "Failed to send stop property service message: " << result.error();
-    }
-}
-
-void PausePropertyService() {
-    control_message_thread.StopAndJoin();
-    restorecon_thread.StopAndJoin();
-    SendStopPropertyServiceMessage();
-    property_service_thread.join();
-}
-
-void ResumePropertyService() {
-    pause_property_service = false;
-    auto new_thread = std::thread{PropertyServiceThread};
-    property_service_thread.swap(new_thread);
-    restorecon_thread.Restart();
-    control_message_thread.Restart();
-}
-
 void StartPropertyService(int* epoll_socket) {
     InitPropertySet("ro.property_service.version", "2");
 
@@ -1256,7 +1157,7 @@
     if (socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, sockets) != 0) {
         PLOG(FATAL) << "Failed to socketpair() between property_service and init";
     }
-    *epoll_socket = from_init_socket = sockets[0];
+    *epoll_socket = sockets[0];
     init_socket = sockets[1];
     accept_messages = true;
 
@@ -1270,8 +1171,7 @@
 
     listen(property_set_fd, 8);
 
-    auto new_thread = std::thread{PropertyServiceThread};
-    property_service_thread.swap(new_thread);
+    std::thread{PropertyServiceThread}.detach();
 }
 
 }  // namespace init