Merge "libcutils: remove unused open_memstream."
diff --git a/adb/adb_utils.cpp b/adb/adb_utils.cpp
index b236fb3..0c3327f 100644
--- a/adb/adb_utils.cpp
+++ b/adb/adb_utils.cpp
@@ -79,22 +79,24 @@
}
std::string escape_arg(const std::string& s) {
- std::string result = s;
-
// Escape any ' in the string (before we single-quote the whole thing).
// The correct way to do this for the shell is to replace ' with '\'' --- that is,
// close the existing single-quoted string, escape a single single-quote, and start
// a new single-quoted string. Like the C preprocessor, the shell will concatenate
// these pieces into one string.
- for (size_t i = 0; i < s.size(); ++i) {
- if (s[i] == '\'') {
- result.insert(i, "'\\'");
- i += 2;
- }
+
+ std::string result;
+ result.push_back('\'');
+
+ size_t base = 0;
+ while (true) {
+ size_t found = s.find('\'', base);
+ result.append(s, base, found - base);
+ if (found == s.npos) break;
+ result.append("'\\''");
+ base = found + 1;
}
- // Prefix and suffix the whole string with '.
- result.insert(result.begin(), '\'');
result.push_back('\'');
return result;
}
diff --git a/adb/adb_utils_test.cpp b/adb/adb_utils_test.cpp
index e1b6287..341323f 100644
--- a/adb/adb_utils_test.cpp
+++ b/adb/adb_utils_test.cpp
@@ -82,30 +82,38 @@
#endif
TEST(adb_utils, escape_arg) {
- ASSERT_EQ(R"('')", escape_arg(""));
+ EXPECT_EQ(R"('')", escape_arg(""));
- ASSERT_EQ(R"('abc')", escape_arg("abc"));
+ EXPECT_EQ(R"('abc')", escape_arg("abc"));
- ASSERT_EQ(R"(' abc')", escape_arg(" abc"));
- ASSERT_EQ(R"(''\''abc')", escape_arg("'abc"));
- ASSERT_EQ(R"('"abc')", escape_arg("\"abc"));
- ASSERT_EQ(R"('\abc')", escape_arg("\\abc"));
- ASSERT_EQ(R"('(abc')", escape_arg("(abc"));
- ASSERT_EQ(R"(')abc')", escape_arg(")abc"));
+ auto wrap = [](const std::string& x) { return '\'' + x + '\''; };
+ const std::string q = R"('\'')";
+ EXPECT_EQ(wrap(q), escape_arg("'"));
+ EXPECT_EQ(wrap(q + q), escape_arg("''"));
+ EXPECT_EQ(wrap(q + "abc" + q), escape_arg("'abc'"));
+ EXPECT_EQ(wrap(q + "abc"), escape_arg("'abc"));
+ EXPECT_EQ(wrap("abc" + q), escape_arg("abc'"));
+ EXPECT_EQ(wrap("abc" + q + "def"), escape_arg("abc'def"));
+ EXPECT_EQ(wrap("a" + q + "b" + q + "c"), escape_arg("a'b'c"));
+ EXPECT_EQ(wrap("a" + q + "bcde" + q + "f"), escape_arg("a'bcde'f"));
- ASSERT_EQ(R"('abc abc')", escape_arg("abc abc"));
- ASSERT_EQ(R"('abc'\''abc')", escape_arg("abc'abc"));
- ASSERT_EQ(R"('abc"abc')", escape_arg("abc\"abc"));
- ASSERT_EQ(R"('abc\abc')", escape_arg("abc\\abc"));
- ASSERT_EQ(R"('abc(abc')", escape_arg("abc(abc"));
- ASSERT_EQ(R"('abc)abc')", escape_arg("abc)abc"));
+ EXPECT_EQ(R"(' abc')", escape_arg(" abc"));
+ EXPECT_EQ(R"('"abc')", escape_arg("\"abc"));
+ EXPECT_EQ(R"('\abc')", escape_arg("\\abc"));
+ EXPECT_EQ(R"('(abc')", escape_arg("(abc"));
+ EXPECT_EQ(R"(')abc')", escape_arg(")abc"));
- ASSERT_EQ(R"('abc ')", escape_arg("abc "));
- ASSERT_EQ(R"('abc'\''')", escape_arg("abc'"));
- ASSERT_EQ(R"('abc"')", escape_arg("abc\""));
- ASSERT_EQ(R"('abc\')", escape_arg("abc\\"));
- ASSERT_EQ(R"('abc(')", escape_arg("abc("));
- ASSERT_EQ(R"('abc)')", escape_arg("abc)"));
+ EXPECT_EQ(R"('abc abc')", escape_arg("abc abc"));
+ EXPECT_EQ(R"('abc"abc')", escape_arg("abc\"abc"));
+ EXPECT_EQ(R"('abc\abc')", escape_arg("abc\\abc"));
+ EXPECT_EQ(R"('abc(abc')", escape_arg("abc(abc"));
+ EXPECT_EQ(R"('abc)abc')", escape_arg("abc)abc"));
+
+ EXPECT_EQ(R"('abc ')", escape_arg("abc "));
+ EXPECT_EQ(R"('abc"')", escape_arg("abc\""));
+ EXPECT_EQ(R"('abc\')", escape_arg("abc\\"));
+ EXPECT_EQ(R"('abc(')", escape_arg("abc("));
+ EXPECT_EQ(R"('abc)')", escape_arg("abc)"));
}
void test_mkdirs(const std::string& basepath) {
diff --git a/adb/client/commandline.h b/adb/client/commandline.h
index 3d10030..3aa03a7 100644
--- a/adb/client/commandline.h
+++ b/adb/client/commandline.h
@@ -83,6 +83,14 @@
DISALLOW_COPY_AND_ASSIGN(DefaultStandardStreamsCallback);
};
+class SilentStandardStreamsCallbackInterface : public StandardStreamsCallbackInterface {
+ public:
+ SilentStandardStreamsCallbackInterface() = default;
+ void OnStdout(const char*, int) override final {}
+ void OnStderr(const char*, int) override final {}
+ int Done(int status) override final { return status; }
+};
+
// Singleton.
extern DefaultStandardStreamsCallback DEFAULT_STANDARD_STREAMS_CALLBACK;
diff --git a/adb/client/file_sync_client.cpp b/adb/client/file_sync_client.cpp
index 1275641..a438dbb 100644
--- a/adb/client/file_sync_client.cpp
+++ b/adb/client/file_sync_client.cpp
@@ -44,6 +44,8 @@
#include "sysdeps/errno.h"
#include "sysdeps/stat.h"
+#include "client/commandline.h"
+
#include <android-base/file.h>
#include <android-base/strings.h>
#include <android-base/stringprintf.h>
@@ -202,12 +204,11 @@
max = SYNC_DATA_MAX; // TODO: decide at runtime.
std::string error;
- FeatureSet features;
- if (!adb_get_feature_set(&features, &error)) {
+ if (!adb_get_feature_set(&features_, &error)) {
fd = -1;
Error("failed to get feature set: %s", error.c_str());
} else {
- have_stat_v2_ = CanUseFeature(features, kFeatureStat2);
+ have_stat_v2_ = CanUseFeature(features_, kFeatureStat2);
fd = adb_connect("sync:", &error);
if (fd < 0) {
Error("connect failed: %s", error.c_str());
@@ -232,6 +233,8 @@
line_printer_.KeepInfoLine();
}
+ const FeatureSet& Features() const { return features_; }
+
bool IsValid() { return fd >= 0; }
bool ReceivedError(const char* from, const char* to) {
@@ -576,6 +579,7 @@
private:
bool expect_done_;
+ FeatureSet features_;
bool have_stat_v2_;
TransferLedger global_ledger_;
@@ -805,7 +809,7 @@
}
static bool local_build_list(SyncConnection& sc, std::vector<copyinfo>* file_list,
- const std::string& lpath,
+ std::vector<std::string>* directory_list, const std::string& lpath,
const std::string& rpath) {
std::vector<copyinfo> dirlist;
std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(lpath.c_str()), closedir);
@@ -848,21 +852,9 @@
// Close this directory and recurse.
dir.reset();
- // Add the current directory to the list if it was empty, to ensure that
- // it gets created.
- if (empty_dir) {
- // TODO(b/25566053): Make pushing empty directories work.
- // TODO(b/25457350): We don't preserve permissions on directories.
- sc.Warning("skipping empty directory '%s'", lpath.c_str());
- copyinfo ci(android::base::Dirname(lpath), android::base::Dirname(rpath),
- android::base::Basename(lpath), S_IFDIR);
- ci.skip = true;
- file_list->push_back(ci);
- return true;
- }
-
for (const copyinfo& ci : dirlist) {
- local_build_list(sc, file_list, ci.lpath, ci.rpath);
+ directory_list->push_back(ci.rpath);
+ local_build_list(sc, file_list, directory_list, ci.lpath, ci.rpath);
}
return true;
@@ -879,11 +871,54 @@
// Recursively build the list of files to copy.
std::vector<copyinfo> file_list;
+ std::vector<std::string> directory_list;
+
+ for (std::string dirpath = rpath; dirpath != "/"; dirpath = android::base::Dirname(dirpath)) {
+ directory_list.push_back(dirpath);
+ }
+ std::reverse(directory_list.begin(), directory_list.end());
+
int skipped = 0;
- if (!local_build_list(sc, &file_list, lpath, rpath)) {
+ if (!local_build_list(sc, &file_list, &directory_list, lpath, rpath)) {
return false;
}
+ // b/110953234:
+ // P shipped with a bug that causes directory creation as a side-effect of a push to fail.
+ // Work around this by explicitly doing a mkdir via shell.
+ //
+ // Devices that don't support shell_v2 are unhappy if we try to send a too-long packet to them,
+ // but they're not affected by this bug, so only apply the workaround if we have shell_v2.
+ //
+ // TODO(b/25457350): We don't preserve permissions on directories.
+ // TODO: Find all of the leaves and `mkdir -p` them instead?
+ if (CanUseFeature(sc.Features(), kFeatureShell2)) {
+ SilentStandardStreamsCallbackInterface cb;
+ std::string cmd = "mkdir";
+ for (const auto& dir : directory_list) {
+ std::string escaped_path = escape_arg(dir);
+ if (escaped_path.size() > 16384) {
+ // Somewhat arbitrarily limit that probably won't ever happen.
+ sc.Error("path too long: %s", escaped_path.c_str());
+ return false;
+ }
+
+ // The maximum should be 64kiB, but that's not including other stuff that gets tacked
+ // onto the command line, so let's be a bit conservative.
+ if (cmd.size() + escaped_path.size() > 32768) {
+ // Dispatch the command, ignoring failure (since the directory might already exist).
+ send_shell_command(cmd, false, &cb);
+ cmd = "mkdir";
+ }
+ cmd += " ";
+ cmd += escaped_path;
+ }
+
+ if (cmd != "mkdir") {
+ send_shell_command(cmd, false, &cb);
+ }
+ }
+
if (check_timestamps) {
for (const copyinfo& ci : file_list) {
if (!sc.SendLstat(ci.rpath.c_str())) {
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index f1197d7..f2911e0 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -314,7 +314,6 @@
#else /* !_WIN32 a.k.a. Unix */
#include <cutils/sockets.h>
-#include <cutils/threads.h>
#include <fcntl.h>
#include <poll.h>
#include <signal.h>
diff --git a/adb/test_device.py b/adb/test_device.py
index 5aa2684..4abe7a7 100644
--- a/adb/test_device.py
+++ b/adb/test_device.py
@@ -750,7 +750,6 @@
if host_dir is not None:
shutil.rmtree(host_dir)
- @unittest.expectedFailure # b/25566053
def test_push_empty(self):
"""Push a directory containing an empty directory to the device."""
self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
diff --git a/base/include/android-base/threads.h b/base/include/android-base/threads.h
index f4ba809..dba1fc6 100644
--- a/base/include/android-base/threads.h
+++ b/base/include/android-base/threads.h
@@ -23,3 +23,8 @@
uint64_t GetThreadId();
}
} // namespace android
+
+#if defined(__GLIBC__)
+// bionic has this Linux-specifix call, but glibc doesn't.
+extern "C" int tgkill(int tgid, int tid, int sig);
+#endif
diff --git a/base/threads.cpp b/base/threads.cpp
index a71382b..48f6197 100644
--- a/base/threads.cpp
+++ b/base/threads.cpp
@@ -46,3 +46,9 @@
} // namespace base
} // namespace android
+
+#if defined(__GLIBC__)
+int tgkill(int tgid, int tid, int sig) {
+ return syscall(__NR_tgkill, tgid, tid, sig);
+}
+#endif
diff --git a/fs_mgr/liblp/Android.bp b/fs_mgr/liblp/Android.bp
index f59fa84..1050cf5 100644
--- a/fs_mgr/liblp/Android.bp
+++ b/fs_mgr/liblp/Android.bp
@@ -46,6 +46,9 @@
cc_test {
name: "liblp_test",
defaults: ["fs_mgr_defaults"],
+ cppflags: [
+ "-Wno-unused-parameter",
+ ],
static_libs: [
"libbase",
"liblog",
diff --git a/fs_mgr/liblp/builder.cpp b/fs_mgr/liblp/builder.cpp
index 421f4e6..720590d 100644
--- a/fs_mgr/liblp/builder.cpp
+++ b/fs_mgr/liblp/builder.cpp
@@ -54,6 +54,8 @@
}
return true;
#else
+ (void)block_device;
+ (void)device_info;
LERROR << __PRETTY_FUNCTION__ << ": Not supported on this operating system.";
return false;
#endif
diff --git a/fs_mgr/liblp/include/liblp/writer.h b/fs_mgr/liblp/include/liblp/writer.h
index efa409d..f4d1ad7 100644
--- a/fs_mgr/liblp/include/liblp/writer.h
+++ b/fs_mgr/liblp/include/liblp/writer.h
@@ -17,33 +17,35 @@
#ifndef LIBLP_WRITER_H
#define LIBLP_WRITER_H
+#include <functional>
#include "metadata_format.h"
namespace android {
namespace fs_mgr {
-// When flashing the initial logical partition layout, we also write geometry
-// information at the start and end of the big physical partition. This helps
-// locate metadata and backup metadata in the case of corruption or a failed
-// update. For normal changes to the metadata, we never modify the geometry.
-enum class SyncMode {
- // Write geometry information.
- Flash,
- // Normal update of a single slot.
- Update
-};
+// Place an initial partition table on the device. This will overwrite the
+// existing geometry, and should not be used for normal partition table
+// updates. False can be returned if the geometry is incompatible with the
+// block device or an I/O error occurs.
+bool FlashPartitionTable(const std::string& block_device, const LpMetadata& metadata,
+ uint32_t slot_number);
-// Write the given partition table to the given block device, writing only
-// copies according to the given sync mode.
-//
-// This will perform some verification, such that the device has enough space
-// to store the metadata as well as all of its extents.
-//
-// The slot number indicates which metadata slot to use.
-bool WritePartitionTable(const char* block_device, const LpMetadata& metadata, SyncMode sync_mode,
- uint32_t slot_number);
-bool WritePartitionTable(int fd, const LpMetadata& metadata, SyncMode sync_mode,
- uint32_t slot_number);
+// Update the partition table for a given metadata slot number. False is
+// returned if an error occurs, which can include:
+// - Invalid slot number.
+// - I/O error.
+// - Corrupt or missing metadata geometry on disk.
+// - Incompatible geometry.
+bool UpdatePartitionTable(const std::string& block_device, const LpMetadata& metadata,
+ uint32_t slot_number);
+
+// These variants are for testing only. The path-based functions should be used
+// for actual operation, so that open() is called with the correct flags.
+bool FlashPartitionTable(int fd, const LpMetadata& metadata, uint32_t slot_number);
+bool UpdatePartitionTable(int fd, const LpMetadata& metadata, uint32_t slot_number);
+
+bool UpdatePartitionTable(int fd, const LpMetadata& metadata, uint32_t slot_number,
+ std::function<bool(int, const std::string&)> writer);
// Helper function to serialize geometry and metadata to a normal file, for
// flashing or debugging.
diff --git a/fs_mgr/liblp/io_test.cpp b/fs_mgr/liblp/io_test.cpp
index 2595654..c3f8f36 100644
--- a/fs_mgr/liblp/io_test.cpp
+++ b/fs_mgr/liblp/io_test.cpp
@@ -102,7 +102,7 @@
if (!exported) {
return {};
}
- if (!WritePartitionTable(fd, *exported.get(), SyncMode::Flash, 0)) {
+ if (!FlashPartitionTable(fd, *exported.get(), 0)) {
return {};
}
return fd;
@@ -131,7 +131,7 @@
unique_fd fd = CreateFakeDisk();
ASSERT_GE(fd, 0);
- EXPECT_FALSE(WritePartitionTable(fd, *exported.get(), SyncMode::Flash, 0));
+ EXPECT_FALSE(FlashPartitionTable(fd, *exported.get(), 0));
}
// Test the basics of flashing a partition and reading it back.
@@ -146,7 +146,7 @@
// Export and flash.
unique_ptr<LpMetadata> exported = builder->Export();
ASSERT_NE(exported, nullptr);
- ASSERT_TRUE(WritePartitionTable(fd, *exported.get(), SyncMode::Flash, 0));
+ ASSERT_TRUE(FlashPartitionTable(fd, *exported.get(), 0));
// Read back. Note that some fields are only filled in during
// serialization, so exported and imported will not be identical. For
@@ -195,7 +195,7 @@
// Change the name before writing to the next slot.
strncpy(imported->partitions[0].name, "vendor", sizeof(imported->partitions[0].name));
- ASSERT_TRUE(WritePartitionTable(fd, *imported.get(), SyncMode::Update, 1));
+ ASSERT_TRUE(UpdatePartitionTable(fd, *imported.get(), 1));
// Read back the original slot, make sure it hasn't changed.
imported = ReadMetadata(fd, 0);
@@ -231,7 +231,7 @@
unique_ptr<LpMetadata> metadata = ReadMetadata(fd, 0);
ASSERT_NE(metadata, nullptr);
for (uint32_t i = 1; i < kMetadataSlots; i++) {
- ASSERT_TRUE(WritePartitionTable(fd, *metadata.get(), SyncMode::Update, i));
+ ASSERT_TRUE(UpdatePartitionTable(fd, *metadata.get(), i));
}
// Verify that we can't read unavailable slots.
@@ -246,25 +246,25 @@
unique_ptr<LpMetadata> imported = ReadMetadata(fd, 0);
ASSERT_NE(imported, nullptr);
- ASSERT_TRUE(WritePartitionTable(fd, *imported.get(), SyncMode::Update, 1));
+ ASSERT_TRUE(UpdatePartitionTable(fd, *imported.get(), 1));
imported->geometry.metadata_max_size += LP_SECTOR_SIZE;
- ASSERT_FALSE(WritePartitionTable(fd, *imported.get(), SyncMode::Update, 1));
+ ASSERT_FALSE(UpdatePartitionTable(fd, *imported.get(), 1));
imported = ReadMetadata(fd, 0);
ASSERT_NE(imported, nullptr);
imported->geometry.metadata_slot_count++;
- ASSERT_FALSE(WritePartitionTable(fd, *imported.get(), SyncMode::Update, 1));
+ ASSERT_FALSE(UpdatePartitionTable(fd, *imported.get(), 1));
imported = ReadMetadata(fd, 0);
ASSERT_NE(imported, nullptr);
imported->geometry.first_logical_sector++;
- ASSERT_FALSE(WritePartitionTable(fd, *imported.get(), SyncMode::Update, 1));
+ ASSERT_FALSE(UpdatePartitionTable(fd, *imported.get(), 1));
imported = ReadMetadata(fd, 0);
ASSERT_NE(imported, nullptr);
imported->geometry.last_logical_sector--;
- ASSERT_FALSE(WritePartitionTable(fd, *imported.get(), SyncMode::Update, 1));
+ ASSERT_FALSE(UpdatePartitionTable(fd, *imported.get(), 1));
}
// Test that changing one bit of metadata is enough to break the checksum.
@@ -353,8 +353,8 @@
ASSERT_GE(fd, 0);
// Check that we are able to write our table.
- ASSERT_TRUE(WritePartitionTable(fd, *exported.get(), SyncMode::Flash, 0));
- ASSERT_TRUE(WritePartitionTable(fd, *exported.get(), SyncMode::Update, 1));
+ ASSERT_TRUE(FlashPartitionTable(fd, *exported.get(), 0));
+ ASSERT_TRUE(UpdatePartitionTable(fd, *exported.get(), 1));
// Check that adding one more partition overflows the metadata allotment.
partition = builder->AddPartition("final", TEST_GUID, LP_PARTITION_ATTR_NONE);
@@ -364,7 +364,7 @@
ASSERT_NE(exported, nullptr);
// The new table should be too large to be written.
- ASSERT_FALSE(WritePartitionTable(fd, *exported.get(), SyncMode::Update, 1));
+ ASSERT_FALSE(UpdatePartitionTable(fd, *exported.get(), 1));
// Check that the first and last logical sectors weren't touched when we
// wrote this almost-full metadata.
@@ -393,3 +393,85 @@
unique_ptr<LpMetadata> imported = ReadFromImageFile(fd);
ASSERT_NE(imported, nullptr);
}
+
+class BadWriter {
+ public:
+ // When requested, write garbage instead of the requested bytes, then
+ // return false.
+ bool operator()(int fd, const std::string& blob) {
+ if (++write_count_ == fail_on_write_) {
+ std::unique_ptr<char[]> new_data = std::make_unique<char[]>(blob.size());
+ memset(new_data.get(), 0xe5, blob.size());
+ EXPECT_TRUE(android::base::WriteFully(fd, new_data.get(), blob.size()));
+ return false;
+ } else {
+ return android::base::WriteFully(fd, blob.data(), blob.size());
+ }
+ }
+ void FailOnWrite(int number) {
+ fail_on_write_ = number;
+ write_count_ = 0;
+ }
+
+ private:
+ int fail_on_write_ = 0;
+ int write_count_ = 0;
+};
+
+// Test that an interrupted flash operation on the "primary" copy of metadata
+// is not fatal.
+TEST(liblp, FlashPrimaryMetadataFailure) {
+ // Initial state.
+ unique_fd fd = CreateFlashedDisk();
+ ASSERT_GE(fd, 0);
+
+ BadWriter writer;
+
+ // Read and write it back.
+ writer.FailOnWrite(1);
+ unique_ptr<LpMetadata> imported = ReadMetadata(fd, 0);
+ ASSERT_NE(imported, nullptr);
+ ASSERT_FALSE(UpdatePartitionTable(fd, *imported.get(), 0, writer));
+
+ // We should still be able to read the backup copy.
+ imported = ReadMetadata(fd, 0);
+ ASSERT_NE(imported, nullptr);
+
+ // Flash again, this time fail the backup copy. We should still be able
+ // to read the primary.
+ writer.FailOnWrite(2);
+ ASSERT_FALSE(UpdatePartitionTable(fd, *imported.get(), 0, writer));
+ imported = ReadMetadata(fd, 0);
+ ASSERT_NE(imported, nullptr);
+}
+
+// Test that an interrupted flash operation on the "backup" copy of metadata
+// is not fatal.
+TEST(liblp, FlashBackupMetadataFailure) {
+ // Initial state.
+ unique_fd fd = CreateFlashedDisk();
+ ASSERT_GE(fd, 0);
+
+ BadWriter writer;
+
+ // Read and write it back.
+ writer.FailOnWrite(2);
+ unique_ptr<LpMetadata> imported = ReadMetadata(fd, 0);
+ ASSERT_NE(imported, nullptr);
+ ASSERT_FALSE(UpdatePartitionTable(fd, *imported.get(), 0, writer));
+
+ // We should still be able to read the primary copy.
+ imported = ReadMetadata(fd, 0);
+ ASSERT_NE(imported, nullptr);
+
+ // Flash again, this time fail the primary copy. We should still be able
+ // to read the primary.
+ //
+ // TODO(dvander): This is currently not handled correctly. liblp does not
+ // guarantee both copies are in sync before the update. The ASSERT_EQ
+ // will change to an ASSERT_NE when this is fixed.
+ writer.FailOnWrite(1);
+ ASSERT_FALSE(UpdatePartitionTable(fd, *imported.get(), 0, writer));
+ imported = ReadMetadata(fd, 0);
+ ASSERT_EQ(imported, nullptr);
+}
diff --git a/fs_mgr/liblp/writer.cpp b/fs_mgr/liblp/writer.cpp
index 89cbabd..36c7b5a 100644
--- a/fs_mgr/liblp/writer.cpp
+++ b/fs_mgr/liblp/writer.cpp
@@ -73,8 +73,14 @@
// Perform sanity checks so we don't accidentally overwrite valid metadata
// with potentially invalid metadata, or random partition data with metadata.
-static bool ValidateGeometryAndMetadata(const LpMetadata& metadata, uint64_t blockdevice_size,
- uint64_t metadata_size) {
+static bool ValidateAndSerializeMetadata(int fd, const LpMetadata& metadata, std::string* blob) {
+ uint64_t blockdevice_size;
+ if (!GetDescriptorSize(fd, &blockdevice_size)) {
+ return false;
+ }
+
+ *blob = SerializeMetadata(metadata);
+
const LpMetadataHeader& header = metadata.header;
const LpMetadataGeometry& geometry = metadata.geometry;
// Validate the usable sector range.
@@ -83,7 +89,7 @@
return false;
}
// Make sure we're writing within the space reserved.
- if (metadata_size > geometry.metadata_max_size) {
+ if (blob->size() > geometry.metadata_max_size) {
LERROR << "Logical partition metadata is too large.";
return false;
}
@@ -124,70 +130,26 @@
return true;
}
-bool WritePartitionTable(int fd, const LpMetadata& metadata, SyncMode sync_mode,
- uint32_t slot_number) {
- uint64_t size;
- if (!GetDescriptorSize(fd, &size)) {
- return false;
- }
+static bool DefaultWriter(int fd, const std::string& blob) {
+ return android::base::WriteFully(fd, blob.data(), blob.size());
+}
- const LpMetadataGeometry& geometry = metadata.geometry;
- if (sync_mode != SyncMode::Flash) {
- // Verify that the old geometry is identical. If it's not, then we've
- // based this new metadata on invalid assumptions.
- LpMetadataGeometry old_geometry;
- if (!ReadLogicalPartitionGeometry(fd, &old_geometry)) {
- return false;
- }
- if (!CompareGeometry(geometry, old_geometry)) {
- LERROR << "Incompatible geometry in new logical partition metadata";
- return false;
- }
- }
-
+static bool WriteMetadata(int fd, const LpMetadataGeometry& geometry, uint32_t slot_number,
+ const std::string& blob,
+ std::function<bool(int, const std::string&)> writer) {
// Make sure we're writing to a valid metadata slot.
if (slot_number >= geometry.metadata_slot_count) {
LERROR << "Invalid logical partition metadata slot number.";
return false;
}
- // Before writing geometry and/or logical partition tables, perform some
- // basic checks that the geometry and tables are coherent, and will fit
- // on the given block device.
- std::string blob = SerializeMetadata(metadata);
- if (!ValidateGeometryAndMetadata(metadata, size, blob.size())) {
- return false;
- }
-
- // First write geometry if this is a flash operation. It gets written to
- // the first and last 4096-byte regions of the device.
- if (sync_mode == SyncMode::Flash) {
- std::string blob = SerializeGeometry(metadata.geometry);
- if (SeekFile64(fd, 0, SEEK_SET) < 0) {
- PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset 0";
- return false;
- }
- if (!android::base::WriteFully(fd, blob.data(), blob.size())) {
- PERROR << __PRETTY_FUNCTION__ << "write " << blob.size() << " bytes failed";
- return false;
- }
- if (SeekFile64(fd, -LP_METADATA_GEOMETRY_SIZE, SEEK_END) < 0) {
- PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset " << -LP_METADATA_GEOMETRY_SIZE;
- return false;
- }
- if (!android::base::WriteFully(fd, blob.data(), blob.size())) {
- PERROR << __PRETTY_FUNCTION__ << "backup write " << blob.size() << " bytes failed";
- return false;
- }
- }
-
// Write the primary copy of the metadata.
int64_t primary_offset = GetPrimaryMetadataOffset(geometry, slot_number);
if (SeekFile64(fd, primary_offset, SEEK_SET) < 0) {
PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset " << primary_offset;
return false;
}
- if (!android::base::WriteFully(fd, blob.data(), blob.size())) {
+ if (!writer(fd, blob)) {
PERROR << __PRETTY_FUNCTION__ << "write " << blob.size() << " bytes failed";
return false;
}
@@ -204,21 +166,92 @@
<< " is within logical partition bounds, sector " << geometry.last_logical_sector;
return false;
}
- if (!android::base::WriteFully(fd, blob.data(), blob.size())) {
+ if (!writer(fd, blob)) {
PERROR << __PRETTY_FUNCTION__ << "backup write " << blob.size() << " bytes failed";
return false;
}
return true;
}
-bool WritePartitionTable(const char* block_device, const LpMetadata& metadata, SyncMode sync_mode,
+bool FlashPartitionTable(int fd, const LpMetadata& metadata, uint32_t slot_number) {
+ // Before writing geometry and/or logical partition tables, perform some
+ // basic checks that the geometry and tables are coherent, and will fit
+ // on the given block device.
+ std::string metadata_blob;
+ if (!ValidateAndSerializeMetadata(fd, metadata, &metadata_blob)) {
+ return false;
+ }
+
+ // Write geometry to the first and last 4096 bytes of the device.
+ std::string blob = SerializeGeometry(metadata.geometry);
+ if (SeekFile64(fd, 0, SEEK_SET) < 0) {
+ PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset 0";
+ return false;
+ }
+ if (!android::base::WriteFully(fd, blob.data(), blob.size())) {
+ PERROR << __PRETTY_FUNCTION__ << "write " << blob.size() << " bytes failed";
+ return false;
+ }
+ if (SeekFile64(fd, -LP_METADATA_GEOMETRY_SIZE, SEEK_END) < 0) {
+ PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset " << -LP_METADATA_GEOMETRY_SIZE;
+ return false;
+ }
+ if (!android::base::WriteFully(fd, blob.data(), blob.size())) {
+ PERROR << __PRETTY_FUNCTION__ << "backup write " << blob.size() << " bytes failed";
+ return false;
+ }
+
+ // Write metadata to the correct slot, now that geometry is in place.
+ return WriteMetadata(fd, metadata.geometry, slot_number, metadata_blob, DefaultWriter);
+}
+
+bool UpdatePartitionTable(int fd, const LpMetadata& metadata, uint32_t slot_number,
+ std::function<bool(int, const std::string&)> writer) {
+ // Before writing geometry and/or logical partition tables, perform some
+ // basic checks that the geometry and tables are coherent, and will fit
+ // on the given block device.
+ std::string blob;
+ if (!ValidateAndSerializeMetadata(fd, metadata, &blob)) {
+ return false;
+ }
+
+ // Verify that the old geometry is identical. If it's not, then we might be
+ // writing a table that was built for a different device, so we must reject
+ // it.
+ const LpMetadataGeometry& geometry = metadata.geometry;
+ LpMetadataGeometry old_geometry;
+ if (!ReadLogicalPartitionGeometry(fd, &old_geometry)) {
+ return false;
+ }
+ if (!CompareGeometry(geometry, old_geometry)) {
+ LERROR << "Incompatible geometry in new logical partition metadata";
+ return false;
+ }
+ return WriteMetadata(fd, geometry, slot_number, blob, writer);
+}
+
+bool FlashPartitionTable(const std::string& block_device, const LpMetadata& metadata,
uint32_t slot_number) {
- android::base::unique_fd fd(open(block_device, O_RDWR | O_SYNC));
+ android::base::unique_fd fd(open(block_device.c_str(), O_RDWR | O_SYNC));
if (fd < 0) {
PERROR << __PRETTY_FUNCTION__ << "open failed: " << block_device;
return false;
}
- return WritePartitionTable(fd, metadata, sync_mode, slot_number);
+ return FlashPartitionTable(fd, metadata, slot_number);
+}
+
+bool UpdatePartitionTable(const std::string& block_device, const LpMetadata& metadata,
+ uint32_t slot_number) {
+ android::base::unique_fd fd(open(block_device.c_str(), O_RDWR | O_SYNC));
+ if (fd < 0) {
+ PERROR << __PRETTY_FUNCTION__ << "open failed: " << block_device;
+ return false;
+ }
+ return UpdatePartitionTable(fd, metadata, slot_number);
+}
+
+bool UpdatePartitionTable(int fd, const LpMetadata& metadata, uint32_t slot_number) {
+ return UpdatePartitionTable(fd, metadata, slot_number, DefaultWriter);
}
bool WriteToImageFile(int fd, const LpMetadata& input) {
diff --git a/libbacktrace/Android.bp b/libbacktrace/Android.bp
index b4bf35f..a10e636 100644
--- a/libbacktrace/Android.bp
+++ b/libbacktrace/Android.bp
@@ -42,7 +42,6 @@
"Backtrace.cpp",
"BacktraceCurrent.cpp",
"BacktracePtrace.cpp",
- "thread_utils.c",
"ThreadEntry.cpp",
"UnwindStack.cpp",
"UnwindStackMap.cpp",
@@ -94,7 +93,6 @@
],
static_libs: [
- "libcutils",
"libprocinfo",
],
@@ -145,7 +143,6 @@
"backtrace_offline_test.cpp",
"backtrace_test.cpp",
"GetPss.cpp",
- "thread_utils.c",
],
cflags: [
@@ -159,7 +156,6 @@
"libbacktrace",
"libdexfile",
"libbase",
- "libcutils",
"liblog",
"libunwindstack",
],
diff --git a/libbacktrace/Backtrace.cpp b/libbacktrace/Backtrace.cpp
index 6445a7c..6bec63c 100644
--- a/libbacktrace/Backtrace.cpp
+++ b/libbacktrace/Backtrace.cpp
@@ -23,6 +23,7 @@
#include <string>
#include <android-base/stringprintf.h>
+#include <android-base/threads.h>
#include <backtrace/Backtrace.h>
#include <backtrace/BacktraceMap.h>
@@ -31,7 +32,6 @@
#include "BacktraceLog.h"
#include "UnwindStack.h"
-#include "thread_utils.h"
using android::base::StringPrintf;
@@ -124,7 +124,7 @@
if (pid == BACKTRACE_CURRENT_PROCESS) {
pid = getpid();
if (tid == BACKTRACE_CURRENT_THREAD) {
- tid = gettid();
+ tid = android::base::GetThreadId();
}
} else if (tid == BACKTRACE_CURRENT_THREAD) {
tid = pid;
diff --git a/libbacktrace/BacktraceCurrent.cpp b/libbacktrace/BacktraceCurrent.cpp
index f6f4423..39cb995 100644
--- a/libbacktrace/BacktraceCurrent.cpp
+++ b/libbacktrace/BacktraceCurrent.cpp
@@ -28,13 +28,13 @@
#include <string>
+#include <android-base/threads.h>
#include <backtrace/Backtrace.h>
#include <backtrace/BacktraceMap.h>
#include "BacktraceAsyncSafeLog.h"
#include "BacktraceCurrent.h"
#include "ThreadEntry.h"
-#include "thread_utils.h"
bool BacktraceCurrent::ReadWord(uint64_t ptr, word_t* out_value) {
if (!VerifyReadWordArgs(ptr, out_value)) {
@@ -76,7 +76,7 @@
return UnwindFromContext(num_ignore_frames, ucontext);
}
- if (Tid() != gettid()) {
+ if (Tid() != android::base::GetThreadId()) {
return UnwindThread(num_ignore_frames);
}
@@ -114,16 +114,17 @@
static void SignalLogOnly(int, siginfo_t*, void*) {
ErrnoRestorer restore;
- BACK_ASYNC_SAFE_LOGE("pid %d, tid %d: Received a spurious signal %d\n", getpid(), gettid(),
- THREAD_SIGNAL);
+ BACK_ASYNC_SAFE_LOGE("pid %d, tid %d: Received a spurious signal %d\n", getpid(),
+ static_cast<int>(android::base::GetThreadId()), THREAD_SIGNAL);
}
static void SignalHandler(int, siginfo_t*, void* sigcontext) {
ErrnoRestorer restore;
- ThreadEntry* entry = ThreadEntry::Get(getpid(), gettid(), false);
+ ThreadEntry* entry = ThreadEntry::Get(getpid(), android::base::GetThreadId(), false);
if (!entry) {
- BACK_ASYNC_SAFE_LOGE("pid %d, tid %d entry not found", getpid(), gettid());
+ BACK_ASYNC_SAFE_LOGE("pid %d, tid %d entry not found", getpid(),
+ static_cast<int>(android::base::GetThreadId()));
return;
}
diff --git a/libbacktrace/BacktraceMap.cpp b/libbacktrace/BacktraceMap.cpp
index 399721d..6a967f7 100644
--- a/libbacktrace/BacktraceMap.cpp
+++ b/libbacktrace/BacktraceMap.cpp
@@ -32,8 +32,6 @@
#include <procinfo/process_map.h>
#endif
-#include "thread_utils.h"
-
using android::base::StringPrintf;
std::string backtrace_map_t::Name() const {
diff --git a/libbacktrace/BacktracePtrace.cpp b/libbacktrace/BacktracePtrace.cpp
index bf6b16f..9da457d 100644
--- a/libbacktrace/BacktracePtrace.cpp
+++ b/libbacktrace/BacktracePtrace.cpp
@@ -28,7 +28,6 @@
#include "BacktraceLog.h"
#include "BacktracePtrace.h"
-#include "thread_utils.h"
#if !defined(__APPLE__)
static bool PtraceRead(pid_t tid, uint64_t addr, word_t* out_value) {
diff --git a/libbacktrace/UnwindStack.cpp b/libbacktrace/UnwindStack.cpp
index e087b2e..4e7f761 100644
--- a/libbacktrace/UnwindStack.cpp
+++ b/libbacktrace/UnwindStack.cpp
@@ -23,10 +23,6 @@
#include <set>
#include <string>
-#if !defined(__ANDROID__)
-#include <cutils/threads.h>
-#endif
-
#include <backtrace/Backtrace.h>
#include <demangle.h>
#include <unwindstack/Elf.h>
diff --git a/libbacktrace/backtrace_benchmarks.cpp b/libbacktrace/backtrace_benchmarks.cpp
index a23e3b4..099ac60 100644
--- a/libbacktrace/backtrace_benchmarks.cpp
+++ b/libbacktrace/backtrace_benchmarks.cpp
@@ -27,6 +27,7 @@
#include <string>
#include <android-base/file.h>
+#include <android-base/threads.h>
#include <benchmark/benchmark.h>
@@ -154,7 +155,7 @@
static void CreateBacktrace(benchmark::State& state, BacktraceMap* map, BacktraceCreateFn fn) {
while (state.KeepRunning()) {
- std::unique_ptr<Backtrace> backtrace(fn(getpid(), gettid(), map));
+ std::unique_ptr<Backtrace> backtrace(fn(getpid(), android::base::GetThreadId(), map));
backtrace->Unwind(0);
}
}
diff --git a/libbacktrace/backtrace_offline_test.cpp b/libbacktrace/backtrace_offline_test.cpp
index 9877f29..7d1027e 100644
--- a/libbacktrace/backtrace_offline_test.cpp
+++ b/libbacktrace/backtrace_offline_test.cpp
@@ -31,9 +31,9 @@
#include <android-base/macros.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
+#include <android-base/threads.h>
#include <backtrace/Backtrace.h>
#include <backtrace/BacktraceMap.h>
-#include <cutils/threads.h>
#include <gtest/gtest.h>
@@ -99,7 +99,7 @@
static void* OfflineThreadFunc(void* arg) {
OfflineThreadArg* fn_arg = reinterpret_cast<OfflineThreadArg*>(arg);
- fn_arg->tid = gettid();
+ fn_arg->tid = android::base::GetThreadId();
test_get_context_and_wait(&fn_arg->ucontext, &fn_arg->exit_flag);
return nullptr;
}
diff --git a/libbacktrace/backtrace_test.cpp b/libbacktrace/backtrace_test.cpp
index f78a31f..06a32c7 100644
--- a/libbacktrace/backtrace_test.cpp
+++ b/libbacktrace/backtrace_test.cpp
@@ -47,16 +47,15 @@
#include <android-base/macros.h>
#include <android-base/stringprintf.h>
#include <android-base/test_utils.h>
+#include <android-base/threads.h>
#include <android-base/unique_fd.h>
#include <cutils/atomic.h>
-#include <cutils/threads.h>
#include <gtest/gtest.h>
// For the THREAD_SIGNAL definition.
#include "BacktraceCurrent.h"
#include "backtrace_testlib.h"
-#include "thread_utils.h"
// Number of microseconds per milliseconds.
#define US_PER_MSEC 1000
@@ -525,7 +524,7 @@
}
void VerifyLevelThread(void*) {
- std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), gettid()));
+ std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), android::base::GetThreadId()));
ASSERT_TRUE(backtrace.get() != nullptr);
ASSERT_TRUE(backtrace->Unwind(0));
VERIFY_NO_ERROR(backtrace->GetError().error_code);
@@ -538,7 +537,7 @@
}
static void VerifyMaxThread(void*) {
- std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), gettid()));
+ std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), android::base::GetThreadId()));
ASSERT_TRUE(backtrace.get() != nullptr);
ASSERT_TRUE(backtrace->Unwind(0));
ASSERT_EQ(BACKTRACE_UNWIND_ERROR_EXCEED_MAX_FRAMES_LIMIT, backtrace->GetError().error_code);
@@ -553,7 +552,7 @@
static void* ThreadLevelRun(void* data) {
thread_t* thread = reinterpret_cast<thread_t*>(data);
- thread->tid = gettid();
+ thread->tid = android::base::GetThreadId();
EXPECT_NE(test_level_one(1, 2, 3, 4, ThreadSetState, data), 0);
return nullptr;
}
@@ -644,7 +643,7 @@
static void* ThreadMaxRun(void* data) {
thread_t* thread = reinterpret_cast<thread_t*>(data);
- thread->tid = gettid();
+ thread->tid = android::base::GetThreadId();
EXPECT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, ThreadSetState, data), 0);
return nullptr;
}
@@ -994,7 +993,7 @@
static void* ThreadReadTest(void* data) {
thread_t* thread_data = reinterpret_cast<thread_t*>(data);
- thread_data->tid = gettid();
+ thread_data->tid = android::base::GetThreadId();
// Create two map pages.
// Mark the second page as not-readable.
@@ -1816,7 +1815,8 @@
static void TestFrameSkipNumbering(create_func_t create_func, map_create_func_t map_create_func) {
std::unique_ptr<BacktraceMap> map(map_create_func(getpid(), false));
- std::unique_ptr<Backtrace> backtrace(create_func(getpid(), gettid(), map.get()));
+ std::unique_ptr<Backtrace> backtrace(
+ create_func(getpid(), android::base::GetThreadId(), map.get()));
backtrace->Unwind(1);
ASSERT_NE(0U, backtrace->NumFrames());
ASSERT_EQ(0U, backtrace->GetFrame(0)->num);
diff --git a/libbacktrace/thread_utils.c b/libbacktrace/thread_utils.c
deleted file mode 100644
index e75f56e..0000000
--- a/libbacktrace/thread_utils.c
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2013 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 "thread_utils.h"
-
-#if !defined(__BIONIC__)
-
-// glibc doesn't implement or export tgkill.
-#include <unistd.h>
-#include <sys/syscall.h>
-
-int tgkill(int tgid, int tid, int sig) {
- return syscall(__NR_tgkill, tgid, tid, sig);
-}
-
-#endif
diff --git a/libbacktrace/thread_utils.h b/libbacktrace/thread_utils.h
deleted file mode 100644
index 9590657..0000000
--- a/libbacktrace/thread_utils.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2013 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.
- */
-
-#ifndef _LIBBACKTRACE_THREAD_UTILS_H
-#define _LIBBACKTRACE_THREAD_UTILS_H
-
-#include <unistd.h>
-
-#if !defined(__ANDROID__)
-#include <cutils/threads.h>
-#endif
-
-__BEGIN_DECLS
-
-int tgkill(int tgid, int tid, int sig);
-
-__END_DECLS
-
-#endif /* _LIBBACKTRACE_THREAD_UTILS_H */
diff --git a/libcutils/hashmap.cpp b/libcutils/hashmap.cpp
index 10e3b25..2a4a52e 100644
--- a/libcutils/hashmap.cpp
+++ b/libcutils/hashmap.cpp
@@ -36,7 +36,7 @@
size_t bucketCount;
int (*hash)(void* key);
bool (*equals)(void* keyA, void* keyB);
- mutex_t lock;
+ mutex_t lock;
size_t size;
};
@@ -44,18 +44,18 @@
int (*hash)(void* key), bool (*equals)(void* keyA, void* keyB)) {
assert(hash != NULL);
assert(equals != NULL);
-
+
Hashmap* map = static_cast<Hashmap*>(malloc(sizeof(Hashmap)));
if (map == NULL) {
return NULL;
}
-
+
// 0.75 load factor.
size_t minimumBucketCount = initialCapacity * 4 / 3;
map->bucketCount = 1;
while (map->bucketCount <= minimumBucketCount) {
// Bucket count must be power of 2.
- map->bucketCount <<= 1;
+ map->bucketCount <<= 1;
}
map->buckets = static_cast<Entry**>(calloc(map->bucketCount, sizeof(Entry*)));
@@ -63,14 +63,14 @@
free(map);
return NULL;
}
-
+
map->size = 0;
map->hash = hash;
map->equals = equals;
-
+
mutex_init(&map->lock);
-
+
return map;
}
@@ -89,12 +89,8 @@
h ^= (((unsigned int) h) >> 14);
h += (h << 4);
h ^= (((unsigned int) h) >> 10);
-
- return h;
-}
-size_t hashmapSize(Hashmap* map) {
- return map->size;
+ return h;
}
static inline size_t calculateIndex(size_t bucketCount, int hash) {
@@ -111,7 +107,7 @@
// Abort expansion.
return;
}
-
+
// Move over existing entries.
size_t i;
for (i = 0; i < map->bucketCount; i++) {
@@ -240,54 +236,6 @@
return NULL;
}
-bool hashmapContainsKey(Hashmap* map, void* key) {
- int hash = hashKey(map, key);
- size_t index = calculateIndex(map->bucketCount, hash);
-
- Entry* entry = map->buckets[index];
- while (entry != NULL) {
- if (equalKeys(entry->key, entry->hash, key, hash, map->equals)) {
- return true;
- }
- entry = entry->next;
- }
-
- return false;
-}
-
-void* hashmapMemoize(Hashmap* map, void* key,
- void* (*initialValue)(void* key, void* context), void* context) {
- int hash = hashKey(map, key);
- size_t index = calculateIndex(map->bucketCount, hash);
-
- Entry** p = &(map->buckets[index]);
- while (true) {
- Entry* current = *p;
-
- // Add a new entry.
- if (current == NULL) {
- *p = createEntry(key, hash, NULL);
- if (*p == NULL) {
- errno = ENOMEM;
- return NULL;
- }
- void* value = initialValue(key, context);
- (*p)->value = value;
- map->size++;
- expandIfNecessary(map);
- return value;
- }
-
- // Return existing value.
- if (equalKeys(current->key, current->hash, key, hash, map->equals)) {
- return current->value;
- }
-
- // Move to next entry.
- p = ¤t->next;
- }
-}
-
void* hashmapRemove(Hashmap* map, void* key) {
int hash = hashKey(map, key);
size_t index = calculateIndex(map->bucketCount, hash);
@@ -310,9 +258,8 @@
return NULL;
}
-void hashmapForEach(Hashmap* map,
- bool (*callback)(void* key, void* value, void* context),
- void* context) {
+void hashmapForEach(Hashmap* map, bool (*callback)(void* key, void* value, void* context),
+ void* context) {
size_t i;
for (i = 0; i < map->bucketCount; i++) {
Entry* entry = map->buckets[i];
@@ -325,34 +272,3 @@
}
}
}
-
-size_t hashmapCurrentCapacity(Hashmap* map) {
- size_t bucketCount = map->bucketCount;
- return bucketCount * 3 / 4;
-}
-
-size_t hashmapCountCollisions(Hashmap* map) {
- size_t collisions = 0;
- size_t i;
- for (i = 0; i < map->bucketCount; i++) {
- Entry* entry = map->buckets[i];
- while (entry != NULL) {
- if (entry->next != NULL) {
- collisions++;
- }
- entry = entry->next;
- }
- }
- return collisions;
-}
-
-int hashmapIntHash(void* key) {
- // Return the key value itself.
- return *((int*) key);
-}
-
-bool hashmapIntEquals(void* keyA, void* keyB) {
- int a = *((int*) keyA);
- int b = *((int*) keyB);
- return a == b;
-}
diff --git a/libcutils/include/cutils/hashmap.h b/libcutils/include/cutils/hashmap.h
index 5cb344c..9cfd669 100644
--- a/libcutils/include/cutils/hashmap.h
+++ b/libcutils/include/cutils/hashmap.h
@@ -16,6 +16,9 @@
/**
* Hash map.
+ *
+ * Use std::map or std::unordered_map instead.
+ * https://en.cppreference.com/w/cpp/container
*/
#ifndef __HASHMAP_H
@@ -68,38 +71,17 @@
void* hashmapGet(Hashmap* map, void* key);
/**
- * Returns true if the map contains an entry for the given key.
- */
-bool hashmapContainsKey(Hashmap* map, void* key);
-
-/**
- * Gets the value for a key. If a value is not found, this function gets a
- * value and creates an entry using the given callback.
- *
- * If memory allocation fails, the callback is not called, this function
- * returns NULL, and errno is set to ENOMEM.
- */
-void* hashmapMemoize(Hashmap* map, void* key,
- void* (*initialValue)(void* key, void* context), void* context);
-
-/**
* Removes an entry from the map. Returns the removed value or NULL if no
* entry was present.
*/
void* hashmapRemove(Hashmap* map, void* key);
/**
- * Gets the number of entries in this map.
- */
-size_t hashmapSize(Hashmap* map);
-
-/**
* Invokes the given callback on each entry in the map. Stops iterating if
* the callback returns false.
*/
-void hashmapForEach(Hashmap* map,
- bool (*callback)(void* key, void* value, void* context),
- void* context);
+void hashmapForEach(Hashmap* map, bool (*callback)(void* key, void* value, void* context),
+ void* context);
/**
* Concurrency support.
@@ -115,36 +97,8 @@
*/
void hashmapUnlock(Hashmap* map);
-/**
- * Key utilities.
- */
-
-/**
- * Hashes int keys. 'key' is a pointer to int.
- */
-int hashmapIntHash(void* key);
-
-/**
- * Compares two int keys for equality.
- */
-bool hashmapIntEquals(void* keyA, void* keyB);
-
-/**
- * For debugging.
- */
-
-/**
- * Gets current capacity.
- */
-size_t hashmapCurrentCapacity(Hashmap* map);
-
-/**
- * Counts the number of entry collisions.
- */
-size_t hashmapCountCollisions(Hashmap* map);
-
#ifdef __cplusplus
}
#endif
-#endif /* __HASHMAP_H */
+#endif /* __HASHMAP_H */
diff --git a/libcutils/str_parms.cpp b/libcutils/str_parms.cpp
index f5a52a7..d818c51 100644
--- a/libcutils/str_parms.cpp
+++ b/libcutils/str_parms.cpp
@@ -354,12 +354,8 @@
char *str_parms_to_str(struct str_parms *str_parms)
{
char *str = NULL;
-
- if (hashmapSize(str_parms->map) > 0)
- hashmapForEach(str_parms->map, combine_strings, &str);
- else
- str = strdup("");
- return str;
+ hashmapForEach(str_parms->map, combine_strings, &str);
+ return (str != NULL) ? str : strdup("");
}
static bool dump_entry(void* key, void* value, void* /*context*/) {
diff --git a/libmemunreachable/tests/ThreadCapture_test.cpp b/libmemunreachable/tests/ThreadCapture_test.cpp
index 4fbf729..933d65a 100644
--- a/libmemunreachable/tests/ThreadCapture_test.cpp
+++ b/libmemunreachable/tests/ThreadCapture_test.cpp
@@ -32,6 +32,8 @@
#include "ScopedDisableMalloc.h"
#include "ScopedPipe.h"
+#include <android-base/threads.h>
+
using namespace std::chrono_literals;
namespace android {
@@ -260,7 +262,7 @@
ThreadCapture thread_capture(ret, heap);
thread_capture.InjectTestFunc([&](pid_t tid) {
- syscall(SYS_tgkill, ret, tid, SIGKILL);
+ tgkill(ret, tid, SIGKILL);
usleep(10000);
});
auto list_tids = allocator::vector<pid_t>(heap);
@@ -319,7 +321,7 @@
ThreadCapture thread_capture(child, heap);
thread_capture.InjectTestFunc([&](pid_t tid) {
- syscall(SYS_tgkill, child, tid, sig);
+ tgkill(child, tid, sig);
usleep(10000);
});
auto list_tids = allocator::vector<pid_t>(heap);
diff --git a/libunwindstack/tests/UnwindTest.cpp b/libunwindstack/tests/UnwindTest.cpp
index 83695bb..ea992c7 100644
--- a/libunwindstack/tests/UnwindTest.cpp
+++ b/libunwindstack/tests/UnwindTest.cpp
@@ -32,6 +32,7 @@
#include <vector>
#include <android-base/stringprintf.h>
+#include <android-base/threads.h>
#include <unwindstack/Maps.h>
#include <unwindstack/Memory.h>
@@ -231,8 +232,7 @@
usleep(1000);
}
ASSERT_NE(0, tid.load());
- // Portable tgkill method.
- ASSERT_EQ(0, syscall(__NR_tgkill, getpid(), tid.load(), SIGUSR1)) << "Error: " << strerror(errno);
+ ASSERT_EQ(0, tgkill(getpid(), tid.load(), SIGUSR1)) << "Error: " << strerror(errno);
// Wait for context data.
void* ucontext;
diff --git a/logcat/event.logtags b/logcat/event.logtags
index 750761f..da8d2d4 100644
--- a/logcat/event.logtags
+++ b/logcat/event.logtags
@@ -113,6 +113,9 @@
# graphics timestamp
# 60100 - 60199 reserved for surfaceflinger
+# audio
+# 61000 - 61199 reserved for audioserver
+
# 0 for screen off, 1 for screen on, 2 for key-guard done
70000 screen_toggled (screen_state|1|5)
diff --git a/rootdir/init.rc b/rootdir/init.rc
index c1ae932..d3f038e 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -318,8 +318,8 @@
start vndservicemanager
# Once everything is setup, no need to modify /.
- # The bind+ro combination avoids modifying any other mount flags.
- mount rootfs rootfs / remount bind ro
+ # The bind+remount combination allows this to work in containers.
+ mount rootfs rootfs / remount bind ro nodev
# Mount shared so changes propagate into child namespaces
mount rootfs rootfs / shared rec
# Mount default storage into root namespace