Merge "Separate namespace acquisition from library loading"
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/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/Android.bp b/libcutils/Android.bp
index cdbb65f..58e59d6 100644
--- a/libcutils/Android.bp
+++ b/libcutils/Android.bp
@@ -65,7 +65,6 @@
"iosched_policy.cpp",
"load_file.cpp",
"native_handle.cpp",
- "open_memstream.c",
"record_stream.cpp",
"sched_policy.cpp",
"sockets.cpp",
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/include/cutils/open_memstream.h b/libcutils/include/cutils/open_memstream.h
deleted file mode 100644
index c1a81eb..0000000
--- a/libcutils/include/cutils/open_memstream.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2010 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 __CUTILS_OPEN_MEMSTREAM_H__
-#define __CUTILS_OPEN_MEMSTREAM_H__
-
-#include <stdio.h>
-
-#if defined(__APPLE__)
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-FILE* open_memstream(char** bufp, size_t* sizep);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __APPLE__ */
-
-#endif /*__CUTILS_OPEN_MEMSTREAM_H__*/
diff --git a/libcutils/include_vndk/cutils/open_memstream.h b/libcutils/include_vndk/cutils/open_memstream.h
deleted file mode 120000
index c894084..0000000
--- a/libcutils/include_vndk/cutils/open_memstream.h
+++ /dev/null
@@ -1 +0,0 @@
-../../include/cutils/open_memstream.h
\ No newline at end of file
diff --git a/libcutils/open_memstream.c b/libcutils/open_memstream.c
deleted file mode 100644
index 9183266..0000000
--- a/libcutils/open_memstream.c
+++ /dev/null
@@ -1,373 +0,0 @@
-/*
- * Copyright (C) 2010 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(__APPLE__)
-
-/*
- * Implementation of the POSIX open_memstream() function, which Linux has
- * but BSD lacks.
- *
- * Summary:
- * - Works like a file-backed FILE* opened with fopen(name, "w"), but the
- * backing is a chunk of memory rather than a file.
- * - The buffer expands as you write more data. Seeking past the end
- * of the file and then writing to it zero-fills the gap.
- * - The values at "*bufp" and "*sizep" should be considered read-only,
- * and are only valid immediately after an fflush() or fclose().
- * - A '\0' is maintained just past the end of the file. This is not included
- * in "*sizep". (The behavior w.r.t. fseek() is not clearly defined.
- * The spec says the null byte is written when a write() advances EOF,
- * but it looks like glibc ensures the null byte is always found at EOF,
- * even if you just seeked backwards. The example on the opengroup.org
- * page suggests that this is the expected behavior. The null must be
- * present after a no-op fflush(), which we can't see, so we have to save
- * and restore it. Annoying, but allows file truncation.)
- * - After fclose(), the caller must eventually free(*bufp).
- *
- * This is built out of funopen(), which BSD has but Linux lacks. There is
- * no flush() operator, so we need to keep the user pointers up to date
- * after each operation.
- *
- * I don't think Windows has any of the above, but we don't need to use
- * them there, so we just supply a stub.
- */
-#include <cutils/open_memstream.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <assert.h>
-
-#if 0
-# define DBUG(x) printf x
-#else
-# define DBUG(x) ((void)0)
-#endif
-
-/*
- * Definition of a seekable, write-only memory stream.
- */
-typedef struct {
- char** bufp; /* pointer to buffer pointer */
- size_t* sizep; /* pointer to eof */
-
- size_t allocSize; /* size of buffer */
- size_t eof; /* furthest point we've written to */
- size_t offset; /* current write offset */
- char saved; /* required by NUL handling */
-} MemStream;
-
-#define kInitialSize 1024
-
-/*
- * Ensure that we have enough storage to write "size" bytes at the
- * current offset. We also have to take into account the extra '\0'
- * that we maintain just past EOF.
- *
- * Returns 0 on success.
- */
-static int ensureCapacity(MemStream* stream, int writeSize)
-{
- DBUG(("+++ ensureCap off=%d size=%d\n", stream->offset, writeSize));
-
- size_t neededSize = stream->offset + writeSize + 1;
- if (neededSize <= stream->allocSize)
- return 0;
-
- size_t newSize;
-
- if (stream->allocSize == 0) {
- newSize = kInitialSize;
- } else {
- newSize = stream->allocSize;
- newSize += newSize / 2; /* expand by 3/2 */
- }
-
- if (newSize < neededSize)
- newSize = neededSize;
- DBUG(("+++ realloc %p->%p to size=%d\n",
- stream->bufp, *stream->bufp, newSize));
- char* newBuf = (char*) realloc(*stream->bufp, newSize);
- if (newBuf == NULL)
- return -1;
-
- *stream->bufp = newBuf;
- stream->allocSize = newSize;
- return 0;
-}
-
-/*
- * Write data to a memstream, expanding the buffer if necessary.
- *
- * If we previously seeked beyond EOF, zero-fill the gap.
- *
- * Returns the number of bytes written.
- */
-static int write_memstream(void* cookie, const char* buf, int size)
-{
- MemStream* stream = (MemStream*) cookie;
-
- if (ensureCapacity(stream, size) < 0)
- return -1;
-
- /* seeked past EOF earlier? */
- if (stream->eof < stream->offset) {
- DBUG(("+++ zero-fill gap from %d to %d\n",
- stream->eof, stream->offset-1));
- memset(*stream->bufp + stream->eof, '\0',
- stream->offset - stream->eof);
- }
-
- /* copy data, advance write pointer */
- memcpy(*stream->bufp + stream->offset, buf, size);
- stream->offset += size;
-
- if (stream->offset > stream->eof) {
- /* EOF has advanced, update it and append null byte */
- DBUG(("+++ EOF advanced to %d, appending nul\n", stream->offset));
- assert(stream->offset < stream->allocSize);
- stream->eof = stream->offset;
- } else {
- /* within previously-written area; save char we're about to stomp */
- DBUG(("+++ within written area, saving '%c' at %d\n",
- *(*stream->bufp + stream->offset), stream->offset));
- stream->saved = *(*stream->bufp + stream->offset);
- }
- *(*stream->bufp + stream->offset) = '\0';
- *stream->sizep = stream->offset;
-
- return size;
-}
-
-/*
- * Seek within a memstream.
- *
- * Returns the new offset, or -1 on failure.
- */
-static fpos_t seek_memstream(void* cookie, fpos_t offset, int whence)
-{
- MemStream* stream = (MemStream*) cookie;
- off_t newPosn = (off_t) offset;
-
- if (whence == SEEK_CUR) {
- newPosn += stream->offset;
- } else if (whence == SEEK_END) {
- newPosn += stream->eof;
- }
-
- if (newPosn < 0 || ((fpos_t)((size_t) newPosn)) != newPosn) {
- /* bad offset - negative or huge */
- DBUG(("+++ bogus seek offset %ld\n", (long) newPosn));
- errno = EINVAL;
- return (fpos_t) -1;
- }
-
- if (stream->offset < stream->eof) {
- /*
- * We were pointing to an area we'd already written to, which means
- * we stomped on a character and must now restore it.
- */
- DBUG(("+++ restoring char '%c' at %d\n",
- stream->saved, stream->offset));
- *(*stream->bufp + stream->offset) = stream->saved;
- }
-
- stream->offset = (size_t) newPosn;
-
- if (stream->offset < stream->eof) {
- /*
- * We're seeked backward into the stream. Preserve the character
- * at EOF and stomp it with a NUL.
- */
- stream->saved = *(*stream->bufp + stream->offset);
- *(*stream->bufp + stream->offset) = '\0';
- *stream->sizep = stream->offset;
- } else {
- /*
- * We're positioned at, or possibly beyond, the EOF. We want to
- * publish the current EOF, not the current position.
- */
- *stream->sizep = stream->eof;
- }
-
- return newPosn;
-}
-
-/*
- * Close the memstream. We free everything but the data buffer.
- */
-static int close_memstream(void* cookie)
-{
- free(cookie);
- return 0;
-}
-
-/*
- * Prepare a memstream.
- */
-FILE* open_memstream(char** bufp, size_t* sizep)
-{
- FILE* fp;
- MemStream* stream;
-
- if (bufp == NULL || sizep == NULL) {
- errno = EINVAL;
- return NULL;
- }
-
- stream = (MemStream*) calloc(1, sizeof(MemStream));
- if (stream == NULL)
- return NULL;
-
- fp = funopen(stream,
- NULL, write_memstream, seek_memstream, close_memstream);
- if (fp == NULL) {
- free(stream);
- return NULL;
- }
-
- *sizep = 0;
- *bufp = NULL;
- stream->bufp = bufp;
- stream->sizep = sizep;
-
- return fp;
-}
-
-
-
-
-#if 0
-#define _GNU_SOURCE
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-/*
- * Simple regression test.
- *
- * To test on desktop Linux with valgrind, it's possible to make a simple
- * change to open_memstream() to use fopencookie instead:
- *
- * cookie_io_functions_t iofuncs =
- * { NULL, write_memstream, seek_memstream, close_memstream };
- * fp = fopencookie(stream, "w", iofuncs);
- *
- * (Some tweaks to seek_memstream are also required, as that takes a
- * pointer to an offset rather than an offset, and returns 0 or -1.)
- */
-int testMemStream(void)
-{
- FILE *stream;
- char *buf;
- size_t len;
- off_t eob;
-
- printf("Test1\n");
-
- /* std example */
- stream = open_memstream(&buf, &len);
- fprintf(stream, "hello my world");
- fflush(stream);
- printf("buf=%s, len=%zu\n", buf, len);
- eob = ftello(stream);
- fseeko(stream, 0, SEEK_SET);
- fprintf(stream, "good-bye");
- fseeko(stream, eob, SEEK_SET);
- fclose(stream);
- printf("buf=%s, len=%zu\n", buf, len);
- free(buf);
-
- printf("Test2\n");
-
- /* std example without final seek-to-end */
- stream = open_memstream(&buf, &len);
- fprintf(stream, "hello my world");
- fflush(stream);
- printf("buf=%s, len=%zu\n", buf, len);
- eob = ftello(stream);
- fseeko(stream, 0, SEEK_SET);
- fprintf(stream, "good-bye");
- //fseeko(stream, eob, SEEK_SET);
- fclose(stream);
- printf("buf=%s, len=%zu\n", buf, len);
- free(buf);
-
- printf("Test3\n");
-
- /* fancy example; should expand buffer with writes */
- static const int kCmpLen = 1024 + 128;
- char* cmp = malloc(kCmpLen);
- memset(cmp, 0, 1024);
- memset(cmp+1024, 0xff, kCmpLen-1024);
- sprintf(cmp, "This-is-a-tes1234");
- sprintf(cmp + 1022, "abcdef");
-
- stream = open_memstream (&buf, &len);
- setvbuf(stream, NULL, _IONBF, 0); /* note: crashes in glibc with this */
- fprintf(stream, "This-is-a-test");
- fseek(stream, -1, SEEK_CUR); /* broken in glibc; can use {13,SEEK_SET} */
- fprintf(stream, "1234");
- fseek(stream, 1022, SEEK_SET);
- fputc('a', stream);
- fputc('b', stream);
- fputc('c', stream);
- fputc('d', stream);
- fputc('e', stream);
- fputc('f', stream);
- fflush(stream);
-
- if (memcmp(buf, cmp, len+1) != 0) {
- printf("mismatch\n");
- } else {
- printf("match\n");
- }
-
- printf("Test4\n");
- stream = open_memstream (&buf, &len);
- fseek(stream, 5000, SEEK_SET);
- fseek(stream, 4096, SEEK_SET);
- fseek(stream, -1, SEEK_SET); /* should have no effect */
- fputc('x', stream);
- if (ftell(stream) == 4097)
- printf("good\n");
- else
- printf("BAD: offset is %ld\n", ftell(stream));
-
- printf("DONE\n");
-
- return 0;
-}
-
-/* expected output:
-Test1
-buf=hello my world, len=14
-buf=good-bye world, len=14
-Test2
-buf=hello my world, len=14
-buf=good-bye, len=8
-Test3
-match
-Test4
-good
-DONE
-*/
-
-#endif
-
-#endif /* __APPLE__ */
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;