Merge "Refine the exported DSU status"
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/apex/Android.bp b/adb/apex/Android.bp
index 0189455..4346f67 100644
--- a/adb/apex/Android.bp
+++ b/adb/apex/Android.bp
@@ -1,5 +1,6 @@
apex_defaults {
name: "com.android.adbd-defaults",
+ updatable: true,
binaries: ["adbd"],
compile_multilib: "both",
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/pairing_connection/tests/pairing_connection_test.cpp b/adb/pairing_connection/tests/pairing_connection_test.cpp
index b6e09f1..86b66aa 100644
--- a/adb/pairing_connection/tests/pairing_connection_test.cpp
+++ b/adb/pairing_connection/tests/pairing_connection_test.cpp
@@ -440,7 +440,7 @@
EXPECT_FALSE(*(server_waiter.is_valid_));
}
-TEST_F(AdbPairingConnectionTest, MultipleClientsOnePass) {
+TEST_F(AdbPairingConnectionTest, DISABLED_MultipleClientsOnePass) {
// Send multiple clients with bad passwords, but send the last one with the
// correct password.
std::vector<uint8_t> pswd{0x01, 0x03, 0x05, 0x07};
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/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/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 5223087..49ca5db 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -97,6 +97,7 @@
using android::base::Basename;
using android::base::GetBoolProperty;
using android::base::Realpath;
+using android::base::SetProperty;
using android::base::StartsWith;
using android::base::Timer;
using android::base::unique_fd;
@@ -178,6 +179,7 @@
return;
}
+ Timer t;
/* Check for the types of filesystems we know how to check */
if (is_extfs(fs_type)) {
/*
@@ -253,15 +255,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 +276,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;
}
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 d274ba4..6c739fc 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",
],
@@ -238,6 +229,7 @@
"liblog",
"liblp",
"libprotobuf-cpp-lite",
+ "libstatslog",
"libutils",
// TODO(b/148818798): remove when parent bug is fixed.
diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp
index 5d2840f..0ffaa71 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);
@@ -1586,9 +1571,6 @@
}
TEST_F(SnapshotUpdateTest, WaitForMerge) {
-#ifdef SKIP_TEST_IN_PRESUBMIT
- GTEST_SKIP() << "WIP failure b/148889015";
-#endif
AddOperationForPartitions();
// Execute the update.
diff --git a/fs_mgr/libsnapshot/snapshotctl.cpp b/fs_mgr/libsnapshot/snapshotctl.cpp
index e35ad4b..34d3d69 100644
--- a/fs_mgr/libsnapshot/snapshotctl.cpp
+++ b/fs_mgr/libsnapshot/snapshotctl.cpp
@@ -24,9 +24,11 @@
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/unique_fd.h>
+#include <android/snapshot/snapshot.pb.h>
#include <libsnapshot/snapshot.h>
-#include "utility.h"
+#include <statslog.h>
+#include "snapshot_stats.h"
#include "utility.h"
using namespace std::string_literals;
@@ -37,17 +39,29 @@
"Actions:\n"
" dump\n"
" Print snapshot states.\n"
- " merge [--logcat] [--log-to-file]\n"
+ " merge [--logcat] [--log-to-file] [--report] [--dry-run]\n"
" Initialize merge and wait for it to be completed.\n"
" If --logcat is specified, log to logcat.\n"
" If --log-to-file is specified, log to /data/misc/snapshotctl_log/.\n"
- " If both specified, log to both. If none specified, log to stdout.\n";
+ " If both specified, log to both. If none specified, log to stdout.\n"
+ " If --report is specified, send merge statistics to statsd.\n"
+ " If --dry-run flag, no real merge operation is is triggered, and\n"
+ " sample statistics are sent to statsd for testing purpose.\n";
return EX_USAGE;
}
namespace android {
namespace snapshot {
+static SnapshotMergeReport GetDummySnapshotMergeReport() {
+ SnapshotMergeReport fake_report;
+
+ fake_report.set_state(UpdateState::MergeCompleted);
+ fake_report.set_resume_count(56);
+
+ return fake_report;
+}
+
bool DumpCmdHandler(int /*argc*/, char** argv) {
android::base::InitLogging(argv, &android::base::StderrLogger);
return SnapshotManager::New()->Dump(std::cout);
@@ -113,24 +127,53 @@
};
bool MergeCmdHandler(int argc, char** argv) {
- auto begin = std::chrono::steady_clock::now();
+ std::chrono::milliseconds passed_ms;
+
+ bool report_to_statsd = false;
+ bool dry_run = false;
+ for (int i = 2; i < argc; ++i) {
+ if (argv[i] == "--report"s) {
+ report_to_statsd = true;
+ } else if (argv[i] == "--dry-run"s) {
+ dry_run = true;
+ }
+ }
// 'snapshotctl merge' is stripped away from arguments to
// Logger.
android::base::InitLogging(argv);
android::base::SetLogger(MergeCmdLogger(argc - 2, argv + 2));
- auto state = SnapshotManager::New()->InitiateMergeAndWait();
+ UpdateState state;
+ SnapshotMergeReport merge_report;
+ if (dry_run) {
+ merge_report = GetDummySnapshotMergeReport();
+ state = merge_report.state();
+ passed_ms = std::chrono::milliseconds(1234);
+ } else {
+ auto begin = std::chrono::steady_clock::now();
- // We could wind up in the Unverified state if the device rolled back or
- // hasn't fully rebooted. Ignore this.
- if (state == UpdateState::None || state == UpdateState::Unverified) {
- return true;
- }
- if (state == UpdateState::MergeCompleted) {
+ state = SnapshotManager::New()->InitiateMergeAndWait(&merge_report);
+
+ // We could wind up in the Unverified state if the device rolled back or
+ // hasn't fully rebooted. Ignore this.
+ if (state == UpdateState::None || state == UpdateState::Unverified) {
+ return true;
+ }
+
auto end = std::chrono::steady_clock::now();
- auto passed = std::chrono::duration_cast<std::chrono::milliseconds>(end - begin).count();
- LOG(INFO) << "Snapshot merged in " << passed << " ms.";
+ passed_ms = std::chrono::duration_cast<std::chrono::milliseconds>(end - begin);
+ }
+
+ if (report_to_statsd) {
+ android::util::stats_write(android::util::SNAPSHOT_MERGE_REPORTED,
+ static_cast<int32_t>(merge_report.state()),
+ static_cast<int64_t>(passed_ms.count()),
+ static_cast<int32_t>(merge_report.resume_count()));
+ }
+
+ if (state == UpdateState::MergeCompleted) {
+ LOG(INFO) << "Snapshot merged in " << passed_ms.count() << " ms.";
return true;
}
diff --git a/fs_mgr/libsnapshot/snapshotctl.rc b/fs_mgr/libsnapshot/snapshotctl.rc
index 5dbe352..ccb2c41 100644
--- a/fs_mgr/libsnapshot/snapshotctl.rc
+++ b/fs_mgr/libsnapshot/snapshotctl.rc
@@ -1,2 +1,2 @@
on property:sys.boot_completed=1
- exec_background - root root -- /system/bin/snapshotctl merge --logcat --log-to-file
+ exec_background - root root -- /system/bin/snapshotctl merge --logcat --log-to-file --report
diff --git a/init/init.cpp b/init/init.cpp
index b0f929c..63aefc1 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -120,7 +120,7 @@
}
};
- if (auto result = epoll->RegisterHandler(epoll_fd, drain_socket); !result) {
+ if (auto result = epoll->RegisterHandler(epoll_fd, drain_socket); !result.ok()) {
LOG(FATAL) << result.error();
}
}
diff --git a/init/mount_namespace.cpp b/init/mount_namespace.cpp
index aa36849..2175075 100644
--- a/init/mount_namespace.cpp
+++ b/init/mount_namespace.cpp
@@ -323,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/reboot.cpp b/init/reboot.cpp
index f7cc36e..cad192d 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -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);
}
@@ -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;
@@ -818,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.
@@ -836,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";
diff --git a/init/service_list.h b/init/service_list.h
index 8cbc878..280a228 100644
--- a/init/service_list.h
+++ b/init/service_list.h
@@ -81,6 +81,11 @@
bool IsServicesUpdated() const { return services_update_finished_; }
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/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/libsync/OWNERS b/libsync/OWNERS
index dc61733..e75b15b 100644
--- a/libsync/OWNERS
+++ b/libsync/OWNERS
@@ -1,3 +1,3 @@
-ghackmann@google.com
+chrisforbes@google.com
+hridya@google.com
jessehall@google.com
-marissaw@google.com
diff --git a/libsystem/OWNERS b/libsystem/OWNERS
index fdea804..4f800d4 100644
--- a/libsystem/OWNERS
+++ b/libsystem/OWNERS
@@ -1,7 +1,6 @@
# graphics/composer
adyabr@google.com
lpy@google.com
-marissaw@google.com
stoza@google.com
vhau@google.com
diff --git a/libutils/include/utils/String16.h b/libutils/include/utils/String16.h
index 013705b..1a4b47e 100644
--- a/libutils/include/utils/String16.h
+++ b/libutils/include/utils/String16.h
@@ -187,7 +187,7 @@
ANDROID_TRIVIAL_MOVE_TRAIT(String16)
static inline std::ostream& operator<<(std::ostream& os, const String16& str) {
- os << String8(str).c_str();
+ os << String8(str);
return os;
}
diff --git a/libutils/include/utils/String8.h b/libutils/include/utils/String8.h
index d0ad314..0bcb716 100644
--- a/libutils/include/utils/String8.h
+++ b/libutils/include/utils/String8.h
@@ -17,7 +17,8 @@
#ifndef ANDROID_STRING8_H
#define ANDROID_STRING8_H
-#include <string> // for std::string
+#include <iostream>
+#include <string>
#include <utils/Errors.h>
#include <utils/Unicode.h>
@@ -232,6 +233,11 @@
// require any change to the underlying SharedBuffer contents or reference count.
ANDROID_TRIVIAL_MOVE_TRAIT(String8)
+static inline std::ostream& operator<<(std::ostream& os, const String8& str) {
+ os << str.c_str();
+ return os;
+}
+
// ---------------------------------------------------------------------------
// No user servicable parts below.
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 91dd7a5..276cc1e 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -733,7 +733,7 @@
mkdir /data/incremental 0771 system system encryption=Require
# Wait for apexd to finish activating APEXes before starting more processes.
- wait_for_prop apexd.status ready
+ wait_for_prop apexd.status activated
perform_apex_config
# Special-case /data/media/obb per b/64566063
@@ -748,7 +748,7 @@
# Allow apexd to snapshot and restore device encrypted apex data in the case
# of a rollback. This should be done immediately after DE_user data keys
# are loaded. APEXes should not access this data until this has been
- # completed.
+ # completed and apexd.status becomes "ready".
exec_start apexd-snapshotde
# Set SELinux security contexts on upgrade or policy update.