snapuserd: Allow connecting to the first-stage daemon.
Currently there is no socket for daemon instances launched during the selinux phase of init. We don't create any sockets due to the complexity of the required sepolicy. This workaround will allow us to create the socket with very minimal sepolicy changes. init will launch a one-off instance of snapuserd in "proxy" mode, and then the following steps will occur: 1. The proxy daemon will be given two sockets, the "normal" socket that snapuserd clients would connect to, and a "proxy" socket. 2. The proxy daemon will listen on the proxy socket. 3. The first-stage daemon will wake up and connect to the proxy daemon as a client. 4. The proxy will send the normal socket via SCM_RIGHTS, then exit. 5. The first-stage daemon can now listen and accept on the normal socket. Ordering of these events is achieved through a snapuserd.proxy_ready property. Some special-casing was needed in init to make this work. The snapuserd socket owned by snapuserd_proxy is placed into a "persist" mode so it doesn't get deleted when snapuserd_proxy exits. There's also a special case method to create a Service object around a previously existing pid. Finally, first-stage init is technically on a different updateable partition than snapuserd. Thus, we add a way to query snapuserd to see if it supports socket handoff. If it does, we communicate this information through an environment variable to second-stage init. Bug: 193833730 Test: manual test Change-Id: I1950b31028980f0138bc03578cd455eb60ea4a58
This commit is contained in:
parent
0b23b2a346
commit
0e5ad5a093
16 changed files with 300 additions and 40 deletions
|
@ -206,6 +206,9 @@ bool OneShotInotify::ConsumeEvents() {
|
|||
}
|
||||
|
||||
int64_t OneShotInotify::RemainingMs() const {
|
||||
if (relative_timeout_ == std::chrono::milliseconds::max()) {
|
||||
return std::chrono::milliseconds::max().count();
|
||||
}
|
||||
auto remaining = (std::chrono::steady_clock::now() - start_time_);
|
||||
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(remaining);
|
||||
return (relative_timeout_ - elapsed).count();
|
||||
|
|
|
@ -23,6 +23,9 @@ namespace fs_mgr {
|
|||
// Wait at most |relative_timeout| milliseconds for |path| to exist. dirname(path)
|
||||
// must already exist. For example, to wait on /dev/block/dm-6, /dev/block must
|
||||
// be a valid directory.
|
||||
//
|
||||
// If relative_timeout is std::chrono::milliseconds::max(), then the wait will
|
||||
// block indefinitely.
|
||||
bool WaitForFile(const std::string& path, const std::chrono::milliseconds relative_timeout);
|
||||
|
||||
// Wait at most |relative_timeout| milliseconds for |path| to stop existing.
|
||||
|
|
|
@ -73,6 +73,7 @@ cc_defaults {
|
|||
"libbrotli",
|
||||
"libcutils_sockets",
|
||||
"libdm",
|
||||
"libfs_mgr",
|
||||
"libgflags",
|
||||
"liblog",
|
||||
"libsnapshot_cow",
|
||||
|
|
|
@ -31,6 +31,7 @@ namespace snapshot {
|
|||
static constexpr uint32_t PACKET_SIZE = 512;
|
||||
|
||||
static constexpr char kSnapuserdSocket[] = "snapuserd";
|
||||
static constexpr char kSnapuserdSocketProxy[] = "snapuserd_proxy";
|
||||
|
||||
// Ensure that the second-stage daemon for snapuserd is running.
|
||||
bool EnsureSnapuserdStarted();
|
||||
|
@ -75,6 +76,9 @@ class SnapuserdClient {
|
|||
// snapuserd to gracefully exit once all handler threads have terminated.
|
||||
// This should only be used on first-stage instances of snapuserd.
|
||||
bool DetachSnapuserd();
|
||||
|
||||
// Returns true if the snapuserd instance supports bridging a socket to second-stage init.
|
||||
bool SupportsSecondStageSocketHandoff();
|
||||
};
|
||||
|
||||
} // namespace snapshot
|
||||
|
|
|
@ -5,3 +5,12 @@ service snapuserd /system/bin/snapuserd
|
|||
user root
|
||||
group root system
|
||||
seclabel u:r:snapuserd:s0
|
||||
|
||||
service snapuserd_proxy /system/bin/snapuserd -socket-handoff
|
||||
socket snapuserd stream 0660 system system
|
||||
socket snapuserd_proxy seqpacket 0660 system root
|
||||
oneshot
|
||||
disabled
|
||||
user root
|
||||
group root system
|
||||
seclabel u:r:snapuserd:s0
|
||||
|
|
|
@ -141,6 +141,16 @@ bool SnapuserdClient::WaitForDeviceDelete(const std::string& control_device) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool SnapuserdClient::SupportsSecondStageSocketHandoff() {
|
||||
std::string msg = "supports,second_stage_socket_handoff";
|
||||
if (!Sendmsg(msg)) {
|
||||
LOG(ERROR) << "Failed to send message " << msg << " to snapuserd";
|
||||
return false;
|
||||
}
|
||||
std::string response = Receivemsg();
|
||||
return response == "success";
|
||||
}
|
||||
|
||||
std::string SnapuserdClient::Receivemsg() {
|
||||
char msg[PACKET_SIZE];
|
||||
ssize_t ret = TEMP_FAILURE_RETRY(recv(sockfd_, msg, sizeof(msg), 0));
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
DEFINE_string(socket, android::snapshot::kSnapuserdSocket, "Named socket or socket path.");
|
||||
DEFINE_bool(no_socket, false,
|
||||
"If true, no socket is used. Each additional argument is an INIT message.");
|
||||
DEFINE_bool(socket_handoff, false,
|
||||
"If true, perform a socket hand-off with an existing snapuserd instance, then exit.");
|
||||
|
||||
namespace android {
|
||||
namespace snapshot {
|
||||
|
@ -33,8 +35,28 @@ namespace snapshot {
|
|||
bool Daemon::StartServer(int argc, char** argv) {
|
||||
int arg_start = gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||
|
||||
sigfillset(&signal_mask_);
|
||||
sigdelset(&signal_mask_, SIGINT);
|
||||
sigdelset(&signal_mask_, SIGTERM);
|
||||
sigdelset(&signal_mask_, SIGUSR1);
|
||||
|
||||
// Masking signals here ensure that after this point, we won't handle INT/TERM
|
||||
// until after we call into ppoll()
|
||||
signal(SIGINT, Daemon::SignalHandler);
|
||||
signal(SIGTERM, Daemon::SignalHandler);
|
||||
signal(SIGPIPE, Daemon::SignalHandler);
|
||||
signal(SIGUSR1, Daemon::SignalHandler);
|
||||
|
||||
MaskAllSignalsExceptIntAndTerm();
|
||||
|
||||
if (FLAGS_socket_handoff) {
|
||||
return server_.RunForSocketHandoff();
|
||||
}
|
||||
if (!FLAGS_no_socket) {
|
||||
return server_.Start(FLAGS_socket);
|
||||
if (!server_.Start(FLAGS_socket)) {
|
||||
return false;
|
||||
}
|
||||
return server_.Run();
|
||||
}
|
||||
|
||||
for (int i = arg_start; i < argc; i++) {
|
||||
|
@ -51,8 +73,7 @@ bool Daemon::StartServer(int argc, char** argv) {
|
|||
|
||||
// Skip the accept() call to avoid spurious log spam. The server will still
|
||||
// run until all handlers have completed.
|
||||
server_.SetTerminating();
|
||||
return true;
|
||||
return server_.WaitForSocket();
|
||||
}
|
||||
|
||||
void Daemon::MaskAllSignalsExceptIntAndTerm() {
|
||||
|
@ -61,6 +82,7 @@ void Daemon::MaskAllSignalsExceptIntAndTerm() {
|
|||
sigdelset(&signal_mask, SIGINT);
|
||||
sigdelset(&signal_mask, SIGTERM);
|
||||
sigdelset(&signal_mask, SIGPIPE);
|
||||
sigdelset(&signal_mask, SIGUSR1);
|
||||
if (sigprocmask(SIG_SETMASK, &signal_mask, NULL) != 0) {
|
||||
PLOG(ERROR) << "Failed to set sigprocmask";
|
||||
}
|
||||
|
@ -74,28 +96,14 @@ void Daemon::MaskAllSignals() {
|
|||
}
|
||||
}
|
||||
|
||||
void Daemon::Run() {
|
||||
sigfillset(&signal_mask_);
|
||||
sigdelset(&signal_mask_, SIGINT);
|
||||
sigdelset(&signal_mask_, SIGTERM);
|
||||
|
||||
// Masking signals here ensure that after this point, we won't handle INT/TERM
|
||||
// until after we call into ppoll()
|
||||
signal(SIGINT, Daemon::SignalHandler);
|
||||
signal(SIGTERM, Daemon::SignalHandler);
|
||||
signal(SIGPIPE, Daemon::SignalHandler);
|
||||
|
||||
LOG(DEBUG) << "Snapuserd-server: ready to accept connections";
|
||||
|
||||
MaskAllSignalsExceptIntAndTerm();
|
||||
|
||||
server_.Run();
|
||||
}
|
||||
|
||||
void Daemon::Interrupt() {
|
||||
server_.Interrupt();
|
||||
}
|
||||
|
||||
void Daemon::ReceivedSocketSignal() {
|
||||
server_.ReceivedSocketSignal();
|
||||
}
|
||||
|
||||
void Daemon::SignalHandler(int signal) {
|
||||
LOG(DEBUG) << "Snapuserd received signal: " << signal;
|
||||
switch (signal) {
|
||||
|
@ -108,6 +116,11 @@ void Daemon::SignalHandler(int signal) {
|
|||
LOG(ERROR) << "Received SIGPIPE signal";
|
||||
break;
|
||||
}
|
||||
case SIGUSR1: {
|
||||
LOG(INFO) << "Received SIGUSR1, attaching to proxy socket";
|
||||
Daemon::Instance().ReceivedSocketSignal();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
LOG(ERROR) << "Received unknown signal " << signal;
|
||||
break;
|
||||
|
@ -126,7 +139,5 @@ int main(int argc, char** argv) {
|
|||
LOG(ERROR) << "Snapuserd daemon failed to start.";
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
daemon.Run();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -36,8 +36,8 @@ class Daemon {
|
|||
}
|
||||
|
||||
bool StartServer(int argc, char** argv);
|
||||
void Run();
|
||||
void Interrupt();
|
||||
void ReceivedSocketSignal();
|
||||
|
||||
private:
|
||||
// Signal mask used with ppoll()
|
||||
|
|
|
@ -25,14 +25,26 @@
|
|||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <android-base/cmsg.h>
|
||||
#include <android-base/logging.h>
|
||||
|
||||
#include <android-base/properties.h>
|
||||
#include <android-base/scopeguard.h>
|
||||
#include <fs_mgr/file_wait.h>
|
||||
#include <snapuserd/snapuserd_client.h>
|
||||
#include "snapuserd.h"
|
||||
#include "snapuserd_server.h"
|
||||
|
||||
#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
|
||||
#include <sys/_system_properties.h>
|
||||
|
||||
namespace android {
|
||||
namespace snapshot {
|
||||
|
||||
using namespace std::string_literals;
|
||||
|
||||
using android::base::borrowed_fd;
|
||||
using android::base::unique_fd;
|
||||
|
||||
DaemonOperations SnapuserdServer::Resolveop(std::string& input) {
|
||||
if (input == "init") return DaemonOperations::INIT;
|
||||
if (input == "start") return DaemonOperations::START;
|
||||
|
@ -40,6 +52,7 @@ DaemonOperations SnapuserdServer::Resolveop(std::string& input) {
|
|||
if (input == "query") return DaemonOperations::QUERY;
|
||||
if (input == "delete") return DaemonOperations::DELETE;
|
||||
if (input == "detach") return DaemonOperations::DETACH;
|
||||
if (input == "supports") return DaemonOperations::SUPPORTS;
|
||||
|
||||
return DaemonOperations::INVALID;
|
||||
}
|
||||
|
@ -193,6 +206,16 @@ bool SnapuserdServer::Receivemsg(android::base::borrowed_fd fd, const std::strin
|
|||
terminating_ = true;
|
||||
return true;
|
||||
}
|
||||
case DaemonOperations::SUPPORTS: {
|
||||
if (out.size() != 2) {
|
||||
LOG(ERROR) << "Malformed supports message, " << out.size() << " parts";
|
||||
return Sendmsg(fd, "fail");
|
||||
}
|
||||
if (out[1] == "second_stage_socket_handoff") {
|
||||
return Sendmsg(fd, "success");
|
||||
}
|
||||
return Sendmsg(fd, "fail");
|
||||
}
|
||||
default: {
|
||||
LOG(ERROR) << "Received unknown message type from client";
|
||||
Sendmsg(fd, "fail");
|
||||
|
@ -245,28 +268,36 @@ void SnapuserdServer::RunThread(std::shared_ptr<DmUserHandler> handler) {
|
|||
}
|
||||
|
||||
bool SnapuserdServer::Start(const std::string& socketname) {
|
||||
bool start_listening = true;
|
||||
|
||||
sockfd_.reset(android_get_control_socket(socketname.c_str()));
|
||||
if (sockfd_ >= 0) {
|
||||
if (listen(sockfd_.get(), 4) < 0) {
|
||||
PLOG(ERROR) << "listen socket failed: " << socketname;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (sockfd_ < 0) {
|
||||
sockfd_.reset(socket_local_server(socketname.c_str(), ANDROID_SOCKET_NAMESPACE_RESERVED,
|
||||
SOCK_STREAM));
|
||||
if (sockfd_ < 0) {
|
||||
PLOG(ERROR) << "Failed to create server socket " << socketname;
|
||||
return false;
|
||||
}
|
||||
start_listening = false;
|
||||
}
|
||||
return StartWithSocket(start_listening);
|
||||
}
|
||||
|
||||
bool SnapuserdServer::StartWithSocket(bool start_listening) {
|
||||
if (start_listening && listen(sockfd_.get(), 4) < 0) {
|
||||
PLOG(ERROR) << "listen socket failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
AddWatchedFd(sockfd_);
|
||||
AddWatchedFd(sockfd_, POLLIN);
|
||||
|
||||
LOG(DEBUG) << "Snapuserd server successfully started with socket name " << socketname;
|
||||
LOG(DEBUG) << "Snapuserd server now accepting connections";
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SnapuserdServer::Run() {
|
||||
LOG(INFO) << "Now listening on snapuserd socket";
|
||||
|
||||
while (!IsTerminating()) {
|
||||
int rv = TEMP_FAILURE_RETRY(poll(watched_fds_.data(), watched_fds_.size(), -1));
|
||||
if (rv < 0) {
|
||||
|
@ -311,10 +342,10 @@ void SnapuserdServer::JoinAllThreads() {
|
|||
}
|
||||
}
|
||||
|
||||
void SnapuserdServer::AddWatchedFd(android::base::borrowed_fd fd) {
|
||||
void SnapuserdServer::AddWatchedFd(android::base::borrowed_fd fd, int events) {
|
||||
struct pollfd p = {};
|
||||
p.fd = fd.get();
|
||||
p.events = POLLIN;
|
||||
p.events = events;
|
||||
watched_fds_.emplace_back(std::move(p));
|
||||
}
|
||||
|
||||
|
@ -325,7 +356,7 @@ void SnapuserdServer::AcceptClient() {
|
|||
return;
|
||||
}
|
||||
|
||||
AddWatchedFd(fd);
|
||||
AddWatchedFd(fd, POLLIN);
|
||||
}
|
||||
|
||||
bool SnapuserdServer::HandleClient(android::base::borrowed_fd fd, int revents) {
|
||||
|
@ -422,5 +453,97 @@ bool SnapuserdServer::RemoveAndJoinHandler(const std::string& misc_name) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool SnapuserdServer::WaitForSocket() {
|
||||
auto scope_guard = android::base::make_scope_guard([this]() -> void { JoinAllThreads(); });
|
||||
|
||||
auto socket_path = ANDROID_SOCKET_DIR "/"s + kSnapuserdSocketProxy;
|
||||
|
||||
if (!android::fs_mgr::WaitForFile(socket_path, std::chrono::milliseconds::max())) {
|
||||
LOG(ERROR)
|
||||
<< "Failed to wait for proxy socket, second-stage snapuserd will fail to connect";
|
||||
return false;
|
||||
}
|
||||
|
||||
// We must re-initialize property service access, since we launched before
|
||||
// second-stage init.
|
||||
__system_properties_init();
|
||||
|
||||
if (!android::base::WaitForProperty("snapuserd.proxy_ready", "true")) {
|
||||
LOG(ERROR)
|
||||
<< "Failed to wait for proxy property, second-stage snapuserd will fail to connect";
|
||||
return false;
|
||||
}
|
||||
|
||||
unique_fd fd(socket_local_client(kSnapuserdSocketProxy, ANDROID_SOCKET_NAMESPACE_RESERVED,
|
||||
SOCK_SEQPACKET));
|
||||
if (fd < 0) {
|
||||
PLOG(ERROR) << "Failed to connect to socket proxy";
|
||||
return false;
|
||||
}
|
||||
|
||||
char code[1];
|
||||
std::vector<unique_fd> fds;
|
||||
ssize_t rv = android::base::ReceiveFileDescriptorVector(fd, code, sizeof(code), 1, &fds);
|
||||
if (rv < 0) {
|
||||
PLOG(ERROR) << "Failed to receive server socket over proxy";
|
||||
return false;
|
||||
}
|
||||
if (fds.empty()) {
|
||||
LOG(ERROR) << "Expected at least one file descriptor from proxy";
|
||||
return false;
|
||||
}
|
||||
|
||||
// We don't care if the ACK is received.
|
||||
code[0] = 'a';
|
||||
if (TEMP_FAILURE_RETRY(send(fd, code, sizeof(code), MSG_NOSIGNAL) < 0)) {
|
||||
PLOG(ERROR) << "Failed to send ACK to proxy";
|
||||
return false;
|
||||
}
|
||||
|
||||
sockfd_ = std::move(fds[0]);
|
||||
if (!StartWithSocket(true)) {
|
||||
return false;
|
||||
}
|
||||
return Run();
|
||||
}
|
||||
|
||||
bool SnapuserdServer::RunForSocketHandoff() {
|
||||
unique_fd proxy_fd(android_get_control_socket(kSnapuserdSocketProxy));
|
||||
if (proxy_fd < 0) {
|
||||
PLOG(FATAL) << "Proxy could not get android control socket " << kSnapuserdSocketProxy;
|
||||
}
|
||||
borrowed_fd server_fd(android_get_control_socket(kSnapuserdSocket));
|
||||
if (server_fd < 0) {
|
||||
PLOG(FATAL) << "Proxy could not get android control socket " << kSnapuserdSocket;
|
||||
}
|
||||
|
||||
if (listen(proxy_fd.get(), 4) < 0) {
|
||||
PLOG(FATAL) << "Proxy listen socket failed";
|
||||
}
|
||||
|
||||
if (!android::base::SetProperty("snapuserd.proxy_ready", "true")) {
|
||||
LOG(FATAL) << "Proxy failed to set ready property";
|
||||
}
|
||||
|
||||
unique_fd client_fd(
|
||||
TEMP_FAILURE_RETRY(accept4(proxy_fd.get(), nullptr, nullptr, SOCK_CLOEXEC)));
|
||||
if (client_fd < 0) {
|
||||
PLOG(FATAL) << "Proxy accept failed";
|
||||
}
|
||||
|
||||
char code[1] = {'a'};
|
||||
std::vector<int> fds = {server_fd.get()};
|
||||
ssize_t rv = android::base::SendFileDescriptorVector(client_fd, code, sizeof(code), fds);
|
||||
if (rv < 0) {
|
||||
PLOG(FATAL) << "Proxy could not send file descriptor to snapuserd";
|
||||
}
|
||||
// Wait for an ACK - results don't matter, we just don't want to risk closing
|
||||
// the proxy socket too early.
|
||||
if (recv(client_fd, code, sizeof(code), 0) < 0) {
|
||||
PLOG(FATAL) << "Proxy could not receive terminating code from snapuserd";
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace snapshot
|
||||
} // namespace android
|
||||
|
|
|
@ -42,6 +42,7 @@ enum class DaemonOperations {
|
|||
STOP,
|
||||
DELETE,
|
||||
DETACH,
|
||||
SUPPORTS,
|
||||
INVALID,
|
||||
};
|
||||
|
||||
|
@ -93,6 +94,7 @@ class SnapuserdServer : public Stoppable {
|
|||
private:
|
||||
android::base::unique_fd sockfd_;
|
||||
bool terminating_;
|
||||
volatile bool received_socket_signal_ = false;
|
||||
std::vector<struct pollfd> watched_fds_;
|
||||
|
||||
std::mutex lock_;
|
||||
|
@ -100,7 +102,7 @@ class SnapuserdServer : public Stoppable {
|
|||
using HandlerList = std::vector<std::shared_ptr<DmUserHandler>>;
|
||||
HandlerList dm_users_;
|
||||
|
||||
void AddWatchedFd(android::base::borrowed_fd fd);
|
||||
void AddWatchedFd(android::base::borrowed_fd fd, int events);
|
||||
void AcceptClient();
|
||||
bool HandleClient(android::base::borrowed_fd fd, int revents);
|
||||
bool Recv(android::base::borrowed_fd fd, std::string* data);
|
||||
|
@ -117,6 +119,7 @@ class SnapuserdServer : public Stoppable {
|
|||
|
||||
void RunThread(std::shared_ptr<DmUserHandler> handler);
|
||||
void JoinAllThreads();
|
||||
bool StartWithSocket(bool start_listening);
|
||||
|
||||
// Find a DmUserHandler within a lock.
|
||||
HandlerList::iterator FindHandler(std::lock_guard<std::mutex>* proof_of_lock,
|
||||
|
@ -129,6 +132,8 @@ class SnapuserdServer : public Stoppable {
|
|||
bool Start(const std::string& socketname);
|
||||
bool Run();
|
||||
void Interrupt();
|
||||
bool RunForSocketHandoff();
|
||||
bool WaitForSocket();
|
||||
|
||||
std::shared_ptr<DmUserHandler> AddHandler(const std::string& misc_name,
|
||||
const std::string& cow_device_path,
|
||||
|
@ -136,6 +141,7 @@ class SnapuserdServer : public Stoppable {
|
|||
bool StartHandler(const std::shared_ptr<DmUserHandler>& handler);
|
||||
|
||||
void SetTerminating() { terminating_ = true; }
|
||||
void ReceivedSocketSignal() { received_socket_signal_ = true; }
|
||||
};
|
||||
|
||||
} // namespace snapshot
|
||||
|
|
|
@ -725,6 +725,40 @@ void SendLoadPersistentPropertiesMessage() {
|
|||
}
|
||||
}
|
||||
|
||||
static Result<void> ConnectEarlyStageSnapuserdAction(const BuiltinArguments& args) {
|
||||
auto pid = GetSnapuserdFirstStagePid();
|
||||
if (!pid) {
|
||||
return {};
|
||||
}
|
||||
|
||||
auto info = GetSnapuserdFirstStageInfo();
|
||||
if (auto iter = std::find(info.begin(), info.end(), "socket"s); iter == info.end()) {
|
||||
// snapuserd does not support socket handoff, so exit early.
|
||||
return {};
|
||||
}
|
||||
|
||||
// Socket handoff is supported.
|
||||
auto svc = ServiceList::GetInstance().FindService("snapuserd");
|
||||
if (!svc) {
|
||||
LOG(FATAL) << "Failed to find snapuserd service entry";
|
||||
}
|
||||
|
||||
svc->SetShutdownCritical();
|
||||
svc->SetStartedInFirstStage(*pid);
|
||||
|
||||
svc = ServiceList::GetInstance().FindService("snapuserd_proxy");
|
||||
if (!svc) {
|
||||
LOG(FATAL) << "Failed find snapuserd_proxy service entry, merge will never initiate";
|
||||
}
|
||||
if (!svc->MarkSocketPersistent("snapuserd")) {
|
||||
LOG(FATAL) << "Could not find snapuserd socket in snapuserd_proxy service entry";
|
||||
}
|
||||
if (auto result = svc->Start(); !result.ok()) {
|
||||
LOG(FATAL) << "Could not start snapuserd_proxy: " << result.error();
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
int SecondStageMain(int argc, char** argv) {
|
||||
if (REBOOT_BOOTLOADER_ON_PANIC) {
|
||||
InstallRebootSignalHandlers();
|
||||
|
@ -852,6 +886,7 @@ int SecondStageMain(int argc, char** argv) {
|
|||
am.QueueBuiltinAction(SetupCgroupsAction, "SetupCgroups");
|
||||
am.QueueBuiltinAction(SetKptrRestrictAction, "SetKptrRestrict");
|
||||
am.QueueBuiltinAction(TestPerfEventSelinuxAction, "TestPerfEventSelinux");
|
||||
am.QueueBuiltinAction(ConnectEarlyStageSnapuserdAction, "ConnectEarlyStageSnapuserd");
|
||||
am.QueueEventTrigger("early-init");
|
||||
|
||||
// Queue an action that waits for coldboot done so we know ueventd has set up all of /dev...
|
||||
|
|
|
@ -269,6 +269,9 @@ void Service::Reap(const siginfo_t& siginfo) {
|
|||
|
||||
// Remove any socket resources we may have created.
|
||||
for (const auto& socket : sockets_) {
|
||||
if (socket.persist) {
|
||||
continue;
|
||||
}
|
||||
auto path = ANDROID_SOCKET_DIR "/" + socket.name;
|
||||
unlink(path.c_str());
|
||||
}
|
||||
|
@ -409,9 +412,7 @@ Result<void> Service::Start() {
|
|||
}
|
||||
|
||||
bool disabled = (flags_ & (SVC_DISABLED | SVC_RESET));
|
||||
// Starting a service removes it from the disabled or reset state and
|
||||
// immediately takes it out of the restarting state if it was in there.
|
||||
flags_ &= (~(SVC_DISABLED|SVC_RESTARTING|SVC_RESET|SVC_RESTART|SVC_DISABLED_START));
|
||||
ResetFlagsForStart();
|
||||
|
||||
// Running processes require no additional work --- if they're in the
|
||||
// process of exiting, we've ensured that they will immediately restart
|
||||
|
@ -622,6 +623,23 @@ Result<void> Service::Start() {
|
|||
return {};
|
||||
}
|
||||
|
||||
void Service::SetStartedInFirstStage(pid_t pid) {
|
||||
LOG(INFO) << "adding first-stage service '" << name_ << "'...";
|
||||
|
||||
time_started_ = boot_clock::now(); // not accurate, but doesn't matter here
|
||||
pid_ = pid;
|
||||
flags_ |= SVC_RUNNING;
|
||||
start_order_ = next_start_order_++;
|
||||
|
||||
NotifyStateChange("running");
|
||||
}
|
||||
|
||||
void Service::ResetFlagsForStart() {
|
||||
// Starting a service removes it from the disabled or reset state and
|
||||
// immediately takes it out of the restarting state if it was in there.
|
||||
flags_ &= ~(SVC_DISABLED | SVC_RESTARTING | SVC_RESET | SVC_RESTART | SVC_DISABLED_START);
|
||||
}
|
||||
|
||||
Result<void> Service::StartIfNotDisabled() {
|
||||
if (!(flags_ & SVC_DISABLED)) {
|
||||
return Start();
|
||||
|
@ -792,5 +810,18 @@ Result<std::unique_ptr<Service>> Service::MakeTemporaryOneshotService(
|
|||
nullptr, str_args, false);
|
||||
}
|
||||
|
||||
// This is used for snapuserd_proxy, which hands off a socket to snapuserd. It's
|
||||
// a special case to support the daemon launched in first-stage init. The persist
|
||||
// feature is not part of the init language and is only used here.
|
||||
bool Service::MarkSocketPersistent(const std::string& socket_name) {
|
||||
for (auto& socket : sockets_) {
|
||||
if (socket.name == socket_name) {
|
||||
socket.persist = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace init
|
||||
} // namespace android
|
||||
|
|
|
@ -99,6 +99,8 @@ class Service {
|
|||
void AddReapCallback(std::function<void(const siginfo_t& siginfo)> callback) {
|
||||
reap_callbacks_.emplace_back(std::move(callback));
|
||||
}
|
||||
void SetStartedInFirstStage(pid_t pid);
|
||||
bool MarkSocketPersistent(const std::string& socket_name);
|
||||
size_t CheckAllCommands() const { return onrestart_.CheckAllCommands(); }
|
||||
|
||||
static bool is_exec_service_running() { return is_exec_service_running_; }
|
||||
|
@ -144,6 +146,7 @@ class Service {
|
|||
void StopOrReset(int how);
|
||||
void KillProcessGroup(int signal, bool report_oneshot = false);
|
||||
void SetProcessAttributesAndCaps();
|
||||
void ResetFlagsForStart();
|
||||
|
||||
static unsigned long next_start_order_;
|
||||
static bool is_exec_service_running_;
|
||||
|
|
|
@ -54,6 +54,7 @@ struct SocketDescriptor {
|
|||
int perm = 0;
|
||||
std::string context;
|
||||
bool passcred = false;
|
||||
bool persist = false;
|
||||
|
||||
// Create() creates the named unix domain socket in /dev/socket and returns a Descriptor object.
|
||||
// It should be called when starting a service, before calling fork(), such that the socket is
|
||||
|
|
|
@ -54,6 +54,7 @@ using android::snapshot::SnapuserdClient;
|
|||
static constexpr char kSnapuserdPath[] = "/system/bin/snapuserd";
|
||||
static constexpr char kSnapuserdFirstStagePidVar[] = "FIRST_STAGE_SNAPUSERD_PID";
|
||||
static constexpr char kSnapuserdFirstStageFdVar[] = "FIRST_STAGE_SNAPUSERD_FD";
|
||||
static constexpr char kSnapuserdFirstStageInfoVar[] = "FIRST_STAGE_SNAPUSERD_INFO";
|
||||
static constexpr char kSnapuserdLabel[] = "u:object_r:snapuserd_exec:s0";
|
||||
static constexpr char kSnapuserdSocketLabel[] = "u:object_r:snapuserd_socket:s0";
|
||||
|
||||
|
@ -87,6 +88,14 @@ void LaunchFirstStageSnapuserd() {
|
|||
_exit(127);
|
||||
}
|
||||
|
||||
auto client = SnapuserdClient::Connect(android::snapshot::kSnapuserdSocket, 10s);
|
||||
if (!client) {
|
||||
LOG(FATAL) << "Could not connect to first-stage snapuserd";
|
||||
}
|
||||
if (client->SupportsSecondStageSocketHandoff()) {
|
||||
setenv(kSnapuserdFirstStageInfoVar, "socket", 1);
|
||||
}
|
||||
|
||||
setenv(kSnapuserdFirstStagePidVar, std::to_string(pid).c_str(), 1);
|
||||
|
||||
LOG(INFO) << "Relaunched snapuserd with pid: " << pid;
|
||||
|
@ -328,5 +337,13 @@ bool IsFirstStageSnapuserdRunning() {
|
|||
return GetSnapuserdFirstStagePid().has_value();
|
||||
}
|
||||
|
||||
std::vector<std::string> GetSnapuserdFirstStageInfo() {
|
||||
const char* pid_str = getenv(kSnapuserdFirstStageInfoVar);
|
||||
if (!pid_str) {
|
||||
return {};
|
||||
}
|
||||
return android::base::Split(pid_str, ",");
|
||||
}
|
||||
|
||||
} // namespace init
|
||||
} // namespace android
|
||||
|
|
|
@ -76,6 +76,9 @@ bool IsFirstStageSnapuserdRunning();
|
|||
// Return the pid of the first-stage instances of snapuserd, if it was started.
|
||||
std::optional<pid_t> GetSnapuserdFirstStagePid();
|
||||
|
||||
// Return snapuserd info strings that were set during first-stage init.
|
||||
std::vector<std::string> GetSnapuserdFirstStageInfo();
|
||||
|
||||
// Save an open fd to /system/bin (in the ramdisk) into an environment. This is
|
||||
// used to later execveat() snapuserd.
|
||||
void SaveRamdiskPathToSnapuserd();
|
||||
|
|
Loading…
Reference in a new issue