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

Commit 4e46a33c authored by Tom Cherry's avatar Tom Cherry Committed by Gerrit Code Review
Browse files

Merge "Reland^2: "init: run property service in a thread""

parents 483c2f90 1ab3dfca
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -129,6 +129,7 @@ cc_library_static {
        "persistent_properties.cpp",
        "persistent_properties.proto",
        "property_service.cpp",
        "property_service.proto",
        "property_type.cpp",
        "reboot.cpp",
        "reboot_utils.cpp",
+24 −1
Original line number Diff line number Diff line
@@ -80,6 +80,7 @@
using namespace std::literals::string_literals;

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

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

    property_set(args[1], args[2]);
    return {};
}
@@ -1016,7 +1026,20 @@ static Result<void> do_loglevel(const BuiltinArguments& args) {
}

static Result<void> do_load_persist_props(const BuiltinArguments& args) {
    load_persist_props();
    // Devices with FDE have load_persist_props called twice; the first time when the temporary
    // /data partition is mounted and then again once /data is truly mounted.  We do not want to
    // read persistent properties from the temporary /data partition or mark persistent properties
    // as having been loaded during the first call, so we return in that case.
    std::string crypto_state = android::base::GetProperty("ro.crypto.state", "");
    std::string crypto_type = android::base::GetProperty("ro.crypto.type", "");
    if (crypto_state == "encrypted" && crypto_type == "block") {
        static size_t num_calls = 0;
        if (++num_calls == 1) return {};
    }

    SendLoadPersistentPropertiesMessage();

    start_waiting_for_property("ro.persistent_properties.ready", "true");
    return {};
}

+66 −1
Original line number Diff line number Diff line
@@ -28,6 +28,9 @@
#include <sys/types.h>
#include <unistd.h>

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

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

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

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

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

void SendLoadPersistentPropertiesMessage() {
    auto init_message = InitMessage{};
    init_message.set_load_persistent_properties(true);
    if (auto result = SendMessage(property_fd, init_message); !result) {
        LOG(ERROR) << "Failed to send load persistent properties message: " << result.error();
    }
}

void SendStopSendingMessagesMessage() {
    auto init_message = InitMessage{};
    init_message.set_stop_sending_messages(true);
    if (auto result = SendMessage(property_fd, init_message); !result) {
        LOG(ERROR) << "Failed to send load persistent properties message: " << result.error();
    }
}

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) {
    if (REBOOT_BOOTLOADER_ON_PANIC) {
        InstallRebootSignalHandlers();
@@ -685,7 +745,12 @@ int SecondStageMain(int argc, char** argv) {
    UmountDebugRamdisk();
    fs_mgr_vendor_overlay_mount_all();
    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);
    set_usb_controller();

+3 −4
Original line number Diff line number Diff line
@@ -31,16 +31,15 @@ namespace init {
Parser CreateParser(ActionManager& action_manager, 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);

void DumpState();

void ResetWaitForProp();

void SendLoadPersistentPropertiesMessage();
void SendStopSendingMessagesMessage();

int SecondStageMain(int argc, char** argv);

}  // namespace init
+156 −72
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@
#include <map>
#include <memory>
#include <mutex>
#include <optional>
#include <queue>
#include <thread>
#include <vector>
@@ -63,8 +64,10 @@
#include "init.h"
#include "persistent_properties.h"
#include "property_type.h"
#include "proto_utils.h"
#include "selinux.h"
#include "subcontext.h"
#include "system/core/init/property_service.pb.h"
#include "util.h"

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

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

static bool persistent_properties_loaded = false;

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

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();

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

@@ -199,7 +209,11 @@ static uint32_t PropertySet(const std::string& name, const std::string& value, s
    if (persistent_properties_loaded && StartsWith(name, "persist.")) {
        WritePersistentProperty(name, value);
    }
    property_changed(name, value);
    // 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;
}

@@ -239,35 +253,10 @@ class AsyncRestorecon {
    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 {
  public:
    SocketConnection(int socket, const 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);
    }
@@ -304,6 +293,9 @@ class SocketConnection {
    }

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

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

    const ucred& cred() { return cred_; }

@@ -389,12 +381,46 @@ class SocketConnection {
        return bytes_left == 0;
    }

    int socket_;
    unique_fd socket_;
    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) {
    if (init_socket == -1) {
        *error = "Received control message after shutdown, ignoring";
        return PROP_ERROR_HANDLE_CONTROL_MESSAGE;
    }

    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) {
        fd = socket->Release();
        control_message->set_fd(fd);
    }

    if (auto result = SendMessage(init_socket, property_msg); !result) {
        // 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;
}

bool CheckControlPropertyPerms(const std::string& name, const std::string& value,
                               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
@@ -462,15 +488,14 @@ uint32_t CheckPermissions(const std::string& name, const std::string& value,

// This returns one of the enum of PROP_SUCCESS or PROP_ERROR*.
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) {
        return ret;
    }

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

    // sys.powerctl is a special property that is used to make the device reboot.  We want to log
@@ -501,6 +526,20 @@ uint32_t HandlePropertySet(const std::string& name, const std::string& value,
    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 constexpr uint32_t kDefaultSocketTimeout = 2000; /* ms */

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

        const auto& cr = socket.cred();
        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) {
            LOG(ERROR) << "Unable to set property '" << prop_name << "' from uid:" << cr.uid
                       << " gid:" << cr.gid << " pid:" << cr.pid << ": " << error;
@@ -577,7 +617,7 @@ static void handle_property_set_fd() {

        const auto& cr = socket.cred();
        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) {
            LOG(ERROR) << "Unable to set property '" << name << "' from uid:" << cr.uid
                       << " gid:" << cr.gid << " pid:" << cr.pid << ": " << error;
@@ -741,33 +781,6 @@ static void load_override_properties() {
    }
}

/* When booting an encrypted system, /data is not mounted when the
 * property service is started, so any properties stored there are
 * not loaded.  Vold triggers init to load these properties once it
 * has mounted /data.
 */
void load_persist_props(void) {
    // Devices with FDE have load_persist_props called twice; the first time when the temporary
    // /data partition is mounted and then again once /data is truly mounted.  We do not want to
    // read persistent properties from the temporary /data partition or mark persistent properties
    // as having been loaded during the first call, so we return in that case.
    std::string crypto_state = android::base::GetProperty("ro.crypto.state", "");
    std::string crypto_type = android::base::GetProperty("ro.crypto.type", "");
    if (crypto_state == "encrypted" && crypto_type == "block") {
        static size_t num_calls = 0;
        if (++num_calls == 1) return;
    }

    load_override_properties();
    /* Read persistent properties after all default values have been loaded. */
    auto persistent_properties = LoadPersistentProperties();
    for (const auto& persistent_property_record : persistent_properties.properties()) {
        property_set(persistent_property_record.name(), persistent_property_record.value());
    }
    persistent_properties_loaded = true;
    property_set("ro.persistent_properties.ready", "true");
}

// If the ro.product.[brand|device|manufacturer|model|name] properties have not been explicitly
// set, derive them from ro.product.${partition}.* properties
static void property_initialize_ro_product_props() {
@@ -985,21 +998,92 @@ void CreateSerializedPropertyInfo() {
    selinux_android_restorecon(kPropertyInfosPath, 0);
}

void StartPropertyService(Epoll* epoll) {
static void HandleInitSocket() {
    auto message = ReadMessage(init_socket);
    if (!message) {
        LOG(ERROR) << "Could not read message from init_dedicated_recv_socket: " << message.error();
        return;
    }

    auto init_message = InitMessage{};
    if (!init_message.ParseFromString(*message)) {
        LOG(ERROR) << "Could not parse message from init";
        return;
    }

    switch (init_message.msg_case()) {
        case InitMessage::kLoadPersistentProperties: {
            load_override_properties();
            // Read persistent properties after all default values have been loaded.
            auto persistent_properties = LoadPersistentProperties();
            for (const auto& persistent_property_record : persistent_properties.properties()) {
                InitPropertySet(persistent_property_record.name(),
                                persistent_property_record.value());
            }
            InitPropertySet("ro.persistent_properties.ready", "true");
            persistent_properties_loaded = true;
            break;
        }
        case InitMessage::kStopSendingMessages: {
            init_socket = -1;
            break;
        }
        default:
            LOG(ERROR) << "Unknown message type from init: " << init_message.msg_case();
    }
}

static void PropertyServiceThread() {
    Epoll epoll;
    if (auto result = epoll.Open(); !result) {
        LOG(FATAL) << result.error();
    }

    if (auto result = epoll.RegisterHandler(property_set_fd, handle_property_set_fd); !result) {
        LOG(FATAL) << result.error();
    }

    if (auto result = epoll.RegisterHandler(init_socket, HandleInitSocket); !result) {
        LOG(FATAL) << result.error();
    }

    while (true) {
        auto pending_functions = epoll.Wait(std::nullopt);
        if (!pending_functions) {
            LOG(ERROR) << pending_functions.error();
        } else {
            for (const auto& function : *pending_functions) {
                (*function)();
            }
        }
    }
}

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

    int sockets[2];
    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 | SOCK_NONBLOCK,
                                   false, 0666, 0, 0, {})) {
        property_set_fd = *result;
    } 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);

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

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

}  // namespace init
Loading