Merge "adb: change mdns tls service names (RFC 6763)."
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/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_utils.h b/adb/client/incremental_utils.h
index d969d94..fe2914d 100644
--- a/adb/client/incremental_utils.h
+++ b/adb/client/incremental_utils.h
@@ -25,6 +25,8 @@
#include <stdint.h>
+#include <android-base/off64_t.h>
+
namespace incremental {
using Size = int64_t;
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 1486e87..0c2569d 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -358,7 +358,7 @@
const struct ext4_super_block* sb, int* fs_stat) {
bool has_quota = (sb->s_feature_ro_compat & cpu_to_le32(EXT4_FEATURE_RO_COMPAT_QUOTA)) != 0;
bool want_quota = entry.fs_mgr_flags.quota;
- bool want_projid = android::base::GetBoolProperty("ro.emulated_storage.projid", false);
+ bool want_projid = android::base::GetBoolProperty("external_storage.projid.enabled", false);
if (has_quota == want_quota) {
return;
@@ -521,7 +521,8 @@
static void tune_casefold(const std::string& blk_device, const struct ext4_super_block* sb,
int* fs_stat) {
bool has_casefold = (sb->s_feature_incompat & cpu_to_le32(EXT4_FEATURE_INCOMPAT_CASEFOLD)) != 0;
- bool wants_casefold = android::base::GetBoolProperty("ro.emulated_storage.casefold", false);
+ bool wants_casefold =
+ android::base::GetBoolProperty("external_storage.casefold.enabled", false);
if (!wants_casefold || has_casefold) return;
diff --git a/fs_mgr/fs_mgr_format.cpp b/fs_mgr/fs_mgr_format.cpp
index 778c0c1..301c907 100644
--- a/fs_mgr/fs_mgr_format.cpp
+++ b/fs_mgr/fs_mgr_format.cpp
@@ -166,8 +166,8 @@
bool needs_projid = false;
if (entry.mount_point == "/data") {
- needs_casefold = android::base::GetBoolProperty("ro.emulated_storage.casefold", false);
- needs_projid = android::base::GetBoolProperty("ro.emulated_storage.projid", false);
+ needs_casefold = android::base::GetBoolProperty("external_storage.casefold.enabled", false);
+ needs_projid = android::base::GetBoolProperty("external_storage.projid.enabled", false);
}
if (entry.fs_type == "f2fs") {
diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp
index a209ea6..bd788f5 100644
--- a/fs_mgr/libsnapshot/Android.bp
+++ b/fs_mgr/libsnapshot/Android.bp
@@ -209,6 +209,7 @@
static_libs: [
"libfstab",
"libsnapshot",
+ "update_metadata-protos",
],
shared_libs: [
"android.hardware.boot@1.0",
@@ -226,3 +227,20 @@
"libutils",
],
}
+
+cc_test {
+ name: "snapshot_power_test",
+ srcs: [
+ "power_test.cpp",
+ ],
+ static_libs: [
+ "libsnapshot",
+ "update_metadata-protos",
+ ],
+ shared_libs: [
+ "libbase",
+ "libfs_mgr_binder",
+ "liblog",
+ ],
+ gtest: false,
+}
diff --git a/fs_mgr/libsnapshot/PowerTest.md b/fs_mgr/libsnapshot/PowerTest.md
new file mode 100644
index 0000000..0b0cb5d
--- /dev/null
+++ b/fs_mgr/libsnapshot/PowerTest.md
@@ -0,0 +1,40 @@
+snapshot\_power\_test
+---------------------
+
+snapshot\_power\_test is a standalone test to simulate power failures during a snapshot-merge operation.
+
+### Test Setup
+
+Start by creating two large files that will be used as the pre-merge and post-merge state. You can take two different partition images (for example, a product.img from two separate builds), or just create random data:
+
+ dd if=/dev/urandom of=pre-merge count=1024 bs=1048576
+ dd if=/dev/urandom of=post-merge count=1024 bs=1048576
+
+Next, push these files to an unencrypted directory on the device:
+
+ adb push pre-merge /data/local/unencrypted
+ adb push post-merge /data/local/unencrypted
+
+Next, run the test setup:
+
+ adb sync data
+ adb shell /data/nativetest64/snapshot_power_test/snapshot_power_test \
+ /data/local/unencrypted/pre-merge \
+ /data/local/unencrypted/post-merge
+
+This will create the necessary fiemap-based images.
+
+### Running
+The actual test can be run via `run_power_test.sh`. Its syntax is:
+
+ run_power_test.sh <POST_MERGE_FILE>
+
+`POST_MERGE_FILE` should be the path on the device of the image to validate the merge against. Example:
+
+ run_power_test.sh /data/local/unencrypted/post-merge
+
+The device will begin the merge with a 5% chance of injecting a kernel crash every 10ms. The device should be capable of rebooting normally without user intervention. Once the merge has completed, the test will run a final check command to validate the contents of the snapshot against the post-merge file. It will error if there are any incorrect blocks.
+
+Two environment variables can be passed to `run_power_test.sh`:
+1. `FAIL_RATE` - A fraction between 0 and 100 (inclusive) indicating the probability the device should inject a kernel crash every 10ms.
+2. `DEVICE_SERIAL` - If multiple devices are attached to adb, this argument is passed as the serial to select (to `adb -s`).
diff --git a/fs_mgr/libsnapshot/power_test.cpp b/fs_mgr/libsnapshot/power_test.cpp
new file mode 100644
index 0000000..4d2548a
--- /dev/null
+++ b/fs_mgr/libsnapshot/power_test.cpp
@@ -0,0 +1,559 @@
+//
+// 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 <errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <chrono>
+#include <iostream>
+#include <random>
+#include <string>
+#include <thread>
+#include <vector>
+
+#include <android-base/file.h>
+#include <android-base/parsedouble.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+#include <android-base/unique_fd.h>
+#include <ext4_utils/ext4_utils.h>
+#include <fstab/fstab.h>
+#include <libdm/dm.h>
+#include <libfiemap/image_manager.h>
+
+using namespace std::chrono_literals;
+using namespace std::string_literals;
+using android::base::borrowed_fd;
+using android::base::unique_fd;
+using android::dm::DeviceMapper;
+using android::dm::DmDeviceState;
+using android::dm::DmTable;
+using android::dm::DmTargetSnapshot;
+using android::dm::SnapshotStorageMode;
+using android::fiemap::ImageManager;
+using android::fs_mgr::Fstab;
+
+namespace android {
+namespace snapshot {
+
+static void usage() {
+ std::cerr << "Usage:\n";
+ std::cerr << " create <orig-payload> <new-payload>\n";
+ std::cerr << "\n";
+ std::cerr << " Create a snapshot device containing the contents of\n";
+ std::cerr << " orig-payload, and then write the contents of new-payload.\n";
+ std::cerr << " The original files are not modified.\n";
+ std::cerr << "\n";
+ std::cerr << " merge <fail-rate>\n";
+ std::cerr << "\n";
+ std::cerr << " Merge the snapshot previously started by create, and wait\n";
+ std::cerr << " for it to complete. Once done, it is compared to the\n";
+ std::cerr << " new-payload for consistency. The original files are not \n";
+ std::cerr << " modified. If a fail-rate is passed (as a fraction between 0\n";
+ std::cerr << " and 100), every 10ms the device has that percent change of\n";
+ std::cerr << " injecting a kernel crash.\n";
+ std::cerr << "\n";
+ std::cerr << " check <new-payload>\n";
+ std::cerr << " Verify that all artifacts are correct after a merge\n";
+ std::cerr << " completes.\n";
+ std::cerr << "\n";
+ std::cerr << " cleanup\n";
+ std::cerr << " Remove all ImageManager artifacts from create/merge.\n";
+}
+
+class PowerTest final {
+ public:
+ PowerTest();
+ bool Run(int argc, char** argv);
+
+ private:
+ bool OpenImageManager();
+ bool Create(int argc, char** argv);
+ bool Merge(int argc, char** argv);
+ bool Check(int argc, char** argv);
+ bool Cleanup();
+ bool CleanupImage(const std::string& name);
+ bool SetupImages(const std::string& first_file, borrowed_fd second_fd);
+ bool MapImages();
+ bool MapSnapshot(SnapshotStorageMode mode);
+ bool GetMergeStatus(DmTargetSnapshot::Status* status);
+
+ static constexpr char kSnapshotName[] = "snapshot-power-test";
+ static constexpr char kSnapshotImageName[] = "snapshot-power-test-image";
+ static constexpr char kSnapshotCowName[] = "snapshot-power-test-cow";
+
+ DeviceMapper& dm_;
+ std::unique_ptr<ImageManager> images_;
+ std::string image_path_;
+ std::string cow_path_;
+ std::string snapshot_path_;
+};
+
+PowerTest::PowerTest() : dm_(DeviceMapper::Instance()) {}
+
+bool PowerTest::Run([[maybe_unused]] int argc, [[maybe_unused]] char** argv) {
+ if (!OpenImageManager()) {
+ return false;
+ }
+
+ if (argc < 2) {
+ usage();
+ return false;
+ }
+ if (argv[1] == "create"s) {
+ return Create(argc, argv);
+ } else if (argv[1] == "merge"s) {
+ return Merge(argc, argv);
+ } else if (argv[1] == "check"s) {
+ return Check(argc, argv);
+ } else if (argv[1] == "cleanup"s) {
+ return Cleanup();
+ } else {
+ usage();
+ return false;
+ }
+}
+
+bool PowerTest::OpenImageManager() {
+ std::vector<std::string> dirs = {
+ "/data/gsi/test",
+ "/metadata/gsi/test",
+ };
+ for (const auto& dir : dirs) {
+ if (mkdir(dir.c_str(), 0700) && errno != EEXIST) {
+ std::cerr << "mkdir " << dir << ": " << strerror(errno) << "\n";
+ return false;
+ }
+ }
+
+ images_ = ImageManager::Open("/metadata/gsi/test", "/data/gsi/test");
+ if (!images_) {
+ std::cerr << "Could not open ImageManager\n";
+ return false;
+ }
+ return true;
+}
+
+bool PowerTest::Create(int argc, char** argv) {
+ if (argc < 4) {
+ usage();
+ return false;
+ }
+
+ std::string first = argv[2];
+ std::string second = argv[3];
+
+ unique_fd second_fd(open(second.c_str(), O_RDONLY));
+ if (second_fd < 0) {
+ std::cerr << "open " << second << ": " << strerror(errno) << "\n";
+ return false;
+ }
+
+ if (!Cleanup()) {
+ return false;
+ }
+ if (!SetupImages(first, second_fd)) {
+ return false;
+ }
+ if (!MapSnapshot(SnapshotStorageMode::Persistent)) {
+ return false;
+ }
+
+ struct stat s;
+ if (fstat(second_fd, &s)) {
+ std::cerr << "fstat " << second << ": " << strerror(errno) << "\n";
+ return false;
+ }
+
+ unique_fd snap_fd(open(snapshot_path_.c_str(), O_WRONLY));
+ if (snap_fd < 0) {
+ std::cerr << "open " << snapshot_path_ << ": " << strerror(errno) << "\n";
+ return false;
+ }
+
+ uint8_t chunk[4096];
+ uint64_t written = 0;
+ while (written < s.st_size) {
+ uint64_t remaining = s.st_size - written;
+ size_t bytes = (size_t)std::min((uint64_t)sizeof(chunk), remaining);
+ if (!android::base::ReadFully(second_fd, chunk, bytes)) {
+ std::cerr << "read " << second << ": " << strerror(errno) << "\n";
+ return false;
+ }
+ if (!android::base::WriteFully(snap_fd, chunk, bytes)) {
+ std::cerr << "write " << snapshot_path_ << ": " << strerror(errno) << "\n";
+ return false;
+ }
+ written += bytes;
+ }
+ if (fsync(snap_fd)) {
+ std::cerr << "fsync: " << strerror(errno) << "\n";
+ return false;
+ }
+
+ sync();
+
+ snap_fd = {};
+ if (!dm_.DeleteDeviceIfExists(kSnapshotName)) {
+ std::cerr << "could not delete dm device " << kSnapshotName << "\n";
+ return false;
+ }
+ if (!images_->UnmapImageIfExists(kSnapshotImageName)) {
+ std::cerr << "failed to unmap " << kSnapshotImageName << "\n";
+ return false;
+ }
+ if (!images_->UnmapImageIfExists(kSnapshotCowName)) {
+ std::cerr << "failed to unmap " << kSnapshotImageName << "\n";
+ return false;
+ }
+ return true;
+}
+
+bool PowerTest::Cleanup() {
+ if (!dm_.DeleteDeviceIfExists(kSnapshotName)) {
+ std::cerr << "could not delete dm device " << kSnapshotName << "\n";
+ return false;
+ }
+ if (!CleanupImage(kSnapshotImageName) || !CleanupImage(kSnapshotCowName)) {
+ return false;
+ }
+ return true;
+}
+
+bool PowerTest::CleanupImage(const std::string& name) {
+ if (!images_->UnmapImageIfExists(name)) {
+ std::cerr << "failed to unmap " << name << "\n";
+ return false;
+ }
+ if (images_->BackingImageExists(name) && !images_->DeleteBackingImage(name)) {
+ std::cerr << "failed to delete " << name << "\n";
+ return false;
+ }
+ return true;
+}
+
+bool PowerTest::SetupImages(const std::string& first, borrowed_fd second_fd) {
+ unique_fd first_fd(open(first.c_str(), O_RDONLY));
+ if (first_fd < 0) {
+ std::cerr << "open " << first << ": " << strerror(errno) << "\n";
+ return false;
+ }
+
+ struct stat s1, s2;
+ if (fstat(first_fd.get(), &s1)) {
+ std::cerr << "first stat: " << strerror(errno) << "\n";
+ return false;
+ }
+ if (fstat(second_fd.get(), &s2)) {
+ std::cerr << "second stat: " << strerror(errno) << "\n";
+ return false;
+ }
+
+ // Pick the bigger size of both images, rounding up to the nearest block.
+ uint64_t s1_size = (s1.st_size + 4095) & ~uint64_t(4095);
+ uint64_t s2_size = (s2.st_size + 4095) & ~uint64_t(4095);
+ uint64_t image_size = std::max(s1_size, s2_size) + (1024 * 1024 * 128);
+ if (!images_->CreateBackingImage(kSnapshotImageName, image_size, 0, nullptr)) {
+ std::cerr << "failed to create " << kSnapshotImageName << "\n";
+ return false;
+ }
+ // Use the same size for the cow.
+ if (!images_->CreateBackingImage(kSnapshotCowName, image_size, 0, nullptr)) {
+ std::cerr << "failed to create " << kSnapshotCowName << "\n";
+ return false;
+ }
+ if (!MapImages()) {
+ return false;
+ }
+
+ unique_fd image_fd(open(image_path_.c_str(), O_WRONLY));
+ if (image_fd < 0) {
+ std::cerr << "open: " << image_path_ << ": " << strerror(errno) << "\n";
+ return false;
+ }
+
+ uint8_t chunk[4096];
+ uint64_t written = 0;
+ while (written < s1.st_size) {
+ uint64_t remaining = s1.st_size - written;
+ size_t bytes = (size_t)std::min((uint64_t)sizeof(chunk), remaining);
+ if (!android::base::ReadFully(first_fd, chunk, bytes)) {
+ std::cerr << "read: " << strerror(errno) << "\n";
+ return false;
+ }
+ if (!android::base::WriteFully(image_fd, chunk, bytes)) {
+ std::cerr << "write: " << strerror(errno) << "\n";
+ return false;
+ }
+ written += bytes;
+ }
+ if (fsync(image_fd)) {
+ std::cerr << "fsync: " << strerror(errno) << "\n";
+ return false;
+ }
+
+ // Zero the first block of the COW.
+ unique_fd cow_fd(open(cow_path_.c_str(), O_WRONLY));
+ if (cow_fd < 0) {
+ std::cerr << "open: " << cow_path_ << ": " << strerror(errno) << "\n";
+ return false;
+ }
+
+ memset(chunk, 0, sizeof(chunk));
+ if (!android::base::WriteFully(cow_fd, chunk, sizeof(chunk))) {
+ std::cerr << "read: " << strerror(errno) << "\n";
+ return false;
+ }
+ if (fsync(cow_fd)) {
+ std::cerr << "fsync: " << strerror(errno) << "\n";
+ return false;
+ }
+ return true;
+}
+
+bool PowerTest::MapImages() {
+ if (!images_->MapImageDevice(kSnapshotImageName, 10s, &image_path_)) {
+ std::cerr << "failed to map " << kSnapshotImageName << "\n";
+ return false;
+ }
+ if (!images_->MapImageDevice(kSnapshotCowName, 10s, &cow_path_)) {
+ std::cerr << "failed to map " << kSnapshotCowName << "\n";
+ return false;
+ }
+ return true;
+}
+
+bool PowerTest::MapSnapshot(SnapshotStorageMode mode) {
+ uint64_t sectors;
+ {
+ unique_fd fd(open(image_path_.c_str(), O_RDONLY));
+ if (fd < 0) {
+ std::cerr << "open: " << image_path_ << ": " << strerror(errno) << "\n";
+ return false;
+ }
+ sectors = get_block_device_size(fd) / 512;
+ }
+
+ DmTable table;
+ table.Emplace<DmTargetSnapshot>(0, sectors, image_path_, cow_path_, mode, 8);
+ if (!dm_.CreateDevice(kSnapshotName, table, &snapshot_path_, 10s)) {
+ std::cerr << "failed to create snapshot device\n";
+ return false;
+ }
+ return true;
+}
+
+bool PowerTest::GetMergeStatus(DmTargetSnapshot::Status* status) {
+ std::vector<DeviceMapper::TargetInfo> targets;
+ if (!dm_.GetTableStatus(kSnapshotName, &targets)) {
+ std::cerr << "failed to get merge status\n";
+ return false;
+ }
+ if (targets.size() != 1) {
+ std::cerr << "merge device has wrong number of targets\n";
+ return false;
+ }
+ if (!DmTargetSnapshot::ParseStatusText(targets[0].data, status)) {
+ std::cerr << "could not parse merge target status text\n";
+ return false;
+ }
+ return true;
+}
+
+static std::string GetUserdataBlockDeviceName() {
+ Fstab fstab;
+ if (!ReadFstabFromFile("/proc/mounts", &fstab)) {
+ return {};
+ }
+
+ auto entry = android::fs_mgr::GetEntryForMountPoint(&fstab, "/data");
+ if (!entry) {
+ return {};
+ }
+
+ auto prefix = "/dev/block/"s;
+ if (!android::base::StartsWith(entry->blk_device, prefix)) {
+ return {};
+ }
+ return entry->blk_device.substr(prefix.size());
+}
+
+bool PowerTest::Merge(int argc, char** argv) {
+ // Start an f2fs GC to really stress things. :TODO: figure out data device
+ auto userdata_dev = GetUserdataBlockDeviceName();
+ if (userdata_dev.empty()) {
+ std::cerr << "could not locate userdata block device\n";
+ return false;
+ }
+
+ auto cmd =
+ android::base::StringPrintf("echo 1 > /sys/fs/f2fs/%s/gc_urgent", userdata_dev.c_str());
+ system(cmd.c_str());
+
+ if (dm_.GetState(kSnapshotName) == DmDeviceState::INVALID) {
+ if (!MapImages()) {
+ return false;
+ }
+ if (!MapSnapshot(SnapshotStorageMode::Merge)) {
+ return false;
+ }
+ }
+
+ std::random_device r;
+ std::default_random_engine re(r());
+ std::uniform_real_distribution<double> dist(0.0, 100.0);
+
+ std::optional<double> failure_rate;
+ if (argc >= 3) {
+ double d;
+ if (!android::base::ParseDouble(argv[2], &d)) {
+ std::cerr << "Could not parse failure rate as double: " << argv[2] << "\n";
+ return false;
+ }
+ failure_rate = d;
+ }
+
+ while (true) {
+ DmTargetSnapshot::Status status;
+ if (!GetMergeStatus(&status)) {
+ return false;
+ }
+ if (!status.error.empty()) {
+ std::cerr << "merge reported error: " << status.error << "\n";
+ return false;
+ }
+ if (status.sectors_allocated == status.metadata_sectors) {
+ break;
+ }
+
+ std::cerr << status.sectors_allocated << " / " << status.metadata_sectors << "\n";
+
+ if (failure_rate && *failure_rate >= dist(re)) {
+ system("echo 1 > /proc/sys/kernel/sysrq");
+ system("echo c > /proc/sysrq-trigger");
+ }
+
+ std::this_thread::sleep_for(10ms);
+ }
+
+ std::cout << "Merge completed.\n";
+ return true;
+}
+
+bool PowerTest::Check([[maybe_unused]] int argc, [[maybe_unused]] char** argv) {
+ if (argc < 3) {
+ std::cerr << "Expected argument: <new-image-path>\n";
+ return false;
+ }
+ std::string md_path, image_path;
+ std::string canonical_path = argv[2];
+
+ if (!dm_.GetDmDevicePathByName(kSnapshotName, &md_path)) {
+ std::cerr << "could not get dm-path for merge device\n";
+ return false;
+ }
+ if (!images_->GetMappedImageDevice(kSnapshotImageName, &image_path)) {
+ std::cerr << "could not get image path\n";
+ return false;
+ }
+
+ unique_fd md_fd(open(md_path.c_str(), O_RDONLY));
+ if (md_fd < 0) {
+ std::cerr << "open: " << md_path << ": " << strerror(errno) << "\n";
+ return false;
+ }
+ unique_fd image_fd(open(image_path.c_str(), O_RDONLY));
+ if (image_fd < 0) {
+ std::cerr << "open: " << image_path << ": " << strerror(errno) << "\n";
+ return false;
+ }
+ unique_fd canonical_fd(open(canonical_path.c_str(), O_RDONLY));
+ if (canonical_fd < 0) {
+ std::cerr << "open: " << canonical_path << ": " << strerror(errno) << "\n";
+ return false;
+ }
+
+ struct stat s;
+ if (fstat(canonical_fd, &s)) {
+ std::cerr << "fstat: " << canonical_path << ": " << strerror(errno) << "\n";
+ return false;
+ }
+ uint64_t canonical_size = s.st_size;
+ uint64_t md_size = get_block_device_size(md_fd);
+ uint64_t image_size = get_block_device_size(image_fd);
+ if (image_size != md_size) {
+ std::cerr << "image size does not match merge device size\n";
+ return false;
+ }
+ if (canonical_size > image_size) {
+ std::cerr << "canonical size " << canonical_size << " is greater than image size "
+ << image_size << "\n";
+ return false;
+ }
+
+ constexpr size_t kBlockSize = 4096;
+ uint8_t canonical_buffer[kBlockSize];
+ uint8_t image_buffer[kBlockSize];
+ uint8_t md_buffer[kBlockSize];
+
+ uint64_t remaining = canonical_size;
+ uint64_t blockno = 0;
+ while (remaining) {
+ size_t bytes = (size_t)std::min((uint64_t)kBlockSize, remaining);
+ if (!android::base::ReadFully(canonical_fd, canonical_buffer, bytes)) {
+ std::cerr << "read: " << canonical_buffer << ": " << strerror(errno) << "\n";
+ return false;
+ }
+ if (!android::base::ReadFully(image_fd, image_buffer, bytes)) {
+ std::cerr << "read: " << image_buffer << ": " << strerror(errno) << "\n";
+ return false;
+ }
+ if (!android::base::ReadFully(md_fd, md_buffer, bytes)) {
+ std::cerr << "read: " << md_buffer << ": " << strerror(errno) << "\n";
+ return false;
+ }
+ if (memcmp(canonical_buffer, image_buffer, bytes)) {
+ std::cerr << "canonical and image differ at block " << blockno << "\n";
+ return false;
+ }
+ if (memcmp(canonical_buffer, md_buffer, bytes)) {
+ std::cerr << "canonical and image differ at block " << blockno << "\n";
+ return false;
+ }
+
+ remaining -= bytes;
+ blockno++;
+ }
+
+ std::cout << "Images all match.\n";
+ return true;
+}
+
+} // namespace snapshot
+} // namespace android
+
+int main(int argc, char** argv) {
+ android::snapshot::PowerTest test;
+
+ if (!test.Run(argc, argv)) {
+ std::cerr << "Unexpected error running test." << std::endl;
+ return 1;
+ }
+ fflush(stdout);
+ return 0;
+}
diff --git a/fs_mgr/libsnapshot/run_power_test.sh b/fs_mgr/libsnapshot/run_power_test.sh
new file mode 100755
index 0000000..dc03dc9
--- /dev/null
+++ b/fs_mgr/libsnapshot/run_power_test.sh
@@ -0,0 +1,35 @@
+#!/bin/bash
+
+set -e
+
+if [ -z "$FAIL_RATE" ]; then
+ FAIL_RATE=5.0
+fi
+if [ ! -z "$ANDROID_SERIAL" ]; then
+ DEVICE_ARGS=-s $ANDROID_SERIAL
+else
+ DEVICE_ARGS=
+fi
+
+TEST_BIN=/data/nativetest64/snapshot_power_test/snapshot_power_test
+
+while :
+do
+ adb $DEVICE_ARGS wait-for-device
+ adb $DEVICE_ARGS root
+ adb $DEVICE_ARGS shell rm $TEST_BIN
+ adb $DEVICE_ARGS sync data
+ set +e
+ output=$(adb $DEVICE_ARGS shell $TEST_BIN merge $FAIL_RATE 2>&1)
+ set -e
+ if [[ "$output" == *"Merge completed"* ]]; then
+ echo "Merge completed."
+ break
+ fi
+ if [[ "$output" == *"Unexpected error"* ]]; then
+ echo "Unexpected error."
+ exit 1
+ fi
+done
+
+adb $DEVICE_ARGS shell $TEST_BIN check $1
diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp
index f82c082..c662838 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -1753,7 +1753,6 @@
protected:
void SetUp() override {
if (!is_virtual_ab_) GTEST_SKIP() << "Test for Virtual A/B devices only";
- GTEST_SKIP() << "WIP failure b/149738928";
SnapshotTest::SetUp();
userdata_ = std::make_unique<LowSpaceUserdata>();
diff --git a/init/Android.bp b/init/Android.bp
index 1b3aa18..edf9099 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -41,6 +41,7 @@
"builtins.cpp",
"devices.cpp",
"firmware_handler.cpp",
+ "first_stage_console.cpp",
"first_stage_init.cpp",
"first_stage_mount.cpp",
"fscrypt_init_extensions.cpp",
@@ -130,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 b49fb3b..da94daf 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -50,6 +50,7 @@
LOCAL_SRC_FILES := \
block_dev_initializer.cpp \
devices.cpp \
+ first_stage_console.cpp \
first_stage_init.cpp \
first_stage_main.cpp \
first_stage_mount.cpp \
@@ -112,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/first_stage_console.cpp b/init/first_stage_console.cpp
new file mode 100644
index 0000000..cae53f4
--- /dev/null
+++ b/init/first_stage_console.cpp
@@ -0,0 +1,95 @@
+/*
+ * 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 "first_stage_console.h"
+
+#include <sys/stat.h>
+#include <sys/sysmacros.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <termios.h>
+
+#include <string>
+#include <thread>
+
+#include <android-base/chrono_utils.h>
+#include <android-base/file.h>
+#include <android-base/logging.h>
+
+static void RunScript() {
+ LOG(INFO) << "Attempting to run /first_stage.sh...";
+ pid_t pid = fork();
+ if (pid != 0) {
+ int status;
+ waitpid(pid, &status, 0);
+ LOG(INFO) << "/first_stage.sh exited with status " << status;
+ return;
+ }
+ const char* path = "/system/bin/sh";
+ const char* args[] = {path, "/first_stage.sh", nullptr};
+ int rv = execv(path, const_cast<char**>(args));
+ LOG(ERROR) << "unable to execv /first_stage.sh, returned " << rv << " errno " << errno;
+}
+
+namespace android {
+namespace init {
+
+void StartConsole() {
+ if (mknod("/dev/console", S_IFCHR | 0600, makedev(5, 1))) {
+ PLOG(ERROR) << "unable to create /dev/console";
+ return;
+ }
+ pid_t pid = fork();
+ if (pid != 0) {
+ int status;
+ waitpid(pid, &status, 0);
+ LOG(ERROR) << "console shell exited with status " << status;
+ return;
+ }
+ int fd = -1;
+ int tries = 50; // should timeout after 5s
+ // The device driver for console may not be ready yet so retry for a while in case of failure.
+ while (tries--) {
+ fd = open("/dev/console", O_RDWR);
+ if (fd != -1) {
+ break;
+ }
+ std::this_thread::sleep_for(100ms);
+ }
+ if (fd == -1) {
+ LOG(ERROR) << "Could not open /dev/console, errno = " << errno;
+ _exit(127);
+ }
+ ioctl(fd, TIOCSCTTY, 0);
+ dup2(fd, STDIN_FILENO);
+ dup2(fd, STDOUT_FILENO);
+ dup2(fd, STDERR_FILENO);
+ close(fd);
+
+ RunScript();
+ const char* path = "/system/bin/sh";
+ const char* args[] = {path, nullptr};
+ int rv = execv(path, const_cast<char**>(args));
+ LOG(ERROR) << "unable to execv, returned " << rv << " errno " << errno;
+ _exit(127);
+}
+
+bool FirstStageConsole(const std::string& cmdline) {
+ return cmdline.find("androidboot.first_stage_console=1") != std::string::npos;
+}
+
+} // namespace init
+} // namespace android
diff --git a/init/first_stage_console.h b/init/first_stage_console.h
new file mode 100644
index 0000000..7485339
--- /dev/null
+++ b/init/first_stage_console.h
@@ -0,0 +1,28 @@
+/*
+ * 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 <string>
+
+namespace android {
+namespace init {
+
+void StartConsole();
+bool FirstStageConsole(const std::string& cmdline);
+
+} // namespace init
+} // namespace android
diff --git a/init/first_stage_init.cpp b/init/first_stage_init.cpp
index ef8ffbe..5eca644 100644
--- a/init/first_stage_init.cpp
+++ b/init/first_stage_init.cpp
@@ -24,12 +24,10 @@
#include <sys/stat.h>
#include <sys/sysmacros.h>
#include <sys/types.h>
-#include <sys/wait.h>
#include <unistd.h>
#include <filesystem>
#include <string>
-#include <thread>
#include <vector>
#include <android-base/chrono_utils.h>
@@ -39,6 +37,7 @@
#include <private/android_filesystem_config.h>
#include "debug_ramdisk.h"
+#include "first_stage_console.h"
#include "first_stage_mount.h"
#include "reboot_utils.h"
#include "switch_root.h"
@@ -94,49 +93,6 @@
}
}
-void StartConsole() {
- if (mknod("/dev/console", S_IFCHR | 0600, makedev(5, 1))) {
- PLOG(ERROR) << "unable to create /dev/console";
- return;
- }
- pid_t pid = fork();
- if (pid != 0) {
- int status;
- waitpid(pid, &status, 0);
- LOG(ERROR) << "console shell exited with status " << status;
- return;
- }
- int fd = -1;
- int tries = 10;
- // The device driver for console may not be ready yet so retry for a while in case of failure.
- while (tries--) {
- fd = open("/dev/console", O_RDWR);
- if (fd != -1) {
- break;
- }
- std::this_thread::sleep_for(100ms);
- }
- if (fd == -1) {
- LOG(ERROR) << "Could not open /dev/console, errno = " << errno;
- _exit(127);
- }
- ioctl(fd, TIOCSCTTY, 0);
- dup2(fd, STDIN_FILENO);
- dup2(fd, STDOUT_FILENO);
- dup2(fd, STDERR_FILENO);
- close(fd);
-
- const char* path = "/system/bin/sh";
- const char* args[] = {path, nullptr};
- int rv = execv(path, const_cast<char**>(args));
- LOG(ERROR) << "unable to execv, returned " << rv << " errno " << errno;
- _exit(127);
-}
-
-bool FirstStageConsole(const std::string& cmdline) {
- return cmdline.find("androidboot.first_stage_console=1") != std::string::npos;
-}
-
bool ForceNormalBoot(const std::string& cmdline) {
return cmdline.find("androidboot.force_normal_boot=1") != std::string::npos;
}
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/liblog/include/log/log_read.h b/liblog/include/log/log_read.h
index f3be0b8..e2bc297 100644
--- a/liblog/include/log/log_read.h
+++ b/liblog/include/log/log_read.h
@@ -16,22 +16,8 @@
#pragma once
-#include <sys/types.h>
-
-/* deal with possible sys/cdefs.h conflict with fcntl.h */
-#ifdef __unused
-#define __unused_defined __unused
-#undef __unused
-#endif
-
-#include <fcntl.h> /* Pick up O_* macros */
-
-/* restore definitions from above */
-#ifdef __unused_defined
-#define __unused __attribute__((__unused__))
-#endif
-
#include <stdint.h>
+#include <sys/types.h>
#include <log/log_id.h>
#include <log/log_time.h>
@@ -40,6 +26,8 @@
extern "C" {
#endif
+#define ANDROID_LOG_WRAP_DEFAULT_TIMEOUT 7200 /* 2 hour default */
+
/*
* Native log reading interface section. See logcat for sample code.
*
@@ -114,13 +102,10 @@
char* buf, size_t len);
int android_logger_set_prune_list(struct logger_list* logger_list, const char* buf, size_t len);
-#ifndef O_NONBLOCK
+/* The below values are used for the `mode` argument of the below functions. */
+/* Note that 0x00000003 were previously used and should be considered reserved. */
#define ANDROID_LOG_NONBLOCK 0x00000800
-#else
-#define ANDROID_LOG_NONBLOCK O_NONBLOCK
-#endif
#define ANDROID_LOG_WRAP 0x40000000 /* Block until buffer about to wrap */
-#define ANDROID_LOG_WRAP_DEFAULT_TIMEOUT 7200 /* 2 hour default */
#define ANDROID_LOG_PSTORE 0x80000000
struct logger_list* android_logger_list_alloc(int mode, unsigned int tail,
diff --git a/liblog/include_vndk/log/log.h b/liblog/include_vndk/log/log.h
index a79beec..ab4adc4 100644
--- a/liblog/include_vndk/log/log.h
+++ b/liblog/include_vndk/log/log.h
@@ -3,6 +3,9 @@
#ifndef _LIBS_LOG_LOG_H
#define _LIBS_LOG_LOG_H
+/* Historically vendors have depended on this header being included. */
+#include <fcntl.h>
+
#include <android/log.h>
#include <log/log_id.h>
#include <log/log_main.h>
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 9afc9a3..57c4c2e 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 {
@@ -373,12 +395,26 @@
srcs: [
"benchmarks/unwind_benchmarks.cpp",
+ "benchmarks/SymbolBenchmark.cpp",
+ ],
+
+ data: [
+ "benchmarks/files/*",
],
shared_libs: [
"libbase",
"libunwindstack",
],
+
+ target: {
+ android: {
+ static_libs: [
+ "libmeminfo",
+ "libprocinfo",
+ ],
+ },
+ },
}
// Generates the elf data for use in the tests for .gnu_debugdata frames.
diff --git a/libunwindstack/Memory.cpp b/libunwindstack/Memory.cpp
index 8de3d98..fac9085 100644
--- a/libunwindstack/Memory.cpp
+++ b/libunwindstack/Memory.cpp
@@ -324,6 +324,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/benchmarks/SymbolBenchmark.cpp b/libunwindstack/benchmarks/SymbolBenchmark.cpp
new file mode 100644
index 0000000..a850ff0
--- /dev/null
+++ b/libunwindstack/benchmarks/SymbolBenchmark.cpp
@@ -0,0 +1,158 @@
+/*
+ * 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 <err.h>
+#include <inttypes.h>
+#include <malloc.h>
+#include <stdint.h>
+
+#include <string>
+#include <vector>
+
+#include <android-base/file.h>
+#include <android-base/strings.h>
+#include <benchmark/benchmark.h>
+
+#include <unwindstack/Elf.h>
+#include <unwindstack/Memory.h>
+
+#if defined(__BIONIC__)
+
+#include <meminfo/procmeminfo.h>
+#include <procinfo/process_map.h>
+
+static void Gather(uint64_t* rss_bytes) {
+ android::meminfo::ProcMemInfo proc_mem(getpid());
+ const std::vector<android::meminfo::Vma>& maps = proc_mem.MapsWithoutUsageStats();
+ for (auto& vma : maps) {
+ if (vma.name == "[anon:libc_malloc]" || android::base::StartsWith(vma.name, "[anon:scudo:") ||
+ android::base::StartsWith(vma.name, "[anon:GWP-ASan")) {
+ android::meminfo::Vma update_vma(vma);
+ if (!proc_mem.FillInVmaStats(update_vma)) {
+ err(1, "FillInVmaStats failed\n");
+ }
+ *rss_bytes += update_vma.usage.rss;
+ }
+ }
+}
+#endif
+
+static void BenchmarkSymbolLookup(benchmark::State& state, std::vector<uint64_t> offsets,
+ std::string elf_file, bool expect_found) {
+#if defined(__BIONIC__)
+ uint64_t rss_bytes = 0;
+#endif
+ uint64_t alloc_bytes = 0;
+ for (auto _ : state) {
+ state.PauseTiming();
+ unwindstack::Elf elf(unwindstack::Memory::CreateFileMemory(elf_file, 0).release());
+ if (!elf.Init() || !elf.valid()) {
+ errx(1, "Internal Error: Cannot open elf.");
+ }
+
+#if defined(__BIONIC__)
+ mallopt(M_PURGE, 0);
+ uint64_t rss_bytes_before = 0;
+ Gather(&rss_bytes_before);
+#endif
+ uint64_t alloc_bytes_before = mallinfo().uordblks;
+ state.ResumeTiming();
+
+ for (auto pc : offsets) {
+ std::string name;
+ uint64_t offset;
+ bool found = elf.GetFunctionName(pc, &name, &offset);
+ if (expect_found && !found) {
+ errx(1, "expected pc 0x%" PRIx64 " present, but not found.", pc);
+ } else if (!expect_found && found) {
+ errx(1, "expected pc 0x%" PRIx64 " not present, but found.", pc);
+ }
+ }
+
+ state.PauseTiming();
+#if defined(__BIONIC__)
+ mallopt(M_PURGE, 0);
+#endif
+ alloc_bytes += mallinfo().uordblks - alloc_bytes_before;
+#if defined(__BIONIC__)
+ Gather(&rss_bytes);
+ rss_bytes -= rss_bytes_before;
+#endif
+ state.ResumeTiming();
+ }
+
+#if defined(__BIONIC__)
+ state.counters["RSS_BYTES"] = rss_bytes / static_cast<double>(state.iterations());
+#endif
+ state.counters["ALLOCATED_BYTES"] = alloc_bytes / static_cast<double>(state.iterations());
+}
+
+static void BenchmarkSymbolLookup(benchmark::State& state, uint64_t pc, std::string elf_file,
+ bool expect_found) {
+ BenchmarkSymbolLookup(state, std::vector<uint64_t>{pc}, elf_file, expect_found);
+}
+
+std::string GetElfFile() {
+ return android::base::GetExecutableDirectory() + "/benchmarks/files/libart_arm.so";
+}
+
+std::string GetSortedElfFile() {
+ return android::base::GetExecutableDirectory() + "/benchmarks/files/boot_arm.oat";
+}
+
+void BM_symbol_not_present(benchmark::State& state) {
+ BenchmarkSymbolLookup(state, 0, GetElfFile(), false);
+}
+BENCHMARK(BM_symbol_not_present);
+
+void BM_symbol_find_single(benchmark::State& state) {
+ BenchmarkSymbolLookup(state, 0x22b2bc, GetElfFile(), true);
+}
+BENCHMARK(BM_symbol_find_single);
+
+void BM_symbol_find_single_many_times(benchmark::State& state) {
+ BenchmarkSymbolLookup(state, std::vector<uint64_t>(15, 0x22b2bc), GetElfFile(), true);
+}
+BENCHMARK(BM_symbol_find_single_many_times);
+
+void BM_symbol_find_multiple(benchmark::State& state) {
+ BenchmarkSymbolLookup(state,
+ std::vector<uint64_t>{0x22b2bc, 0xd5d30, 0x1312e8, 0x13582e, 0x1389c8},
+ GetElfFile(), true);
+}
+BENCHMARK(BM_symbol_find_multiple);
+
+void BM_symbol_not_present_from_sorted(benchmark::State& state) {
+ BenchmarkSymbolLookup(state, 0, GetSortedElfFile(), false);
+}
+BENCHMARK(BM_symbol_not_present_from_sorted);
+
+void BM_symbol_find_single_from_sorted(benchmark::State& state) {
+ BenchmarkSymbolLookup(state, 0x138638, GetSortedElfFile(), true);
+}
+BENCHMARK(BM_symbol_find_single_from_sorted);
+
+void BM_symbol_find_single_many_times_from_sorted(benchmark::State& state) {
+ BenchmarkSymbolLookup(state, std::vector<uint64_t>(15, 0x138638), GetSortedElfFile(), true);
+}
+BENCHMARK(BM_symbol_find_single_many_times_from_sorted);
+
+void BM_symbol_find_multiple_from_sorted(benchmark::State& state) {
+ BenchmarkSymbolLookup(state,
+ std::vector<uint64_t>{0x138638, 0x84350, 0x14df18, 0x1f3a38, 0x1f3ca8},
+ GetSortedElfFile(), true);
+}
+BENCHMARK(BM_symbol_find_multiple_from_sorted);
diff --git a/libunwindstack/benchmarks/files/boot_arm.oat b/libunwindstack/benchmarks/files/boot_arm.oat
new file mode 100644
index 0000000..51188eb
--- /dev/null
+++ b/libunwindstack/benchmarks/files/boot_arm.oat
Binary files differ
diff --git a/libunwindstack/benchmarks/files/libart_arm.so b/libunwindstack/benchmarks/files/libart_arm.so
new file mode 100644
index 0000000..2201faf
--- /dev/null
+++ b/libunwindstack/benchmarks/files/libart_arm.so
Binary files differ
diff --git a/libunwindstack/include/unwindstack/Memory.h b/libunwindstack/include/unwindstack/Memory.h
index ecd908a..26252b6 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/include/ziparchive/zip_archive.h b/libziparchive/include/ziparchive/zip_archive.h
index 3d51de9..005d697 100644
--- a/libziparchive/include/ziparchive/zip_archive.h
+++ b/libziparchive/include/ziparchive/zip_archive.h
@@ -48,9 +48,10 @@
// Modification time. The zipfile format specifies
// that the first two little endian bytes contain the time
// and the last two little endian bytes contain the date.
- // See `GetModificationTime`.
+ // See `GetModificationTime`. Use signed integer to avoid the
+ // sub-overflow.
// TODO: should be overridden by extra time field, if present.
- uint32_t mod_time;
+ int32_t mod_time;
// Returns `mod_time` as a broken-down struct tm.
struct tm GetModificationTime() const;
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index 7bf2120..014f881 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -1570,6 +1570,7 @@
return true;
}
+// This function returns the embedded timestamp as is; and doesn't perform validations.
tm ZipEntryCommon::GetModificationTime() const {
tm t = {};
diff --git a/logcat/event.logtags b/logcat/event.logtags
index 3a1d36f..56a670a 100644
--- a/logcat/event.logtags
+++ b/logcat/event.logtags
@@ -145,6 +145,8 @@
# libcore failure logging
90100 exp_det_cert_pin_failure (certs|4)
+# 150000 - 160000 reserved for Android Automotive builds
+
1397638484 snet_event_log (subtag|3) (uid|1) (message|3)
# for events that go to stats log buffer