blob: 0b885678f1fffee57d9db735a4e9fc745d4f5668 [file] [log] [blame]
/*
* Copyright (C) 2020 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.
*/
#include <android-base/logging.h>
#include <android-base/properties.h>
#include <android-base/strings.h>
#include <gflags/gflags.h>
#include <snapuserd/snapuserd_client.h>
#include "snapuserd_daemon.h"
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.");
DEFINE_bool(user_snapshot, false, "If true, user-space snapshots are used");
DEFINE_bool(io_uring, false, "If true, io_uring feature is enabled");
namespace android {
namespace snapshot {
bool Daemon::IsUserspaceSnapshotsEnabled() {
return android::base::GetBoolProperty("ro.virtual_ab.userspace.snapshots.enabled", false);
}
bool Daemon::IsDmSnapshotTestingEnabled() {
return android::base::GetBoolProperty("snapuserd.test.dm.snapshots", false);
}
bool Daemon::StartDaemon(int argc, char** argv) {
int arg_start = gflags::ParseCommandLineFlags(&argc, &argv, true);
// Daemon launched from first stage init and during selinux transition
// will have the command line "-user_snapshot" flag set if the user-space
// snapshots are enabled.
//
// Daemon launched as a init service during "socket-handoff" and when OTA
// is applied will check for the property. This is ok as the system
// properties are valid at this point. We can't do this during first
// stage init and hence use the command line flags to get the information.
bool user_snapshots = FLAGS_user_snapshot;
if (!user_snapshots) {
user_snapshots = (!IsDmSnapshotTestingEnabled() && IsUserspaceSnapshotsEnabled());
}
if (user_snapshots) {
LOG(INFO) << "Starting daemon for user-space snapshots.....";
return StartServerForUserspaceSnapshots(arg_start, argc, argv);
} else {
LOG(INFO) << "Starting daemon for dm-snapshots.....";
return StartServerForDmSnapshot(arg_start, argc, argv);
}
}
bool Daemon::StartServerForUserspaceSnapshots(int arg_start, int argc, char** argv) {
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();
user_server_.SetServerRunning();
if (FLAGS_io_uring) {
user_server_.SetIouringEnabled();
}
if (FLAGS_socket_handoff) {
return user_server_.RunForSocketHandoff();
}
if (!FLAGS_no_socket) {
if (!user_server_.Start(FLAGS_socket)) {
return false;
}
return user_server_.Run();
}
for (int i = arg_start; i < argc; i++) {
auto parts = android::base::Split(argv[i], ",");
if (parts.size() != 4) {
LOG(ERROR) << "Malformed message, expected three sub-arguments.";
return false;
}
auto handler = user_server_.AddHandler(parts[0], parts[1], parts[2], parts[3]);
if (!handler || !user_server_.StartHandler(handler)) {
return false;
}
}
// Skip the accept() call to avoid spurious log spam. The server will still
// run until all handlers have completed.
return user_server_.WaitForSocket();
}
bool Daemon::StartServerForDmSnapshot(int arg_start, int argc, char** argv) {
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) {
if (!server_.Start(FLAGS_socket)) {
return false;
}
return server_.Run();
}
for (int i = arg_start; i < argc; i++) {
auto parts = android::base::Split(argv[i], ",");
if (parts.size() != 3) {
LOG(ERROR) << "Malformed message, expected three sub-arguments.";
return false;
}
auto handler = server_.AddHandler(parts[0], parts[1], parts[2]);
if (!handler || !server_.StartHandler(handler)) {
return false;
}
}
// Skip the accept() call to avoid spurious log spam. The server will still
// run until all handlers have completed.
return server_.WaitForSocket();
}
void Daemon::MaskAllSignalsExceptIntAndTerm() {
sigset_t signal_mask;
sigfillset(&signal_mask);
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";
}
}
void Daemon::MaskAllSignals() {
sigset_t signal_mask;
sigfillset(&signal_mask);
if (sigprocmask(SIG_SETMASK, &signal_mask, NULL) != 0) {
PLOG(ERROR) << "Couldn't mask all signals";
}
}
void Daemon::Interrupt() {
// TODO: We cannot access system property during first stage init.
// Until we remove the dm-snapshot code, we will have this check
// and verify it through a temp variable.
if (user_server_.IsServerRunning()) {
user_server_.Interrupt();
} else {
server_.Interrupt();
}
}
void Daemon::ReceivedSocketSignal() {
if (user_server_.IsServerRunning()) {
user_server_.ReceivedSocketSignal();
} else {
server_.ReceivedSocketSignal();
}
}
void Daemon::SignalHandler(int signal) {
LOG(DEBUG) << "Snapuserd received signal: " << signal;
switch (signal) {
case SIGINT:
case SIGTERM: {
Daemon::Instance().Interrupt();
break;
}
case SIGPIPE: {
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;
}
}
} // namespace snapshot
} // namespace android
int main(int argc, char** argv) {
android::base::InitLogging(argv, &android::base::KernelLogger);
LOG(INFO) << "snapuserd daemon about to start";
android::snapshot::Daemon& daemon = android::snapshot::Daemon::Instance();
if (!daemon.StartDaemon(argc, argv)) {
LOG(ERROR) << "Snapuserd daemon failed to start";
exit(EXIT_FAILURE);
}
return 0;
}