Merge "Reland^2: "init: run property service in a thread""
This commit is contained in:
commit
4e46a33c70
|
@ -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",
|
||||
|
|
|
@ -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 {};
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -25,17 +25,15 @@
|
|||
namespace android {
|
||||
namespace init {
|
||||
|
||||
static constexpr const char kRestoreconProperty[] = "selinux.restorecon_recursive";
|
||||
|
||||
bool CanReadProperty(const std::string& source_context, const std::string& name);
|
||||
|
||||
extern uint32_t (*property_set)(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);
|
||||
|
||||
void property_init();
|
||||
void property_load_boot_defaults(bool load_debug_prop);
|
||||
void load_persist_props();
|
||||
void StartPropertyService(Epoll* epoll);
|
||||
void StartPropertyService(int* epoll_socket);
|
||||
|
||||
} // namespace init
|
||||
} // namespace android
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
syntax = "proto2";
|
||||
option optimize_for = LITE_RUNTIME;
|
||||
|
||||
message PropertyMessage {
|
||||
message ControlMessage {
|
||||
optional string msg = 1;
|
||||
optional string name = 2;
|
||||
optional int32 pid = 3;
|
||||
optional int32 fd = 4;
|
||||
}
|
||||
|
||||
message ChangedMessage {
|
||||
optional string name = 1;
|
||||
optional string value = 2;
|
||||
}
|
||||
|
||||
oneof msg {
|
||||
ControlMessage control_message = 1;
|
||||
ChangedMessage changed_message = 2;
|
||||
};
|
||||
}
|
||||
|
||||
message InitMessage {
|
||||
oneof msg {
|
||||
bool load_persistent_properties = 1;
|
||||
bool stop_sending_messages = 2;
|
||||
};
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "result.h"
|
||||
|
||||
namespace android {
|
||||
namespace init {
|
||||
|
||||
constexpr size_t kBufferSize = 4096;
|
||||
|
||||
inline Result<std::string> ReadMessage(int socket) {
|
||||
char buffer[kBufferSize] = {};
|
||||
auto result = TEMP_FAILURE_RETRY(recv(socket, buffer, sizeof(buffer), 0));
|
||||
if (result == 0) {
|
||||
return Error();
|
||||
} else if (result < 0) {
|
||||
return ErrnoError();
|
||||
}
|
||||
return std::string(buffer, result);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
Result<void> SendMessage(int socket, const T& message) {
|
||||
std::string message_string;
|
||||
if (!message.SerializeToString(&message_string)) {
|
||||
return Error() << "Unable to serialize message";
|
||||
}
|
||||
|
||||
if (message_string.size() > kBufferSize) {
|
||||
return Error() << "Serialized message too long to send";
|
||||
}
|
||||
|
||||
if (auto result =
|
||||
TEMP_FAILURE_RETRY(send(socket, message_string.c_str(), message_string.size(), 0));
|
||||
result != static_cast<long>(message_string.size())) {
|
||||
return ErrnoError() << "send() failed to send message contents";
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
} // namespace init
|
||||
} // namespace android
|
|
@ -730,6 +730,12 @@ bool HandlePowerctlMessage(const std::string& command) {
|
|||
s->UnSetExec();
|
||||
}
|
||||
|
||||
// We no longer process messages about properties changing coming from property service, so we
|
||||
// need to tell property service to stop sending us these messages, otherwise it'll fill the
|
||||
// buffers and block indefinitely, causing future property sets, including those that init makes
|
||||
// during shutdown in Service::NotifyStateChange() to also block indefinitely.
|
||||
SendStopSendingMessagesMessage();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -18,16 +18,17 @@
|
|||
|
||||
#include <fcntl.h>
|
||||
#include <poll.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <android-base/file.h>
|
||||
#include <android-base/logging.h>
|
||||
#include <android-base/properties.h>
|
||||
#include <android-base/strings.h>
|
||||
#include <selinux/android.h>
|
||||
|
||||
#include "action.h"
|
||||
#include "builtins.h"
|
||||
#include "proto_utils.h"
|
||||
#include "util.h"
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
|
@ -59,45 +60,6 @@ const char* const paths_and_secontexts[2][2] = {
|
|||
|
||||
namespace {
|
||||
|
||||
constexpr size_t kBufferSize = 4096;
|
||||
|
||||
Result<std::string> ReadMessage(int socket) {
|
||||
char buffer[kBufferSize] = {};
|
||||
auto result = TEMP_FAILURE_RETRY(recv(socket, buffer, sizeof(buffer), 0));
|
||||
if (result == 0) {
|
||||
return Error();
|
||||
} else if (result < 0) {
|
||||
return ErrnoError();
|
||||
}
|
||||
return std::string(buffer, result);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
Result<void> SendMessage(int socket, const T& message) {
|
||||
std::string message_string;
|
||||
if (!message.SerializeToString(&message_string)) {
|
||||
return Error() << "Unable to serialize message";
|
||||
}
|
||||
|
||||
if (message_string.size() > kBufferSize) {
|
||||
return Error() << "Serialized message too long to send";
|
||||
}
|
||||
|
||||
if (auto result =
|
||||
TEMP_FAILURE_RETRY(send(socket, message_string.c_str(), message_string.size(), 0));
|
||||
result != static_cast<long>(message_string.size())) {
|
||||
return ErrnoError() << "send() failed to send message contents";
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<std::pair<std::string, std::string>> properties_to_set;
|
||||
|
||||
uint32_t SubcontextPropertySet(const std::string& name, const std::string& value) {
|
||||
properties_to_set.emplace_back(name, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
class SubcontextProcess {
|
||||
public:
|
||||
SubcontextProcess(const BuiltinFunctionMap* function_map, std::string context, int init_fd)
|
||||
|
@ -131,14 +93,6 @@ void SubcontextProcess::RunCommand(const SubcontextCommand::ExecuteCommand& exec
|
|||
result = RunBuiltinFunction(map_result->function, args, context_);
|
||||
}
|
||||
|
||||
for (const auto& [name, value] : properties_to_set) {
|
||||
auto property = reply->add_properties_to_set();
|
||||
property->set_name(name);
|
||||
property->set_value(value);
|
||||
}
|
||||
|
||||
properties_to_set.clear();
|
||||
|
||||
if (result) {
|
||||
reply->set_success(true);
|
||||
} else {
|
||||
|
@ -224,7 +178,10 @@ int SubcontextMain(int argc, char** argv, const BuiltinFunctionMap* function_map
|
|||
|
||||
SelabelInitialize();
|
||||
|
||||
property_set = SubcontextPropertySet;
|
||||
property_set = [](const std::string& key, const std::string& value) -> uint32_t {
|
||||
android::base::SetProperty(key, value);
|
||||
return 0;
|
||||
};
|
||||
|
||||
auto subcontext_process = SubcontextProcess(function_map, context, init_fd);
|
||||
subcontext_process.MainLoop();
|
||||
|
@ -311,15 +268,6 @@ Result<void> Subcontext::Execute(const std::vector<std::string>& args) {
|
|||
return subcontext_reply.error();
|
||||
}
|
||||
|
||||
for (const auto& property : subcontext_reply->properties_to_set()) {
|
||||
ucred cr = {.pid = pid_, .uid = 0, .gid = 0};
|
||||
std::string error;
|
||||
if (HandlePropertySet(property.name(), property.value(), context_, cr, &error) != 0) {
|
||||
LOG(ERROR) << "Subcontext init could not set '" << property.name() << "' to '"
|
||||
<< property.value() << "': " << error;
|
||||
}
|
||||
}
|
||||
|
||||
if (subcontext_reply->reply_case() == SubcontextReply::kFailure) {
|
||||
auto& failure = subcontext_reply->failure();
|
||||
return ResultError(failure.error_string(), failure.error_errno());
|
||||
|
|
|
@ -38,10 +38,4 @@ message SubcontextReply {
|
|||
Failure failure = 2;
|
||||
ExpandArgsReply expand_args_reply = 3;
|
||||
}
|
||||
|
||||
message PropertyToSet {
|
||||
optional string name = 1;
|
||||
optional string value = 2;
|
||||
}
|
||||
repeated PropertyToSet properties_to_set = 4;
|
||||
}
|
Loading…
Reference in New Issue