Merge "libdm: Fix WaitForFile early-returning on failed accesses." into rvc-dev
diff --git a/CleanSpec.mk b/CleanSpec.mk
index c84bd24..0a534a2 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -90,3 +90,4 @@
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/debug_ramdisk/product_services)
$(call add-clean-step, find $(PRODUCT_OUT) -type l -name "charger" -print0 | xargs -0 rm -f)
$(call add-clean-step, rm -f $(PRODUCT_OUT)/system/bin/adbd)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/etc/init/snapshotctl.rc)
diff --git a/adb/Android.bp b/adb/Android.bp
index fea8c78..a26017f 100644
--- a/adb/Android.bp
+++ b/adb/Android.bp
@@ -375,6 +375,7 @@
srcs: libadb_srcs + libadb_linux_srcs + libadb_posix_srcs + [
"daemon/auth.cpp",
"daemon/jdwp_service.cpp",
+ "daemon/logging.cpp",
"daemon/adb_wifi.cpp",
],
@@ -418,6 +419,12 @@
srcs: [
"daemon/usb_dummy.cpp",
]
+ },
+ recovery: {
+ exclude_shared_libs: [
+ "libadb_pairing_auth",
+ "libadb_pairing_connection",
+ ],
}
},
}
@@ -477,6 +484,10 @@
exclude_srcs: [
"daemon/abb_service.cpp",
],
+ exclude_shared_libs: [
+ "libadb_pairing_auth",
+ "libadb_pairing_connection",
+ ],
},
},
}
@@ -512,6 +523,15 @@
"libselinux",
],
+ target: {
+ recovery: {
+ exclude_shared_libs: [
+ "libadb_pairing_auth",
+ "libadb_pairing_connection",
+ ],
+ }
+ },
+
static_libs: [
"libadbd_services",
"libcutils_sockets",
@@ -544,6 +564,8 @@
},
static_libs: [
+ "libadb_crypto",
+ "libadb_tls_connection",
"libadbconnection_server",
"libadbd",
"libadbd_services",
@@ -561,15 +583,22 @@
],
shared_libs: [
- "libadb_crypto",
"libadb_pairing_connection",
"libadb_protos",
- "libadb_tls_connection",
"libadbd_auth",
"libadbd_fs",
"libcrypto",
],
+ target: {
+ recovery: {
+ exclude_shared_libs: [
+ "libadb_pairing_auth",
+ "libadb_pairing_connection",
+ ],
+ }
+ },
+
required: [
"libadbd_auth",
"libadbd_fs",
diff --git a/adb/adb.cpp b/adb/adb.cpp
index 554a754..98db191 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -34,6 +34,7 @@
#include <condition_variable>
#include <mutex>
#include <string>
+#include <string_view>
#include <thread>
#include <vector>
@@ -61,6 +62,8 @@
#include <sys/mount.h>
#include <android-base/properties.h>
using namespace std::chrono_literals;
+
+#include "daemon/logging.h"
#endif
std::string adb_version() {
@@ -312,6 +315,9 @@
#if ADB_HOST
handle_online(t);
#else
+ ADB_LOG(Connection) << "received CNXN: version=" << p->msg.arg0 << ", maxdata = " << p->msg.arg1
+ << ", banner = '" << banner << "'";
+
if (t->use_tls) {
// We still handshake in TLS mode. If auth_required is disabled,
// we'll just not verify the client's certificate. This should be the
diff --git a/adb/crypto/Android.bp b/adb/crypto/Android.bp
index b7f75ed..ce1de4a 100644
--- a/adb/crypto/Android.bp
+++ b/adb/crypto/Android.bp
@@ -45,8 +45,6 @@
host_supported: true,
recovery_available: true,
- stl: "libc++_static",
-
shared_libs: [
"libadb_protos",
"libbase",
diff --git a/adb/daemon/logging.cpp b/adb/daemon/logging.cpp
new file mode 100644
index 0000000..203c6c7
--- /dev/null
+++ b/adb/daemon/logging.cpp
@@ -0,0 +1,89 @@
+/*
+ * 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 "daemon/logging.h"
+
+#include <mutex>
+#include <optional>
+#include <string_view>
+
+#include <android-base/no_destructor.h>
+#include <android-base/properties.h>
+#include <android-base/strings.h>
+#include <android-base/thread_annotations.h>
+
+#if defined(__ANDROID__)
+struct LogStatus {
+ bool enabled[static_cast<size_t>(adb::LogType::COUNT)];
+
+ bool& operator[](adb::LogType type) { return enabled[static_cast<size_t>(type)]; }
+};
+
+using android::base::CachedProperty;
+using android::base::NoDestructor;
+
+static NoDestructor<std::mutex> log_mutex;
+static NoDestructor<CachedProperty> log_property GUARDED_BY(log_mutex)("debug.adbd.logging");
+static std::optional<LogStatus> cached_log_status GUARDED_BY(log_mutex);
+
+static NoDestructor<CachedProperty> persist_log_property
+ GUARDED_BY(log_mutex)("persist.debug.adbd.logging");
+static std::optional<LogStatus> cached_persist_log_status GUARDED_BY(log_mutex);
+
+static LogStatus ParseLogStatus(std::string_view str) {
+ LogStatus result = {};
+ for (const auto& part : android::base::Split(std::string(str), ",")) {
+ if (part == "cnxn") {
+ result[adb::LogType::Connection] = true;
+ } else if (part == "service") {
+ result[adb::LogType::Service] = true;
+ } else if (part == "shell") {
+ result[adb::LogType::Shell] = true;
+ } else if (part == "all") {
+ result[adb::LogType::Connection] = true;
+ result[adb::LogType::Service] = true;
+ result[adb::LogType::Shell] = true;
+ }
+ }
+ return result;
+}
+
+static LogStatus GetLogStatus(android::base::CachedProperty* property,
+ std::optional<LogStatus>* cached_status) REQUIRES(log_mutex) {
+ bool changed;
+ const char* value = property->Get(&changed);
+ if (changed || !*cached_status) {
+ **cached_status = ParseLogStatus(value);
+ }
+ return **cached_status;
+}
+
+namespace adb {
+bool is_logging_enabled(LogType type) {
+ std::lock_guard<std::mutex> lock(*log_mutex);
+ return GetLogStatus(log_property.get(), &cached_log_status)[type] ||
+ GetLogStatus(persist_log_property.get(), &cached_persist_log_status)[type];
+}
+} // namespace adb
+
+#else
+
+namespace adb {
+bool is_logging_enabled(LogType type) {
+ return false;
+}
+} // namespace adb
+#endif
diff --git a/adb/daemon/logging.h b/adb/daemon/logging.h
new file mode 100644
index 0000000..3e28bef
--- /dev/null
+++ b/adb/daemon/logging.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2007 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 <android-base/logging.h>
+
+namespace adb {
+enum class LogType {
+ Connection,
+ Service,
+ Shell,
+ COUNT,
+};
+
+bool is_logging_enabled(LogType type);
+
+#define ADB_LOG(type) ::adb::is_logging_enabled(::adb::LogType::type) && LOG(INFO)
+
+} // namespace adb
diff --git a/adb/daemon/services.cpp b/adb/daemon/services.cpp
index 4ec90d2..6bbf66e 100644
--- a/adb/daemon/services.cpp
+++ b/adb/daemon/services.cpp
@@ -54,10 +54,10 @@
#include "daemon/file_sync_service.h"
#include "daemon/framebuffer_service.h"
+#include "daemon/logging.h"
#include "daemon/restart_service.h"
#include "daemon/shell_service.h"
-
void reconnect_service(unique_fd fd, atransport* t) {
WriteFdExactly(fd.get(), "done");
kick_transport(t);
@@ -259,6 +259,8 @@
}
unique_fd daemon_service_to_fd(std::string_view name, atransport* transport) {
+ ADB_LOG(Service) << "transport " << transport->serial_name() << " opening service " << name;
+
#if defined(__ANDROID__) && !defined(__ANDROID_RECOVERY__)
if (name.starts_with("abb:") || name.starts_with("abb_exec:")) {
return execute_abb_command(name);
diff --git a/adb/daemon/shell_service.cpp b/adb/daemon/shell_service.cpp
index f62032d..fbfae1e 100644
--- a/adb/daemon/shell_service.cpp
+++ b/adb/daemon/shell_service.cpp
@@ -107,6 +107,7 @@
#include "adb_trace.h"
#include "adb_unique_fd.h"
#include "adb_utils.h"
+#include "daemon/logging.h"
#include "security_log_tags.h"
#include "shell_protocol.h"
@@ -760,14 +761,14 @@
D("post waitpid (pid=%d) status=%04x", pid_, status);
if (WIFSIGNALED(status)) {
exit_code = 0x80 | WTERMSIG(status);
- D("subprocess killed by signal %d", WTERMSIG(status));
+ ADB_LOG(Shell) << "subprocess " << pid_ << " killed by signal " << WTERMSIG(status);
break;
} else if (!WIFEXITED(status)) {
D("subprocess didn't exit");
break;
} else if (WEXITSTATUS(status) >= 0) {
exit_code = WEXITSTATUS(status);
- D("subprocess exit code = %d", WEXITSTATUS(status));
+ ADB_LOG(Shell) << "subprocess " << pid_ << " exited with status " << exit_code;
break;
}
}
diff --git a/adb/daemon/usb.cpp b/adb/daemon/usb.cpp
index 0928198..87937fb 100644
--- a/adb/daemon/usb.cpp
+++ b/adb/daemon/usb.cpp
@@ -282,6 +282,7 @@
monitor_thread_ = std::thread([this]() {
adb_thread_setname("UsbFfs-monitor");
+ LOG(INFO) << "UsbFfs-monitor thread spawned";
bool bound = false;
bool enabled = false;
@@ -427,6 +428,8 @@
worker_started_ = true;
worker_thread_ = std::thread([this]() {
adb_thread_setname("UsbFfs-worker");
+ LOG(INFO) << "UsbFfs-worker thread spawned";
+
for (size_t i = 0; i < kUsbReadQueueDepth; ++i) {
read_requests_[i] = CreateReadBlock(next_read_id_++);
if (!SubmitRead(&read_requests_[i])) {
@@ -525,14 +528,16 @@
}
if (id.direction == TransferDirection::READ) {
- HandleRead(id, event.res);
+ if (!HandleRead(id, event.res)) {
+ return;
+ }
} else {
HandleWrite(id);
}
}
}
- void HandleRead(TransferId id, int64_t size) {
+ bool HandleRead(TransferId id, int64_t size) {
uint64_t read_idx = id.id % kUsbReadQueueDepth;
IoReadBlock* block = &read_requests_[read_idx];
block->pending = false;
@@ -542,7 +547,7 @@
if (block->id().id != needed_read_id_) {
LOG(VERBOSE) << "read " << block->id().id << " completed while waiting for "
<< needed_read_id_;
- return;
+ return true;
}
for (uint64_t id = needed_read_id_;; ++id) {
@@ -551,15 +556,22 @@
if (current_block->pending) {
break;
}
- ProcessRead(current_block);
+ if (!ProcessRead(current_block)) {
+ return false;
+ }
++needed_read_id_;
}
+
+ return true;
}
- void ProcessRead(IoReadBlock* block) {
+ bool ProcessRead(IoReadBlock* block) {
if (!block->payload.empty()) {
if (!incoming_header_.has_value()) {
- CHECK_EQ(sizeof(amessage), block->payload.size());
+ if (block->payload.size() != sizeof(amessage)) {
+ HandleError("received packet of unexpected length while reading header");
+ return false;
+ }
amessage& msg = incoming_header_.emplace();
memcpy(&msg, block->payload.data(), sizeof(msg));
LOG(DEBUG) << "USB read:" << dump_header(&msg);
@@ -567,7 +579,10 @@
} else {
size_t bytes_left = incoming_header_->data_length - incoming_payload_.size();
Block payload = std::move(block->payload);
- CHECK_LE(payload.size(), bytes_left);
+ if (block->payload.size() > bytes_left) {
+ HandleError("received too many bytes while waiting for payload");
+ return false;
+ }
incoming_payload_.append(std::move(payload));
}
@@ -590,6 +605,7 @@
PrepareReadBlock(block, block->id().id + kUsbReadQueueDepth);
SubmitRead(block);
+ return true;
}
bool SubmitRead(IoReadBlock* block) {
diff --git a/adb/daemon/usb_ffs.cpp b/adb/daemon/usb_ffs.cpp
index b19fa5d..cb7e2fb 100644
--- a/adb/daemon/usb_ffs.cpp
+++ b/adb/daemon/usb_ffs.cpp
@@ -299,6 +299,7 @@
}
// Signal only when writing the descriptors to ffs
android::base::SetProperty("sys.usb.ffs.ready", "1");
+ *out_control = std::move(control);
}
bulk_out.reset(adb_open(USB_FFS_ADB_OUT, O_RDONLY));
@@ -313,7 +314,6 @@
return false;
}
- *out_control = std::move(control);
*out_bulk_in = std::move(bulk_in);
*out_bulk_out = std::move(bulk_out);
return true;
diff --git a/adb/pairing_auth/Android.bp b/adb/pairing_auth/Android.bp
index 0850047..a43f4d0 100644
--- a/adb/pairing_auth/Android.bp
+++ b/adb/pairing_auth/Android.bp
@@ -47,7 +47,7 @@
use_version_lib: false,
host_supported: true,
- recovery_available: true,
+ recovery_available: false,
stl: "libc++_static",
diff --git a/adb/pairing_connection/Android.bp b/adb/pairing_connection/Android.bp
index c053854..bcde7b1 100644
--- a/adb/pairing_connection/Android.bp
+++ b/adb/pairing_connection/Android.bp
@@ -52,7 +52,7 @@
stl: "libc++_static",
host_supported: true,
- recovery_available: true,
+ recovery_available: false,
static_libs: [
"libbase",
@@ -131,7 +131,7 @@
],
host_supported: true,
- recovery_available: true,
+ recovery_available: false,
stl: "libc++_static",
diff --git a/adb/test_adb.py b/adb/test_adb.py
index 3d6de26..c872fb0 100755
--- a/adb/test_adb.py
+++ b/adb/test_adb.py
@@ -33,6 +33,11 @@
import unittest
import warnings
+def find_open_port():
+ # Find an open port.
+ with socket.socket() as s:
+ s.bind(("localhost", 0))
+ return s.getsockname()[1]
@contextlib.contextmanager
def fake_adbd(protocol=socket.AF_INET, port=0):
@@ -126,10 +131,7 @@
This creates an ADB server and returns the port it's listening on.
"""
- port = 5038
- # Kill any existing server on this non-default port.
- subprocess.check_output(["adb", "-P", str(port), "kill-server"],
- stderr=subprocess.STDOUT)
+ port = find_open_port()
read_pipe, write_pipe = os.pipe()
if sys.platform == "win32":
@@ -224,10 +226,7 @@
# adb server, this also tests whether multiple instances of the adb
# server conflict on adb.log.
- port = 5038
- # Kill any existing server on this non-default port.
- subprocess.check_output(["adb", "-P", str(port), "kill-server"],
- stderr=subprocess.STDOUT)
+ port = find_open_port()
try:
# We get warnings for unclosed files for the subprocess's pipes,
@@ -289,12 +288,8 @@
"""
Tests that the server can start up on ::1 and that it's accessible
"""
- server_port = 5037
- # Kill any existing server on this non-default port.
- subprocess.check_output(
- ["adb", "-P", str(server_port), "kill-server"],
- stderr=subprocess.STDOUT,
- )
+
+ server_port = find_open_port()
try:
subprocess.check_output(
["adb", "-L", "tcp:[::1]:{}".format(server_port), "server"],
diff --git a/adb/tls/Android.bp b/adb/tls/Android.bp
index 49833ff..f2837e1 100644
--- a/adb/tls/Android.bp
+++ b/adb/tls/Android.bp
@@ -42,12 +42,8 @@
"//system/core/adb:__subpackages__",
],
- stl: "libc++_static",
-
- static_libs: [
- "libbase",
- ],
shared_libs: [
+ "libbase",
"libcrypto",
"liblog",
"libssl",
diff --git a/base/include/android-base/properties.h b/base/include/android-base/properties.h
index 31823df..49f1f31 100644
--- a/base/include/android-base/properties.h
+++ b/base/include/android-base/properties.h
@@ -20,8 +20,11 @@
#include <chrono>
#include <limits>
+#include <optional>
#include <string>
+struct prop_info;
+
namespace android {
namespace base {
@@ -67,5 +70,32 @@
std::chrono::milliseconds::max());
#endif
+#if defined(__BIONIC__) && __cplusplus >= 201703L
+// Cached system property lookup. For code that needs to read the same property multiple times,
+// this class helps optimize those lookups.
+class CachedProperty {
+ public:
+ explicit CachedProperty(const char* property_name);
+
+ // Returns the current value of the underlying system property as cheaply as possible.
+ // The returned pointer is valid until the next call to Get. Because most callers are going
+ // to want to parse the string returned here and cached that as well, this function performs
+ // no locking, and is completely thread unsafe. It is the caller's responsibility to provide a
+ // lock for thread-safety.
+ //
+ // Note: *changed can be set to true even if the contents of the property remain the same.
+ const char* Get(bool* changed = nullptr);
+
+ private:
+ std::string property_name_;
+ const prop_info* prop_info_;
+ std::optional<uint32_t> cached_area_serial_;
+ std::optional<uint32_t> cached_property_serial_;
+ char cached_value_[92];
+ bool is_read_only_;
+ const char* read_only_property_;
+};
+#endif
+
} // namespace base
} // namespace android
diff --git a/base/logging.cpp b/base/logging.cpp
index f42b996..9360a56 100644
--- a/base/logging.cpp
+++ b/base/logging.cpp
@@ -447,7 +447,7 @@
// See the comment in SetLogger().
static std::atomic<AbortFunction*> abort_function(nullptr);
auto* old_abort_function = abort_function.exchange(new AbortFunction(aborter));
- __android_log_set_aborter([](const char* abort_message) {
+ liblog_functions->__android_log_set_aborter([](const char* abort_message) {
auto& function = *abort_function.load(std::memory_order_acquire);
function(abort_message);
});
@@ -578,7 +578,7 @@
if (liblog_functions) {
__android_logger_data logger_data = {
sizeof(__android_logger_data), LOG_ID_DEFAULT, priority, tag, file, line};
- __android_log_write_logger_data(&logger_data, message);
+ liblog_functions->__android_log_write_logger_data(&logger_data, message);
} else {
if (tag == nullptr) {
std::lock_guard<std::recursive_mutex> lock(TagLock());
diff --git a/base/properties.cpp b/base/properties.cpp
index 4731bf2..35e41a8 100644
--- a/base/properties.cpp
+++ b/base/properties.cpp
@@ -30,6 +30,7 @@
#include <android-base/parsebool.h>
#include <android-base/parseint.h>
+#include <android-base/strings.h>
namespace android {
namespace base {
@@ -195,6 +196,62 @@
return (WaitForPropertyCreation(key, relative_timeout, start_time) != nullptr);
}
+CachedProperty::CachedProperty(const char* property_name)
+ : property_name_(property_name),
+ prop_info_(nullptr),
+ cached_area_serial_(0),
+ cached_property_serial_(0),
+ is_read_only_(android::base::StartsWith(property_name, "ro.")),
+ read_only_property_(nullptr) {
+ static_assert(sizeof(cached_value_) == PROP_VALUE_MAX);
+}
+
+const char* CachedProperty::Get(bool* changed) {
+ std::optional<uint32_t> initial_property_serial_ = cached_property_serial_;
+
+ // Do we have a `struct prop_info` yet?
+ if (prop_info_ == nullptr) {
+ // `__system_property_find` is expensive, so only retry if a property
+ // has been created since last time we checked.
+ uint32_t property_area_serial = __system_property_area_serial();
+ if (property_area_serial != cached_area_serial_) {
+ prop_info_ = __system_property_find(property_name_.c_str());
+ cached_area_serial_ = property_area_serial;
+ }
+ }
+
+ if (prop_info_ != nullptr) {
+ // Only bother re-reading the property if it's actually changed since last time.
+ uint32_t property_serial = __system_property_serial(prop_info_);
+ if (property_serial != cached_property_serial_) {
+ __system_property_read_callback(
+ prop_info_,
+ [](void* data, const char*, const char* value, uint32_t serial) {
+ CachedProperty* instance = reinterpret_cast<CachedProperty*>(data);
+ instance->cached_property_serial_ = serial;
+ // Read only properties can be larger than PROP_VALUE_MAX, but also never change value
+ // or location, thus we return the pointer from the shared memory directly.
+ if (instance->is_read_only_) {
+ instance->read_only_property_ = value;
+ } else {
+ strlcpy(instance->cached_value_, value, PROP_VALUE_MAX);
+ }
+ },
+ this);
+ }
+ }
+
+ if (changed) {
+ *changed = cached_property_serial_ != initial_property_serial_;
+ }
+
+ if (is_read_only_) {
+ return read_only_property_;
+ } else {
+ return cached_value_;
+ }
+}
+
#endif
} // namespace base
diff --git a/base/properties_test.cpp b/base/properties_test.cpp
index e7d4880..c30c41e 100644
--- a/base/properties_test.cpp
+++ b/base/properties_test.cpp
@@ -230,3 +230,28 @@
GTEST_LOG_(INFO) << "This test does nothing on the host.\n";
#endif
}
+
+TEST(properties, CachedProperty) {
+#if defined(__BIONIC__)
+ android::base::CachedProperty cached_property("debug.libbase.CachedProperty_test");
+ bool changed;
+ cached_property.Get(&changed);
+
+ android::base::SetProperty("debug.libbase.CachedProperty_test", "foo");
+ ASSERT_STREQ("foo", cached_property.Get(&changed));
+ ASSERT_TRUE(changed);
+
+ ASSERT_STREQ("foo", cached_property.Get(&changed));
+ ASSERT_FALSE(changed);
+
+ android::base::SetProperty("debug.libbase.CachedProperty_test", "bar");
+ ASSERT_STREQ("bar", cached_property.Get(&changed));
+ ASSERT_TRUE(changed);
+
+ ASSERT_STREQ("bar", cached_property.Get(&changed));
+ ASSERT_FALSE(changed);
+
+#else
+ GTEST_LOG_(INFO) << "This test does nothing on the host.\n";
+#endif
+}
diff --git a/debuggerd/include/debuggerd/handler.h b/debuggerd/include/debuggerd/handler.h
index 4f24360..665d24a 100644
--- a/debuggerd/include/debuggerd/handler.h
+++ b/debuggerd/include/debuggerd/handler.h
@@ -19,7 +19,9 @@
#include <bionic/reserved_signals.h>
#include <signal.h>
#include <stdint.h>
+#include <string.h>
#include <sys/cdefs.h>
+#include <sys/system_properties.h>
#include <sys/types.h>
__BEGIN_DECLS
@@ -50,16 +52,21 @@
#define DEBUGGER_SIGNAL BIONIC_SIGNAL_DEBUGGER
static void __attribute__((__unused__)) debuggerd_register_handlers(struct sigaction* action) {
- sigaction(SIGABRT, action, nullptr);
- sigaction(SIGBUS, action, nullptr);
- sigaction(SIGFPE, action, nullptr);
- sigaction(SIGILL, action, nullptr);
- sigaction(SIGSEGV, action, nullptr);
-#if defined(SIGSTKFLT)
- sigaction(SIGSTKFLT, action, nullptr);
-#endif
- sigaction(SIGSYS, action, nullptr);
- sigaction(SIGTRAP, action, nullptr);
+ char value[PROP_VALUE_MAX] = "";
+ bool enabled =
+ !(__system_property_get("ro.debuggable", value) > 0 && !strcmp(value, "1") &&
+ __system_property_get("debug.debuggerd.disable", value) > 0 && !strcmp(value, "1"));
+ if (enabled) {
+ sigaction(SIGABRT, action, nullptr);
+ sigaction(SIGBUS, action, nullptr);
+ sigaction(SIGFPE, action, nullptr);
+ sigaction(SIGILL, action, nullptr);
+ sigaction(SIGSEGV, action, nullptr);
+ sigaction(SIGSTKFLT, action, nullptr);
+ sigaction(SIGSYS, action, nullptr);
+ sigaction(SIGTRAP, action, nullptr);
+ }
+
sigaction(BIONIC_SIGNAL_DEBUGGER, action, nullptr);
}
diff --git a/fastboot/device/commands.cpp b/fastboot/device/commands.cpp
index 2c9dec9..ca120c6 100644
--- a/fastboot/device/commands.cpp
+++ b/fastboot/device/commands.cpp
@@ -261,7 +261,7 @@
}
// If the slot is not changing, do nothing.
- if (slot == boot_control_hal->getCurrentSlot()) {
+ if (args[1] == device->GetCurrentSlot()) {
return device->WriteOkay("");
}
diff --git a/fs_mgr/TEST_MAPPING b/fs_mgr/TEST_MAPPING
index 705d4e3..676f446 100644
--- a/fs_mgr/TEST_MAPPING
+++ b/fs_mgr/TEST_MAPPING
@@ -13,7 +13,7 @@
"name": "fiemap_writer_test"
},
{
- "name": "vts_libsnapshot_test_presubmit"
+ "name": "vts_libsnapshot_test"
}
]
}
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 8840e7d..2e46b4f 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -96,7 +96,9 @@
using android::base::Basename;
using android::base::GetBoolProperty;
+using android::base::Readlink;
using android::base::Realpath;
+using android::base::SetProperty;
using android::base::StartsWith;
using android::base::Timer;
using android::base::unique_fd;
@@ -178,6 +180,7 @@
return;
}
+ Timer t;
/* Check for the types of filesystems we know how to check */
if (is_extfs(fs_type)) {
/*
@@ -253,15 +256,19 @@
}
}
} else if (is_f2fs(fs_type)) {
- const char* f2fs_fsck_argv[] = {F2FS_FSCK_BIN, "-a", blk_device.c_str()};
- const char* f2fs_fsck_forced_argv[] = {F2FS_FSCK_BIN, "-f", blk_device.c_str()};
+ const char* f2fs_fsck_argv[] = {F2FS_FSCK_BIN, "-a", "-c", "10000", "--debug-cache",
+ blk_device.c_str()};
+ const char* f2fs_fsck_forced_argv[] = {
+ F2FS_FSCK_BIN, "-f", "-c", "10000", "--debug-cache", blk_device.c_str()};
if (should_force_check(*fs_stat)) {
- LINFO << "Running " << F2FS_FSCK_BIN << " -f " << realpath(blk_device);
+ LINFO << "Running " << F2FS_FSCK_BIN << " -f -c 10000 --debug-cache"
+ << realpath(blk_device);
ret = logwrap_fork_execvp(ARRAY_SIZE(f2fs_fsck_forced_argv), f2fs_fsck_forced_argv,
&status, false, LOG_KLOG | LOG_FILE, false, FSCK_LOG_FILE);
} else {
- LINFO << "Running " << F2FS_FSCK_BIN << " -a " << realpath(blk_device);
+ LINFO << "Running " << F2FS_FSCK_BIN << " -a -c 10000 --debug-cache"
+ << realpath(blk_device);
ret = logwrap_fork_execvp(ARRAY_SIZE(f2fs_fsck_argv), f2fs_fsck_argv, &status, false,
LOG_KLOG | LOG_FILE, false, FSCK_LOG_FILE);
}
@@ -270,7 +277,8 @@
LERROR << "Failed trying to run " << F2FS_FSCK_BIN;
}
}
-
+ android::base::SetProperty("ro.boottime.init.fsck." + Basename(target),
+ std::to_string(t.duration().count()));
return;
}
@@ -512,8 +520,7 @@
// Enable casefold if needed.
static void tune_casefold(const std::string& blk_device, const struct ext4_super_block* sb,
int* fs_stat) {
- bool has_casefold =
- (sb->s_feature_ro_compat & cpu_to_le32(EXT4_FEATURE_INCOMPAT_CASEFOLD)) != 0;
+ bool has_casefold = (sb->s_feature_incompat & cpu_to_le32(EXT4_FEATURE_INCOMPAT_CASEFOLD)) != 0;
bool wants_casefold = android::base::GetBoolProperty("ro.emulated_storage.casefold", false);
if (!wants_casefold || has_casefold) return;
@@ -1582,6 +1589,79 @@
}
}
+static std::string ResolveBlockDevice(const std::string& block_device) {
+ if (!StartsWith(block_device, "/dev/block/")) {
+ LWARNING << block_device << " is not a block device";
+ return block_device;
+ }
+ std::string name = block_device.substr(5);
+ if (!StartsWith(name, "block/dm-")) {
+ // Not a dm-device, but might be a symlink. Optimistically try to readlink.
+ std::string result;
+ if (Readlink(block_device, &result)) {
+ return result;
+ } else if (errno == EINVAL) {
+ // After all, it wasn't a symlink.
+ return block_device;
+ } else {
+ LERROR << "Failed to readlink " << block_device;
+ return "";
+ }
+ }
+ // It's a dm-device, let's find what's inside!
+ std::string sys_dir = "/sys/" + name;
+ while (true) {
+ std::string slaves_dir = sys_dir + "/slaves";
+ std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(slaves_dir.c_str()), closedir);
+ if (!dir) {
+ LERROR << "Failed to open " << slaves_dir;
+ return "";
+ }
+ std::string sub_device_name = "";
+ for (auto entry = readdir(dir.get()); entry; entry = readdir(dir.get())) {
+ if (entry->d_type != DT_LNK) continue;
+ if (!sub_device_name.empty()) {
+ LERROR << "Too many slaves in " << slaves_dir;
+ return "";
+ }
+ sub_device_name = entry->d_name;
+ }
+ if (sub_device_name.empty()) {
+ LERROR << "No slaves in " << slaves_dir;
+ return "";
+ }
+ if (!StartsWith(sub_device_name, "dm-")) {
+ // Not a dm-device! We can stop now.
+ return "/dev/block/" + sub_device_name;
+ }
+ // Still a dm-device, keep digging.
+ sys_dir = "/sys/block/" + sub_device_name;
+ }
+}
+
+FstabEntry* fs_mgr_get_mounted_entry_for_userdata(Fstab* fstab, const FstabEntry& mounted_entry) {
+ std::string resolved_block_device = ResolveBlockDevice(mounted_entry.blk_device);
+ if (resolved_block_device.empty()) {
+ return nullptr;
+ }
+ LINFO << "/data is mounted on " << resolved_block_device;
+ for (auto& entry : *fstab) {
+ if (entry.mount_point != "/data") {
+ continue;
+ }
+ std::string block_device;
+ if (!Readlink(entry.blk_device, &block_device)) {
+ LWARNING << "Failed to readlink " << entry.blk_device;
+ block_device = entry.blk_device;
+ }
+ if (block_device == resolved_block_device) {
+ return &entry;
+ }
+ }
+ LERROR << "Didn't find entry that was used to mount /data";
+ return nullptr;
+}
+
// TODO(b/143970043): return different error codes based on which step failed.
int fs_mgr_remount_userdata_into_checkpointing(Fstab* fstab) {
Fstab proc_mounts;
@@ -1590,16 +1670,13 @@
return -1;
}
std::string block_device;
- if (auto entry = GetEntryForMountPoint(&proc_mounts, "/data"); entry != nullptr) {
- // Note: we don't care about a userdata wrapper here, since it's safe
- // to remount on top of the bow device instead, there will be no
- // conflicts.
- block_device = entry->blk_device;
- } else {
+ auto mounted_entry = GetEntryForMountPoint(&proc_mounts, "/data");
+ if (mounted_entry == nullptr) {
LERROR << "/data is not mounted";
return -1;
}
- auto fstab_entry = GetMountedEntryForUserdata(fstab);
+ block_device = mounted_entry->blk_device;
+ auto fstab_entry = fs_mgr_get_mounted_entry_for_userdata(fstab, *mounted_entry);
if (fstab_entry == nullptr) {
LERROR << "Can't find /data in fstab";
return -1;
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index e4bb092..f3f1cb7 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -30,6 +30,7 @@
#include <android-base/file.h>
#include <android-base/parseint.h>
+#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <libgsi/libgsi.h>
@@ -654,6 +655,21 @@
}
}
+void EnableMandatoryFlags(Fstab* fstab) {
+ // Devices launched in R and after should enable fs_verity on userdata. The flag causes tune2fs
+ // to enable the feature. A better alternative would be to enable on mkfs at the beginning.
+ if (android::base::GetIntProperty("ro.product.first_api_level", 0) >= 30) {
+ std::vector<FstabEntry*> data_entries = GetEntriesForMountPoint(fstab, "/data");
+ for (auto&& entry : data_entries) {
+ // Besides ext4, f2fs is also supported. But the image is already created with verity
+ // turned on when it was first introduced.
+ if (entry->fs_type == "ext4") {
+ entry->fs_mgr_flags.fs_verity = true;
+ }
+ }
+ }
+}
+
bool ReadFstabFromFile(const std::string& path, Fstab* fstab) {
auto fstab_file = std::unique_ptr<FILE, decltype(&fclose)>{fopen(path.c_str(), "re"), fclose};
if (!fstab_file) {
@@ -674,6 +690,7 @@
}
SkipMountingPartitions(fstab);
+ EnableMandatoryFlags(fstab);
return true;
}
@@ -797,89 +814,6 @@
return entries;
}
-static std::string ResolveBlockDevice(const std::string& block_device) {
- if (!StartsWith(block_device, "/dev/block/")) {
- LWARNING << block_device << " is not a block device";
- return block_device;
- }
- std::string name = block_device.substr(5);
- if (!StartsWith(name, "block/dm-")) {
- // Not a dm-device, but might be a symlink. Optimistically try to readlink.
- std::string result;
- if (Readlink(block_device, &result)) {
- return result;
- } else if (errno == EINVAL) {
- // After all, it wasn't a symlink.
- return block_device;
- } else {
- LERROR << "Failed to readlink " << block_device;
- return "";
- }
- }
- // It's a dm-device, let's find what's inside!
- std::string sys_dir = "/sys/" + name;
- while (true) {
- std::string slaves_dir = sys_dir + "/slaves";
- std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(slaves_dir.c_str()), closedir);
- if (!dir) {
- LERROR << "Failed to open " << slaves_dir;
- return "";
- }
- std::string sub_device_name = "";
- for (auto entry = readdir(dir.get()); entry; entry = readdir(dir.get())) {
- if (entry->d_type != DT_LNK) continue;
- if (!sub_device_name.empty()) {
- LERROR << "Too many slaves in " << slaves_dir;
- return "";
- }
- sub_device_name = entry->d_name;
- }
- if (sub_device_name.empty()) {
- LERROR << "No slaves in " << slaves_dir;
- return "";
- }
- if (!StartsWith(sub_device_name, "dm-")) {
- // Not a dm-device! We can stop now.
- return "/dev/block/" + sub_device_name;
- }
- // Still a dm-device, keep digging.
- sys_dir = "/sys/block/" + sub_device_name;
- }
-}
-
-FstabEntry* GetMountedEntryForUserdata(Fstab* fstab) {
- Fstab mounts;
- if (!ReadFstabFromFile("/proc/mounts", &mounts)) {
- LERROR << "Failed to read /proc/mounts";
- return nullptr;
- }
- auto mounted_entry = GetEntryForMountPoint(&mounts, "/data");
- if (mounted_entry == nullptr) {
- LWARNING << "/data is not mounted";
- return nullptr;
- }
- std::string resolved_block_device = ResolveBlockDevice(mounted_entry->blk_device);
- if (resolved_block_device.empty()) {
- return nullptr;
- }
- LINFO << "/data is mounted on " << resolved_block_device;
- for (auto& entry : *fstab) {
- if (entry.mount_point != "/data") {
- continue;
- }
- std::string block_device;
- if (!Readlink(entry.blk_device, &block_device)) {
- LWARNING << "Failed to readlink " << entry.blk_device;
- block_device = entry.blk_device;
- }
- if (block_device == resolved_block_device) {
- return &entry;
- }
- }
- LERROR << "Didn't find entry that was used to mount /data";
- return nullptr;
-}
-
std::set<std::string> GetBootDevices() {
// First check the kernel commandline, then try the device tree otherwise
std::string dt_file_name = get_android_dt_dir() + "/boot_devices";
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index 9bc38f9..3d556c9 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -107,6 +107,10 @@
// it destroys verity devices from device mapper after the device is unmounted.
int fs_mgr_umount_all(android::fs_mgr::Fstab* fstab);
+// Finds a entry in |fstab| that was used to mount a /data |mounted_entry| from
+// /proc/mounts.
+android::fs_mgr::FstabEntry* fs_mgr_get_mounted_entry_for_userdata(
+ android::fs_mgr::Fstab* fstab, const android::fs_mgr::FstabEntry& mounted_entry);
int fs_mgr_remount_userdata_into_checkpointing(android::fs_mgr::Fstab* fstab);
// Finds the dm_bow device on which this block device is stacked, or returns
diff --git a/fs_mgr/include_fstab/fstab/fstab.h b/fs_mgr/include_fstab/fstab/fstab.h
index c94d7ac..009c04c 100644
--- a/fs_mgr/include_fstab/fstab/fstab.h
+++ b/fs_mgr/include_fstab/fstab/fstab.h
@@ -102,7 +102,6 @@
FstabEntry* GetEntryForMountPoint(Fstab* fstab, const std::string& path);
// The Fstab can contain multiple entries for the same mount point with different configurations.
std::vector<FstabEntry*> GetEntriesForMountPoint(Fstab* fstab, const std::string& path);
-FstabEntry* GetMountedEntryForUserdata(Fstab* fstab);
// This method builds DSU fstab entries and transfer the fstab.
//
diff --git a/fs_mgr/libdm/dm_target.cpp b/fs_mgr/libdm/dm_target.cpp
index 6461788..29b1032 100644
--- a/fs_mgr/libdm/dm_target.cpp
+++ b/fs_mgr/libdm/dm_target.cpp
@@ -243,12 +243,10 @@
return android::base::Join(argv, " ");
}
-const std::string DmTargetDefaultKey::name_ = "default-key";
-
bool DmTargetDefaultKey::IsLegacy(bool* result) {
DeviceMapper& dm = DeviceMapper::Instance();
DmTargetTypeInfo info;
- if (!dm.GetTargetByName(name_, &info)) return false;
+ if (!dm.GetTargetByName(kName, &info)) return false;
// dm-default-key was modified to be like dm-crypt with version 2
*result = !info.IsAtLeast(2, 0, 0);
return true;
diff --git a/fs_mgr/libdm/include/libdm/dm_target.h b/fs_mgr/libdm/include/libdm/dm_target.h
index d2e50d3..050d0b6 100644
--- a/fs_mgr/libdm/include/libdm/dm_target.h
+++ b/fs_mgr/libdm/include/libdm/dm_target.h
@@ -287,7 +287,7 @@
blockdev_(blockdev),
start_sector_(start_sector) {}
- std::string name() const override { return name_; }
+ std::string name() const override { return kName; }
bool Valid() const override;
std::string GetParameterString() const override;
static bool IsLegacy(bool* result);
@@ -296,7 +296,8 @@
void SetWrappedKeyV0() { is_hw_wrapped_ = true; }
private:
- static const std::string name_;
+ inline static const std::string kName = "default-key";
+
std::string cipher_;
std::string key_;
std::string blockdev_;
diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp
index 63bdcc5..0a0a21d 100644
--- a/fs_mgr/libsnapshot/Android.bp
+++ b/fs_mgr/libsnapshot/Android.bp
@@ -208,21 +208,12 @@
defaults: ["libsnapshot_test_defaults"],
}
-cc_test {
- name: "vts_libsnapshot_test_presubmit",
- defaults: ["libsnapshot_test_defaults"],
- cppflags: [
- "-DSKIP_TEST_IN_PRESUBMIT",
- ],
-}
-
cc_binary {
name: "snapshotctl",
srcs: [
"snapshotctl.cpp",
],
static_libs: [
- "libdm",
"libfstab",
"libsnapshot",
],
@@ -244,7 +235,4 @@
// TODO(b/148818798): remove when parent bug is fixed.
"libutilscallstack",
],
- init_rc: [
- "snapshotctl.rc",
- ],
}
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/return.h b/fs_mgr/libsnapshot/include/libsnapshot/return.h
index 1f132fa..dedc445 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/return.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/return.h
@@ -30,7 +30,6 @@
enum class ErrorCode : int32_t {
SUCCESS = static_cast<int32_t>(FiemapStatus::ErrorCode::SUCCESS),
ERROR = static_cast<int32_t>(FiemapStatus::ErrorCode::ERROR),
- NEEDS_REBOOT = ERROR + 1,
NO_SPACE = static_cast<int32_t>(FiemapStatus::ErrorCode::NO_SPACE),
};
ErrorCode error_code() const { return error_code_; }
@@ -43,7 +42,6 @@
static Return Ok() { return Return(ErrorCode::SUCCESS); }
static Return Error() { return Return(ErrorCode::ERROR); }
static Return NoSpace(uint64_t size) { return Return(ErrorCode::NO_SPACE, size); }
- static Return NeedsReboot() { return Return(ErrorCode::NEEDS_REBOOT); }
// Does not set required_size_ properly even when status.error_code() == NO_SPACE.
explicit Return(const FiemapStatus& status)
: error_code_(FromFiemapStatusErrorCode(status.error_code())), required_size_(0) {}
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
index b440c71..81f616c 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
@@ -125,6 +125,9 @@
// might be needed to perform first-stage mounts.
static bool IsSnapshotManagerNeeded();
+ // Helper function for second stage init to restorecon on the rollback indicator.
+ static std::string GetGlobalRollbackIndicatorPath();
+
// Begin an update. This must be called before creating any snapshots. It
// will fail if GetUpdateState() != None.
bool BeginUpdate();
@@ -140,7 +143,6 @@
// Before calling this function, all snapshots must be mapped.
bool FinishedSnapshotWrites();
- private:
// Initiate a merge on all snapshot devices. This should only be used after an
// update has been marked successful after booting.
bool InitiateMerge();
@@ -149,7 +151,11 @@
// /data is mounted.
//
// If a merge is in progress, this function will block until the merge is
- // completed. If a merge or update was cancelled, this will clean up any
+ // completed.
+ // - Callback is called periodically during the merge. If callback()
+ // returns false during the merge, ProcessUpdateState() will pause
+ // and returns Merging.
+ // If a merge or update was cancelled, this will clean up any
// update artifacts and return.
//
// Note that after calling this, GetUpdateState() may still return that a
@@ -169,9 +175,9 @@
//
// The optional callback allows the caller to periodically check the
// progress with GetUpdateState().
- UpdateState ProcessUpdateState(const std::function<void()>& callback = {});
+ UpdateState ProcessUpdateState(const std::function<bool()>& callback = {},
+ const std::function<bool()>& before_cancel = {});
- public:
// Initiate the merge if necessary, then wait for the merge to finish.
// See InitiateMerge() and ProcessUpdateState() for details.
// Returns:
@@ -179,16 +185,8 @@
// - Unverified if called on the source slot
// - MergeCompleted if merge is completed
// - other states indicating an error has occurred
- UpdateState InitiateMergeAndWait(SnapshotMergeReport* report = nullptr);
-
- // Wait for the merge if rebooted into the new slot. Does NOT initiate a
- // merge. If the merge has not been initiated (but should be), wait.
- // Returns:
- // - Return::Ok(): there is no merge or merge finishes
- // - Return::NeedsReboot(): merge finishes but need a reboot before
- // applying the next update.
- // - Return::Error(): other irrecoverable errors
- Return WaitForMerge();
+ UpdateState InitiateMergeAndWait(SnapshotMergeReport* report = nullptr,
+ const std::function<bool()>& before_cancel = {});
// Find the status of the current update, if any.
//
@@ -375,14 +373,23 @@
// Check for a cancelled or rolled back merge, returning true if such a
// condition was detected and handled.
- bool HandleCancelledUpdate(LockedFile* lock);
+ bool HandleCancelledUpdate(LockedFile* lock, const std::function<bool()>& before_cancel);
// Helper for HandleCancelledUpdate. Assumes booting from new slot.
bool AreAllSnapshotsCancelled(LockedFile* lock);
+ // Determine whether partition names in |snapshots| have been flashed and
+ // store result to |out|.
+ // Return true if values are successfully retrieved and false on error
+ // (e.g. super partition metadata cannot be read). When it returns true,
+ // |out| stores true for partitions that have been flashed and false for
+ // partitions that have not been flashed.
+ bool GetSnapshotFlashingStatus(LockedFile* lock, const std::vector<std::string>& snapshots,
+ std::map<std::string, bool>* out);
+
// Remove artifacts created by the update process, such as snapshots, and
// set the update state to None.
- bool RemoveAllUpdateState(LockedFile* lock);
+ bool RemoveAllUpdateState(LockedFile* lock, const std::function<bool()>& prolog = {});
// Interact with /metadata/ota.
std::unique_ptr<LockedFile> OpenLock(int lock_flags);
@@ -437,8 +444,8 @@
// UpdateState::MergeCompleted
// UpdateState::MergeFailed
// UpdateState::MergeNeedsReboot
- UpdateState CheckMergeState();
- UpdateState CheckMergeState(LockedFile* lock);
+ UpdateState CheckMergeState(const std::function<bool()>& before_cancel);
+ UpdateState CheckMergeState(LockedFile* lock, const std::function<bool()>& before_cancel);
UpdateState CheckTargetMergeState(LockedFile* lock, const std::string& name);
// Interact with status files under /metadata/ota/snapshots.
@@ -513,6 +520,11 @@
std::string ReadUpdateSourceSlotSuffix();
+ // Helper for RemoveAllSnapshots.
+ // Check whether |name| should be deleted as a snapshot name.
+ bool ShouldDeleteSnapshot(LockedFile* lock, const std::map<std::string, bool>& flashing_status,
+ Slot current_slot, const std::string& name);
+
std::string gsid_dir_;
std::string metadata_dir_;
std::unique_ptr<IDeviceInfo> device_;
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stats.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stats.h
new file mode 100644
index 0000000..91dd34f
--- /dev/null
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stats.h
@@ -0,0 +1,59 @@
+// 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.
+
+#pragma once
+
+#include <chrono>
+#include <memory>
+
+#include <android/snapshot/snapshot.pb.h>
+#include <libsnapshot/snapshot.h>
+
+namespace android {
+namespace snapshot {
+
+class SnapshotMergeStats {
+ public:
+ // Not thread safe.
+ static SnapshotMergeStats* GetInstance(SnapshotManager& manager);
+
+ // Called when merge starts or resumes.
+ bool Start();
+ void set_state(android::snapshot::UpdateState state);
+
+ // Called when merge ends. Properly clean up permanent storage.
+ class Result {
+ public:
+ virtual ~Result() {}
+ virtual const SnapshotMergeReport& report() const = 0;
+ // Time between successful Start() / Resume() to Finish().
+ virtual std::chrono::steady_clock::duration merge_time() const = 0;
+ };
+ std::unique_ptr<Result> Finish();
+
+ private:
+ bool ReadState();
+ bool WriteState();
+ bool DeleteState();
+ SnapshotMergeStats(const std::string& path);
+
+ std::string path_;
+ SnapshotMergeReport report_;
+ // Time of the last successful Start() / Resume() call.
+ std::chrono::time_point<std::chrono::steady_clock> start_time_;
+ bool running_{false};
+};
+
+} // namespace snapshot
+} // namespace android
diff --git a/fs_mgr/libsnapshot/return.cpp b/fs_mgr/libsnapshot/return.cpp
index 6559c12..cc64af5 100644
--- a/fs_mgr/libsnapshot/return.cpp
+++ b/fs_mgr/libsnapshot/return.cpp
@@ -24,8 +24,6 @@
switch (error_code()) {
case ErrorCode::ERROR:
return "Error";
- case ErrorCode::NEEDS_REBOOT:
- return "Retry after reboot";
case ErrorCode::SUCCESS:
[[fallthrough]];
case ErrorCode::NO_SPACE:
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index 2fe06fb..154b5d7 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -43,10 +43,10 @@
#endif
#include <android/snapshot/snapshot.pb.h>
+#include <libsnapshot/snapshot_stats.h>
#include "device_info.h"
#include "partition_cow_creator.h"
#include "snapshot_metadata_updater.h"
-#include "snapshot_stats.h"
#include "utility.h"
namespace android {
@@ -81,6 +81,7 @@
using namespace std::string_literals;
static constexpr char kBootIndicatorPath[] = "/metadata/ota/snapshot-boot";
+static constexpr char kRollbackIndicatorPath[] = "/metadata/ota/rollback-indicator";
static constexpr auto kUpdateStateCheckInterval = 2s;
// Note: IImageManager is an incomplete type in the header, so the default
@@ -219,7 +220,12 @@
return true;
}
-bool SnapshotManager::RemoveAllUpdateState(LockedFile* lock) {
+bool SnapshotManager::RemoveAllUpdateState(LockedFile* lock, const std::function<bool()>& prolog) {
+ if (prolog && !prolog()) {
+ LOG(WARNING) << "Can't RemoveAllUpdateState: prolog failed.";
+ return false;
+ }
+
LOG(INFO) << "Removing all update state.";
#ifdef LIBSNAPSHOT_USE_CALLSTACK
@@ -789,9 +795,10 @@
// Note that when a merge fails, we will *always* try again to complete the
// merge each time the device boots. There is no harm in doing so, and if
// the problem was transient, we might manage to get a new outcome.
-UpdateState SnapshotManager::ProcessUpdateState(const std::function<void()>& callback) {
+UpdateState SnapshotManager::ProcessUpdateState(const std::function<bool()>& callback,
+ const std::function<bool()>& before_cancel) {
while (true) {
- UpdateState state = CheckMergeState();
+ UpdateState state = CheckMergeState(before_cancel);
if (state == UpdateState::MergeFailed) {
AcknowledgeMergeFailure();
}
@@ -801,8 +808,8 @@
return state;
}
- if (callback) {
- callback();
+ if (callback && !callback()) {
+ return state;
}
// This wait is not super time sensitive, so we have a relatively
@@ -811,24 +818,27 @@
}
}
-UpdateState SnapshotManager::CheckMergeState() {
+UpdateState SnapshotManager::CheckMergeState(const std::function<bool()>& before_cancel) {
auto lock = LockExclusive();
if (!lock) {
return UpdateState::MergeFailed;
}
- UpdateState state = CheckMergeState(lock.get());
+ UpdateState state = CheckMergeState(lock.get(), before_cancel);
if (state == UpdateState::MergeCompleted) {
// Do this inside the same lock. Failures get acknowledged without the
// lock, because flock() might have failed.
AcknowledgeMergeSuccess(lock.get());
} else if (state == UpdateState::Cancelled) {
- RemoveAllUpdateState(lock.get());
+ if (!RemoveAllUpdateState(lock.get(), before_cancel)) {
+ return ReadSnapshotUpdateStatus(lock.get()).state();
+ }
}
return state;
}
-UpdateState SnapshotManager::CheckMergeState(LockedFile* lock) {
+UpdateState SnapshotManager::CheckMergeState(LockedFile* lock,
+ const std::function<bool()>& before_cancel) {
UpdateState state = ReadUpdateState(lock);
switch (state) {
case UpdateState::None:
@@ -849,7 +859,7 @@
// This is an edge case. Normally cancelled updates are detected
// via the merge poll below, but if we never started a merge, we
// need to also check here.
- if (HandleCancelledUpdate(lock)) {
+ if (HandleCancelledUpdate(lock, before_cancel)) {
return UpdateState::Cancelled;
}
return state;
@@ -1003,7 +1013,7 @@
}
std::string SnapshotManager::GetRollbackIndicatorPath() {
- return metadata_dir_ + "/rollback-indicator";
+ return metadata_dir_ + "/" + android::base::Basename(kRollbackIndicatorPath);
}
void SnapshotManager::AcknowledgeMergeSuccess(LockedFile* lock) {
@@ -1169,7 +1179,8 @@
return true;
}
-bool SnapshotManager::HandleCancelledUpdate(LockedFile* lock) {
+bool SnapshotManager::HandleCancelledUpdate(LockedFile* lock,
+ const std::function<bool()>& before_cancel) {
auto slot = GetCurrentSlot();
if (slot == Slot::Unknown) {
return false;
@@ -1177,15 +1188,30 @@
// If all snapshots were reflashed, then cancel the entire update.
if (AreAllSnapshotsCancelled(lock)) {
- RemoveAllUpdateState(lock);
- return true;
+ LOG(WARNING) << "Detected re-flashing, cancelling unverified update.";
+ return RemoveAllUpdateState(lock, before_cancel);
}
- // This unverified update might be rolled back, or it might not (b/147347110
- // comment #77). Take no action, as update_engine is responsible for deciding
- // whether to cancel.
- LOG(ERROR) << "Update state is being processed before reboot, taking no action.";
- return false;
+ // If update has been rolled back, then cancel the entire update.
+ // Client (update_engine) is responsible for doing additional cleanup work on its own states
+ // when ProcessUpdateState() returns UpdateState::Cancelled.
+ auto current_slot = GetCurrentSlot();
+ if (current_slot != Slot::Source) {
+ LOG(INFO) << "Update state is being processed while booting at " << current_slot
+ << " slot, taking no action.";
+ return false;
+ }
+
+ // current_slot == Source. Attempt to detect rollbacks.
+ if (access(GetRollbackIndicatorPath().c_str(), F_OK) != 0) {
+ // This unverified update is not attempted. Take no action.
+ PLOG(INFO) << "Rollback indicator not detected. "
+ << "Update state is being processed before reboot, taking no action.";
+ return false;
+ }
+
+ LOG(WARNING) << "Detected rollback, cancelling unverified update.";
+ return RemoveAllUpdateState(lock, before_cancel);
}
std::unique_ptr<LpMetadata> SnapshotManager::ReadCurrentMetadata() {
@@ -1219,6 +1245,28 @@
return true;
}
+ std::map<std::string, bool> flashing_status;
+
+ if (!GetSnapshotFlashingStatus(lock, snapshots, &flashing_status)) {
+ LOG(WARNING) << "Failed to determine whether partitions have been flashed. Not"
+ << "removing update states.";
+ return false;
+ }
+
+ bool all_snapshots_cancelled = std::all_of(flashing_status.begin(), flashing_status.end(),
+ [](const auto& pair) { return pair.second; });
+
+ if (all_snapshots_cancelled) {
+ LOG(WARNING) << "All partitions are re-flashed after update, removing all update states.";
+ }
+ return all_snapshots_cancelled;
+}
+
+bool SnapshotManager::GetSnapshotFlashingStatus(LockedFile* lock,
+ const std::vector<std::string>& snapshots,
+ std::map<std::string, bool>* out) {
+ CHECK(lock);
+
auto source_slot_suffix = ReadUpdateSourceSlotSuffix();
if (source_slot_suffix.empty()) {
return false;
@@ -1244,20 +1292,17 @@
return false;
}
- bool all_snapshots_cancelled = true;
for (const auto& snapshot_name : snapshots) {
if (GetMetadataPartitionState(*metadata, snapshot_name) ==
MetadataPartitionState::Updated) {
- all_snapshots_cancelled = false;
- continue;
+ out->emplace(snapshot_name, false);
+ } else {
+ // Delete snapshots for partitions that are re-flashed after the update.
+ LOG(WARNING) << "Detected re-flashing of partition " << snapshot_name << ".";
+ out->emplace(snapshot_name, true);
}
- // Delete snapshots for partitions that are re-flashed after the update.
- LOG(WARNING) << "Detected re-flashing of partition " << snapshot_name << ".";
}
- if (all_snapshots_cancelled) {
- LOG(WARNING) << "All partitions are re-flashed after update, removing all update states.";
- }
- return all_snapshots_cancelled;
+ return true;
}
bool SnapshotManager::RemoveAllSnapshots(LockedFile* lock) {
@@ -1267,10 +1312,38 @@
return false;
}
+ std::map<std::string, bool> flashing_status;
+ if (!GetSnapshotFlashingStatus(lock, snapshots, &flashing_status)) {
+ LOG(WARNING) << "Failed to get flashing status";
+ }
+
+ auto current_slot = GetCurrentSlot();
bool ok = true;
bool has_mapped_cow_images = false;
for (const auto& name : snapshots) {
- if (!UnmapPartitionWithSnapshot(lock, name) || !DeleteSnapshot(lock, name)) {
+ // If booting off source slot, it is okay to unmap and delete all the snapshots.
+ // If boot indicator is missing, update state is None or Initiated, so
+ // it is also okay to unmap and delete all the snapshots.
+ // If booting off target slot,
+ // - should not unmap because:
+ // - In Android mode, snapshots are not mapped, but
+ // filesystems are mounting off dm-linear targets directly.
+ // - In recovery mode, assume nothing is mapped, so it is optional to unmap.
+ // - If partition is flashed or unknown, it is okay to delete snapshots.
+ // Otherwise (UPDATED flag), only delete snapshots if they are not mapped
+ // as dm-snapshot (for example, after merge completes).
+ bool should_unmap = current_slot != Slot::Target;
+ bool should_delete = ShouldDeleteSnapshot(lock, flashing_status, current_slot, name);
+
+ bool partition_ok = true;
+ if (should_unmap && !UnmapPartitionWithSnapshot(lock, name)) {
+ partition_ok = false;
+ }
+ if (partition_ok && should_delete && !DeleteSnapshot(lock, name)) {
+ partition_ok = false;
+ }
+
+ if (!partition_ok) {
// Remember whether or not we were able to unmap the cow image.
auto cow_image_device = GetCowImageDeviceName(name);
has_mapped_cow_images |=
@@ -1293,6 +1366,34 @@
return ok;
}
+// See comments in RemoveAllSnapshots().
+bool SnapshotManager::ShouldDeleteSnapshot(LockedFile* lock,
+ const std::map<std::string, bool>& flashing_status,
+ Slot current_slot, const std::string& name) {
+ if (current_slot != Slot::Target) {
+ return true;
+ }
+ auto it = flashing_status.find(name);
+ if (it == flashing_status.end()) {
+ LOG(WARNING) << "Can't determine flashing status for " << name;
+ return true;
+ }
+ if (it->second) {
+ // partition flashed, okay to delete obsolete snapshots
+ return true;
+ }
+ // partition updated, only delete if not dm-snapshot
+ SnapshotStatus status;
+ if (!ReadSnapshotStatus(lock, name, &status)) {
+ LOG(WARNING) << "Unable to read snapshot status for " << name
+ << ", guessing snapshot device name";
+ auto extra_name = GetSnapshotExtraDeviceName(name);
+ return !IsSnapshotDevice(name) && !IsSnapshotDevice(extra_name);
+ }
+ auto dm_name = GetSnapshotDeviceName(name, status);
+ return !IsSnapshotDevice(dm_name);
+}
+
UpdateState SnapshotManager::GetUpdateState(double* progress) {
// If we've never started an update, the state file won't exist.
auto state_file = GetStateFilePath();
@@ -1369,6 +1470,10 @@
return access(kBootIndicatorPath, F_OK) == 0;
}
+std::string SnapshotManager::GetGlobalRollbackIndicatorPath() {
+ return kRollbackIndicatorPath;
+}
+
bool SnapshotManager::NeedSnapshotsInFirstStageMount() {
// If we fail to read, we'll wind up using CreateLogicalPartitions, which
// will create devices that look like the old slot, except with extra
@@ -1379,12 +1484,14 @@
auto slot = GetCurrentSlot();
if (slot != Slot::Target) {
- if (slot == Slot::Source && !device_->IsRecovery()) {
+ if (slot == Slot::Source) {
// Device is rebooting into the original slot, so mark this as a
// rollback.
auto path = GetRollbackIndicatorPath();
if (!android::base::WriteStringToFile("1", path)) {
PLOG(ERROR) << "Unable to write rollback indicator: " << path;
+ } else {
+ LOG(INFO) << "Rollback detected, writing rollback indicator to " << path;
}
}
LOG(INFO) << "Not booting from new slot. Will not mount snapshots.";
@@ -2388,7 +2495,8 @@
return AutoUnmountDevice::New(device_->GetMetadataDir());
}
-UpdateState SnapshotManager::InitiateMergeAndWait(SnapshotMergeReport* stats_report) {
+UpdateState SnapshotManager::InitiateMergeAndWait(SnapshotMergeReport* stats_report,
+ const std::function<bool()>& before_cancel) {
{
auto lock = LockExclusive();
// Sync update state from file with bootloader.
@@ -2398,23 +2506,24 @@
}
}
- SnapshotMergeStats merge_stats(*this);
+ auto merge_stats = SnapshotMergeStats::GetInstance(*this);
unsigned int last_progress = 0;
- auto callback = [&]() -> void {
+ auto callback = [&]() -> bool {
double progress;
GetUpdateState(&progress);
if (last_progress < static_cast<unsigned int>(progress)) {
last_progress = progress;
LOG(INFO) << "Waiting for merge to complete: " << last_progress << "%.";
}
+ return true; // continue
};
LOG(INFO) << "Waiting for any previous merge request to complete. "
<< "This can take up to several minutes.";
- merge_stats.Resume();
- auto state = ProcessUpdateState(callback);
- merge_stats.set_state(state);
+ merge_stats->Start();
+ auto state = ProcessUpdateState(callback, before_cancel);
+ merge_stats->set_state(state);
if (state == UpdateState::None) {
LOG(INFO) << "Can't find any snapshot to merge.";
return state;
@@ -2425,10 +2534,6 @@
return state;
}
- // This is the first snapshot merge that is requested after OTA. We can
- // initialize the merge duration statistics.
- merge_stats.Start();
-
if (!InitiateMerge()) {
LOG(ERROR) << "Failed to initiate merge.";
return state;
@@ -2436,43 +2541,22 @@
// All other states can be handled by ProcessUpdateState.
LOG(INFO) << "Waiting for merge to complete. This can take up to several minutes.";
last_progress = 0;
- state = ProcessUpdateState(callback);
- merge_stats.set_state(state);
+ state = ProcessUpdateState(callback, before_cancel);
+ merge_stats->set_state(state);
}
LOG(INFO) << "Merge finished with state \"" << state << "\".";
if (stats_report) {
- *stats_report = merge_stats.GetReport();
+ auto result = merge_stats->Finish();
+ if (result) {
+ *stats_report = result->report();
+ } else {
+ LOG(WARNING) << "SnapshotMergeStatus::Finish failed.";
+ }
}
return state;
}
-Return SnapshotManager::WaitForMerge() {
- LOG(INFO) << "Waiting for any previous merge request to complete. "
- << "This can take up to several minutes.";
- while (true) {
- auto state = ProcessUpdateState();
- if (state == UpdateState::Unverified && GetCurrentSlot() == Slot::Target) {
- LOG(INFO) << "Wait for merge to be initiated.";
- std::this_thread::sleep_for(kUpdateStateCheckInterval);
- continue;
- }
- LOG(INFO) << "Wait for merge exits with state " << state;
- switch (state) {
- case UpdateState::None:
- [[fallthrough]];
- case UpdateState::MergeCompleted:
- [[fallthrough]];
- case UpdateState::Cancelled:
- return Return::Ok();
- case UpdateState::MergeNeedsReboot:
- return Return::NeedsReboot();
- default:
- return Return::Error();
- }
- }
-}
-
bool SnapshotManager::HandleImminentDataWipe(const std::function<void()>& callback) {
if (!device_->IsRecovery()) {
LOG(ERROR) << "Data wipes are only allowed in recovery.";
@@ -2503,7 +2587,10 @@
return false;
}
- UpdateState state = ProcessUpdateState(callback);
+ UpdateState state = ProcessUpdateState([&]() -> bool {
+ callback();
+ return true;
+ });
LOG(INFO) << "Update state in recovery: " << state;
switch (state) {
case UpdateState::MergeFailed:
diff --git a/fs_mgr/libsnapshot/snapshot_stats.cpp b/fs_mgr/libsnapshot/snapshot_stats.cpp
index 635b47d..5da7b98 100644
--- a/fs_mgr/libsnapshot/snapshot_stats.cpp
+++ b/fs_mgr/libsnapshot/snapshot_stats.cpp
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "snapshot_stats.h"
+#include <libsnapshot/snapshot_stats.h>
#include <sstream>
@@ -23,22 +23,17 @@
namespace android {
namespace snapshot {
-SnapshotMergeStats::SnapshotMergeStats(SnapshotManager& parent) : parent_(parent) {
- init_time_ = std::chrono::steady_clock::now();
+SnapshotMergeStats* SnapshotMergeStats::GetInstance(SnapshotManager& parent) {
+ static SnapshotMergeStats g_instance(parent.GetMergeStateFilePath());
+ CHECK(g_instance.path_ == parent.GetMergeStateFilePath());
+ return &g_instance;
}
-SnapshotMergeStats::~SnapshotMergeStats() {
- std::string error;
- auto file_path = parent_.GetMergeStateFilePath();
- if (!android::base::RemoveFileIfExists(file_path, &error)) {
- LOG(ERROR) << "Failed to remove merge statistics file " << file_path << ": " << error;
- return;
- }
-}
+SnapshotMergeStats::SnapshotMergeStats(const std::string& path) : path_(path), running_(false) {}
bool SnapshotMergeStats::ReadState() {
std::string contents;
- if (!android::base::ReadFileToString(parent_.GetMergeStateFilePath(), &contents)) {
+ if (!android::base::ReadFileToString(path_, &contents)) {
PLOG(INFO) << "Read merge statistics file failed";
return false;
}
@@ -55,34 +50,73 @@
LOG(ERROR) << "Unable to serialize SnapshotMergeStats.";
return false;
}
- auto file_path = parent_.GetMergeStateFilePath();
- if (!WriteStringToFileAtomic(contents, file_path)) {
+ if (!WriteStringToFileAtomic(contents, path_)) {
PLOG(ERROR) << "Could not write to merge statistics file";
return false;
}
return true;
}
-void SnapshotMergeStats::Start() {
- report_.set_resume_count(0);
- report_.set_state(UpdateState::None);
- WriteState();
+bool SnapshotMergeStats::DeleteState() {
+ std::string error;
+ if (!android::base::RemoveFileIfExists(path_, &error)) {
+ LOG(ERROR) << "Failed to remove merge statistics file " << path_ << ": " << error;
+ return false;
+ }
+ return true;
}
-void SnapshotMergeStats::Resume() {
- if (!ReadState()) {
- return;
+bool SnapshotMergeStats::Start() {
+ if (running_) {
+ LOG(ERROR) << "SnapshotMergeStats running_ == " << running_;
+ return false;
}
- report_.set_resume_count(report_.resume_count() + 1);
- WriteState();
+ running_ = true;
+
+ start_time_ = std::chrono::steady_clock::now();
+ if (ReadState()) {
+ report_.set_resume_count(report_.resume_count() + 1);
+ } else {
+ report_.set_resume_count(0);
+ report_.set_state(UpdateState::None);
+ }
+
+ return WriteState();
}
void SnapshotMergeStats::set_state(android::snapshot::UpdateState state) {
report_.set_state(state);
}
-SnapshotMergeReport SnapshotMergeStats::GetReport() {
- return report_;
+class SnapshotMergeStatsResultImpl : public SnapshotMergeStats::Result {
+ public:
+ SnapshotMergeStatsResultImpl(const SnapshotMergeReport& report,
+ std::chrono::steady_clock::duration merge_time)
+ : report_(report), merge_time_(merge_time) {}
+ const SnapshotMergeReport& report() const override { return report_; }
+ std::chrono::steady_clock::duration merge_time() const override { return merge_time_; }
+
+ private:
+ SnapshotMergeReport report_;
+ std::chrono::steady_clock::duration merge_time_;
+};
+
+std::unique_ptr<SnapshotMergeStats::Result> SnapshotMergeStats::Finish() {
+ if (!running_) {
+ LOG(ERROR) << "SnapshotMergeStats running_ == " << running_;
+ return nullptr;
+ }
+ running_ = false;
+
+ auto result = std::make_unique<SnapshotMergeStatsResultImpl>(
+ report_, std::chrono::steady_clock::now() - start_time_);
+
+ // We still want to report result if state is not deleted. Just leave
+ // it there and move on. A side effect is that it may be reported over and
+ // over again in the future, but there is nothing we can do.
+ (void)DeleteState();
+
+ return result;
}
} // namespace snapshot
diff --git a/fs_mgr/libsnapshot/snapshot_stats.h b/fs_mgr/libsnapshot/snapshot_stats.h
deleted file mode 100644
index 60109a4..0000000
--- a/fs_mgr/libsnapshot/snapshot_stats.h
+++ /dev/null
@@ -1,45 +0,0 @@
-// 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.
-
-#pragma once
-
-#include <chrono>
-
-#include <android/snapshot/snapshot.pb.h>
-#include <libsnapshot/snapshot.h>
-
-namespace android {
-namespace snapshot {
-
-class SnapshotMergeStats {
- public:
- SnapshotMergeStats(SnapshotManager& parent);
- ~SnapshotMergeStats();
- void Start();
- void Resume();
- void set_state(android::snapshot::UpdateState state);
- SnapshotMergeReport GetReport();
-
- private:
- bool ReadState();
- bool WriteState();
-
- const SnapshotManager& parent_;
- SnapshotMergeReport report_;
- std::chrono::time_point<std::chrono::steady_clock> init_time_;
- std::chrono::time_point<std::chrono::steady_clock> end_time_;
-};
-
-} // namespace snapshot
-} // namespace android
diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp
index 5d2840f..7d16ec2 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -506,9 +506,6 @@
}
TEST_F(SnapshotTest, FirstStageMountAndMerge) {
-#ifdef SKIP_TEST_IN_PRESUBMIT
- GTEST_SKIP() << "WIP failure b/148889015";
-#endif
ASSERT_TRUE(AcquireLock());
static const uint64_t kDeviceSize = 1024 * 1024;
@@ -565,9 +562,6 @@
}
TEST_F(SnapshotTest, FlashSuperDuringMerge) {
-#ifdef SKIP_TEST_IN_PRESUBMIT
- GTEST_SKIP() << "WIP failure b/148889015";
-#endif
ASSERT_TRUE(AcquireLock());
static const uint64_t kDeviceSize = 1024 * 1024;
@@ -979,9 +973,6 @@
// Also test UnmapUpdateSnapshot unmaps everything.
// Also test first stage mount and merge after this.
TEST_F(SnapshotUpdateTest, FullUpdateFlow) {
-#ifdef SKIP_TEST_IN_PRESUBMIT
- GTEST_SKIP() << "WIP failure b/148889015";
-#endif
// OTA client blindly unmaps all partitions that are possibly mapped.
for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
ASSERT_TRUE(sm->UnmapUpdateSnapshot(name));
@@ -1129,9 +1120,6 @@
// Test that the old partitions are not modified.
TEST_F(SnapshotUpdateTest, TestRollback) {
-#ifdef SKIP_TEST_IN_PRESUBMIT
- GTEST_SKIP() << "WIP failure b/148889015";
-#endif
// Execute the update.
ASSERT_TRUE(sm->BeginUpdate());
ASSERT_TRUE(sm->UnmapUpdateSnapshot("sys_b"));
@@ -1309,9 +1297,6 @@
}
TEST_F(SnapshotUpdateTest, MergeCannotRemoveCow) {
-#ifdef SKIP_TEST_IN_PRESUBMIT
- GTEST_SKIP() << "WIP failure b/148889015";
-#endif
// Make source partitions as big as possible to force COW image to be created.
SetSize(sys_, 5_MiB);
SetSize(vnd_, 5_MiB);
@@ -1585,48 +1570,6 @@
<< "FinishedSnapshotWrites should detect overflow of CoW device.";
}
-TEST_F(SnapshotUpdateTest, WaitForMerge) {
-#ifdef SKIP_TEST_IN_PRESUBMIT
- GTEST_SKIP() << "WIP failure b/148889015";
-#endif
- AddOperationForPartitions();
-
- // Execute the update.
- ASSERT_TRUE(sm->BeginUpdate());
- ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
-
- // Write some data to target partitions.
- for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
- ASSERT_TRUE(WriteSnapshotAndHash(name));
- }
-
- ASSERT_TRUE(sm->FinishedSnapshotWrites());
-
- // Simulate shutting down the device.
- ASSERT_TRUE(UnmapAll());
-
- // After reboot, init does first stage mount.
- {
- auto init = SnapshotManager::NewForFirstStageMount(new TestDeviceInfo(fake_super, "_b"));
- ASSERT_NE(nullptr, init);
- ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
- }
-
- auto new_sm = SnapshotManager::New(new TestDeviceInfo(fake_super, "_b"));
- ASSERT_NE(nullptr, new_sm);
-
- auto waiter = std::async(std::launch::async, [&new_sm] { return new_sm->WaitForMerge(); });
- ASSERT_EQ(std::future_status::timeout, waiter.wait_for(1s))
- << "WaitForMerge should block when not initiated";
-
- auto merger =
- std::async(std::launch::async, [&new_sm] { return new_sm->InitiateMergeAndWait(); });
- // Small images, so should be merged pretty quickly.
- ASSERT_EQ(std::future_status::ready, waiter.wait_for(3s)) << "WaitForMerge did not finish";
- ASSERT_TRUE(waiter.get());
- ASSERT_THAT(merger.get(), AnyOf(UpdateState::None, UpdateState::MergeCompleted));
-}
-
TEST_F(SnapshotUpdateTest, LowSpace) {
static constexpr auto kMaxFree = 10_MiB;
auto userdata = std::make_unique<LowSpaceUserdata>();
diff --git a/fs_mgr/libsnapshot/snapshotctl.cpp b/fs_mgr/libsnapshot/snapshotctl.cpp
index 34d3d69..aa5e9c1 100644
--- a/fs_mgr/libsnapshot/snapshotctl.cpp
+++ b/fs_mgr/libsnapshot/snapshotctl.cpp
@@ -26,9 +26,9 @@
#include <android-base/unique_fd.h>
#include <android/snapshot/snapshot.pb.h>
#include <libsnapshot/snapshot.h>
+#include <libsnapshot/snapshot_stats.h>
#include <statslog.h>
-#include "snapshot_stats.h"
#include "utility.h"
using namespace std::string_literals;
@@ -178,6 +178,7 @@
}
LOG(ERROR) << "Snapshot failed to merge with state \"" << state << "\".";
+
return false;
}
diff --git a/fs_mgr/libsnapshot/snapshotctl.rc b/fs_mgr/libsnapshot/snapshotctl.rc
deleted file mode 100644
index 5dbe352..0000000
--- a/fs_mgr/libsnapshot/snapshotctl.rc
+++ /dev/null
@@ -1,2 +0,0 @@
-on property:sys.boot_completed=1
- exec_background - root root -- /system/bin/snapshotctl merge --logcat --log-to-file
diff --git a/fs_mgr/tests/fs_mgr_test.cpp b/fs_mgr/tests/fs_mgr_test.cpp
index 9caae35..16e38f1 100644
--- a/fs_mgr/tests/fs_mgr_test.cpp
+++ b/fs_mgr/tests/fs_mgr_test.cpp
@@ -27,6 +27,7 @@
#include <android-base/file.h>
#include <android-base/properties.h>
#include <android-base/strings.h>
+#include <fs_mgr.h>
#include <fstab/fstab.h>
#include <gtest/gtest.h>
@@ -1001,6 +1002,10 @@
}
Fstab fstab;
ASSERT_TRUE(ReadDefaultFstab(&fstab)) << "Failed to read default fstab";
- ASSERT_NE(nullptr, GetMountedEntryForUserdata(&fstab))
+ Fstab proc_mounts;
+ ASSERT_TRUE(ReadFstabFromFile("/proc/mounts", &proc_mounts)) << "Failed to read /proc/mounts";
+ auto mounted_entry = GetEntryForMountPoint(&proc_mounts, "/data");
+ ASSERT_NE(mounted_entry, nullptr) << "/data is not mounted";
+ ASSERT_NE(nullptr, fs_mgr_get_mounted_entry_for_userdata(&fstab, *mounted_entry))
<< "/data wasn't mounted from default fstab";
}
diff --git a/init/Android.bp b/init/Android.bp
index f28934e..52628f3 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -28,6 +28,7 @@
"rlimit_parser.cpp",
"service.cpp",
"service_list.cpp",
+ "service_lock.cpp",
"service_parser.cpp",
"service_utils.cpp",
"subcontext.cpp",
@@ -81,6 +82,7 @@
"-Wextra",
"-Wno-unused-parameter",
"-Werror",
+ "-Wthread-safety",
"-DALLOW_FIRST_STAGE_CONSOLE=0",
"-DALLOW_LOCAL_PROP_OVERRIDE=0",
"-DALLOW_PERMISSIVE_SELINUX=0",
@@ -88,6 +90,7 @@
"-DWORLD_WRITABLE_KMSG=0",
"-DDUMP_ON_UMOUNT_FAILURE=0",
"-DSHUTDOWN_ZERO_TIMEOUT=0",
+ "-DINIT_FULL_SOURCES",
],
product_variables: {
debuggable: {
@@ -267,6 +270,37 @@
static_libs: ["libinit"],
}
+cc_defaults {
+ name: "libinit_test_utils_libraries_defaults",
+ shared_libs: [
+ "libbase",
+ "libcutils",
+ "libselinux",
+ "libhidl-gen-utils",
+ "liblog",
+ "libprocessgroup",
+ "libprotobuf-cpp-lite",
+ ],
+}
+
+cc_library_static {
+ name: "libinit_test_utils",
+ defaults: ["libinit_test_utils_libraries_defaults"],
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Wno-unused-parameter",
+ "-Werror",
+ ],
+ srcs: init_common_sources + [
+ "test_utils/service_utils.cpp",
+ ],
+ whole_static_libs: [
+ "libcap",
+ ],
+ export_include_dirs: ["test_utils/include"], // for tests
+}
+
// Host Verifier
// ------------------------------------------------------------------------------
diff --git a/init/action_manager.cpp b/init/action_manager.cpp
index ebca762..b45f5cd 100644
--- a/init/action_manager.cpp
+++ b/init/action_manager.cpp
@@ -41,10 +41,12 @@
}
void ActionManager::QueueEventTrigger(const std::string& trigger) {
+ auto lock = std::lock_guard{event_queue_lock_};
event_queue_.emplace(trigger);
}
void ActionManager::QueuePropertyChange(const std::string& name, const std::string& value) {
+ auto lock = std::lock_guard{event_queue_lock_};
event_queue_.emplace(std::make_pair(name, value));
}
@@ -53,6 +55,7 @@
}
void ActionManager::QueueBuiltinAction(BuiltinFunction func, const std::string& name) {
+ auto lock = std::lock_guard{event_queue_lock_};
auto action = std::make_unique<Action>(true, nullptr, "<Builtin Action>", 0, name,
std::map<std::string, std::string>{});
action->AddCommand(std::move(func), {name}, 0);
@@ -62,15 +65,18 @@
}
void ActionManager::ExecuteOneCommand() {
- // Loop through the event queue until we have an action to execute
- while (current_executing_actions_.empty() && !event_queue_.empty()) {
- for (const auto& action : actions_) {
- if (std::visit([&action](const auto& event) { return action->CheckEvent(event); },
- event_queue_.front())) {
- current_executing_actions_.emplace(action.get());
+ {
+ auto lock = std::lock_guard{event_queue_lock_};
+ // Loop through the event queue until we have an action to execute
+ while (current_executing_actions_.empty() && !event_queue_.empty()) {
+ for (const auto& action : actions_) {
+ if (std::visit([&action](const auto& event) { return action->CheckEvent(event); },
+ event_queue_.front())) {
+ current_executing_actions_.emplace(action.get());
+ }
}
+ event_queue_.pop();
}
- event_queue_.pop();
}
if (current_executing_actions_.empty()) {
@@ -103,6 +109,7 @@
}
bool ActionManager::HasMoreCommands() const {
+ auto lock = std::lock_guard{event_queue_lock_};
return !current_executing_actions_.empty() || !event_queue_.empty();
}
@@ -113,6 +120,7 @@
}
void ActionManager::ClearQueue() {
+ auto lock = std::lock_guard{event_queue_lock_};
// We are shutting down so don't claim the oneshot builtin actions back
current_executing_actions_ = {};
event_queue_ = {};
diff --git a/init/action_manager.h b/init/action_manager.h
index a2b95ac..b6f93d9 100644
--- a/init/action_manager.h
+++ b/init/action_manager.h
@@ -16,9 +16,12 @@
#pragma once
+#include <mutex>
#include <string>
#include <vector>
+#include <android-base/thread_annotations.h>
+
#include "action.h"
#include "builtins.h"
@@ -48,7 +51,9 @@
void operator=(ActionManager const&) = delete;
std::vector<std::unique_ptr<Action>> actions_;
- std::queue<std::variant<EventTrigger, PropertyChange, BuiltinAction>> event_queue_;
+ std::queue<std::variant<EventTrigger, PropertyChange, BuiltinAction>> event_queue_
+ GUARDED_BY(event_queue_lock_);
+ mutable std::mutex event_queue_lock_;
std::queue<const Action*> current_executing_actions_;
std::size_t current_command_;
};
diff --git a/init/action_parser.cpp b/init/action_parser.cpp
index f316871..52f6a1f 100644
--- a/init/action_parser.cpp
+++ b/init/action_parser.cpp
@@ -21,7 +21,7 @@
#include <android-base/properties.h>
#include <android-base/strings.h>
-#if defined(__ANDROID__)
+#ifdef INIT_FULL_SOURCES
#include "property_service.h"
#include "selinux.h"
#else
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 200bfff..dd5af72 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -151,6 +151,7 @@
template <typename F>
static void ForEachServiceInClass(const std::string& classname, F function) {
+ auto lock = std::lock_guard{service_lock};
for (const auto& service : ServiceList::GetInstance()) {
if (service->classnames().count(classname)) std::invoke(function, service);
}
@@ -162,6 +163,7 @@
return {};
// Starting a class does not start services which are explicitly disabled.
// They must be started individually.
+ auto lock = std::lock_guard{service_lock};
for (const auto& service : ServiceList::GetInstance()) {
if (service->classnames().count(args[1])) {
if (auto result = service->StartIfNotDisabled(); !result.ok()) {
@@ -184,6 +186,7 @@
// stopped either.
return {};
}
+ auto lock = std::lock_guard{service_lock};
for (const auto& service : ServiceList::GetInstance()) {
if (service->classnames().count(args[1])) {
if (auto result = service->StartIfPostData(); !result.ok()) {
@@ -234,6 +237,7 @@
}
static Result<void> do_enable(const BuiltinArguments& args) {
+ auto lock = std::lock_guard{service_lock};
Service* svc = ServiceList::GetInstance().FindService(args[1]);
if (!svc) return Error() << "Could not find service";
@@ -245,6 +249,7 @@
}
static Result<void> do_exec(const BuiltinArguments& args) {
+ auto lock = std::lock_guard{service_lock};
auto service = Service::MakeTemporaryOneshotService(args.args);
if (!service.ok()) {
return Error() << "Could not create exec service: " << service.error();
@@ -258,6 +263,7 @@
}
static Result<void> do_exec_background(const BuiltinArguments& args) {
+ auto lock = std::lock_guard{service_lock};
auto service = Service::MakeTemporaryOneshotService(args.args);
if (!service.ok()) {
return Error() << "Could not create exec background service: " << service.error();
@@ -271,6 +277,7 @@
}
static Result<void> do_exec_start(const BuiltinArguments& args) {
+ auto lock = std::lock_guard{service_lock};
Service* service = ServiceList::GetInstance().FindService(args[1]);
if (!service) {
return Error() << "Service not found";
@@ -340,6 +347,7 @@
}
static Result<void> do_interface_restart(const BuiltinArguments& args) {
+ auto lock = std::lock_guard{service_lock};
Service* svc = ServiceList::GetInstance().FindInterface(args[1]);
if (!svc) return Error() << "interface " << args[1] << " not found";
svc->Restart();
@@ -347,6 +355,7 @@
}
static Result<void> do_interface_start(const BuiltinArguments& args) {
+ auto lock = std::lock_guard{service_lock};
Service* svc = ServiceList::GetInstance().FindInterface(args[1]);
if (!svc) return Error() << "interface " << args[1] << " not found";
if (auto result = svc->Start(); !result.ok()) {
@@ -356,6 +365,7 @@
}
static Result<void> do_interface_stop(const BuiltinArguments& args) {
+ auto lock = std::lock_guard{service_lock};
Service* svc = ServiceList::GetInstance().FindInterface(args[1]);
if (!svc) return Error() << "interface " << args[1] << " not found";
svc->Stop();
@@ -740,6 +750,7 @@
}
static Result<void> do_start(const BuiltinArguments& args) {
+ auto lock = std::lock_guard{service_lock};
Service* svc = ServiceList::GetInstance().FindService(args[1]);
if (!svc) return Error() << "service " << args[1] << " not found";
if (auto result = svc->Start(); !result.ok()) {
@@ -749,6 +760,7 @@
}
static Result<void> do_stop(const BuiltinArguments& args) {
+ auto lock = std::lock_guard{service_lock};
Service* svc = ServiceList::GetInstance().FindService(args[1]);
if (!svc) return Error() << "service " << args[1] << " not found";
svc->Stop();
@@ -756,6 +768,7 @@
}
static Result<void> do_restart(const BuiltinArguments& args) {
+ auto lock = std::lock_guard{service_lock};
Service* svc = ServiceList::GetInstance().FindService(args[1]);
if (!svc) return Error() << "service " << args[1] << " not found";
svc->Restart();
@@ -1111,6 +1124,7 @@
function(StringPrintf("Exec service failed, status %d", siginfo.si_status));
}
});
+ auto lock = std::lock_guard{service_lock};
if (auto result = (*service)->ExecStart(); !result.ok()) {
function("ExecStart failed: " + result.error().message());
}
@@ -1250,6 +1264,7 @@
}
success &= parser.ParseConfigFile(c);
}
+ auto lock = std::lock_guard{service_lock};
ServiceList::GetInstance().MarkServicesUpdate();
if (success) {
return {};
diff --git a/init/init.cpp b/init/init.cpp
index 5bf1b36..b0f929c 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -33,7 +33,9 @@
#include <functional>
#include <map>
#include <memory>
+#include <mutex>
#include <optional>
+#include <thread>
#include <vector>
#include <android-base/chrono_utils.h>
@@ -95,15 +97,148 @@
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;
-static std::string wait_prop_value;
-static std::string shutdown_command;
-static bool do_shutdown = false;
-
static std::unique_ptr<Subcontext> subcontext;
+// Init epolls various FDs to wait for various inputs. It previously waited on property changes
+// with a blocking socket that contained the information related to the change, however, it was easy
+// to fill that socket and deadlock the system. Now we use locks to handle the property changes
+// directly in the property thread, however we still must wake the epoll to inform init that there
+// is a change to process, so we use this FD. It is non-blocking, since we do not care how many
+// times WakeEpoll() is called, only that the epoll will wake.
+static int wake_epoll_fd = -1;
+static void InstallInitNotifier(Epoll* epoll) {
+ int sockets[2];
+ if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0, sockets) != 0) {
+ PLOG(FATAL) << "Failed to socketpair() between property_service and init";
+ }
+ int epoll_fd = sockets[0];
+ wake_epoll_fd = sockets[1];
+
+ auto drain_socket = [epoll_fd] {
+ char buf[512];
+ while (read(epoll_fd, buf, sizeof(buf)) > 0) {
+ }
+ };
+
+ if (auto result = epoll->RegisterHandler(epoll_fd, drain_socket); !result) {
+ LOG(FATAL) << result.error();
+ }
+}
+
+static void WakeEpoll() {
+ constexpr char value[] = "1";
+ write(wake_epoll_fd, value, sizeof(value));
+}
+
+static class PropWaiterState {
+ public:
+ bool StartWaiting(const char* name, const char* value) {
+ auto lock = std::lock_guard{lock_};
+ if (waiting_for_prop_) {
+ return false;
+ }
+ if (GetProperty(name, "") != value) {
+ // Current property value is not equal to expected value
+ wait_prop_name_ = name;
+ wait_prop_value_ = value;
+ waiting_for_prop_.reset(new Timer());
+ } else {
+ LOG(INFO) << "start_waiting_for_property(\"" << name << "\", \"" << value
+ << "\"): already set";
+ }
+ return true;
+ }
+
+ void ResetWaitForProp() {
+ auto lock = std::lock_guard{lock_};
+ ResetWaitForPropLocked();
+ }
+
+ void CheckAndResetWait(const std::string& name, const std::string& value) {
+ auto lock = std::lock_guard{lock_};
+ // We always record how long init waited for ueventd to tell us cold boot finished.
+ // If we aren't waiting on this property, it means that ueventd finished before we even
+ // started to wait.
+ if (name == kColdBootDoneProp) {
+ auto time_waited = waiting_for_prop_ ? waiting_for_prop_->duration().count() : 0;
+ std::thread([time_waited] {
+ SetProperty("ro.boottime.init.cold_boot_wait", std::to_string(time_waited));
+ }).detach();
+ }
+
+ if (waiting_for_prop_) {
+ if (wait_prop_name_ == name && wait_prop_value_ == value) {
+ LOG(INFO) << "Wait for property '" << wait_prop_name_ << "=" << wait_prop_value_
+ << "' took " << *waiting_for_prop_;
+ ResetWaitForPropLocked();
+ WakeEpoll();
+ }
+ }
+ }
+
+ // This is not thread safe because it releases the lock when it returns, so the waiting state
+ // may change. However, we only use this function to prevent running commands in the main
+ // thread loop when we are waiting, so we do not care about false positives; only false
+ // negatives. StartWaiting() and this function are always called from the same thread, so false
+ // negatives are not possible and therefore we're okay.
+ bool MightBeWaiting() {
+ auto lock = std::lock_guard{lock_};
+ return static_cast<bool>(waiting_for_prop_);
+ }
+
+ private:
+ void ResetWaitForPropLocked() {
+ wait_prop_name_.clear();
+ wait_prop_value_.clear();
+ waiting_for_prop_.reset();
+ }
+
+ std::mutex lock_;
+ std::unique_ptr<Timer> waiting_for_prop_{nullptr};
+ std::string wait_prop_name_;
+ std::string wait_prop_value_;
+
+} prop_waiter_state;
+
+bool start_waiting_for_property(const char* name, const char* value) {
+ return prop_waiter_state.StartWaiting(name, value);
+}
+
+void ResetWaitForProp() {
+ prop_waiter_state.ResetWaitForProp();
+}
+
+static class ShutdownState {
+ public:
+ void TriggerShutdown(const std::string& command) {
+ // We can't call HandlePowerctlMessage() directly in this function,
+ // because it modifies the contents of the action queue, which can cause the action queue
+ // to get into a bad state if this function is called from a command being executed by the
+ // action queue. Instead we set this flag and ensure that shutdown happens before the next
+ // command is run in the main init loop.
+ auto lock = std::lock_guard{shutdown_command_lock_};
+ shutdown_command_ = command;
+ do_shutdown_ = true;
+ WakeEpoll();
+ }
+
+ std::optional<std::string> CheckShutdown() {
+ auto lock = std::lock_guard{shutdown_command_lock_};
+ if (do_shutdown_ && !IsShuttingDown()) {
+ do_shutdown_ = false;
+ return shutdown_command_;
+ }
+ return {};
+ }
+
+ private:
+ std::mutex shutdown_command_lock_;
+ std::string shutdown_command_;
+ bool do_shutdown_ = false;
+} shutdown_state;
+
void DumpState() {
+ auto lock = std::lock_guard{service_lock};
ServiceList::GetInstance().DumpState();
ActionManager::GetInstance().DumpState();
}
@@ -156,40 +291,7 @@
}
}
-bool start_waiting_for_property(const char *name, const char *value)
-{
- if (waiting_for_prop) {
- return false;
- }
- if (GetProperty(name, "") != value) {
- // Current property value is not equal to expected value
- wait_prop_name = name;
- wait_prop_value = value;
- waiting_for_prop.reset(new Timer());
- } else {
- LOG(INFO) << "start_waiting_for_property(\""
- << name << "\", \"" << value << "\"): already set";
- }
- return true;
-}
-
-void ResetWaitForProp() {
- wait_prop_name.clear();
- wait_prop_value.clear();
- waiting_for_prop.reset();
-}
-
-static void TriggerShutdown(const std::string& command) {
- // We can't call HandlePowerctlMessage() directly in this function,
- // because it modifies the contents of the action queue, which can cause the action queue
- // to get into a bad state if this function is called from a command being executed by the
- // action queue. Instead we set this flag and ensure that shutdown happens before the next
- // command is run in the main init loop.
- shutdown_command = command;
- do_shutdown = true;
-}
-
-void property_changed(const std::string& name, const std::string& value) {
+void PropertyChanged(const std::string& name, const std::string& value) {
// If the property is sys.powerctl, we bypass the event queue and immediately handle it.
// This is to ensure that init will always and immediately shutdown/reboot, regardless of
// if there are other pending events to process or if init is waiting on an exec service or
@@ -197,30 +299,20 @@
// In non-thermal-shutdown case, 'shutdown' trigger will be fired to let device specific
// commands to be executed.
if (name == "sys.powerctl") {
- TriggerShutdown(value);
+ trigger_shutdown(value);
}
- if (property_triggers_enabled) ActionManager::GetInstance().QueuePropertyChange(name, value);
-
- // We always record how long init waited for ueventd to tell us cold boot finished.
- // If we aren't waiting on this property, it means that ueventd finished before we even started
- // to wait.
- if (name == kColdBootDoneProp) {
- auto time_waited = waiting_for_prop ? waiting_for_prop->duration().count() : 0;
- SetProperty("ro.boottime.init.cold_boot_wait", std::to_string(time_waited));
+ if (property_triggers_enabled) {
+ ActionManager::GetInstance().QueuePropertyChange(name, value);
+ WakeEpoll();
}
- if (waiting_for_prop) {
- if (wait_prop_name == name && wait_prop_value == value) {
- LOG(INFO) << "Wait for property '" << wait_prop_name << "=" << wait_prop_value
- << "' took " << *waiting_for_prop;
- ResetWaitForProp();
- }
- }
+ prop_waiter_state.CheckAndResetWait(name, value);
}
static std::optional<boot_clock::time_point> HandleProcessActions() {
std::optional<boot_clock::time_point> next_process_action_time;
+ auto lock = std::lock_guard{service_lock};
for (const auto& s : ServiceList::GetInstance()) {
if ((s->flags() & SVC_RUNNING) && s->timeout_period()) {
auto timeout_time = s->time_started() + *s->timeout_period();
@@ -249,7 +341,7 @@
return next_process_action_time;
}
-static Result<void> DoControlStart(Service* service) {
+static Result<void> DoControlStart(Service* service) REQUIRES(service_lock) {
return service->Start();
}
@@ -258,7 +350,7 @@
return {};
}
-static Result<void> DoControlRestart(Service* service) {
+static Result<void> DoControlRestart(Service* service) REQUIRES(service_lock) {
service->Restart();
return {};
}
@@ -292,7 +384,7 @@
return control_message_functions;
}
-bool HandleControlMessage(const std::string& msg, const std::string& name, pid_t pid) {
+bool HandleControlMessage(const std::string& msg, const std::string& name, pid_t from_pid) {
const auto& map = get_control_message_map();
const auto it = map.find(msg);
@@ -301,7 +393,7 @@
return false;
}
- std::string cmdline_path = StringPrintf("proc/%d/cmdline", pid);
+ std::string cmdline_path = StringPrintf("proc/%d/cmdline", from_pid);
std::string process_cmdline;
if (ReadFileToString(cmdline_path, &process_cmdline)) {
std::replace(process_cmdline.begin(), process_cmdline.end(), '\0', ' ');
@@ -312,6 +404,8 @@
const ControlMessageFunction& function = it->second;
+ auto lock = std::lock_guard{service_lock};
+
Service* svc = nullptr;
switch (function.target) {
@@ -329,23 +423,24 @@
if (svc == nullptr) {
LOG(ERROR) << "Control message: Could not find '" << name << "' for ctl." << msg
- << " from pid: " << pid << " (" << process_cmdline << ")";
+ << " from pid: " << from_pid << " (" << process_cmdline << ")";
return false;
}
if (auto result = function.action(svc); !result.ok()) {
LOG(ERROR) << "Control message: Could not ctl." << msg << " for '" << name
- << "' from pid: " << pid << " (" << process_cmdline << "): " << result.error();
+ << "' from pid: " << from_pid << " (" << process_cmdline
+ << "): " << result.error();
return false;
}
LOG(INFO) << "Control message: Processed ctl." << msg << " for '" << name
- << "' from pid: " << pid << " (" << process_cmdline << ")";
+ << "' from pid: " << from_pid << " (" << process_cmdline << ")";
return true;
}
static Result<void> wait_for_coldboot_done_action(const BuiltinArguments& args) {
- if (!start_waiting_for_property(kColdBootDoneProp, "true")) {
+ if (!prop_waiter_state.StartWaiting(kColdBootDoneProp, "true")) {
LOG(FATAL) << "Could not wait for '" << kColdBootDoneProp << "'";
}
@@ -493,6 +588,7 @@
}
auto found = false;
+ auto lock = std::lock_guard{service_lock};
for (const auto& service : ServiceList::GetInstance()) {
auto svc = service.get();
if (svc->keycodes() == keycodes) {
@@ -579,44 +675,6 @@
}
}
-static void HandlePropertyFd() {
- auto message = ReadMessage(property_fd);
- if (!message.ok()) {
- 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();
@@ -624,7 +682,7 @@
boot_clock::time_point start_time = boot_clock::now();
- trigger_shutdown = TriggerShutdown;
+ trigger_shutdown = [](const std::string& command) { shutdown_state.TriggerShutdown(command); };
SetStdioToDevNull(argv);
InitKernelLogging(argv);
@@ -684,11 +742,8 @@
}
InstallSignalFdHandler(&epoll);
-
+ InstallInitNotifier(&epoll);
StartPropertyService(&property_fd);
- if (auto result = epoll.RegisterHandler(property_fd, HandlePropertyFd); !result.ok()) {
- LOG(FATAL) << "Could not register epoll handler for property fd: " << result.error();
- }
// Make the time that init stages started available for bootstat to log.
RecordStageBoottimes(start_time);
@@ -723,11 +778,10 @@
if (false) DumpState();
// Make the GSI status available before scripts start running.
- if (android::gsi::IsGsiRunning()) {
- SetProperty("ro.gsid.image_running", "1");
- } else {
- SetProperty("ro.gsid.image_running", "0");
- }
+ auto is_running = android::gsi::IsGsiRunning() ? "1" : "0";
+ SetProperty(gsi::kGsiBootedProp, is_running);
+ auto is_installed = android::gsi::IsGsiInstalled() ? "1" : "0";
+ SetProperty(gsi::kGsiInstalledProp, is_installed);
am.QueueBuiltinAction(SetupCgroupsAction, "SetupCgroups");
am.QueueBuiltinAction(SetKptrRestrictAction, "SetKptrRestrict");
@@ -742,6 +796,7 @@
Keychords keychords;
am.QueueBuiltinAction(
[&epoll, &keychords](const BuiltinArguments& args) -> Result<void> {
+ auto lock = std::lock_guard{service_lock};
for (const auto& svc : ServiceList::GetInstance()) {
keychords.Register(svc->keycodes());
}
@@ -772,12 +827,12 @@
// By default, sleep until something happens.
auto epoll_timeout = std::optional<std::chrono::milliseconds>{};
- if (do_shutdown && !IsShuttingDown()) {
- do_shutdown = false;
- HandlePowerctlMessage(shutdown_command);
+ auto shutdown_command = shutdown_state.CheckShutdown();
+ if (shutdown_command) {
+ HandlePowerctlMessage(*shutdown_command);
}
- if (!(waiting_for_prop || Service::is_exec_service_running())) {
+ if (!(prop_waiter_state.MightBeWaiting() || Service::is_exec_service_running())) {
am.ExecuteOneCommand();
}
if (!IsShuttingDown()) {
@@ -791,7 +846,7 @@
}
}
- if (!(waiting_for_prop || Service::is_exec_service_running())) {
+ if (!(prop_waiter_state.MightBeWaiting() || Service::is_exec_service_running())) {
// If there's more work to do, wake up again immediately.
if (am.HasMoreCommands()) epoll_timeout = 0ms;
}
diff --git a/init/init.h b/init/init.h
index 4bbca6f..bcf24e7 100644
--- a/init/init.h
+++ b/init/init.h
@@ -41,6 +41,9 @@
void SendStopSendingMessagesMessage();
void SendStartSendingMessagesMessage();
+void PropertyChanged(const std::string& name, const std::string& value);
+bool HandleControlMessage(const std::string& msg, const std::string& name, pid_t from_pid);
+
int SecondStageMain(int argc, char** argv);
} // namespace init
diff --git a/init/init_test.cpp b/init/init_test.cpp
index caf3e03..3053bd8 100644
--- a/init/init_test.cpp
+++ b/init/init_test.cpp
@@ -167,6 +167,7 @@
ServiceList service_list;
TestInitText(init_script, BuiltinFunctionMap(), {}, &service_list);
+ auto lock = std::lock_guard{service_lock};
ASSERT_EQ(1, std::distance(service_list.begin(), service_list.end()));
auto service = service_list.begin()->get();
diff --git a/init/lmkd_service.cpp b/init/lmkd_service.cpp
index dd1ab4d..a531d0a 100644
--- a/init/lmkd_service.cpp
+++ b/init/lmkd_service.cpp
@@ -79,7 +79,8 @@
}
static void RegisterServices(pid_t exclude_pid) {
- for (const auto& service : ServiceList::GetInstance().services()) {
+ auto lock = std::lock_guard{service_lock};
+ for (const auto& service : ServiceList::GetInstance()) {
auto svc = service.get();
if (svc->oom_score_adjust() != DEFAULT_OOM_SCORE_ADJUST) {
// skip if process is excluded or not yet forked (pid==0)
diff --git a/init/mount_namespace.cpp b/init/mount_namespace.cpp
index 0749fe3..2175075 100644
--- a/init/mount_namespace.cpp
+++ b/init/mount_namespace.cpp
@@ -29,6 +29,7 @@
#include <android-base/unique_fd.h>
#include <apex_manifest.pb.h>
+#include "property_service.h"
#include "util.h"
namespace android {
@@ -290,6 +291,14 @@
return true;
}
if (default_ns_id != GetMountNamespaceId()) {
+ // The property service thread and its descendent threads must be in the correct mount
+ // namespace to call Service::Start(), however setns() only operates on a single thread and
+ // fails when secondary threads attempt to join the same mount namespace. Therefore, we
+ // must join the property service thread and its descendents before the setns() call. Those
+ // threads are then started again after the setns() call, and they'll be in the proper
+ // namespace.
+ PausePropertyService();
+
if (setns(default_ns_fd.get(), CLONE_NEWNS) == -1) {
PLOG(ERROR) << "Failed to switch back to the default mount namespace.";
return false;
@@ -299,6 +308,8 @@
LOG(ERROR) << result.error();
return false;
}
+
+ ResumePropertyService();
}
LOG(INFO) << "Switched to default mount namespace";
@@ -312,10 +323,20 @@
}
if (bootstrap_ns_id != GetMountNamespaceId() && bootstrap_ns_fd.get() != -1 &&
IsApexUpdatable()) {
+ // The property service thread and its descendent threads must be in the correct mount
+ // namespace to call Service::Start(), however setns() only operates on a single thread and
+ // fails when secondary threads attempt to join the same mount namespace. Therefore, we
+ // must join the property service thread and its descendents before the setns() call. Those
+ // threads are then started again after the setns() call, and they'll be in the proper
+ // namespace.
+ PausePropertyService();
+
if (setns(bootstrap_ns_fd.get(), CLONE_NEWNS) == -1) {
PLOG(ERROR) << "Failed to switch to bootstrap mount namespace.";
return false;
}
+
+ ResumePropertyService();
}
return true;
}
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 84644e8..319a241 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -92,8 +92,10 @@
static bool persistent_properties_loaded = false;
static int property_set_fd = -1;
+static int from_init_socket = -1;
static int init_socket = -1;
static bool accept_messages = false;
+static std::thread property_service_thread;
static PropertyInfoAreaFile property_info_area;
@@ -147,17 +149,6 @@
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.ok()) {
- 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();
@@ -196,47 +187,137 @@
// 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 (accept_messages) {
- SendPropertyChanged(name, value);
+ PropertyChanged(name, value);
}
return PROP_SUCCESS;
}
-class AsyncRestorecon {
+template <typename T>
+class SingleThreadExecutor {
public:
- void TriggerRestorecon(const std::string& path) {
- auto guard = std::lock_guard{mutex_};
- paths_.emplace(path);
+ virtual ~SingleThreadExecutor() {}
- if (!thread_started_) {
- thread_started_ = true;
- std::thread{&AsyncRestorecon::ThreadFunction, this}.detach();
+ template <typename F = T>
+ void Run(F&& item) {
+ auto guard = std::lock_guard{mutex_};
+ items_.emplace(std::forward<F>(item));
+
+ if (thread_state_ == ThreadState::kRunning || thread_state_ == ThreadState::kStopped) {
+ return;
+ }
+
+ if (thread_state_ == ThreadState::kPendingJoin) {
+ thread_.join();
+ }
+
+ StartThread();
+ }
+
+ void StopAndJoin() {
+ auto lock = std::unique_lock{mutex_};
+ if (thread_state_ == ThreadState::kPendingJoin) {
+ thread_.join();
+ } else if (thread_state_ == ThreadState::kRunning) {
+ thread_state_ = ThreadState::kStopped;
+ lock.unlock();
+ thread_.join();
+ lock.lock();
+ }
+
+ thread_state_ = ThreadState::kStopped;
+ }
+
+ void Restart() {
+ auto guard = std::lock_guard{mutex_};
+ if (items_.empty()) {
+ thread_state_ = ThreadState::kNotStarted;
+ } else {
+ StartThread();
+ }
+ }
+
+ void MaybeJoin() {
+ auto guard = std::lock_guard{mutex_};
+ if (thread_state_ == ThreadState::kPendingJoin) {
+ thread_.join();
+ thread_state_ = ThreadState::kNotStarted;
}
}
private:
+ virtual void Execute(T&& item) = 0;
+
+ void StartThread() {
+ thread_state_ = ThreadState::kRunning;
+ auto thread = std::thread{&SingleThreadExecutor::ThreadFunction, this};
+ std::swap(thread_, thread);
+ }
+
void ThreadFunction() {
auto lock = std::unique_lock{mutex_};
- while (!paths_.empty()) {
- auto path = paths_.front();
- paths_.pop();
+ while (!items_.empty()) {
+ auto item = items_.front();
+ items_.pop();
lock.unlock();
- if (selinux_android_restorecon(path.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE) != 0) {
- LOG(ERROR) << "Asynchronous restorecon of '" << path << "' failed'";
- }
- android::base::SetProperty(kRestoreconProperty, path);
+ Execute(std::move(item));
lock.lock();
}
- thread_started_ = false;
+ if (thread_state_ != ThreadState::kStopped) {
+ thread_state_ = ThreadState::kPendingJoin;
+ }
}
std::mutex mutex_;
- std::queue<std::string> paths_;
- bool thread_started_ = false;
+ std::queue<T> items_;
+ enum class ThreadState {
+ kNotStarted, // Initial state when starting the program or when restarting with no items to
+ // process.
+ kRunning, // The thread is running and is in a state that it will process new items if
+ // are run.
+ kPendingJoin, // The thread has run to completion and is pending join(). A new thread must
+ // be launched for new items to be processed.
+ kStopped, // This executor has stopped and will not process more items until Restart() is
+ // called. Currently pending items will be processed and the thread will be
+ // joined.
+ };
+ ThreadState thread_state_ = ThreadState::kNotStarted;
+ std::thread thread_;
};
+class RestoreconThread : public SingleThreadExecutor<std::string> {
+ virtual void Execute(std::string&& path) override {
+ if (selinux_android_restorecon(path.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE) != 0) {
+ LOG(ERROR) << "Asynchronous restorecon of '" << path << "' failed'";
+ }
+ android::base::SetProperty(kRestoreconProperty, path);
+ }
+};
+
+struct ControlMessageInfo {
+ std::string message;
+ std::string name;
+ pid_t pid;
+ int fd;
+};
+
+class ControlMessageThread : public SingleThreadExecutor<ControlMessageInfo> {
+ virtual void Execute(ControlMessageInfo&& info) override {
+ bool success = HandleControlMessage(info.message, info.name, info.pid);
+
+ uint32_t response = success ? PROP_SUCCESS : PROP_ERROR_HANDLE_CONTROL_MESSAGE;
+ if (info.fd != -1) {
+ TEMP_FAILURE_RETRY(send(info.fd, &response, sizeof(response), 0));
+ close(info.fd);
+ }
+ }
+};
+
+static RestoreconThread restorecon_thread;
+static ControlMessageThread control_message_thread;
+
class SocketConnection {
public:
SocketConnection(int socket, const ucred& cred) : socket_(socket), cred_(cred) {}
@@ -378,29 +459,17 @@
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().
+ // We must release the fd before spawning the thread, otherwise there will be a race with the
+ // thread. If the thread calls close() before this function calls Release(), then fdsan will see
+ // the wrong tag and abort().
int fd = -1;
if (socket != nullptr && SelinuxGetVendorAndroidVersion() > __ANDROID_API_Q__) {
fd = socket->Release();
- control_message->set_fd(fd);
}
- if (auto result = SendMessage(init_socket, property_msg); !result.ok()) {
- // 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;
- }
+ // Handling a control message likely calls SetProperty, which we must synchronously handle,
+ // therefore we must fork a thread to handle it.
+ control_message_thread.Run({msg, name, pid, fd});
return PROP_SUCCESS;
}
@@ -502,8 +571,7 @@
// We use a thread to do this restorecon operation to prevent holding up init, as it may take
// a long time to complete.
if (name == kRestoreconProperty && cr.pid != 1 && !value.empty()) {
- static AsyncRestorecon async_restorecon;
- async_restorecon.TriggerRestorecon(value);
+ restorecon_thread.Run(value);
return PROP_SUCCESS;
}
@@ -745,7 +813,9 @@
static void update_sys_usb_config() {
bool is_debuggable = android::base::GetBoolProperty("ro.debuggable", false);
std::string config = android::base::GetProperty("persist.sys.usb.config", "");
- if (config.empty()) {
+ // b/150130503, add (config == "none") condition here to prevent appending
+ // ",adb" if "none" is explicitly defined in default prop.
+ if (config.empty() || config == "none") {
InitPropertySet("persist.sys.usb.config", is_debuggable ? "adb" : "none");
} else if (is_debuggable && config.find("adb") == std::string::npos &&
config.length() + 4 < PROP_VALUE_MAX) {
@@ -1082,6 +1152,8 @@
PropertyLoadBootDefaults();
}
+static bool pause_property_service = false;
+
static void HandleInitSocket() {
auto message = ReadMessage(init_socket);
if (!message.ok()) {
@@ -1116,6 +1188,10 @@
accept_messages = true;
break;
}
+ case InitMessage::kPausePropertyService: {
+ pause_property_service = true;
+ break;
+ }
default:
LOG(ERROR) << "Unknown message type from init: " << init_message.msg_case();
}
@@ -1136,7 +1212,7 @@
LOG(FATAL) << result.error();
}
- while (true) {
+ while (!pause_property_service) {
auto pending_functions = epoll.Wait(std::nullopt);
if (!pending_functions.ok()) {
LOG(ERROR) << pending_functions.error();
@@ -1145,9 +1221,34 @@
(*function)();
}
}
+ control_message_thread.MaybeJoin();
+ restorecon_thread.MaybeJoin();
}
}
+void SendStopPropertyServiceMessage() {
+ auto init_message = InitMessage{};
+ init_message.set_pause_property_service(true);
+ if (auto result = SendMessage(from_init_socket, init_message); !result.ok()) {
+ LOG(ERROR) << "Failed to send stop property service message: " << result.error();
+ }
+}
+
+void PausePropertyService() {
+ control_message_thread.StopAndJoin();
+ restorecon_thread.StopAndJoin();
+ SendStopPropertyServiceMessage();
+ property_service_thread.join();
+}
+
+void ResumePropertyService() {
+ pause_property_service = false;
+ auto new_thread = std::thread{PropertyServiceThread};
+ property_service_thread.swap(new_thread);
+ restorecon_thread.Restart();
+ control_message_thread.Restart();
+}
+
void StartPropertyService(int* epoll_socket) {
InitPropertySet("ro.property_service.version", "2");
@@ -1155,7 +1256,7 @@
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];
+ *epoll_socket = from_init_socket = sockets[0];
init_socket = sockets[1];
accept_messages = true;
@@ -1169,7 +1270,8 @@
listen(property_set_fd, 8);
- std::thread{PropertyServiceThread}.detach();
+ auto new_thread = std::thread{PropertyServiceThread};
+ property_service_thread.swap(new_thread);
}
} // namespace init
diff --git a/init/property_service.h b/init/property_service.h
index 506d116..e921326 100644
--- a/init/property_service.h
+++ b/init/property_service.h
@@ -31,6 +31,8 @@
void PropertyInit();
void StartPropertyService(int* epoll_socket);
+void ResumePropertyService();
+void PausePropertyService();
} // namespace init
} // namespace android
diff --git a/init/property_service.proto b/init/property_service.proto
index 08268d9..36245b2 100644
--- a/init/property_service.proto
+++ b/init/property_service.proto
@@ -41,5 +41,6 @@
bool load_persistent_properties = 1;
bool stop_sending_messages = 2;
bool start_sending_messages = 3;
+ bool pause_property_service = 4;
};
}
diff --git a/init/reboot.cpp b/init/reboot.cpp
index 048c1e7..cad192d 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -85,7 +85,7 @@
static const std::set<std::string> kDebuggingServices{"tombstoned", "logd", "adbd", "console"};
-static std::vector<Service*> GetDebuggingServices(bool only_post_data) {
+static std::vector<Service*> GetDebuggingServices(bool only_post_data) REQUIRES(service_lock) {
std::vector<Service*> ret;
ret.reserve(kDebuggingServices.size());
for (const auto& s : ServiceList::GetInstance()) {
@@ -96,8 +96,10 @@
return ret;
}
-static void PersistRebootReason(const char* reason) {
- SetProperty(LAST_REBOOT_REASON_PROPERTY, reason);
+static void PersistRebootReason(const char* reason, bool write_to_property) {
+ if (write_to_property) {
+ SetProperty(LAST_REBOOT_REASON_PROPERTY, reason);
+ }
WriteStringToFile(reason, LAST_REBOOT_REASON_FILE);
}
@@ -179,7 +181,7 @@
};
// Turn off backlight while we are performing power down cleanup activities.
-static void TurnOffBacklight() {
+static void TurnOffBacklight() REQUIRES(service_lock) {
Service* service = ServiceList::GetInstance().FindService("blank_screen");
if (service == nullptr) {
LOG(WARNING) << "cannot find blank_screen in TurnOffBacklight";
@@ -535,14 +537,6 @@
Timer t;
LOG(INFO) << "Reboot start, reason: " << reason << ", reboot_target: " << reboot_target;
- // If /data isn't mounted then we can skip the extra reboot steps below, since we don't need to
- // worry about unmounting it.
- if (!IsDataMounted()) {
- sync();
- RebootSystem(cmd, reboot_target);
- abort();
- }
-
// Ensure last reboot reason is reduced to canonical
// alias reported in bootloader or system boot reason.
size_t skip = 0;
@@ -552,9 +546,17 @@
reasons[1] == "hard" || reasons[1] == "warm")) {
skip = strlen("reboot,");
}
- PersistRebootReason(reason.c_str() + skip);
+ PersistRebootReason(reason.c_str() + skip, true);
sync();
+ // If /data isn't mounted then we can skip the extra reboot steps below, since we don't need to
+ // worry about unmounting it.
+ if (!IsDataMounted()) {
+ sync();
+ RebootSystem(cmd, reboot_target);
+ abort();
+ }
+
bool is_thermal_shutdown = cmd == ANDROID_RB_THERMOFF;
auto shutdown_timeout = 0ms;
@@ -587,6 +589,7 @@
// Start reboot monitor thread
sem_post(&reboot_semaphore);
+ auto lock = std::lock_guard{service_lock};
// watchdogd is a vendor specific component but should be alive to complete shutdown safely.
const std::set<std::string> to_starts{"watchdogd"};
std::vector<Service*> stop_first;
@@ -706,6 +709,7 @@
// Skip wait for prop if it is in progress
ResetWaitForProp();
// Clear EXEC flag if there is one pending
+ auto lock = std::lock_guard{service_lock};
for (const auto& s : ServiceList::GetInstance()) {
s->UnSetExec();
}
@@ -749,6 +753,7 @@
return Error() << "Failed to set sys.init.userspace_reboot.in_progress property";
}
EnterShutdown();
+ auto lock = std::lock_guard{service_lock};
if (!SetProperty("sys.powerctl", "")) {
return Error() << "Failed to reset sys.powerctl property";
}
@@ -815,6 +820,7 @@
LOG(INFO) << "Re-enabling service '" << s->name() << "'";
s->Enable();
}
+ ServiceList::GetInstance().ResetState();
LeaveShutdown();
ActionManager::GetInstance().QueueEventTrigger("userspace-reboot-resume");
guard.Disable(); // Go on with userspace reboot.
@@ -833,7 +839,8 @@
if (!WaitForProperty("sys.boot_completed", "1", timeout)) {
LOG(ERROR) << "Failed to boot in " << timeout.count() << "ms. Switching to full reboot";
// In this case device is in a boot loop. Only way to recover is to do dirty reboot.
- PersistRebootReason("userspace_failed,watchdog_triggered");
+ // Since init might be wedged, don't try to write reboot reason into a persistent property.
+ PersistRebootReason("userspace_failed,watchdog_triggered", false);
RebootSystem(ANDROID_RB_RESTART2, "userspace_failed,watchdog_triggered");
}
LOG(INFO) << "Device booted, stopping userspace reboot watchdog";
@@ -907,6 +914,7 @@
run_fsck = true;
} else if (cmd_params[1] == "thermal") {
// Turn off sources of heat immediately.
+ auto lock = std::lock_guard{service_lock};
TurnOffBacklight();
// run_fsck is false to avoid delay
cmd = ANDROID_RB_THERMOFF;
diff --git a/init/selinux.cpp b/init/selinux.cpp
index c5b7576..acbcbd6 100644
--- a/init/selinux.cpp
+++ b/init/selinux.cpp
@@ -66,6 +66,7 @@
#include <android-base/unique_fd.h>
#include <fs_avb/fs_avb.h>
#include <libgsi/libgsi.h>
+#include <libsnapshot/snapshot.h>
#include <selinux/android.h>
#include "debug_ramdisk.h"
@@ -78,6 +79,7 @@
using android::base::Timer;
using android::base::unique_fd;
using android::fs_mgr::AvbHandle;
+using android::snapshot::SnapshotManager;
namespace android {
namespace init {
@@ -535,7 +537,11 @@
selinux_android_restorecon("/linkerconfig", 0);
- selinux_android_restorecon(gsi::kDsuAvbKeyDir, SELINUX_ANDROID_RESTORECON_RECURSE);
+ // adb remount, snapshot-based updates, and DSUs all create files during
+ // first-stage init.
+ selinux_android_restorecon("/metadata", SELINUX_ANDROID_RESTORECON_RECURSE);
+
+ selinux_android_restorecon(SnapshotManager::GetGlobalRollbackIndicatorPath().c_str(), 0);
}
int SelinuxKlogCallback(int type, const char* fmt, ...) {
diff --git a/init/service.cpp b/init/service.cpp
index 665a1b0..b12d11a 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -40,7 +40,7 @@
#include "service_list.h"
#include "util.h"
-#if defined(__ANDROID__)
+#ifdef INIT_FULL_SOURCES
#include <ApexProperties.sysprop.h>
#include <android/api-level.h>
@@ -303,7 +303,7 @@
return;
}
-#if defined(__ANDROID__)
+#if INIT_FULL_SOURCES
static bool is_apex_updatable = android::sysprop::ApexProperties::updatable().value_or(false);
#else
static bool is_apex_updatable = false;
diff --git a/init/service.h b/init/service.h
index cf3f0c2..d2a4462 100644
--- a/init/service.h
+++ b/init/service.h
@@ -27,12 +27,14 @@
#include <vector>
#include <android-base/chrono_utils.h>
+#include <android-base/thread_annotations.h>
#include <cutils/iosched_policy.h>
#include "action.h"
#include "capabilities.h"
#include "keyword_map.h"
#include "parser.h"
+#include "service_lock.h"
#include "service_utils.h"
#include "subcontext.h"
@@ -77,17 +79,17 @@
bool IsRunning() { return (flags_ & SVC_RUNNING) != 0; }
bool IsEnabled() { return (flags_ & SVC_DISABLED) == 0; }
- Result<void> ExecStart();
- Result<void> Start();
- Result<void> StartIfNotDisabled();
- Result<void> StartIfPostData();
- Result<void> Enable();
+ Result<void> ExecStart() REQUIRES(service_lock);
+ Result<void> Start() REQUIRES(service_lock);
+ Result<void> StartIfNotDisabled() REQUIRES(service_lock);
+ Result<void> StartIfPostData() REQUIRES(service_lock);
+ Result<void> Enable() REQUIRES(service_lock);
void Reset();
void ResetIfPostData();
void Stop();
void Terminate();
void Timeout();
- void Restart();
+ void Restart() REQUIRES(service_lock);
void Reap(const siginfo_t& siginfo);
void DumpState() const;
void SetShutdownCritical() { flags_ |= SVC_SHUTDOWN_CRITICAL; }
diff --git a/init/service_list.h b/init/service_list.h
index 1838624..280a228 100644
--- a/init/service_list.h
+++ b/init/service_list.h
@@ -17,9 +17,13 @@
#pragma once
#include <memory>
+#include <mutex>
#include <vector>
+#include <android-base/thread_annotations.h>
+
#include "service.h"
+#include "service_lock.h"
namespace android {
namespace init {
@@ -32,16 +36,16 @@
ServiceList();
size_t CheckAllCommands();
- void AddService(std::unique_ptr<Service> service);
- void RemoveService(const Service& svc);
+ void AddService(std::unique_ptr<Service> service) REQUIRES(service_lock);
+ void RemoveService(const Service& svc) REQUIRES(service_lock);
template <class UnaryPredicate>
- void RemoveServiceIf(UnaryPredicate predicate) {
+ void RemoveServiceIf(UnaryPredicate predicate) REQUIRES(service_lock) {
services_.erase(std::remove_if(services_.begin(), services_.end(), predicate),
services_.end());
}
template <typename T, typename F = decltype(&Service::name)>
- Service* FindService(T value, F function = &Service::name) const {
+ Service* FindService(T value, F function = &Service::name) const REQUIRES(service_lock) {
auto svc = std::find_if(services_.begin(), services_.end(),
[&function, &value](const std::unique_ptr<Service>& s) {
return std::invoke(function, s) == value;
@@ -52,7 +56,7 @@
return nullptr;
}
- Service* FindInterface(const std::string& interface_name) {
+ Service* FindInterface(const std::string& interface_name) REQUIRES(service_lock) {
for (const auto& svc : services_) {
if (svc->interfaces().count(interface_name) > 0) {
return svc.get();
@@ -62,18 +66,25 @@
return nullptr;
}
- void DumpState() const;
+ void DumpState() const REQUIRES(service_lock);
- auto begin() const { return services_.begin(); }
- auto end() const { return services_.end(); }
- const std::vector<std::unique_ptr<Service>>& services() const { return services_; }
- const std::vector<Service*> services_in_shutdown_order() const;
+ auto begin() const REQUIRES(service_lock) { return services_.begin(); }
+ auto end() const REQUIRES(service_lock) { return services_.end(); }
+ const std::vector<std::unique_ptr<Service>>& services() const REQUIRES(service_lock) {
+ return services_;
+ }
+ const std::vector<Service*> services_in_shutdown_order() const REQUIRES(service_lock);
void MarkPostData();
bool IsPostData();
- void MarkServicesUpdate();
+ void MarkServicesUpdate() REQUIRES(service_lock);
bool IsServicesUpdated() const { return services_update_finished_; }
- void DelayService(const Service& service);
+ void DelayService(const Service& service) REQUIRES(service_lock);
+
+ void ResetState() {
+ post_data_ = false;
+ services_update_finished_ = false;
+ }
private:
std::vector<std::unique_ptr<Service>> services_;
diff --git a/init/service_lock.cpp b/init/service_lock.cpp
new file mode 100644
index 0000000..404d439
--- /dev/null
+++ b/init/service_lock.cpp
@@ -0,0 +1,25 @@
+/*
+ * 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 "service_lock.h"
+
+namespace android {
+namespace init {
+
+RecursiveMutex service_lock;
+
+} // namespace init
+} // namespace android
diff --git a/init/service_lock.h b/init/service_lock.h
new file mode 100644
index 0000000..6b94271
--- /dev/null
+++ b/init/service_lock.h
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <mutex>
+
+#include <android-base/thread_annotations.h>
+
+namespace android {
+namespace init {
+
+// This class exists to add thread annotations, since they're absent from std::recursive_mutex.
+
+class CAPABILITY("mutex") RecursiveMutex {
+ public:
+ void lock() ACQUIRE() { mutex_.lock(); }
+ void unlock() RELEASE() { mutex_.unlock(); }
+
+ private:
+ std::recursive_mutex mutex_;
+};
+
+extern RecursiveMutex service_lock;
+
+} // namespace init
+} // namespace android
diff --git a/init/service_parser.cpp b/init/service_parser.cpp
index 4b04ba0..51f4c97 100644
--- a/init/service_parser.cpp
+++ b/init/service_parser.cpp
@@ -34,7 +34,7 @@
#include "service_utils.h"
#include "util.h"
-#if defined(__ANDROID__)
+#ifdef INIT_FULL_SOURCES
#include <android/api-level.h>
#include <sys/system_properties.h>
@@ -168,6 +168,7 @@
const std::string fullname = interface_name + "/" + instance_name;
+ auto lock = std::lock_guard{service_lock};
for (const auto& svc : *service_list_) {
if (svc->interfaces().count(fullname) > 0) {
return Error() << "Interface '" << fullname << "' redefined in " << service_->name()
@@ -598,6 +599,7 @@
}
}
+ auto lock = std::lock_guard{service_lock};
Service* old_service = service_list_->FindService(service_->name());
if (old_service) {
if (!service_->is_override()) {
diff --git a/init/sigchld_handler.cpp b/init/sigchld_handler.cpp
index 9b2c7d9..064d64d 100644
--- a/init/sigchld_handler.cpp
+++ b/init/sigchld_handler.cpp
@@ -64,6 +64,8 @@
std::string wait_string;
Service* service = nullptr;
+ auto lock = std::lock_guard{service_lock};
+
if (SubcontextChildReap(pid)) {
name = "Subcontext";
} else {
diff --git a/init/subcontext.cpp b/init/subcontext.cpp
index 3260159..5263c14 100644
--- a/init/subcontext.cpp
+++ b/init/subcontext.cpp
@@ -31,7 +31,7 @@
#include "proto_utils.h"
#include "util.h"
-#if defined(__ANDROID__)
+#ifdef INIT_FULL_SOURCES
#include <android/api-level.h>
#include "property_service.h"
#include "selabel.h"
diff --git a/init/test_utils/Android.bp b/init/test_utils/Android.bp
deleted file mode 100644
index 1cb05b6..0000000
--- a/init/test_utils/Android.bp
+++ /dev/null
@@ -1,27 +0,0 @@
-cc_library_static {
- name: "libinit_test_utils",
- cflags: [
- "-Wall",
- "-Wextra",
- "-Wno-unused-parameter",
- "-Werror",
- ],
- srcs: [
- "service_utils.cpp",
- ],
- shared_libs: [
- "libcutils",
- "liblog",
- "libjsoncpp",
- "libprotobuf-cpp-lite",
- "libhidl-gen-utils",
- ],
- whole_static_libs: [
- "libinit",
- "libpropertyinfoparser",
- ],
- static_libs: [
- "libbase",
- ],
- export_include_dirs: ["include"], // for tests
-}
diff --git a/init/util.cpp b/init/util.cpp
index 503c705..24f94ec 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -41,7 +41,7 @@
#include <cutils/sockets.h>
#include <selinux/android.h>
-#if defined(__ANDROID__)
+#ifdef INIT_FULL_SOURCES
#include <android/api-level.h>
#include <sys/system_properties.h>
diff --git a/libcutils/include/cutils/trace.h b/libcutils/include/cutils/trace.h
index e12c32c..c74ee3e 100644
--- a/libcutils/include/cutils/trace.h
+++ b/libcutils/include/cutils/trace.h
@@ -88,12 +88,6 @@
#error ATRACE_TAG must be defined to be one of the tags defined in cutils/trace.h
#endif
-// Set this to 0 to revert to the old Binder-based atrace implementation.
-// This is only here in case rollbacks do not apply cleanly.
-// TODO(fmayer): Remove this once we are confident this won't need to be
-// rolled back, no later than 2020-03-01.
-#define ATRACE_SHMEM 1
-
/**
* Opens the trace file for writing and reads the property for initial tags.
* The atrace.tags.enableflags property sets the tags to trace.
@@ -121,15 +115,11 @@
* prevent tracing within the Zygote process.
*/
void atrace_set_tracing_enabled(bool enabled);
+
/**
- * If !ATRACE_SHMEM:
- * Flag indicating whether setup has been completed, initialized to 0.
- * Nonzero indicates setup has completed.
- * Note: This does NOT indicate whether or not setup was successful.
- * If ATRACE_SHMEM:
- * This is always set to false. This forces code that uses an old version
- * of this header to always call into atrace_setup, in which we call
- * atrace_init unconditionally.
+ * This is always set to false. This forces code that uses an old version
+ * of this header to always call into atrace_setup, in which we call
+ * atrace_init unconditionally.
*/
extern atomic_bool atrace_is_ready;
@@ -154,28 +144,8 @@
#define ATRACE_INIT() atrace_init()
#define ATRACE_GET_ENABLED_TAGS() atrace_get_enabled_tags()
-#if ATRACE_SHMEM
void atrace_init();
uint64_t atrace_get_enabled_tags();
-#else
-static inline void atrace_init()
-{
- if (CC_UNLIKELY(!atomic_load_explicit(&atrace_is_ready, memory_order_acquire))) {
- atrace_setup();
- }
-}
-
-/**
- * Get the mask of all tags currently enabled.
- * It can be used as a guard condition around more expensive trace calculations.
- * Every trace function calls this, which ensures atrace_init is run.
- */
-static inline uint64_t atrace_get_enabled_tags()
-{
- atrace_init();
- return atrace_enabled_tags;
-}
-#endif
/**
* Test if a given tag is currently enabled.
diff --git a/libcutils/trace-dev.cpp b/libcutils/trace-dev.cpp
index 9ca1729..5a09a2d 100644
--- a/libcutils/trace-dev.cpp
+++ b/libcutils/trace-dev.cpp
@@ -41,9 +41,6 @@
} else {
atrace_enabled_tags = atrace_get_property();
}
-#if !ATRACE_SHMEM
- atomic_store_explicit(&atrace_is_ready, true, memory_order_release);
-#endif
}
static void atrace_seq_number_changed(uint32_t prev_seq_no, uint32_t seq_no) {
@@ -69,11 +66,7 @@
void atrace_setup()
{
-#if ATRACE_SHMEM
atrace_init();
-#else
- pthread_once(&atrace_once_control, atrace_init_once);
-#endif
}
void atrace_begin_body(const char* name)
diff --git a/libcutils/trace-dev.inc b/libcutils/trace-dev.inc
index a57a4c5..3ec98b3 100644
--- a/libcutils/trace-dev.inc
+++ b/libcutils/trace-dev.inc
@@ -71,8 +71,6 @@
static const prop_info* atrace_property_info = reinterpret_cast<const prop_info*>(empty_pi);
#endif
-#if ATRACE_SHMEM
-
/**
* This is called when the sequence number of debug.atrace.tags.enableflags
* changes and we need to reload the enabled tags.
@@ -96,7 +94,6 @@
atrace_init();
return atrace_enabled_tags;
}
-#endif
// Set whether this process is debuggable, which determines whether
// application-level tracing is allowed when the ro.debuggable system property
@@ -186,19 +183,17 @@
void atrace_update_tags()
{
uint64_t tags;
- if (ATRACE_SHMEM || CC_UNLIKELY(atomic_load_explicit(&atrace_is_ready, memory_order_acquire))) {
- if (atomic_load_explicit(&atrace_is_enabled, memory_order_acquire)) {
- tags = atrace_get_property();
- pthread_mutex_lock(&atrace_tags_mutex);
- atrace_enabled_tags = tags;
- pthread_mutex_unlock(&atrace_tags_mutex);
- } else {
- // Tracing is disabled for this process, so we simply don't
- // initialize the tags.
- pthread_mutex_lock(&atrace_tags_mutex);
- atrace_enabled_tags = ATRACE_TAG_NOT_READY;
- pthread_mutex_unlock(&atrace_tags_mutex);
- }
+ if (atomic_load_explicit(&atrace_is_enabled, memory_order_acquire)) {
+ tags = atrace_get_property();
+ pthread_mutex_lock(&atrace_tags_mutex);
+ atrace_enabled_tags = tags;
+ pthread_mutex_unlock(&atrace_tags_mutex);
+ } else {
+ // Tracing is disabled for this process, so we simply don't
+ // initialize the tags.
+ pthread_mutex_lock(&atrace_tags_mutex);
+ atrace_enabled_tags = ATRACE_TAG_NOT_READY;
+ pthread_mutex_unlock(&atrace_tags_mutex);
}
}
diff --git a/libcutils/trace-host.cpp b/libcutils/trace-host.cpp
index c21d0ee..9781ad3 100644
--- a/libcutils/trace-host.cpp
+++ b/libcutils/trace-host.cpp
@@ -30,10 +30,8 @@
void atrace_async_end_body(const char* /*name*/, int32_t /*cookie*/) {}
void atrace_int_body(const char* /*name*/, int32_t /*value*/) {}
void atrace_int64_body(const char* /*name*/, int64_t /*value*/) {}
-#if ATRACE_SHMEM
void atrace_init() {}
uint64_t atrace_get_enabled_tags()
{
return ATRACE_TAG_NOT_READY;
}
-#endif
diff --git a/liblog/Android.bp b/liblog/Android.bp
index 7f183c2..f1e5118 100644
--- a/liblog/Android.bp
+++ b/liblog/Android.bp
@@ -101,11 +101,6 @@
versions: ["29", "30"],
},
- // TODO(tomcherry): Renable this before release branch is cut
- header_abi_checker: {
- enabled: false,
- },
-
cflags: [
"-Wall",
"-Werror",
diff --git a/liblog/liblog.map.txt b/liblog/liblog.map.txt
index 198cdae..9dcbbc9 100644
--- a/liblog/liblog.map.txt
+++ b/liblog/liblog.map.txt
@@ -65,7 +65,7 @@
android_log_parser_reset; # llndk
};
-LIGLOG_R { # introduced=30
+LIBLOG_R { # introduced=30
global:
__android_log_call_aborter;
__android_log_default_aborter;
diff --git a/libstats/pull/Android.bp b/libstats/pull/Android.bp
index d74a36b..1a9cb92 100644
--- a/libstats/pull/Android.bp
+++ b/libstats/pull/Android.bp
@@ -17,8 +17,8 @@
// ==========================================================
// Native library to register a pull atom callback with statsd
// ==========================================================
-cc_library_shared {
- name: "libstatspull",
+cc_defaults {
+ name: "libstatspull_defaults",
srcs: [
"stats_pull_atom_callback.cpp",
],
@@ -31,12 +31,16 @@
"libbinder_ndk",
"liblog",
"statsd-aidl-ndk_platform",
+ "libstatssocket",
],
static_libs: [
"libutils",
- // TODO(b/149340100): Clean this up when libstatssocket is moved to the apex.
- "libstatssocket",
- "libcutils",
+ ],
+}
+cc_library_shared {
+ name: "libstatspull",
+ defaults: [
+ "libstatspull_defaults"
],
// enumerate stable entry points for APEX use
stubs: {
@@ -50,3 +54,14 @@
"test_com.android.os.statsd",
],
}
+
+// ONLY USE IN TESTS.
+cc_library_static {
+ name: "libstatspull_private",
+ defaults: [
+ "libstatspull_defaults",
+ ],
+ visibility: [
+ "//frameworks/base/apex/statsd/tests/libstatspull",
+ ],
+}
diff --git a/libstats/socket/Android.bp b/libstats/socket/Android.bp
index 437879b..b02ab42 100644
--- a/libstats/socket/Android.bp
+++ b/libstats/socket/Android.bp
@@ -17,23 +17,43 @@
// =========================================================================
// Native library to write stats log to statsd socket on Android R and later
// =========================================================================
-cc_library {
- name: "libstatssocket",
+cc_defaults {
+ name: "libstatssocket_defaults",
srcs: [
"stats_buffer_writer.c",
"stats_event.c",
"stats_socket.c",
"statsd_writer.c",
],
- host_supported: true,
- cflags: [
- "-Wall",
- "-Werror",
- ],
export_include_dirs: ["include"],
static_libs: [
"libcutils", // does not expose a stable C API
],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+}
+
+cc_library {
+ name: "libstatssocket",
+ defaults: [
+ "libstatssocket_defaults",
+ ],
+ host_supported: true,
+ target: {
+ // On android, libstatssocket should only be linked as a shared lib
+ android: {
+ static: {
+ enabled: false,
+ },
+ },
+ host: {
+ shared: {
+ enabled: false,
+ },
+ },
+ },
// enumerate stable entry points for APEX use
stubs: {
@@ -43,13 +63,23 @@
],
},
apex_available: [
- //TODO(b/149340100): Remove this once libstatssocket is only linked as shared.
- "//apex_available:platform",
"com.android.os.statsd",
"test_com.android.os.statsd",
],
}
+//TODO (b/149842105): Figure out if there is a better solution for this.
+cc_test_library {
+ name: "libstatssocket_private",
+ defaults: [
+ "libstatssocket_defaults",
+ ],
+ visibility: [
+ "//frameworks/base/apex/statsd/tests/libstatspull",
+ "//frameworks/base/cmds/statsd",
+ ],
+}
+
cc_library_headers {
name: "libstatssocket_headers",
export_include_dirs: ["include"],
@@ -67,7 +97,7 @@
"-Werror",
],
static_libs: [
- "libstatssocket",
+ "libstatssocket_private",
],
shared_libs: [
"libcutils",
@@ -84,7 +114,7 @@
],
static_libs: [
"libgmock",
- "libstatssocket",
+ "libstatssocket_private",
],
shared_libs: [
"libcutils",
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index 834b20b..1cf2061 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -207,31 +207,37 @@
// exact entry with time specified in ms or us precision.
if ((realtime.tv_nsec % 1000) == 0) ++realtime.tv_nsec;
- LogBufferElement* elem =
- new LogBufferElement(log_id, realtime, uid, pid, tid, msg, len);
- if (log_id != LOG_ID_SECURITY) {
- int prio = ANDROID_LOG_INFO;
- const char* tag = nullptr;
- size_t tag_len = 0;
- if (log_id == LOG_ID_EVENTS || log_id == LOG_ID_STATS) {
- tag = tagToName(elem->getTag());
- if (tag) {
- tag_len = strlen(tag);
- }
- } else {
- prio = *msg;
- tag = msg + 1;
- tag_len = strnlen(tag, len - 1);
+ LogBufferElement* elem = new LogBufferElement(log_id, realtime, uid, pid, tid, msg, len);
+
+ // b/137093665: don't coalesce security messages.
+ if (log_id == LOG_ID_SECURITY) {
+ wrlock();
+ log(elem);
+ unlock();
+
+ return len;
+ }
+
+ int prio = ANDROID_LOG_INFO;
+ const char* tag = nullptr;
+ size_t tag_len = 0;
+ if (log_id == LOG_ID_EVENTS || log_id == LOG_ID_STATS) {
+ tag = tagToName(elem->getTag());
+ if (tag) {
+ tag_len = strlen(tag);
}
- if (!__android_log_is_loggable_len(prio, tag, tag_len,
- ANDROID_LOG_VERBOSE)) {
- // Log traffic received to total
- wrlock();
- stats.addTotal(elem);
- unlock();
- delete elem;
- return -EACCES;
- }
+ } else {
+ prio = *msg;
+ tag = msg + 1;
+ tag_len = strnlen(tag, len - 1);
+ }
+ if (!__android_log_is_loggable_len(prio, tag, tag_len, ANDROID_LOG_VERBOSE)) {
+ // Log traffic received to total
+ wrlock();
+ stats.addTotal(elem);
+ unlock();
+ delete elem;
+ return -EACCES;
}
wrlock();
diff --git a/logwrapper/logwrap.cpp b/logwrapper/logwrap.cpp
index 5337801..5a518bc 100644
--- a/logwrapper/logwrap.cpp
+++ b/logwrapper/logwrap.cpp
@@ -374,7 +374,7 @@
}
if (log_target & LOG_FILE) {
- fd = open(file_path, O_WRONLY | O_CREAT, 0664);
+ fd = open(file_path, O_WRONLY | O_CREAT | O_CLOEXEC, 0664);
if (fd < 0) {
ERROR("Cannot log to file %s\n", file_path);
log_target &= ~LOG_FILE;
diff --git a/rootdir/init.rc b/rootdir/init.rc
index ae9d695..c59f911 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -701,9 +701,7 @@
# A tmpfs directory, which will contain all apps CE DE data directory that
# bind mount from the original source.
- chown root root /data_mirror
- chmod 0700 /data_mirror
- mount tmpfs tmpfs /data_mirror mode=0700,uid=0,gid=1000 nodev noexec nosuid
+ mount tmpfs tmpfs /data_mirror nodev noexec nosuid mode=0700,uid=0,gid=1000
restorecon /data_mirror
mkdir /data_mirror/data_ce 0700 root root
mkdir /data_mirror/data_de 0700 root root