Merge "Optimize Memory::ReadString"
diff --git a/adb/Android.bp b/adb/Android.bp
index 6386a78..19e921f 100644
--- a/adb/Android.bp
+++ b/adb/Android.bp
@@ -695,6 +695,7 @@
"daemon/shell_service_test.cpp",
"shell_service_protocol.cpp",
"shell_service_protocol_test.cpp",
+ "mdns_test.cpp",
],
shared_libs: [
diff --git a/adb/adb.cpp b/adb/adb.cpp
index 08d3904..06fdb69 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -149,7 +149,7 @@
case A_WRTE: tag = "WRTE"; break;
case A_AUTH: tag = "AUTH"; break;
case A_STLS:
- tag = "ATLS";
+ tag = "STLS";
break;
default: tag = "????"; break;
}
diff --git a/adb/adb_mdns.h b/adb/adb_mdns.h
index 6b37355..3111248 100644
--- a/adb/adb_mdns.h
+++ b/adb/adb_mdns.h
@@ -19,9 +19,14 @@
#include <android-base/macros.h>
-const char* kADBServiceType = "_adb._tcp";
-const char* kADBSecurePairingServiceType = "_adb_secure_pairing._tcp";
-const char* kADBSecureConnectServiceType = "_adb_secure_connect._tcp";
+// The rules for Service Names [RFC6335] state that they may be no more
+// than fifteen characters long (not counting the mandatory underscore),
+// consisting of only letters, digits, and hyphens, must begin and end
+// with a letter or digit, must not contain consecutive hyphens, and
+// must contain at least one letter.
+#define ADB_MDNS_SERVICE_TYPE "adb"
+#define ADB_MDNS_TLS_PAIRING_TYPE "adb-tls-pairing"
+#define ADB_MDNS_TLS_CONNECT_TYPE "adb-tls-connect"
const int kADBTransportServiceRefIndex = 0;
const int kADBSecurePairingServiceRefIndex = 1;
@@ -71,11 +76,10 @@
const char* kADBSecureConnectServiceTxtRecord =
ADB_SECURE_SERVICE_VERSION_TXT_RECORD(ADB_SECURE_SERVICE_VERSION);
-const char* kADBDNSServices[] = {
- kADBServiceType,
- kADBSecurePairingServiceType,
- kADBSecureConnectServiceType,
-};
+#define ADB_FULL_MDNS_SERVICE_TYPE(atype) ("_" atype "._tcp")
+const char* kADBDNSServices[] = {ADB_FULL_MDNS_SERVICE_TYPE(ADB_MDNS_SERVICE_TYPE),
+ ADB_FULL_MDNS_SERVICE_TYPE(ADB_MDNS_TLS_PAIRING_TYPE),
+ ADB_FULL_MDNS_SERVICE_TYPE(ADB_MDNS_TLS_CONNECT_TYPE)};
const char* kADBDNSServiceTxtRecords[] = {
nullptr,
diff --git a/adb/client/adb_client.cpp b/adb/client/adb_client.cpp
index 0ad0465..31c938c 100644
--- a/adb/client/adb_client.cpp
+++ b/adb/client/adb_client.cpp
@@ -416,14 +416,18 @@
return android::base::StringPrintf("%s:%s", prefix, command);
}
-const FeatureSet& adb_get_feature_set() {
- static const android::base::NoDestructor<FeatureSet> features([] {
- std::string result;
- if (!adb_query(format_host_command("features"), &result, &result)) {
- fprintf(stderr, "failed to get feature set: %s\n", result.c_str());
- return FeatureSet{};
- }
- return StringToFeatureSet(result);
- }());
- return *features;
+const std::optional<FeatureSet>& adb_get_feature_set(std::string* error) {
+ static std::string cached_error [[clang::no_destroy]];
+ static const std::optional<FeatureSet> features
+ [[clang::no_destroy]] ([]() -> std::optional<FeatureSet> {
+ std::string result;
+ if (adb_query(format_host_command("features"), &result, &cached_error)) {
+ return StringToFeatureSet(result);
+ }
+ return std::nullopt;
+ }());
+ if (!features && error) {
+ *error = cached_error;
+ }
+ return features;
}
diff --git a/adb/client/adb_client.h b/adb/client/adb_client.h
index bf0be40..27be28f 100644
--- a/adb/client/adb_client.h
+++ b/adb/client/adb_client.h
@@ -76,7 +76,7 @@
std::string format_host_command(const char* _Nonnull command);
// Get the feature set of the current preferred transport.
-const FeatureSet& adb_get_feature_set();
+const std::optional<FeatureSet>& adb_get_feature_set(std::string* _Nullable error);
#if defined(__linux__)
// Get the path of a file containing the path to the server executable, if the socket spec set via
diff --git a/adb/client/adb_install.cpp b/adb/client/adb_install.cpp
index 3810cc8..59c8563 100644
--- a/adb/client/adb_install.cpp
+++ b/adb/client/adb_install.cpp
@@ -57,11 +57,12 @@
}
static bool can_use_feature(const char* feature) {
- auto&& features = adb_get_feature_set();
- if (features.empty()) {
+ // We ignore errors here, if the device is missing, we'll notice when we try to push install.
+ auto&& features = adb_get_feature_set(nullptr);
+ if (!features) {
return false;
}
- return CanUseFeature(features, feature);
+ return CanUseFeature(*features, feature);
}
static InstallMode best_install_mode() {
diff --git a/adb/client/auth.cpp b/adb/client/auth.cpp
index 4b2fa04..b674a81 100644
--- a/adb/client/auth.cpp
+++ b/adb/client/auth.cpp
@@ -504,6 +504,12 @@
}).detach();
}
+// Callback given to SSL_set_cert_cb to select a certificate when server requests
+// for a certificate. This is where the server will give us a CA-issuer list, and
+// figure out if the server knows any of our public keys. We currently always return
+// 1 here to indicate success, since we always try a key here (in the case of no auth).
+// See https://commondatastorage.googleapis.com/chromium-boringssl-docs/ssl.h.html#SSL_set_cert_cb
+// for more details.
int adb_tls_set_certificate(SSL* ssl) {
LOG(INFO) << __func__;
diff --git a/adb/client/commandline.cpp b/adb/client/commandline.cpp
index 6a7493f..29f9dc1 100644
--- a/adb/client/commandline.cpp
+++ b/adb/client/commandline.cpp
@@ -672,16 +672,17 @@
}
static int adb_shell(int argc, const char** argv) {
- auto&& features = adb_get_feature_set();
- if (features.empty()) {
- return 1;
+ std::string error;
+ auto&& features = adb_get_feature_set(&error);
+ if (!features) {
+ error_exit("%s", error.c_str());
}
enum PtyAllocationMode { kPtyAuto, kPtyNo, kPtyYes, kPtyDefinitely };
// Defaults.
- char escape_char = '~'; // -e
- bool use_shell_protocol = CanUseFeature(features, kFeatureShell2); // -x
+ char escape_char = '~'; // -e
+ bool use_shell_protocol = CanUseFeature(*features, kFeatureShell2); // -x
PtyAllocationMode tty = use_shell_protocol ? kPtyAuto : kPtyDefinitely; // -t/-T
// Parse shell-specific command-line options.
@@ -757,7 +758,7 @@
if (!use_shell_protocol) {
if (shell_type_arg != kShellServiceArgPty) {
fprintf(stderr, "error: %s only supports allocating a pty\n",
- !CanUseFeature(features, kFeatureShell2) ? "device" : "-x");
+ !CanUseFeature(*features, kFeatureShell2) ? "device" : "-x");
return 1;
} else {
// If we're not using the shell protocol, the type argument must be empty.
@@ -777,11 +778,13 @@
}
static int adb_abb(int argc, const char** argv) {
- auto&& features = adb_get_feature_set();
- if (features.empty()) {
+ std::string error;
+ auto&& features = adb_get_feature_set(&error);
+ if (!features) {
+ error_exit("%s", error.c_str());
return 1;
}
- if (!CanUseFeature(features, kFeatureAbb)) {
+ if (!CanUseFeature(*features, kFeatureAbb)) {
error_exit("abb is not supported by the device");
}
@@ -1159,9 +1162,9 @@
// Use shell protocol if it's supported and the caller doesn't explicitly
// disable it.
if (!disable_shell_protocol) {
- auto&& features = adb_get_feature_set();
- if (!features.empty()) {
- use_shell_protocol = CanUseFeature(features, kFeatureShell2);
+ auto&& features = adb_get_feature_set(nullptr);
+ if (features) {
+ use_shell_protocol = CanUseFeature(*features, kFeatureShell2);
} else {
// Device was unreachable.
attempt_connection = false;
@@ -1810,12 +1813,13 @@
}
return adb_connect_command(android::base::StringPrintf("tcpip:%d", port));
} else if (!strcmp(argv[0], "remount")) {
- auto&& features = adb_get_feature_set();
- if (features.empty()) {
- return 1;
+ std::string error;
+ auto&& features = adb_get_feature_set(&error);
+ if (!features) {
+ error_exit("%s", error.c_str());
}
- if (CanUseFeature(features, kFeatureRemountShell)) {
+ if (CanUseFeature(*features, kFeatureRemountShell)) {
std::vector<const char*> args = {"shell"};
args.insert(args.cend(), argv, argv + argc);
return adb_shell_noinput(args.size(), args.data());
@@ -2034,11 +2038,12 @@
} else if (!strcmp(argv[0], "track-jdwp")) {
return adb_connect_command("track-jdwp");
} else if (!strcmp(argv[0], "track-app")) {
- auto&& features = adb_get_feature_set();
- if (features.empty()) {
- return 1;
+ std::string error;
+ auto&& features = adb_get_feature_set(&error);
+ if (!features) {
+ error_exit("%s", error.c_str());
}
- if (!CanUseFeature(features, kFeatureTrackApp)) {
+ if (!CanUseFeature(*features, kFeatureTrackApp)) {
error_exit("track-app is not supported by the device");
}
TrackAppStreamsCallback callback;
@@ -2064,13 +2069,14 @@
return 0;
} else if (!strcmp(argv[0], "features")) {
// Only list the features common to both the adb client and the device.
- auto&& features = adb_get_feature_set();
- if (features.empty()) {
- return 1;
+ std::string error;
+ auto&& features = adb_get_feature_set(&error);
+ if (!features) {
+ error_exit("%s", error.c_str());
}
- for (const std::string& name : features) {
- if (CanUseFeature(features, name)) {
+ for (const std::string& name : *features) {
+ if (CanUseFeature(*features, name)) {
printf("%s\n", name.c_str());
}
}
diff --git a/adb/client/file_sync_client.cpp b/adb/client/file_sync_client.cpp
index f2c673a..7185939 100644
--- a/adb/client/file_sync_client.cpp
+++ b/adb/client/file_sync_client.cpp
@@ -225,21 +225,22 @@
class SyncConnection {
public:
- SyncConnection()
- : acknowledgement_buffer_(sizeof(sync_status) + SYNC_DATA_MAX),
- features_(adb_get_feature_set()) {
+ SyncConnection() : acknowledgement_buffer_(sizeof(sync_status) + SYNC_DATA_MAX) {
acknowledgement_buffer_.resize(0);
max = SYNC_DATA_MAX; // TODO: decide at runtime.
- if (features_.empty()) {
- Error("failed to get feature set");
+ std::string error;
+ auto&& features = adb_get_feature_set(&error);
+ if (!features) {
+ Error("failed to get feature set: %s", error.c_str());
} else {
- have_stat_v2_ = CanUseFeature(features_, kFeatureStat2);
- have_ls_v2_ = CanUseFeature(features_, kFeatureLs2);
- have_sendrecv_v2_ = CanUseFeature(features_, kFeatureSendRecv2);
- have_sendrecv_v2_brotli_ = CanUseFeature(features_, kFeatureSendRecv2Brotli);
- have_sendrecv_v2_lz4_ = CanUseFeature(features_, kFeatureSendRecv2LZ4);
- have_sendrecv_v2_dry_run_send_ = CanUseFeature(features_, kFeatureSendRecv2DryRunSend);
+ features_ = &*features;
+ have_stat_v2_ = CanUseFeature(*features, kFeatureStat2);
+ have_ls_v2_ = CanUseFeature(*features, kFeatureLs2);
+ have_sendrecv_v2_ = CanUseFeature(*features, kFeatureSendRecv2);
+ have_sendrecv_v2_brotli_ = CanUseFeature(*features, kFeatureSendRecv2Brotli);
+ have_sendrecv_v2_lz4_ = CanUseFeature(*features, kFeatureSendRecv2LZ4);
+ have_sendrecv_v2_dry_run_send_ = CanUseFeature(*features, kFeatureSendRecv2DryRunSend);
std::string error;
fd.reset(adb_connect("sync:", &error));
if (fd < 0) {
@@ -283,7 +284,7 @@
return compression;
}
- const FeatureSet& Features() const { return features_; }
+ const FeatureSet& Features() const { return *features_; }
bool IsValid() { return fd >= 0; }
@@ -921,7 +922,7 @@
private:
std::deque<std::pair<std::string, std::string>> deferred_acknowledgements_;
Block acknowledgement_buffer_;
- const FeatureSet& features_;
+ const FeatureSet* features_ = nullptr;
bool have_stat_v2_;
bool have_ls_v2_;
bool have_sendrecv_v2_;
diff --git a/adb/client/incremental_server.cpp b/adb/client/incremental_server.cpp
index 1a1361c..bfe18c0 100644
--- a/adb/client/incremental_server.cpp
+++ b/adb/client/incremental_server.cpp
@@ -264,7 +264,7 @@
char* pendingBlocks_ = nullptr;
// True when client notifies that all the data has been received
- bool servingComplete_;
+ bool servingComplete_ = false;
};
bool IncrementalServer::SkipToRequest(void* buffer, size_t* size, bool blocking) {
diff --git a/adb/libs/adbconnection/adbconnection_client.cpp b/adb/libs/adbconnection/adbconnection_client.cpp
index b569421..7e16148 100644
--- a/adb/libs/adbconnection/adbconnection_client.cpp
+++ b/adb/libs/adbconnection/adbconnection_client.cpp
@@ -122,16 +122,7 @@
return nullptr;
}
-#if defined(__APPLE__)
- ctx->control_socket_.reset(socket(AF_UNIX, SOCK_SEQPACKET, 0));
- // TODO: find a better home for all these copies of the mac CLOEXEC workaround.
- if (int fd = ctx->control_socket_.get(), flags = fcntl(fd, F_GETFD);
- flags != -1 && (flags & FD_CLOEXEC) == 0) {
- fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
- }
-#else
ctx->control_socket_.reset(socket(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0));
-#endif
if (ctx->control_socket_ < 0) {
PLOG(ERROR) << "failed to create Unix domain socket";
return nullptr;
@@ -149,7 +140,13 @@
int rc = connect(ctx->control_socket_.get(), reinterpret_cast<sockaddr*>(&addr), addr_len);
if (rc != 0) {
- PLOG(ERROR) << "failed to connect to jdwp control socket";
+ if (errno == ECONNREFUSED) {
+ // On userdebug devices, every Java process is debuggable, so if adbd is explicitly turned
+ // off, this would spew enormous amounts of red-herring errors.
+ LOG(DEBUG) << "failed to connect to jdwp control socket, adbd not running?";
+ } else {
+ PLOG(ERROR) << "failed to connect to jdwp control socket";
+ }
return nullptr;
}
diff --git a/adb/mdns_test.cpp b/adb/mdns_test.cpp
new file mode 100644
index 0000000..1f662c1
--- /dev/null
+++ b/adb/mdns_test.cpp
@@ -0,0 +1,107 @@
+/*
+ * 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 <gtest/gtest.h>
+
+#include "adb_mdns.h"
+
+static bool isValidMdnsServiceName(std::string_view name) {
+ // The rules for Service Names [RFC6335] state that they may be no more
+ // than fifteen characters long (not counting the mandatory underscore),
+ // consisting of only letters, digits, and hyphens, must begin and end
+ // with a letter or digit, must not contain consecutive hyphens, and
+ // must contain at least one letter.
+
+ // No more than 15 characters long
+ if (name.empty() || name.size() > 15) {
+ return false;
+ }
+
+ bool hasAtLeastOneLetter = false;
+ bool sawHyphen = false;
+ for (size_t i = 0; i < name.size(); ++i) {
+ // Must contain at least one letter
+ // Only contains letters, digits and hyphens
+ if (name[i] == '-') {
+ // Cannot be at beginning or end
+ if (i == 0 || i == name.size() - 1) {
+ return false;
+ }
+ if (sawHyphen) {
+ // Consecutive hyphen found
+ return false;
+ }
+ sawHyphen = true;
+ continue;
+ }
+
+ sawHyphen = false;
+ if ((name[i] >= 'a' && name[i] <= 'z') || (name[i] >= 'A' && name[i] <= 'Z')) {
+ hasAtLeastOneLetter = true;
+ continue;
+ }
+
+ if (name[i] >= '0' && name[i] <= '9') {
+ continue;
+ }
+
+ // Invalid character
+ return false;
+ }
+
+ return hasAtLeastOneLetter;
+}
+
+TEST(mdns, test_isValidMdnsServiceName) {
+ // Longer than 15 characters
+ EXPECT_FALSE(isValidMdnsServiceName("abcd1234abcd1234"));
+
+ // Contains invalid characters
+ EXPECT_FALSE(isValidMdnsServiceName("a*a"));
+ EXPECT_FALSE(isValidMdnsServiceName("a_a"));
+ EXPECT_FALSE(isValidMdnsServiceName("_a"));
+
+ // Does not begin or end with letter or digit
+ EXPECT_FALSE(isValidMdnsServiceName(""));
+ EXPECT_FALSE(isValidMdnsServiceName("-"));
+ EXPECT_FALSE(isValidMdnsServiceName("-a"));
+ EXPECT_FALSE(isValidMdnsServiceName("-1"));
+ EXPECT_FALSE(isValidMdnsServiceName("a-"));
+ EXPECT_FALSE(isValidMdnsServiceName("1-"));
+
+ // Contains consecutive hyphens
+ EXPECT_FALSE(isValidMdnsServiceName("a--a"));
+
+ // Does not contain at least one letter
+ EXPECT_FALSE(isValidMdnsServiceName("1"));
+ EXPECT_FALSE(isValidMdnsServiceName("12"));
+ EXPECT_FALSE(isValidMdnsServiceName("1-2"));
+
+ // Some valid names
+ EXPECT_TRUE(isValidMdnsServiceName("a"));
+ EXPECT_TRUE(isValidMdnsServiceName("a1"));
+ EXPECT_TRUE(isValidMdnsServiceName("1A"));
+ EXPECT_TRUE(isValidMdnsServiceName("aZ"));
+ EXPECT_TRUE(isValidMdnsServiceName("a-Z"));
+ EXPECT_TRUE(isValidMdnsServiceName("a-b-Z"));
+ EXPECT_TRUE(isValidMdnsServiceName("abc-def-123-456"));
+}
+
+TEST(mdns, ServiceName_RFC6335) {
+ EXPECT_TRUE(isValidMdnsServiceName(ADB_MDNS_SERVICE_TYPE));
+ EXPECT_TRUE(isValidMdnsServiceName(ADB_MDNS_TLS_PAIRING_TYPE));
+ EXPECT_TRUE(isValidMdnsServiceName(ADB_MDNS_TLS_CONNECT_TYPE));
+}
diff --git a/adb/transport.cpp b/adb/transport.cpp
index 963c3c1..25ed366 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -505,11 +505,10 @@
int osh = cast_handle_to_int(adb_get_os_handle(fd_));
#if ADB_HOST
- tls_ = TlsConnection::Create(TlsConnection::Role::Client,
+ tls_ = TlsConnection::Create(TlsConnection::Role::Client, x509_str, evp_str, osh);
#else
- tls_ = TlsConnection::Create(TlsConnection::Role::Server,
+ tls_ = TlsConnection::Create(TlsConnection::Role::Server, x509_str, evp_str, osh);
#endif
- x509_str, evp_str, osh);
CHECK(tls_);
#if ADB_HOST
// TLS 1.3 gives the client no message if the server rejected the
diff --git a/fastboot/Android.bp b/fastboot/Android.bp
index 884856d..3a2deb7 100644
--- a/fastboot/Android.bp
+++ b/fastboot/Android.bp
@@ -145,6 +145,7 @@
static_libs: [
"libhealthhalutils",
"libsnapshot_nobinder",
+ "update_metadata-protos",
],
header_libs: [
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 0c2569d..d2daaa1 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -62,6 +62,7 @@
#include <fs_mgr_overlayfs.h>
#include <fscrypt/fscrypt.h>
#include <libdm/dm.h>
+#include <libdm/loop_control.h>
#include <liblp/metadata_format.h>
#include <linux/fs.h>
#include <linux/loop.h>
@@ -105,6 +106,7 @@
using android::dm::DeviceMapper;
using android::dm::DmDeviceState;
using android::dm::DmTargetLinear;
+using android::dm::LoopControl;
// Realistically, this file should be part of the android::fs_mgr namespace;
using namespace android::fs_mgr;
@@ -1908,19 +1910,6 @@
return InstallZramDevice(bdev);
}
- // Get free loopback
- unique_fd loop_fd(TEMP_FAILURE_RETRY(open("/dev/loop-control", O_RDWR | O_CLOEXEC)));
- if (loop_fd.get() == -1) {
- PERROR << "Cannot open loop-control";
- return false;
- }
-
- int num = ioctl(loop_fd.get(), LOOP_CTL_GET_FREE);
- if (num == -1) {
- PERROR << "Cannot get free loop slot";
- return false;
- }
-
// Prepare target path
unique_fd target_fd(TEMP_FAILURE_RETRY(open(loop.c_str(), O_RDWR | O_CREAT | O_CLOEXEC, 0600)));
if (target_fd.get() == -1) {
@@ -1932,25 +1921,21 @@
return false;
}
- // Connect loopback (device_fd) to target path (target_fd)
- std::string device = android::base::StringPrintf("/dev/block/loop%d", num);
- unique_fd device_fd(TEMP_FAILURE_RETRY(open(device.c_str(), O_RDWR | O_CLOEXEC)));
- if (device_fd.get() == -1) {
- PERROR << "Cannot open /dev/block/loop" << num;
- return false;
- }
-
- if (ioctl(device_fd.get(), LOOP_SET_FD, target_fd.get())) {
- PERROR << "Cannot set loopback to target path";
+ // Allocate loop device and attach it to file_path.
+ LoopControl loop_control;
+ std::string device;
+ if (!loop_control.Attach(target_fd.get(), 5s, &device)) {
return false;
}
// set block size & direct IO
- if (ioctl(device_fd.get(), LOOP_SET_BLOCK_SIZE, 4096)) {
- PWARNING << "Cannot set 4KB blocksize to /dev/block/loop" << num;
+ unique_fd device_fd(TEMP_FAILURE_RETRY(open(device.c_str(), O_RDWR | O_CLOEXEC)));
+ if (device_fd.get() == -1) {
+ PERROR << "Cannot open " << device;
+ return false;
}
- if (ioctl(device_fd.get(), LOOP_SET_DIRECT_IO, 1)) {
- PWARNING << "Cannot set direct_io to /dev/block/loop" << num;
+ if (!LoopControl::EnableDirectIo(device_fd.get())) {
+ return false;
}
return InstallZramDevice(device);
diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp
index 4e3984c..384595d 100644
--- a/fs_mgr/libsnapshot/Android.bp
+++ b/fs_mgr/libsnapshot/Android.bp
@@ -26,7 +26,6 @@
"libbase",
"libcutils",
"liblog",
- "liblp",
],
static_libs: [
"libdm",
@@ -73,6 +72,7 @@
"device_info.cpp",
"snapshot.cpp",
"snapshot_stats.cpp",
+ "snapshot_stub.cpp",
"snapshot_metadata_updater.cpp",
"partition_cow_creator.cpp",
"return.cpp",
@@ -209,6 +209,7 @@
static_libs: [
"libfstab",
"libsnapshot",
+ "update_metadata-protos",
],
shared_libs: [
"android.hardware.boot@1.0",
@@ -234,6 +235,7 @@
],
static_libs: [
"libsnapshot",
+ "update_metadata-protos",
],
shared_libs: [
"libbase",
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/mock_device_info.h b/fs_mgr/libsnapshot/include/libsnapshot/mock_device_info.h
new file mode 100644
index 0000000..ef9d648
--- /dev/null
+++ b/fs_mgr/libsnapshot/include/libsnapshot/mock_device_info.h
@@ -0,0 +1,37 @@
+// 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 <libsnapshot/snapshot.h>
+
+#include <gmock/gmock.h>
+
+namespace android::snapshot {
+
+class MockDeviceInfo : public SnapshotManager::IDeviceInfo {
+ public:
+ MOCK_METHOD(std::string, GetGsidDir, (), (const, override));
+ MOCK_METHOD(std::string, GetMetadataDir, (), (const, override));
+ MOCK_METHOD(std::string, GetSlotSuffix, (), (const, override));
+ MOCK_METHOD(std::string, GetOtherSlotSuffix, (), (const, override));
+ MOCK_METHOD(std::string, GetSuperDevice, (uint32_t slot), (const, override));
+ MOCK_METHOD(const android::fs_mgr::IPartitionOpener&, GetPartitionOpener, (), (const));
+ MOCK_METHOD(bool, IsOverlayfsSetup, (), (const, override));
+ MOCK_METHOD(bool, SetBootControlMergeStatus, (MergeStatus status), (override));
+ MOCK_METHOD(bool, SetSlotAsUnbootable, (unsigned int slot), (override));
+ MOCK_METHOD(bool, IsRecovery, (), (const, override));
+};
+
+} // namespace android::snapshot
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot.h
new file mode 100644
index 0000000..758d66c
--- /dev/null
+++ b/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot.h
@@ -0,0 +1,54 @@
+// 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 <libsnapshot/snapshot.h>
+
+#include <gmock/gmock.h>
+
+namespace android::snapshot {
+
+class MockSnapshotManager : public ISnapshotManager {
+ public:
+ MOCK_METHOD(bool, BeginUpdate, (), (override));
+ MOCK_METHOD(bool, CancelUpdate, (), (override));
+ MOCK_METHOD(bool, FinishedSnapshotWrites, (bool wipe), (override));
+ MOCK_METHOD(bool, InitiateMerge, (), (override));
+
+ MOCK_METHOD(UpdateState, ProcessUpdateState,
+ (const std::function<bool()>& callback, const std::function<bool()>& before_cancel),
+ (override));
+ MOCK_METHOD(UpdateState, GetUpdateState, (double* progress), (override));
+ MOCK_METHOD(Return, CreateUpdateSnapshots,
+ (const chromeos_update_engine::DeltaArchiveManifest& manifest), (override));
+ MOCK_METHOD(bool, MapUpdateSnapshot,
+ (const android::fs_mgr::CreateLogicalPartitionParams& params,
+ std::string* snapshot_path),
+ (override));
+ MOCK_METHOD(bool, UnmapUpdateSnapshot, (const std::string& target_partition_name), (override));
+ MOCK_METHOD(bool, NeedSnapshotsInFirstStageMount, (), (override));
+ MOCK_METHOD(bool, CreateLogicalAndSnapshotPartitions,
+ (const std::string& super_device, const std::chrono::milliseconds& timeout_ms),
+ (override));
+ MOCK_METHOD(bool, HandleImminentDataWipe, (const std::function<void()>& callback), (override));
+ MOCK_METHOD(CreateResult, RecoveryCreateSnapshotDevices, (), (override));
+ MOCK_METHOD(CreateResult, RecoveryCreateSnapshotDevices,
+ (const std::unique_ptr<AutoDevice>& metadata_device), (override));
+ MOCK_METHOD(bool, Dump, (std::ostream & os), (override));
+ MOCK_METHOD(std::unique_ptr<AutoDevice>, EnsureMetadataMounted, (), (override));
+ MOCK_METHOD(ISnapshotMergeStats*, GetSnapshotMergeStatsInstance, (), (override));
+};
+
+} // namespace android::snapshot
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
index 1daa83b..fff667e 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
@@ -70,6 +70,8 @@
struct AutoDeleteSnapshot;
struct AutoDeviceList;
struct PartitionCowCreator;
+class ISnapshotMergeStats;
+class SnapshotMergeStats;
class SnapshotStatus;
static constexpr const std::string_view kCowGroupName = "cow";
@@ -83,17 +85,7 @@
NOT_CREATED,
};
-class SnapshotManager final {
- using CreateLogicalPartitionParams = android::fs_mgr::CreateLogicalPartitionParams;
- using IPartitionOpener = android::fs_mgr::IPartitionOpener;
- using LpMetadata = android::fs_mgr::LpMetadata;
- using MetadataBuilder = android::fs_mgr::MetadataBuilder;
- using DeltaArchiveManifest = chromeos_update_engine::DeltaArchiveManifest;
- using MergeStatus = android::hardware::boot::V1_1::MergeStatus;
- using FiemapStatus = android::fiemap::FiemapStatus;
-
- friend class SnapshotMergeStats;
-
+class ISnapshotManager {
public:
// Dependency injection for testing.
class IDeviceInfo {
@@ -104,39 +96,23 @@
virtual std::string GetSlotSuffix() const = 0;
virtual std::string GetOtherSlotSuffix() const = 0;
virtual std::string GetSuperDevice(uint32_t slot) const = 0;
- virtual const IPartitionOpener& GetPartitionOpener() const = 0;
+ virtual const android::fs_mgr::IPartitionOpener& GetPartitionOpener() const = 0;
virtual bool IsOverlayfsSetup() const = 0;
- virtual bool SetBootControlMergeStatus(MergeStatus status) = 0;
+ virtual bool SetBootControlMergeStatus(
+ android::hardware::boot::V1_1::MergeStatus status) = 0;
virtual bool SetSlotAsUnbootable(unsigned int slot) = 0;
virtual bool IsRecovery() const = 0;
};
-
- ~SnapshotManager();
-
- // Return a new SnapshotManager instance, or null on error. The device
- // pointer is owned for the lifetime of SnapshotManager. If null, a default
- // instance will be created.
- static std::unique_ptr<SnapshotManager> New(IDeviceInfo* device = nullptr);
-
- // This is similar to New(), except designed specifically for first-stage
- // init or recovery.
- static std::unique_ptr<SnapshotManager> NewForFirstStageMount(IDeviceInfo* device = nullptr);
-
- // Helper function for first-stage init to check whether a SnapshotManager
- // 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();
+ virtual ~ISnapshotManager() = default;
// Begin an update. This must be called before creating any snapshots. It
// will fail if GetUpdateState() != None.
- bool BeginUpdate();
+ virtual bool BeginUpdate() = 0;
// Cancel an update; any snapshots will be deleted. This is allowed if the
// state == Initiated, None, or Unverified (before rebooting to the new
// slot).
- bool CancelUpdate();
+ virtual bool CancelUpdate() = 0;
// Mark snapshot writes as having completed. After this, new snapshots cannot
// be created, and the device must either cancel the OTA (either before
@@ -144,11 +120,11 @@
// Before calling this function, all snapshots must be mapped.
// If |wipe| is set to true, wipe is scheduled after reboot, and snapshots
// may need to be merged before wiping.
- bool FinishedSnapshotWrites(bool wipe);
+ virtual bool FinishedSnapshotWrites(bool wipe) = 0;
// Initiate a merge on all snapshot devices. This should only be used after an
// update has been marked successful after booting.
- bool InitiateMerge();
+ virtual bool InitiateMerge() = 0;
// Perform any necessary post-boot actions. This should be run soon after
// /data is mounted.
@@ -178,8 +154,8 @@
//
// The optional callback allows the caller to periodically check the
// progress with GetUpdateState().
- UpdateState ProcessUpdateState(const std::function<bool()>& callback = {},
- const std::function<bool()>& before_cancel = {});
+ virtual UpdateState ProcessUpdateState(const std::function<bool()>& callback = {},
+ const std::function<bool()>& before_cancel = {}) = 0;
// Find the status of the current update, if any.
//
@@ -187,28 +163,30 @@
// Merging: Value in the range [0, 100]
// MergeCompleted: 100
// Other: 0
- UpdateState GetUpdateState(double* progress = nullptr);
+ virtual UpdateState GetUpdateState(double* progress = nullptr) = 0;
// Create necessary COW device / files for OTA clients. New logical partitions will be added to
// group "cow" in target_metadata. Regions of partitions of current_metadata will be
// "write-protected" and snapshotted.
- Return CreateUpdateSnapshots(const DeltaArchiveManifest& manifest);
+ virtual Return CreateUpdateSnapshots(
+ const chromeos_update_engine::DeltaArchiveManifest& manifest) = 0;
// Map a snapshotted partition for OTA clients to write to. Write-protected regions are
// determined previously in CreateSnapshots.
- bool MapUpdateSnapshot(const CreateLogicalPartitionParams& params, std::string* snapshot_path);
+ virtual bool MapUpdateSnapshot(const android::fs_mgr::CreateLogicalPartitionParams& params,
+ std::string* snapshot_path) = 0;
// Unmap a snapshot device that's previously mapped with MapUpdateSnapshot.
- bool UnmapUpdateSnapshot(const std::string& target_partition_name);
+ virtual bool UnmapUpdateSnapshot(const std::string& target_partition_name) = 0;
// If this returns true, first-stage mount must call
// CreateLogicalAndSnapshotPartitions rather than CreateLogicalPartitions.
- bool NeedSnapshotsInFirstStageMount();
+ virtual bool NeedSnapshotsInFirstStageMount() = 0;
// Perform first-stage mapping of snapshot targets. This replaces init's
// call to CreateLogicalPartitions when snapshots are present.
- bool CreateLogicalAndSnapshotPartitions(const std::string& super_device,
- const std::chrono::milliseconds& timeout_ms = {});
+ virtual bool CreateLogicalAndSnapshotPartitions(
+ const std::string& super_device, const std::chrono::milliseconds& timeout_ms = {}) = 0;
// This method should be called preceding any wipe or flash of metadata or
// userdata. It is only valid in recovery or fastbootd, and it ensures that
@@ -221,7 +199,7 @@
//
// Returns true on success (or nothing to do), false on failure. The
// optional callback fires periodically to query progress via GetUpdateState.
- bool HandleImminentDataWipe(const std::function<void()>& callback = {});
+ virtual bool HandleImminentDataWipe(const std::function<void()>& callback = {}) = 0;
// This method is only allowed in recovery and is used as a helper to
// initialize the snapshot devices as a requirement to mount a snapshotted
@@ -234,14 +212,15 @@
// be aborted.
// This function mounts /metadata when called, and unmounts /metadata upon
// return.
- CreateResult RecoveryCreateSnapshotDevices();
+ virtual CreateResult RecoveryCreateSnapshotDevices() = 0;
// Same as RecoveryCreateSnapshotDevices(), but does not auto mount/umount
// /metadata.
- CreateResult RecoveryCreateSnapshotDevices(const std::unique_ptr<AutoDevice>& metadata_device);
+ virtual CreateResult RecoveryCreateSnapshotDevices(
+ const std::unique_ptr<AutoDevice>& metadata_device) = 0;
// Dump debug information.
- bool Dump(std::ostream& os);
+ virtual bool Dump(std::ostream& os) = 0;
// Ensure metadata directory is mounted in recovery. When the returned
// AutoDevice is destroyed, the metadata directory is automatically
@@ -257,7 +236,65 @@
// auto b = mgr->EnsureMetadataMounted(); // does nothing
// b.reset() // unmounts
// a.reset() // does nothing
- std::unique_ptr<AutoDevice> EnsureMetadataMounted();
+ virtual std::unique_ptr<AutoDevice> EnsureMetadataMounted() = 0;
+
+ // Return the associated ISnapshotMergeStats instance. Never null.
+ virtual ISnapshotMergeStats* GetSnapshotMergeStatsInstance() = 0;
+};
+
+class SnapshotManager final : public ISnapshotManager {
+ using CreateLogicalPartitionParams = android::fs_mgr::CreateLogicalPartitionParams;
+ using IPartitionOpener = android::fs_mgr::IPartitionOpener;
+ using LpMetadata = android::fs_mgr::LpMetadata;
+ using MetadataBuilder = android::fs_mgr::MetadataBuilder;
+ using DeltaArchiveManifest = chromeos_update_engine::DeltaArchiveManifest;
+ using MergeStatus = android::hardware::boot::V1_1::MergeStatus;
+ using FiemapStatus = android::fiemap::FiemapStatus;
+
+ friend class SnapshotMergeStats;
+
+ public:
+ ~SnapshotManager();
+
+ // Return a new SnapshotManager instance, or null on error. The device
+ // pointer is owned for the lifetime of SnapshotManager. If null, a default
+ // instance will be created.
+ static std::unique_ptr<SnapshotManager> New(IDeviceInfo* device = nullptr);
+
+ // This is similar to New(), except designed specifically for first-stage
+ // init or recovery.
+ static std::unique_ptr<SnapshotManager> NewForFirstStageMount(IDeviceInfo* device = nullptr);
+
+ // Helper function for first-stage init to check whether a SnapshotManager
+ // 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();
+
+ // ISnapshotManager overrides.
+ bool BeginUpdate() override;
+ bool CancelUpdate() override;
+ bool FinishedSnapshotWrites(bool wipe) override;
+ bool InitiateMerge() override;
+ UpdateState ProcessUpdateState(const std::function<bool()>& callback = {},
+ const std::function<bool()>& before_cancel = {}) override;
+ UpdateState GetUpdateState(double* progress = nullptr) override;
+ Return CreateUpdateSnapshots(const DeltaArchiveManifest& manifest) override;
+ bool MapUpdateSnapshot(const CreateLogicalPartitionParams& params,
+ std::string* snapshot_path) override;
+ bool UnmapUpdateSnapshot(const std::string& target_partition_name) override;
+ bool NeedSnapshotsInFirstStageMount() override;
+ bool CreateLogicalAndSnapshotPartitions(
+ const std::string& super_device,
+ const std::chrono::milliseconds& timeout_ms = {}) override;
+ bool HandleImminentDataWipe(const std::function<void()>& callback = {}) override;
+ CreateResult RecoveryCreateSnapshotDevices() override;
+ CreateResult RecoveryCreateSnapshotDevices(
+ const std::unique_ptr<AutoDevice>& metadata_device) override;
+ bool Dump(std::ostream& os) override;
+ std::unique_ptr<AutoDevice> EnsureMetadataMounted() override;
+ ISnapshotMergeStats* GetSnapshotMergeStatsInstance() override;
private:
FRIEND_TEST(SnapshotTest, CleanFirstStageMount);
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stats.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stats.h
index 91dd34f..4caf632 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stats.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stats.h
@@ -23,14 +23,12 @@
namespace android {
namespace snapshot {
-class SnapshotMergeStats {
+class ISnapshotMergeStats {
public:
- // Not thread safe.
- static SnapshotMergeStats* GetInstance(SnapshotManager& manager);
-
+ virtual ~ISnapshotMergeStats() = default;
// Called when merge starts or resumes.
- bool Start();
- void set_state(android::snapshot::UpdateState state);
+ virtual bool Start() = 0;
+ virtual void set_state(android::snapshot::UpdateState state) = 0;
// Called when merge ends. Properly clean up permanent storage.
class Result {
@@ -40,7 +38,19 @@
// Time between successful Start() / Resume() to Finish().
virtual std::chrono::steady_clock::duration merge_time() const = 0;
};
- std::unique_ptr<Result> Finish();
+ // Return nullptr if any failure.
+ virtual std::unique_ptr<Result> Finish() = 0;
+};
+
+class SnapshotMergeStats : public ISnapshotMergeStats {
+ public:
+ // Not thread safe.
+ static SnapshotMergeStats* GetInstance(SnapshotManager& manager);
+
+ // ISnapshotMergeStats overrides
+ bool Start() override;
+ void set_state(android::snapshot::UpdateState state) override;
+ std::unique_ptr<Result> Finish() override;
private:
bool ReadState();
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stub.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stub.h
new file mode 100644
index 0000000..9b2590c
--- /dev/null
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stub.h
@@ -0,0 +1,52 @@
+// 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 <libsnapshot/snapshot.h>
+
+namespace android::snapshot {
+
+class SnapshotManagerStub : public ISnapshotManager {
+ public:
+ // Create a stubbed snapshot manager. All calls into the stub fails.
+ static std::unique_ptr<ISnapshotManager> New();
+
+ // ISnapshotManager overrides.
+ bool BeginUpdate() override;
+ bool CancelUpdate() override;
+ bool FinishedSnapshotWrites(bool wipe) override;
+ bool InitiateMerge() override;
+ UpdateState ProcessUpdateState(const std::function<bool()>& callback = {},
+ const std::function<bool()>& before_cancel = {}) override;
+ UpdateState GetUpdateState(double* progress = nullptr) override;
+ Return CreateUpdateSnapshots(
+ const chromeos_update_engine::DeltaArchiveManifest& manifest) override;
+ bool MapUpdateSnapshot(const android::fs_mgr::CreateLogicalPartitionParams& params,
+ std::string* snapshot_path) override;
+ bool UnmapUpdateSnapshot(const std::string& target_partition_name) override;
+ bool NeedSnapshotsInFirstStageMount() override;
+ bool CreateLogicalAndSnapshotPartitions(
+ const std::string& super_device,
+ const std::chrono::milliseconds& timeout_ms = {}) override;
+ bool HandleImminentDataWipe(const std::function<void()>& callback = {}) override;
+ CreateResult RecoveryCreateSnapshotDevices() override;
+ CreateResult RecoveryCreateSnapshotDevices(
+ const std::unique_ptr<AutoDevice>& metadata_device) override;
+ bool Dump(std::ostream& os) override;
+ std::unique_ptr<AutoDevice> EnsureMetadataMounted() override;
+ ISnapshotMergeStats* GetSnapshotMergeStatsInstance() override;
+};
+
+} // namespace android::snapshot
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index c9fa28e..eafeea2 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -2685,5 +2685,9 @@
return true;
}
+ISnapshotMergeStats* SnapshotManager::GetSnapshotMergeStatsInstance() {
+ return SnapshotMergeStats::GetInstance(*this);
+}
+
} // namespace snapshot
} // namespace android
diff --git a/fs_mgr/libsnapshot/snapshot_stub.cpp b/fs_mgr/libsnapshot/snapshot_stub.cpp
new file mode 100644
index 0000000..2747b03
--- /dev/null
+++ b/fs_mgr/libsnapshot/snapshot_stub.cpp
@@ -0,0 +1,125 @@
+// 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 <libsnapshot/snapshot_stub.h>
+
+#include <android-base/logging.h>
+
+#include <libsnapshot/snapshot_stats.h>
+
+using android::fs_mgr::CreateLogicalPartitionParams;
+using chromeos_update_engine::DeltaArchiveManifest;
+
+namespace android::snapshot {
+
+std::unique_ptr<ISnapshotManager> SnapshotManagerStub::New() {
+ return std::make_unique<SnapshotManagerStub>();
+}
+
+bool SnapshotManagerStub::BeginUpdate() {
+ LOG(ERROR) << __FUNCTION__ << " should never be called.";
+ return false;
+}
+
+bool SnapshotManagerStub::CancelUpdate() {
+ LOG(ERROR) << __FUNCTION__ << " should never be called.";
+ return false;
+}
+
+bool SnapshotManagerStub::FinishedSnapshotWrites(bool) {
+ LOG(ERROR) << __FUNCTION__ << " should never be called.";
+ return false;
+}
+
+bool SnapshotManagerStub::InitiateMerge() {
+ LOG(ERROR) << __FUNCTION__ << " should never be called.";
+ return false;
+}
+
+UpdateState SnapshotManagerStub::ProcessUpdateState(const std::function<bool()>&,
+ const std::function<bool()>&) {
+ LOG(ERROR) << __FUNCTION__ << " should never be called.";
+ return UpdateState::None;
+}
+
+UpdateState SnapshotManagerStub::GetUpdateState(double*) {
+ LOG(ERROR) << __FUNCTION__ << " should never be called.";
+ return UpdateState::None;
+}
+
+Return SnapshotManagerStub::CreateUpdateSnapshots(const DeltaArchiveManifest&) {
+ LOG(ERROR) << __FUNCTION__ << " should never be called.";
+ return Return::Error();
+}
+
+bool SnapshotManagerStub::MapUpdateSnapshot(const CreateLogicalPartitionParams&, std::string*) {
+ LOG(ERROR) << __FUNCTION__ << " should never be called.";
+ return false;
+}
+
+bool SnapshotManagerStub::UnmapUpdateSnapshot(const std::string&) {
+ LOG(ERROR) << __FUNCTION__ << " should never be called.";
+ return false;
+}
+
+bool SnapshotManagerStub::NeedSnapshotsInFirstStageMount() {
+ LOG(ERROR) << __FUNCTION__ << " should never be called.";
+ return false;
+}
+
+bool SnapshotManagerStub::CreateLogicalAndSnapshotPartitions(const std::string&,
+ const std::chrono::milliseconds&) {
+ LOG(ERROR) << __FUNCTION__ << " should never be called.";
+ return false;
+}
+
+bool SnapshotManagerStub::HandleImminentDataWipe(const std::function<void()>&) {
+ LOG(ERROR) << __FUNCTION__ << " should never be called.";
+ return false;
+}
+
+CreateResult SnapshotManagerStub::RecoveryCreateSnapshotDevices() {
+ LOG(ERROR) << __FUNCTION__ << " should never be called.";
+ return CreateResult::ERROR;
+}
+
+CreateResult SnapshotManagerStub::RecoveryCreateSnapshotDevices(
+ const std::unique_ptr<AutoDevice>&) {
+ LOG(ERROR) << __FUNCTION__ << " should never be called.";
+ return CreateResult::ERROR;
+}
+
+bool SnapshotManagerStub::Dump(std::ostream&) {
+ LOG(ERROR) << __FUNCTION__ << " should never be called.";
+ return false;
+}
+
+std::unique_ptr<AutoDevice> SnapshotManagerStub::EnsureMetadataMounted() {
+ LOG(ERROR) << __FUNCTION__ << " should never be called.";
+ return nullptr;
+}
+
+class SnapshotMergeStatsStub : public ISnapshotMergeStats {
+ bool Start() override { return false; }
+ void set_state(android::snapshot::UpdateState) override {}
+ std::unique_ptr<Result> Finish() override { return nullptr; }
+};
+
+ISnapshotMergeStats* SnapshotManagerStub::GetSnapshotMergeStatsInstance() {
+ static SnapshotMergeStatsStub snapshot_merge_stats;
+ LOG(ERROR) << __FUNCTION__ << " should never be called.";
+ return &snapshot_merge_stats;
+}
+
+} // namespace android::snapshot
diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp
index c662838..53a37be 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -41,6 +41,11 @@
#include <libsnapshot/test_helpers.h>
#include "utility.h"
+// Mock classes are not used. Header included to ensure mocked class definition aligns with the
+// class itself.
+#include <libsnapshot/mock_device_info.h>
+#include <libsnapshot/mock_snapshot.h>
+
namespace android {
namespace snapshot {
diff --git a/init/Android.bp b/init/Android.bp
index 827a829..edf9099 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -131,6 +131,7 @@
"libpropertyinfoparser",
"libsnapshot_init",
"lib_apex_manifest_proto_lite",
+ "update_metadata-protos",
],
shared_libs: [
"libbacktrace",
diff --git a/init/Android.mk b/init/Android.mk
index 416b732..da94daf 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -113,6 +113,7 @@
libext2_uuid \
libprotobuf-cpp-lite \
libsnapshot_init \
+ update_metadata-protos \
LOCAL_SANITIZE := signed-integer-overflow
# First stage init is weird: it may start without stdout/stderr, and no /proc.
diff --git a/init/reboot.cpp b/init/reboot.cpp
index 2f91663..72f0450 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -203,6 +203,7 @@
}
static Result<void> CallVdc(const std::string& system, const std::string& cmd) {
+ LOG(INFO) << "Calling /system/bin/vdc " << system << " " << cmd;
const char* vdc_argv[] = {"/system/bin/vdc", system.c_str(), cmd.c_str()};
int status;
if (logwrap_fork_execvp(arraysize(vdc_argv), vdc_argv, &status, false, LOG_KLOG, true,
@@ -456,10 +457,14 @@
#define ZRAM_RESET "/sys/block/zram0/reset"
#define ZRAM_BACK_DEV "/sys/block/zram0/backing_dev"
static Result<void> KillZramBackingDevice() {
+ if (access(ZRAM_BACK_DEV, F_OK) != 0 && errno == ENOENT) {
+ LOG(INFO) << "No zram backing device configured";
+ return {};
+ }
std::string backing_dev;
- if (!android::base::ReadFileToString(ZRAM_BACK_DEV, &backing_dev)) return {};
-
- if (!android::base::StartsWith(backing_dev, "/dev/block/loop")) return {};
+ if (!android::base::ReadFileToString(ZRAM_BACK_DEV, &backing_dev)) {
+ return ErrnoError() << "Failed to read " << ZRAM_BACK_DEV;
+ }
// cut the last "\n"
backing_dev.erase(backing_dev.length() - 1);
@@ -478,6 +483,11 @@
<< " failed";
}
+ if (!android::base::StartsWith(backing_dev, "/dev/block/loop")) {
+ LOG(INFO) << backing_dev << " is not a loop device. Exiting early";
+ return {};
+ }
+
// clear loopback device
unique_fd loop(TEMP_FAILURE_RETRY(open(backing_dev.c_str(), O_RDWR | O_CLOEXEC)));
if (loop.get() < 0) {
@@ -785,7 +795,7 @@
}
auto sigterm_timeout = GetMillisProperty("init.userspace_reboot.sigterm.timeoutmillis", 5s);
auto sigkill_timeout = GetMillisProperty("init.userspace_reboot.sigkill.timeoutmillis", 10s);
- LOG(INFO) << "Timeout to terminate services : " << sigterm_timeout.count() << "ms"
+ LOG(INFO) << "Timeout to terminate services: " << sigterm_timeout.count() << "ms "
<< "Timeout to kill services: " << sigkill_timeout.count() << "ms";
StopServicesAndLogViolations(stop_first, sigterm_timeout, true /* SIGTERM */);
if (int r = StopServicesAndLogViolations(stop_first, sigkill_timeout, false /* SIGKILL */);
diff --git a/libcutils/arch-x86/android_memset16.S b/libcutils/arch-x86/android_memset16.S
index cb2ff14..f4d497e 100755
--- a/libcutils/arch-x86/android_memset16.S
+++ b/libcutils/arch-x86/android_memset16.S
@@ -105,14 +105,16 @@
/* We loaded the jump table and adjuested EDX. Go. */ \
jmp *%ebx
- .section .gnu.linkonce.t.__x86.get_pc_thunk.bx,"ax",@progbits
+ .section .text.__x86.get_pc_thunk.bx,"axG",@progbits,__x86.get_pc_thunk.bx,comdat
.globl __x86.get_pc_thunk.bx
.hidden __x86.get_pc_thunk.bx
ALIGN (4)
.type __x86.get_pc_thunk.bx,@function
__x86.get_pc_thunk.bx:
+ cfi_startproc
movl (%esp), %ebx
ret
+ cfi_endproc
#else
# define ENTRANCE
# define RETURN_END ret
diff --git a/libcutils/arch-x86/android_memset32.S b/libcutils/arch-x86/android_memset32.S
index f4326dc..b928f6b 100755
--- a/libcutils/arch-x86/android_memset32.S
+++ b/libcutils/arch-x86/android_memset32.S
@@ -105,14 +105,16 @@
/* We loaded the jump table and adjuested EDX. Go. */ \
jmp *%ebx
- .section .gnu.linkonce.t.__x86.get_pc_thunk.bx,"ax",@progbits
+ .section .text.__x86.get_pc_thunk.bx,"axG",@progbits,__x86.get_pc_thunk.bx,comdat
.globl __x86.get_pc_thunk.bx
.hidden __x86.get_pc_thunk.bx
ALIGN (4)
.type __x86.get_pc_thunk.bx,@function
__x86.get_pc_thunk.bx:
+ cfi_startproc
movl (%esp), %ebx
ret
+ cfi_endproc
#else
# define ENTRANCE
# define RETURN_END ret
diff --git a/liblog/include/log/log.h b/liblog/include/log/log.h
index 90d1e76..19edb83 100644
--- a/liblog/include/log/log.h
+++ b/liblog/include/log/log.h
@@ -87,8 +87,6 @@
/*
* Event log entry types.
*/
-#ifndef __AndroidEventLogType_defined
-#define __AndroidEventLogType_defined
typedef enum {
/* Special markers for android_log_list_element type */
EVENT_TYPE_LIST_STOP = '\n', /* declare end of list */
@@ -101,9 +99,6 @@
EVENT_TYPE_LIST = 3,
EVENT_TYPE_FLOAT = 4,
} AndroidEventLogType;
-#endif
-#define sizeof_AndroidEventLogType sizeof(typeof_AndroidEventLogType)
-#define typeof_AndroidEventLogType unsigned char
#ifndef LOG_EVENT_INT
#define LOG_EVENT_INT(_tag, _value) \
diff --git a/liblog/logger_write.cpp b/liblog/logger_write.cpp
index c174b85..d15b367 100644
--- a/liblog/logger_write.cpp
+++ b/liblog/logger_write.cpp
@@ -330,7 +330,7 @@
ErrnoRestorer errno_restorer;
if (!__android_log_is_loggable(prio, tag, ANDROID_LOG_VERBOSE)) {
- return 0;
+ return -EPERM;
}
__android_log_message log_message = {
@@ -343,7 +343,7 @@
ErrnoRestorer errno_restorer;
if (!__android_log_is_loggable(prio, tag, ANDROID_LOG_VERBOSE)) {
- return 0;
+ return -EPERM;
}
__attribute__((uninitialized)) char buf[LOG_BUF_SIZE];
@@ -360,7 +360,7 @@
ErrnoRestorer errno_restorer;
if (!__android_log_is_loggable(prio, tag, ANDROID_LOG_VERBOSE)) {
- return 0;
+ return -EPERM;
}
va_list ap;
@@ -380,7 +380,7 @@
ErrnoRestorer errno_restorer;
if (!__android_log_is_loggable(prio, tag, ANDROID_LOG_VERBOSE)) {
- return 0;
+ return -EPERM;
}
va_list ap;
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index 21da12d..bf7d69e 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -57,6 +57,7 @@
"MapInfo.cpp",
"Maps.cpp",
"Memory.cpp",
+ "MemoryMte.cpp",
"LocalUnwinder.cpp",
"Regs.cpp",
"RegsArm.cpp",
@@ -101,6 +102,16 @@
"liblog",
"liblzma",
],
+
+ header_libs: [
+ "bionic_libc_platform_headers",
+ ],
+
+ product_variables: {
+ experimental_mte: {
+ cflags: ["-DANDROID_EXPERIMENTAL_MTE"],
+ },
+ },
}
cc_library {
@@ -213,6 +224,7 @@
"tests/MemoryRangesTest.cpp",
"tests/MemoryRemoteTest.cpp",
"tests/MemoryTest.cpp",
+ "tests/MemoryMteTest.cpp",
"tests/RegsInfoTest.cpp",
"tests/RegsIterateTest.cpp",
"tests/RegsStepIfSignalHandlerTest.cpp",
@@ -268,6 +280,16 @@
"tests/files/offline/straddle_arm/*",
"tests/files/offline/straddle_arm64/*",
],
+
+ header_libs: [
+ "bionic_libc_platform_headers",
+ ],
+
+ product_variables: {
+ experimental_mte: {
+ cflags: ["-DANDROID_EXPERIMENTAL_MTE"],
+ },
+ },
}
cc_test {
diff --git a/libunwindstack/Memory.cpp b/libunwindstack/Memory.cpp
index e142b97..b4623fa 100644
--- a/libunwindstack/Memory.cpp
+++ b/libunwindstack/Memory.cpp
@@ -334,6 +334,16 @@
return ProcessVmRead(getpid(), addr, dst, size);
}
+#if !defined(ANDROID_EXPERIMENTAL_MTE)
+long MemoryRemote::ReadTag(uint64_t) {
+ return -1;
+}
+
+long MemoryLocal::ReadTag(uint64_t) {
+ return -1;
+}
+#endif
+
MemoryRange::MemoryRange(const std::shared_ptr<Memory>& memory, uint64_t begin, uint64_t length,
uint64_t offset)
: memory_(memory), begin_(begin), length_(length), offset_(offset) {}
diff --git a/libunwindstack/MemoryCache.h b/libunwindstack/MemoryCache.h
index 769d907..d97640d 100644
--- a/libunwindstack/MemoryCache.h
+++ b/libunwindstack/MemoryCache.h
@@ -33,6 +33,7 @@
virtual ~MemoryCache() = default;
size_t Read(uint64_t addr, void* dst, size_t size) override;
+ long ReadTag(uint64_t addr) override { return impl_->ReadTag(addr); }
void Clear() override { cache_.clear(); }
diff --git a/libunwindstack/MemoryLocal.h b/libunwindstack/MemoryLocal.h
index 7e027cf..741f107 100644
--- a/libunwindstack/MemoryLocal.h
+++ b/libunwindstack/MemoryLocal.h
@@ -31,6 +31,7 @@
bool IsLocal() const override { return true; }
size_t Read(uint64_t addr, void* dst, size_t size) override;
+ long ReadTag(uint64_t addr) override;
};
} // namespace unwindstack
diff --git a/libunwindstack/MemoryMte.cpp b/libunwindstack/MemoryMte.cpp
new file mode 100644
index 0000000..d1d0ebc
--- /dev/null
+++ b/libunwindstack/MemoryMte.cpp
@@ -0,0 +1,57 @@
+/*
+ * 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.
+ */
+
+#if defined(ANDROID_EXPERIMENTAL_MTE)
+
+#include <sys/ptrace.h>
+
+#include <bionic/mte.h>
+#include <bionic/mte_kernel.h>
+
+#include "MemoryLocal.h"
+#include "MemoryRemote.h"
+
+namespace unwindstack {
+
+long MemoryRemote::ReadTag(uint64_t addr) {
+#if defined(__aarch64__)
+ return ptrace(PTRACE_PEEKTAG, pid_, (void*)addr, nullptr);
+#else
+ (void)addr;
+ return -1;
+#endif
+}
+
+long MemoryLocal::ReadTag(uint64_t addr) {
+#if defined(__aarch64__)
+ // Check that the memory is readable first. This is racy with the ldg but there's not much
+ // we can do about it.
+ char data;
+ if (!mte_supported() || !Read(addr, &data, 1)) {
+ return -1;
+ }
+
+ __asm__ __volatile__(".arch_extension mte; ldg %0, [%0]" : "+r"(addr) : : "memory");
+ return (addr >> 56) & 0xf;
+#else
+ (void)addr;
+ return -1;
+#endif
+}
+
+} // namespace unwindstack
+
+#endif
diff --git a/libunwindstack/MemoryRemote.h b/libunwindstack/MemoryRemote.h
index db367d6..dd09c88 100644
--- a/libunwindstack/MemoryRemote.h
+++ b/libunwindstack/MemoryRemote.h
@@ -32,6 +32,7 @@
virtual ~MemoryRemote() = default;
size_t Read(uint64_t addr, void* dst, size_t size) override;
+ long ReadTag(uint64_t addr) override;
pid_t pid() { return pid_; }
diff --git a/libunwindstack/include/unwindstack/Memory.h b/libunwindstack/include/unwindstack/Memory.h
index 995230e..3d81878 100644
--- a/libunwindstack/include/unwindstack/Memory.h
+++ b/libunwindstack/include/unwindstack/Memory.h
@@ -44,6 +44,7 @@
virtual bool IsLocal() const { return false; }
virtual size_t Read(uint64_t addr, void* dst, size_t size) = 0;
+ virtual long ReadTag(uint64_t) { return -1; }
bool ReadFully(uint64_t addr, void* dst, size_t size);
diff --git a/libunwindstack/tests/MemoryMteTest.cpp b/libunwindstack/tests/MemoryMteTest.cpp
new file mode 100644
index 0000000..3ae322e
--- /dev/null
+++ b/libunwindstack/tests/MemoryMteTest.cpp
@@ -0,0 +1,99 @@
+/*
+ * 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.
+ */
+
+#if defined(ANDROID_EXPERIMENTAL_MTE)
+
+#include <sys/mman.h>
+#include <sys/types.h>
+
+#include <gtest/gtest.h>
+
+#include <bionic/mte.h>
+
+#include "MemoryLocal.h"
+#include "MemoryRemote.h"
+#include "TestUtils.h"
+
+namespace unwindstack {
+
+static uintptr_t CreateTagMapping() {
+ uintptr_t mapping =
+ reinterpret_cast<uintptr_t>(mmap(nullptr, getpagesize(), PROT_READ | PROT_WRITE | PROT_MTE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
+ if (reinterpret_cast<void*>(mapping) == MAP_FAILED) {
+ return 0;
+ }
+#if defined(__aarch64__)
+ __asm__ __volatile__(".arch_extension mte; stg %0, [%0]"
+ :
+ : "r"(mapping + (1ULL << 56))
+ : "memory");
+#endif
+ return mapping;
+}
+
+TEST(MemoryMteTest, remote_read_tag) {
+#if !defined(__aarch64__)
+ GTEST_SKIP() << "Requires aarch64";
+#else
+ if (!mte_supported()) {
+ GTEST_SKIP() << "Requires MTE";
+ }
+#endif
+
+ uintptr_t mapping = CreateTagMapping();
+ ASSERT_NE(0U, mapping);
+
+ pid_t pid;
+ if ((pid = fork()) == 0) {
+ while (true)
+ ;
+ exit(1);
+ }
+ ASSERT_LT(0, pid);
+ TestScopedPidReaper reap(pid);
+
+ ASSERT_TRUE(TestAttach(pid));
+
+ MemoryRemote remote(pid);
+
+ EXPECT_EQ(1, remote.ReadTag(mapping));
+ EXPECT_EQ(0, remote.ReadTag(mapping + 16));
+
+ ASSERT_TRUE(TestDetach(pid));
+}
+
+TEST(MemoryMteTest, local_read_tag) {
+#if !defined(__aarch64__)
+ GTEST_SKIP() << "Requires aarch64";
+#else
+ if (!mte_supported()) {
+ GTEST_SKIP() << "Requires MTE";
+ }
+#endif
+
+ uintptr_t mapping = CreateTagMapping();
+ ASSERT_NE(0U, mapping);
+
+ MemoryLocal local;
+
+ EXPECT_EQ(1, local.ReadTag(mapping));
+ EXPECT_EQ(0, local.ReadTag(mapping + 16));
+}
+
+} // namespace unwindstack
+
+#endif
diff --git a/libunwindstack/tests/MemoryRemoteTest.cpp b/libunwindstack/tests/MemoryRemoteTest.cpp
index c90dedc..385078d 100644
--- a/libunwindstack/tests/MemoryRemoteTest.cpp
+++ b/libunwindstack/tests/MemoryRemoteTest.cpp
@@ -26,8 +26,10 @@
#include <vector>
-#include <android-base/test_utils.h>
#include <android-base/file.h>
+#include <android-base/test_utils.h>
+#include <bionic/mte.h>
+#include <bionic/mte_kernel.h>
#include <gtest/gtest.h>
#include "MemoryRemote.h"
@@ -37,24 +39,7 @@
namespace unwindstack {
-class MemoryRemoteTest : public ::testing::Test {
- protected:
- static bool Attach(pid_t pid) {
- if (ptrace(PTRACE_ATTACH, pid, 0, 0) == -1) {
- return false;
- }
-
- return TestQuiescePid(pid);
- }
-
- static bool Detach(pid_t pid) {
- return ptrace(PTRACE_DETACH, pid, 0, 0) == 0;
- }
-
- static constexpr size_t NS_PER_SEC = 1000000000ULL;
-};
-
-TEST_F(MemoryRemoteTest, read) {
+TEST(MemoryRemoteTest, read) {
std::vector<uint8_t> src(1024);
memset(src.data(), 0x4c, 1024);
@@ -66,7 +51,7 @@
ASSERT_LT(0, pid);
TestScopedPidReaper reap(pid);
- ASSERT_TRUE(Attach(pid));
+ ASSERT_TRUE(TestAttach(pid));
MemoryRemote remote(pid);
@@ -76,10 +61,10 @@
ASSERT_EQ(0x4cU, dst[i]) << "Failed at byte " << i;
}
- ASSERT_TRUE(Detach(pid));
+ ASSERT_TRUE(TestDetach(pid));
}
-TEST_F(MemoryRemoteTest, read_large) {
+TEST(MemoryRemoteTest, read_large) {
static constexpr size_t kTotalPages = 245;
std::vector<uint8_t> src(kTotalPages * getpagesize());
for (size_t i = 0; i < kTotalPages; i++) {
@@ -95,7 +80,7 @@
ASSERT_LT(0, pid);
TestScopedPidReaper reap(pid);
- ASSERT_TRUE(Attach(pid));
+ ASSERT_TRUE(TestAttach(pid));
MemoryRemote remote(pid);
@@ -105,10 +90,10 @@
ASSERT_EQ(i / getpagesize(), dst[i]) << "Failed at byte " << i;
}
- ASSERT_TRUE(Detach(pid));
+ ASSERT_TRUE(TestDetach(pid));
}
-TEST_F(MemoryRemoteTest, read_partial) {
+TEST(MemoryRemoteTest, read_partial) {
char* mapping = static_cast<char*>(
mmap(nullptr, 4 * getpagesize(), PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
ASSERT_NE(MAP_FAILED, mapping);
@@ -128,7 +113,7 @@
// Unmap from our process.
ASSERT_EQ(0, munmap(mapping, 3 * getpagesize()));
- ASSERT_TRUE(Attach(pid));
+ ASSERT_TRUE(TestAttach(pid));
MemoryRemote remote(pid);
@@ -149,10 +134,10 @@
ASSERT_EQ(0x4cU, dst[i]) << "Failed at byte " << i;
}
- ASSERT_TRUE(Detach(pid));
+ ASSERT_TRUE(TestDetach(pid));
}
-TEST_F(MemoryRemoteTest, read_fail) {
+TEST(MemoryRemoteTest, read_fail) {
int pagesize = getpagesize();
void* src = mmap(nullptr, pagesize * 2, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE,-1, 0);
memset(src, 0x4c, pagesize * 2);
@@ -169,7 +154,7 @@
ASSERT_LT(0, pid);
TestScopedPidReaper reap(pid);
- ASSERT_TRUE(Attach(pid));
+ ASSERT_TRUE(TestAttach(pid));
MemoryRemote remote(pid);
@@ -188,10 +173,10 @@
ASSERT_EQ(0, munmap(src, pagesize));
- ASSERT_TRUE(Detach(pid));
+ ASSERT_TRUE(TestDetach(pid));
}
-TEST_F(MemoryRemoteTest, read_overflow) {
+TEST(MemoryRemoteTest, read_overflow) {
pid_t pid;
if ((pid = fork()) == 0) {
while (true)
@@ -201,7 +186,7 @@
ASSERT_LT(0, pid);
TestScopedPidReaper reap(pid);
- ASSERT_TRUE(Attach(pid));
+ ASSERT_TRUE(TestAttach(pid));
MemoryRemote remote(pid);
@@ -209,10 +194,10 @@
std::vector<uint8_t> dst(200);
ASSERT_FALSE(remote.ReadFully(UINT64_MAX - 100, dst.data(), 200));
- ASSERT_TRUE(Detach(pid));
+ ASSERT_TRUE(TestDetach(pid));
}
-TEST_F(MemoryRemoteTest, read_illegal) {
+TEST(MemoryRemoteTest, read_illegal) {
pid_t pid;
if ((pid = fork()) == 0) {
while (true);
@@ -221,7 +206,7 @@
ASSERT_LT(0, pid);
TestScopedPidReaper reap(pid);
- ASSERT_TRUE(Attach(pid));
+ ASSERT_TRUE(TestAttach(pid));
MemoryRemote remote(pid);
@@ -229,10 +214,10 @@
ASSERT_FALSE(remote.ReadFully(0, dst.data(), 1));
ASSERT_FALSE(remote.ReadFully(0, dst.data(), 100));
- ASSERT_TRUE(Detach(pid));
+ ASSERT_TRUE(TestDetach(pid));
}
-TEST_F(MemoryRemoteTest, read_mprotect_hole) {
+TEST(MemoryRemoteTest, read_mprotect_hole) {
size_t page_size = getpagesize();
void* mapping =
mmap(nullptr, 3 * getpagesize(), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
@@ -250,7 +235,7 @@
ASSERT_EQ(0, munmap(mapping, 3 * page_size));
- ASSERT_TRUE(Attach(pid));
+ ASSERT_TRUE(TestAttach(pid));
MemoryRemote remote(pid);
std::vector<uint8_t> dst(getpagesize() * 4, 0xCC);
@@ -263,9 +248,11 @@
for (size_t i = read_size; i < dst.size(); ++i) {
ASSERT_EQ(0xCC, dst[i]);
}
+
+ ASSERT_TRUE(TestDetach(pid));
}
-TEST_F(MemoryRemoteTest, read_munmap_hole) {
+TEST(MemoryRemoteTest, read_munmap_hole) {
size_t page_size = getpagesize();
void* mapping =
mmap(nullptr, 3 * getpagesize(), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
@@ -285,7 +272,7 @@
ASSERT_EQ(0, munmap(mapping, page_size));
ASSERT_EQ(0, munmap(static_cast<char*>(mapping) + 2 * page_size, page_size));
- ASSERT_TRUE(Attach(pid));
+ ASSERT_TRUE(TestAttach(pid));
MemoryRemote remote(pid);
std::vector<uint8_t> dst(getpagesize() * 4, 0xCC);
@@ -297,11 +284,13 @@
for (size_t i = read_size; i < dst.size(); ++i) {
ASSERT_EQ(0xCC, dst[i]);
}
+
+ ASSERT_TRUE(TestDetach(pid));
}
// Verify that the memory remote object chooses a memory read function
// properly. Either process_vm_readv or ptrace.
-TEST_F(MemoryRemoteTest, read_choose_correctly) {
+TEST(MemoryRemoteTest, read_choose_correctly) {
size_t page_size = getpagesize();
void* mapping =
mmap(nullptr, 2 * getpagesize(), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
@@ -320,7 +309,7 @@
ASSERT_EQ(0, munmap(mapping, 2 * page_size));
- ASSERT_TRUE(Attach(pid));
+ ASSERT_TRUE(TestAttach(pid));
// We know that process_vm_readv of a mprotect'd PROT_NONE region will fail.
// Read from the PROT_NONE area first to force the choice of ptrace.
@@ -348,6 +337,8 @@
bytes = remote_readv.Read(reinterpret_cast<uint64_t>(mapping) + page_size, &value, sizeof(value));
ASSERT_EQ(sizeof(value), bytes);
ASSERT_EQ(0xfcfcfcfcU, value);
+
+ ASSERT_TRUE(TestDetach(pid));
}
} // namespace unwindstack
diff --git a/libunwindstack/tests/TestUtils.h b/libunwindstack/tests/TestUtils.h
index a4d7b9b..0685006 100644
--- a/libunwindstack/tests/TestUtils.h
+++ b/libunwindstack/tests/TestUtils.h
@@ -21,6 +21,7 @@
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
+#include <unistd.h>
namespace unwindstack {
@@ -50,6 +51,18 @@
return ready;
}
+inline bool TestAttach(pid_t pid) {
+ if (ptrace(PTRACE_ATTACH, pid, 0, 0) == -1) {
+ return false;
+ }
+
+ return TestQuiescePid(pid);
+}
+
+inline bool TestDetach(pid_t pid) {
+ return ptrace(PTRACE_DETACH, pid, 0, 0) == 0;
+}
+
void TestCheckForLeaks(void (*unwind_func)(void*), void* data);
} // namespace unwindstack
diff --git a/libziparchive/ziptool.cpp b/libziparchive/ziptool.cpp
index 17d4833..a261535 100644
--- a/libziparchive/ziptool.cpp
+++ b/libziparchive/ziptool.cpp
@@ -263,12 +263,12 @@
snprintf(time, sizeof(time), "%04d-%02d-%02d %02d:%02d", t.tm_year + 1900, t.tm_mon + 1,
t.tm_mday, t.tm_hour, t.tm_min);
if (flag_v) {
- printf("%8" PRIu64 " %s %8" PRIu64 " %3.0f%% %s %08x %s\n", entry.uncompressed_length,
+ printf("%8" PRIu64 " %s %8" PRIu64 " %3.0f%% %s %08x %s\n", entry.uncompressed_length,
(entry.method == kCompressStored) ? "Stored" : "Defl:N", entry.compressed_length,
CompressionRatio(entry.uncompressed_length, entry.compressed_length), time, entry.crc32,
name.c_str());
} else {
- printf("%9" PRIu64 " %s %s\n", entry.uncompressed_length, time, name.c_str());
+ printf("%9" PRIu64 " %s %s\n", entry.uncompressed_length, time, name.c_str());
}
}