Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8efca4bb authored by Tom Cherry's avatar Tom Cherry
Browse files

Reland: "init: run property service in a thread"

It's been a long standing issue that init cannot respond to property
set messages when it is running a builtin command.  This is
particularly problematic when the commands involve IPC to vold or
other daemons, as it prevents them from being able to set properties.

This change has init run property service in a thread, which
eliminates the above issue.

This change may also serve as a starting block to running property
service in an entirely different process to better isolate init from
handling property requests.

Test: CF boots, walleye boots, properties are set appropriately
Change-Id: I13b8bf240c9fcb1d2d5890a8be2f0ef74efd4adf
parent a033693a
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -128,6 +128,7 @@ cc_library_static {
        "persistent_properties.cpp",
        "persistent_properties.cpp",
        "persistent_properties.proto",
        "persistent_properties.proto",
        "property_service.cpp",
        "property_service.cpp",
        "property_service.proto",
        "property_type.cpp",
        "property_type.cpp",
        "reboot.cpp",
        "reboot.cpp",
        "reboot_utils.cpp",
        "reboot_utils.cpp",
+10 −0
Original line number Original line Diff line number Diff line
@@ -80,6 +80,7 @@
using namespace std::literals::string_literals;
using namespace std::literals::string_literals;


using android::base::Basename;
using android::base::Basename;
using android::base::StartsWith;
using android::base::unique_fd;
using android::base::unique_fd;
using android::fs_mgr::Fstab;
using android::fs_mgr::Fstab;
using android::fs_mgr::ReadFstabFromFile;
using android::fs_mgr::ReadFstabFromFile;
@@ -687,6 +688,15 @@ static Result<void> do_swapon_all(const BuiltinArguments& args) {
}
}


static Result<void> do_setprop(const BuiltinArguments& args) {
static Result<void> do_setprop(const BuiltinArguments& args) {
    if (StartsWith(args[1], "ctl.")) {
        return Error() << "InitPropertySet: Do not set ctl. properties from init; call the Service "
                          "functions directly";
    }
    if (args[1] == kRestoreconProperty) {
        return Error() << "InitPropertySet: Do not set '" << kRestoreconProperty
                       << "' from init; use the restorecon builtin directly";
    }

    property_set(args[1], args[2]);
    property_set(args[1], args[2]);
    return {};
    return {};
}
}
+50 −1
Original line number Original line Diff line number Diff line
@@ -28,6 +28,9 @@
#include <sys/types.h>
#include <sys/types.h>
#include <unistd.h>
#include <unistd.h>


#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
#include <sys/_system_properties.h>

#include <functional>
#include <functional>
#include <map>
#include <map>
#include <memory>
#include <memory>
@@ -61,6 +64,7 @@
#include "mount_handler.h"
#include "mount_handler.h"
#include "mount_namespace.h"
#include "mount_namespace.h"
#include "property_service.h"
#include "property_service.h"
#include "proto_utils.h"
#include "reboot.h"
#include "reboot.h"
#include "reboot_utils.h"
#include "reboot_utils.h"
#include "security.h"
#include "security.h"
@@ -69,6 +73,7 @@
#include "service.h"
#include "service.h"
#include "service_parser.h"
#include "service_parser.h"
#include "sigchld_handler.h"
#include "sigchld_handler.h"
#include "system/core/init/property_service.pb.h"
#include "util.h"
#include "util.h"


using namespace std::chrono_literals;
using namespace std::chrono_literals;
@@ -90,6 +95,7 @@ static int property_triggers_enabled = 0;
static char qemu[32];
static char qemu[32];


static int signal_fd = -1;
static int signal_fd = -1;
static int property_fd = -1;


static std::unique_ptr<Timer> waiting_for_prop(nullptr);
static std::unique_ptr<Timer> waiting_for_prop(nullptr);
static std::string wait_prop_name;
static std::string wait_prop_name;
@@ -613,6 +619,44 @@ static void RecordStageBoottimes(const boot_clock::time_point& second_stage_star
                                selinux_start_time_ns));
                                selinux_start_time_ns));
}
}


static void HandlePropertyFd() {
    auto message = ReadMessage(property_fd);
    if (!message) {
        LOG(ERROR) << "Could not read message from property service: " << message.error();
        return;
    }

    auto property_message = PropertyMessage{};
    if (!property_message.ParseFromString(*message)) {
        LOG(ERROR) << "Could not parse message from property service";
        return;
    }

    switch (property_message.msg_case()) {
        case PropertyMessage::kControlMessage: {
            auto& control_message = property_message.control_message();
            bool success = HandleControlMessage(control_message.msg(), control_message.name(),
                                                control_message.pid());

            uint32_t response = success ? PROP_SUCCESS : PROP_ERROR_HANDLE_CONTROL_MESSAGE;
            if (control_message.has_fd()) {
                int fd = control_message.fd();
                TEMP_FAILURE_RETRY(send(fd, &response, sizeof(response), 0));
                close(fd);
            }
            break;
        }
        case PropertyMessage::kChangedMessage: {
            auto& changed_message = property_message.changed_message();
            property_changed(changed_message.name(), changed_message.value());
            break;
        }
        default:
            LOG(ERROR) << "Unknown message type from property service: "
                       << property_message.msg_case();
    }
}

int SecondStageMain(int argc, char** argv) {
int SecondStageMain(int argc, char** argv) {
    if (REBOOT_BOOTLOADER_ON_PANIC) {
    if (REBOOT_BOOTLOADER_ON_PANIC) {
        InstallRebootSignalHandlers();
        InstallRebootSignalHandlers();
@@ -684,7 +728,12 @@ int SecondStageMain(int argc, char** argv) {
    UmountDebugRamdisk();
    UmountDebugRamdisk();
    fs_mgr_vendor_overlay_mount_all();
    fs_mgr_vendor_overlay_mount_all();
    export_oem_lock_status();
    export_oem_lock_status();
    StartPropertyService(&epoll);

    StartPropertyService(&property_fd);
    if (auto result = epoll.RegisterHandler(property_fd, HandlePropertyFd); !result) {
        LOG(FATAL) << "Could not register epoll handler for property fd: " << result.error();
    }

    MountHandler mount_handler(&epoll);
    MountHandler mount_handler(&epoll);
    set_usb_controller();
    set_usb_controller();


+0 −4
Original line number Original line Diff line number Diff line
@@ -31,10 +31,6 @@ namespace init {
Parser CreateParser(ActionManager& action_manager, ServiceList& service_list);
Parser CreateParser(ActionManager& action_manager, ServiceList& service_list);
Parser CreateServiceOnlyParser(ServiceList& service_list);
Parser CreateServiceOnlyParser(ServiceList& service_list);


bool HandleControlMessage(const std::string& msg, const std::string& arg, pid_t pid);

void property_changed(const std::string& name, const std::string& value);

bool start_waiting_for_property(const char *name, const char *value);
bool start_waiting_for_property(const char *name, const char *value);


void DumpState();
void DumpState();
+101 −50
Original line number Original line Diff line number Diff line
@@ -42,6 +42,7 @@
#include <map>
#include <map>
#include <memory>
#include <memory>
#include <mutex>
#include <mutex>
#include <optional>
#include <queue>
#include <queue>
#include <thread>
#include <thread>
#include <vector>
#include <vector>
@@ -63,8 +64,10 @@
#include "init.h"
#include "init.h"
#include "persistent_properties.h"
#include "persistent_properties.h"
#include "property_type.h"
#include "property_type.h"
#include "proto_utils.h"
#include "selinux.h"
#include "selinux.h"
#include "subcontext.h"
#include "subcontext.h"
#include "system/core/init/property_service.pb.h"
#include "util.h"
#include "util.h"


using namespace std::literals;
using namespace std::literals;
@@ -76,6 +79,7 @@ using android::base::StartsWith;
using android::base::StringPrintf;
using android::base::StringPrintf;
using android::base::Timer;
using android::base::Timer;
using android::base::Trim;
using android::base::Trim;
using android::base::unique_fd;
using android::base::WriteStringToFile;
using android::base::WriteStringToFile;
using android::properties::BuildTrie;
using android::properties::BuildTrie;
using android::properties::ParsePropertyInfoFile;
using android::properties::ParsePropertyInfoFile;
@@ -85,18 +89,13 @@ using android::properties::PropertyInfoEntry;
namespace android {
namespace android {
namespace init {
namespace init {


static constexpr const char kRestoreconProperty[] = "selinux.restorecon_recursive";

static bool persistent_properties_loaded = false;
static bool persistent_properties_loaded = false;


static int property_set_fd = -1;
static int property_set_fd = -1;
static int init_socket = -1;


static PropertyInfoAreaFile property_info_area;
static PropertyInfoAreaFile property_info_area;


uint32_t InitPropertySet(const std::string& name, const std::string& value);

uint32_t (*property_set)(const std::string& name, const std::string& value) = InitPropertySet;

void CreateSerializedPropertyInfo();
void CreateSerializedPropertyInfo();


struct PropertyAuditData {
struct PropertyAuditData {
@@ -164,6 +163,17 @@ static bool CheckMacPerms(const std::string& name, const char* target_context,
    return has_access;
    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) {
        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) {
static uint32_t PropertySet(const std::string& name, const std::string& value, std::string* error) {
    size_t valuelen = value.size();
    size_t valuelen = value.size();


@@ -199,7 +209,16 @@ static uint32_t PropertySet(const std::string& name, const std::string& value, s
    if (persistent_properties_loaded && StartsWith(name, "persist.")) {
    if (persistent_properties_loaded && StartsWith(name, "persist.")) {
        WritePersistentProperty(name, value);
        WritePersistentProperty(name, value);
    }
    }
    property_changed(name, value);
    // If init sets ro.persistent_properties.ready to true, then it has finished writing persistent
    // properties, and we should write future persistent properties to disk.
    if (name == "ro.persistent_properties.ready" && value == "true") {
        persistent_properties_loaded = true;
    }
    // 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 (init_socket != -1) {
        SendPropertyChanged(name, value);
    }
    return PROP_SUCCESS;
    return PROP_SUCCESS;
}
}


@@ -239,35 +258,10 @@ class AsyncRestorecon {
    bool thread_started_ = false;
    bool thread_started_ = false;
};
};


uint32_t InitPropertySet(const std::string& name, const std::string& value) {
    if (StartsWith(name, "ctl.")) {
        LOG(ERROR) << "InitPropertySet: Do not set ctl. properties from init; call the Service "
                      "functions directly";
        return PROP_ERROR_INVALID_NAME;
    }
    if (name == kRestoreconProperty) {
        LOG(ERROR) << "InitPropertySet: Do not set '" << kRestoreconProperty
                   << "' from init; use the restorecon builtin directly";
        return PROP_ERROR_INVALID_NAME;
    }

    uint32_t result = 0;
    ucred cr = {.pid = 1, .uid = 0, .gid = 0};
    std::string error;
    result = HandlePropertySet(name, value, kInitContext.c_str(), cr, &error);
    if (result != PROP_SUCCESS) {
        LOG(ERROR) << "Init cannot set '" << name << "' to '" << value << "': " << error;
    }

    return result;
}

class SocketConnection {
class SocketConnection {
  public:
  public:
    SocketConnection(int socket, const ucred& cred) : socket_(socket), cred_(cred) {}
    SocketConnection(int socket, const ucred& cred) : socket_(socket), cred_(cred) {}


    ~SocketConnection() { close(socket_); }

    bool RecvUint32(uint32_t* value, uint32_t* timeout_ms) {
    bool RecvUint32(uint32_t* value, uint32_t* timeout_ms) {
        return RecvFully(value, sizeof(*value), timeout_ms);
        return RecvFully(value, sizeof(*value), timeout_ms);
    }
    }
@@ -304,6 +298,9 @@ class SocketConnection {
    }
    }


    bool SendUint32(uint32_t value) {
    bool SendUint32(uint32_t value) {
        if (!socket_.ok()) {
            return false;
        }
        int result = TEMP_FAILURE_RETRY(send(socket_, &value, sizeof(value), 0));
        int result = TEMP_FAILURE_RETRY(send(socket_, &value, sizeof(value), 0));
        return result == sizeof(value);
        return result == sizeof(value);
    }
    }
@@ -318,7 +315,9 @@ class SocketConnection {
        return true;
        return true;
    }
    }


    int socket() { return socket_; }
    int Release() { return socket_.release(); }

    int socket() { return socket_.get(); }


    const ucred& cred() { return cred_; }
    const ucred& cred() { return cred_; }


@@ -389,12 +388,34 @@ class SocketConnection {
        return bytes_left == 0;
        return bytes_left == 0;
    }
    }


    int socket_;
    unique_fd socket_;
    ucred cred_;
    ucred cred_;

    DISALLOW_IMPLICIT_CONSTRUCTORS(SocketConnection);
};
};


static uint32_t SendControlMessage(const std::string& msg, const std::string& name, pid_t pid,
                                   SocketConnection* socket, std::string* error) {
    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);
    if (socket != nullptr) {
        control_message->set_fd(socket->socket());
    }

    if (auto result = SendMessage(init_socket, property_msg); !result) {
        *error = "Failed to send control message: " + result.error().message();
        return PROP_ERROR_HANDLE_CONTROL_MESSAGE;
    }

    if (socket != nullptr) {
        // We've successfully sent the fd to init, so release it here.
        socket->Release();
    }

    return PROP_SUCCESS;
}

bool CheckControlPropertyPerms(const std::string& name, const std::string& value,
bool CheckControlPropertyPerms(const std::string& name, const std::string& value,
                               const std::string& source_context, const ucred& cr) {
                               const std::string& source_context, const ucred& cr) {
    // We check the legacy method first but these properties are dontaudit, so we only log an audit
    // We check the legacy method first but these properties are dontaudit, so we only log an audit
@@ -462,15 +483,14 @@ uint32_t CheckPermissions(const std::string& name, const std::string& value,


// This returns one of the enum of PROP_SUCCESS or PROP_ERROR*.
// This returns one of the enum of PROP_SUCCESS or PROP_ERROR*.
uint32_t HandlePropertySet(const std::string& name, const std::string& value,
uint32_t HandlePropertySet(const std::string& name, const std::string& value,
                           const std::string& source_context, const ucred& cr, std::string* error) {
                           const std::string& source_context, const ucred& cr,
                           SocketConnection* socket, std::string* error) {
    if (auto ret = CheckPermissions(name, value, source_context, cr, error); ret != PROP_SUCCESS) {
    if (auto ret = CheckPermissions(name, value, source_context, cr, error); ret != PROP_SUCCESS) {
        return ret;
        return ret;
    }
    }


    if (StartsWith(name, "ctl.")) {
    if (StartsWith(name, "ctl.")) {
        return HandleControlMessage(name.c_str() + 4, value, cr.pid)
        return SendControlMessage(name.c_str() + 4, value, cr.pid, socket, error);
                       ? PROP_SUCCESS
                       : PROP_ERROR_HANDLE_CONTROL_MESSAGE;
    }
    }


    // sys.powerctl is a special property that is used to make the device reboot.  We want to log
    // sys.powerctl is a special property that is used to make the device reboot.  We want to log
@@ -501,6 +521,20 @@ uint32_t HandlePropertySet(const std::string& name, const std::string& value,
    return PropertySet(name, value, error);
    return PropertySet(name, value, error);
}
}


uint32_t InitPropertySet(const std::string& name, const std::string& value) {
    uint32_t result = 0;
    ucred cr = {.pid = 1, .uid = 0, .gid = 0};
    std::string error;
    result = HandlePropertySet(name, value, kInitContext.c_str(), cr, nullptr, &error);
    if (result != PROP_SUCCESS) {
        LOG(ERROR) << "Init cannot set '" << name << "' to '" << value << "': " << error;
    }

    return result;
}

uint32_t (*property_set)(const std::string& name, const std::string& value) = InitPropertySet;

static void handle_property_set_fd() {
static void handle_property_set_fd() {
    static constexpr uint32_t kDefaultSocketTimeout = 2000; /* ms */
    static constexpr uint32_t kDefaultSocketTimeout = 2000; /* ms */


@@ -549,7 +583,8 @@ static void handle_property_set_fd() {


        const auto& cr = socket.cred();
        const auto& cr = socket.cred();
        std::string error;
        std::string error;
        uint32_t result = HandlePropertySet(prop_name, prop_value, source_context, cr, &error);
        uint32_t result =
                HandlePropertySet(prop_name, prop_value, source_context, cr, nullptr, &error);
        if (result != PROP_SUCCESS) {
        if (result != PROP_SUCCESS) {
            LOG(ERROR) << "Unable to set property '" << prop_name << "' from uid:" << cr.uid
            LOG(ERROR) << "Unable to set property '" << prop_name << "' from uid:" << cr.uid
                       << " gid:" << cr.gid << " pid:" << cr.pid << ": " << error;
                       << " gid:" << cr.gid << " pid:" << cr.pid << ": " << error;
@@ -577,11 +612,12 @@ static void handle_property_set_fd() {


        const auto& cr = socket.cred();
        const auto& cr = socket.cred();
        std::string error;
        std::string error;
        uint32_t result = HandlePropertySet(name, value, source_context, cr, &error);
        uint32_t result = HandlePropertySet(name, value, source_context, cr, &socket, &error);
        if (result != PROP_SUCCESS) {
        if (result != PROP_SUCCESS) {
            LOG(ERROR) << "Unable to set property '" << name << "' from uid:" << cr.uid
            LOG(ERROR) << "Unable to set property '" << name << "' from uid:" << cr.uid
                       << " gid:" << cr.gid << " pid:" << cr.pid << ": " << error;
                       << " gid:" << cr.gid << " pid:" << cr.pid << ": " << error;
        }
        }

        socket.SendUint32(result);
        socket.SendUint32(result);
        break;
        break;
      }
      }
@@ -764,7 +800,6 @@ void load_persist_props(void) {
    for (const auto& persistent_property_record : persistent_properties.properties()) {
    for (const auto& persistent_property_record : persistent_properties.properties()) {
        property_set(persistent_property_record.name(), persistent_property_record.value());
        property_set(persistent_property_record.name(), persistent_property_record.value());
    }
    }
    persistent_properties_loaded = true;
    property_set("ro.persistent_properties.ready", "true");
    property_set("ro.persistent_properties.ready", "true");
}
}


@@ -985,21 +1020,37 @@ void CreateSerializedPropertyInfo() {
    selinux_android_restorecon(kPropertyInfosPath, 0);
    selinux_android_restorecon(kPropertyInfosPath, 0);
}
}


void StartPropertyService(Epoll* epoll) {
static void PropertyServiceThread() {
    while (true) {
        handle_property_set_fd();
    }
}

void StartPropertyService(int* epoll_socket) {
    property_set("ro.property_service.version", "2");
    property_set("ro.property_service.version", "2");


    if (auto result = CreateSocket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
    int sockets[2];
                                   false, 0666, 0, 0, {})) {
    if (socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, sockets) != 0) {
        PLOG(FATAL) << "Failed to socketpair() between property_service and init";
    }
    *epoll_socket = sockets[0];
    init_socket = sockets[1];

    if (auto result = CreateSocket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC, false, 0666, 0, 0,
                                   {})) {
        property_set_fd = *result;
        property_set_fd = *result;
    } else {
    } else {
        PLOG(FATAL) << "start_property_service socket creation failed: " << result.error();
        LOG(FATAL) << "start_property_service socket creation failed: " << result.error();
    }
    }


    listen(property_set_fd, 8);
    listen(property_set_fd, 8);


    if (auto result = epoll->RegisterHandler(property_set_fd, handle_property_set_fd); !result) {
    std::thread{PropertyServiceThread}.detach();
        PLOG(FATAL) << result.error();

    }
    property_set = [](const std::string& key, const std::string& value) -> uint32_t {
        android::base::SetProperty(key, value);
        return 0;
    };
}
}


}  // namespace init
}  // namespace init
Loading