Merge "ueventd: let scripts provide firmware directories"
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/file.cpp b/base/file.cpp
index 2f697a1..d6fe753 100644
--- a/base/file.cpp
+++ b/base/file.cpp
@@ -199,17 +199,23 @@
bool RemoveFileIfExists(const std::string& path, std::string* err) {
struct stat st;
#if defined(_WIN32)
- //TODO: Windows version can't handle symbol link correctly.
+ // TODO: Windows version can't handle symbolic links correctly.
int result = stat(path.c_str(), &st);
bool file_type_removable = (result == 0 && S_ISREG(st.st_mode));
#else
int result = lstat(path.c_str(), &st);
bool file_type_removable = (result == 0 && (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)));
#endif
+ if (result == -1) {
+ if (errno == ENOENT || errno == ENOTDIR) return true;
+ if (err != nullptr) *err = strerror(errno);
+ return false;
+ }
+
if (result == 0) {
if (!file_type_removable) {
if (err != nullptr) {
- *err = "is not a regular or symbol link file";
+ *err = "is not a regular file or symbolic link";
}
return false;
}
diff --git a/base/file_test.cpp b/base/file_test.cpp
index 02b431d..6794652 100644
--- a/base/file_test.cpp
+++ b/base/file_test.cpp
@@ -26,6 +26,10 @@
#include "android-base/test_utils.h"
+#if !defined(_WIN32)
+#include <pwd.h>
+#endif
+
TEST(file, ReadFileToString_ENOENT) {
std::string s("hello");
errno = 0;
@@ -115,7 +119,7 @@
ASSERT_FALSE(android::base::ReadFully(tf.fd, &s[0], s.size()));
}
-TEST(file, RemoveFileIfExist) {
+TEST(file, RemoveFileIfExists) {
TemporaryFile tf;
ASSERT_TRUE(tf.fd != -1);
close(tf.fd);
@@ -126,9 +130,43 @@
TemporaryDir td;
ASSERT_FALSE(android::base::RemoveFileIfExists(td.path));
ASSERT_FALSE(android::base::RemoveFileIfExists(td.path, &err));
- ASSERT_EQ("is not a regular or symbol link file", err);
+ ASSERT_EQ("is not a regular file or symbolic link", err);
}
+TEST(file, RemoveFileIfExists_ENOTDIR) {
+ TemporaryFile tf;
+ close(tf.fd);
+ tf.fd = -1;
+ std::string err{"xxx"};
+ ASSERT_TRUE(android::base::RemoveFileIfExists(std::string{tf.path} + "/abc", &err));
+ ASSERT_EQ("xxx", err);
+}
+
+#if !defined(_WIN32)
+TEST(file, RemoveFileIfExists_EACCES) {
+ // EACCES -- one of the directories in the path has no search permission
+ // root can bypass permission restrictions, so drop root.
+ if (getuid() == 0) {
+ passwd* shell = getpwnam("shell");
+ setgid(shell->pw_gid);
+ setuid(shell->pw_uid);
+ }
+
+ TemporaryDir td;
+ TemporaryFile tf(td.path);
+ close(tf.fd);
+ tf.fd = -1;
+ std::string err{"xxx"};
+ // Remove dir's search permission.
+ ASSERT_TRUE(chmod(td.path, S_IRUSR | S_IWUSR) == 0);
+ ASSERT_FALSE(android::base::RemoveFileIfExists(tf.path, &err));
+ ASSERT_EQ("Permission denied", err);
+ // Set dir's search permission again.
+ ASSERT_TRUE(chmod(td.path, S_IRWXU) == 0);
+ ASSERT_TRUE(android::base::RemoveFileIfExists(tf.path, &err));
+}
+#endif
+
TEST(file, Readlink) {
#if !defined(_WIN32)
// Linux doesn't allow empty symbolic links.
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..1434b21 100644
--- a/fs_mgr/liblp/Android.bp
+++ b/fs_mgr/liblp/Android.bp
@@ -24,6 +24,7 @@
],
srcs: [
"builder.cpp",
+ "images.cpp",
"reader.cpp",
"utility.cpp",
"writer.cpp",
@@ -33,6 +34,7 @@
"liblog",
"libcrypto",
"libcrypto_utils",
+ "libsparse",
],
whole_static_libs: [
"libext2_uuid",
@@ -46,6 +48,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 720590d..9d710f9 100644
--- a/fs_mgr/liblp/builder.cpp
+++ b/fs_mgr/liblp/builder.cpp
@@ -27,8 +27,8 @@
#include <android-base/unique_fd.h>
#include <uuid/uuid.h>
-#include "liblp/metadata_format.h"
-#include "liblp/reader.h"
+#include "liblp/liblp.h"
+#include "reader.h"
#include "utility.h"
namespace android {
@@ -200,6 +200,11 @@
metadata_max_size = AlignTo(metadata_max_size, LP_SECTOR_SIZE);
// Check that device properties are sane.
+ device_info_ = device_info;
+ if (device_info_.size % LP_SECTOR_SIZE != 0) {
+ LERROR << "Block device size must be a multiple of 512.";
+ return false;
+ }
if (device_info_.alignment_offset % LP_SECTOR_SIZE != 0) {
LERROR << "Alignment offset is not sector-aligned.";
return false;
@@ -212,7 +217,6 @@
LERROR << "Partition alignment offset is greater than its alignment.";
return false;
}
- device_info_ = device_info;
// We reserve a geometry block (4KB) plus space for each copy of the
// maximum size of a metadata blob. Then, we double that space since
@@ -250,6 +254,7 @@
geometry_.metadata_slot_count = metadata_slot_count;
geometry_.alignment = device_info_.alignment;
geometry_.alignment_offset = device_info_.alignment_offset;
+ geometry_.block_device_size = device_info_.size;
return true;
}
diff --git a/fs_mgr/liblp/builder_test.cpp b/fs_mgr/liblp/builder_test.cpp
index 08440a3..b610fd4 100644
--- a/fs_mgr/liblp/builder_test.cpp
+++ b/fs_mgr/liblp/builder_test.cpp
@@ -106,19 +106,9 @@
static const uint32_t kMetadataSize = 1024;
static const uint32_t kMetadataSlots = 2;
- // If the disk size is not aligned to 512 bytes, make sure it still leaves
- // space at the end for backup metadata, and that it doesn't overlap with
- // the space for logical partitions.
unique_ptr<MetadataBuilder> builder =
MetadataBuilder::New(kDiskSize, kMetadataSize, kMetadataSlots);
- unique_ptr<LpMetadata> exported = builder->Export();
- ASSERT_NE(exported, nullptr);
-
- static const size_t kMetadataSpace =
- (kMetadataSize * kMetadataSlots) + LP_METADATA_GEOMETRY_SIZE;
- uint64_t space_at_end =
- kDiskSize - (exported->geometry.last_logical_sector + 1) * LP_SECTOR_SIZE;
- EXPECT_GE(space_at_end, kMetadataSpace);
+ ASSERT_EQ(builder, nullptr);
}
TEST(liblp, MetadataAlignment) {
@@ -148,15 +138,10 @@
EXPECT_EQ(exported->geometry.first_logical_sector, 1472);
EXPECT_EQ(exported->geometry.last_logical_sector, 2035);
- // Test only an alignment offset (which should simply bump up the first
- // logical sector).
+ // Alignment offset without alignment doesn't mean anything.
device_info.alignment = 0;
builder = MetadataBuilder::New(device_info, 1024, 2);
- ASSERT_NE(builder, nullptr);
- exported = builder->Export();
- ASSERT_NE(exported, nullptr);
- EXPECT_EQ(exported->geometry.first_logical_sector, 1484);
- EXPECT_EQ(exported->geometry.last_logical_sector, 2035);
+ ASSERT_EQ(builder, nullptr);
// Test a small alignment with an alignment offset.
device_info.alignment = 12 * 1024;
diff --git a/fs_mgr/liblp/images.cpp b/fs_mgr/liblp/images.cpp
new file mode 100644
index 0000000..93c5618
--- /dev/null
+++ b/fs_mgr/liblp/images.cpp
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2018 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 "images.h"
+
+#include <limits.h>
+
+#include <android-base/file.h>
+#include <android-base/unique_fd.h>
+#include <sparse/sparse.h>
+
+#include "reader.h"
+#include "utility.h"
+#include "writer.h"
+
+namespace android {
+namespace fs_mgr {
+
+std::unique_ptr<LpMetadata> ReadFromImageFile(int fd) {
+ LpMetadataGeometry geometry;
+ if (!ReadLogicalPartitionGeometry(fd, &geometry)) {
+ return nullptr;
+ }
+ if (SeekFile64(fd, LP_METADATA_GEOMETRY_SIZE, SEEK_SET) < 0) {
+ PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset " << LP_METADATA_GEOMETRY_SIZE;
+ return nullptr;
+ }
+ std::unique_ptr<LpMetadata> metadata = ParseMetadata(fd);
+ if (!metadata) {
+ return nullptr;
+ }
+ metadata->geometry = geometry;
+ return metadata;
+}
+
+std::unique_ptr<LpMetadata> ReadFromImageFile(const char* file) {
+ android::base::unique_fd fd(open(file, O_RDONLY));
+ if (fd < 0) {
+ PERROR << __PRETTY_FUNCTION__ << "open failed: " << file;
+ return nullptr;
+ }
+ return ReadFromImageFile(fd);
+}
+
+bool WriteToImageFile(int fd, const LpMetadata& input) {
+ std::string geometry = SerializeGeometry(input.geometry);
+ std::string padding(LP_METADATA_GEOMETRY_SIZE - geometry.size(), '\0');
+ std::string metadata = SerializeMetadata(input);
+
+ std::string everything = geometry + padding + metadata;
+
+ if (!android::base::WriteFully(fd, everything.data(), everything.size())) {
+ PERROR << __PRETTY_FUNCTION__ << "write " << everything.size() << " bytes failed";
+ return false;
+ }
+ return true;
+}
+
+bool WriteToImageFile(const char* file, const LpMetadata& input) {
+ android::base::unique_fd fd(open(file, O_CREAT | O_RDWR | O_TRUNC, 0644));
+ if (fd < 0) {
+ PERROR << __PRETTY_FUNCTION__ << "open failed: " << file;
+ return false;
+ }
+ return WriteToImageFile(fd, input);
+}
+
+// We use an object to build the sparse file since it requires that data
+// pointers be held alive until the sparse file is destroyed. It's easier
+// to do this when the data pointers are all in one place.
+class SparseBuilder {
+ public:
+ explicit SparseBuilder(const LpMetadata& metadata);
+
+ bool Build();
+ bool Export(const char* file);
+ bool IsValid() const { return file_ != nullptr; }
+
+ private:
+ bool AddData(const std::string& blob, uint32_t block);
+
+ const LpMetadata& metadata_;
+ const LpMetadataGeometry& geometry_;
+ std::unique_ptr<sparse_file, decltype(&sparse_file_destroy)> file_;
+ std::string geometry_blob_;
+ std::string metadata_blob_;
+};
+
+SparseBuilder::SparseBuilder(const LpMetadata& metadata)
+ : metadata_(metadata),
+ geometry_(metadata.geometry),
+ file_(sparse_file_new(LP_SECTOR_SIZE, geometry_.block_device_size), sparse_file_destroy) {}
+
+bool SparseBuilder::Export(const char* file) {
+ android::base::unique_fd fd(open(file, O_CREAT | O_RDWR | O_TRUNC, 0644));
+ if (fd < 0) {
+ PERROR << "open failed: " << file;
+ return false;
+ }
+ // No gzip compression; sparseify; no checksum.
+ int ret = sparse_file_write(file_.get(), fd, false, true, false);
+ if (ret != 0) {
+ LERROR << "sparse_file_write failed (error code " << ret << ")";
+ return false;
+ }
+ return true;
+}
+
+bool SparseBuilder::AddData(const std::string& blob, uint32_t block) {
+ void* data = const_cast<char*>(blob.data());
+ int ret = sparse_file_add_data(file_.get(), data, blob.size(), block);
+ if (ret != 0) {
+ LERROR << "sparse_file_add_data failed (error code " << ret << ")";
+ return false;
+ }
+ return true;
+}
+
+bool SparseBuilder::Build() {
+ geometry_blob_ = SerializeGeometry(geometry_);
+ geometry_blob_.resize(LP_METADATA_GEOMETRY_SIZE);
+ if (!AddData(geometry_blob_, 0)) {
+ return false;
+ }
+
+ // Metadata immediately follows geometry, and we write the same metadata
+ // to all slots.
+ uint32_t metadata_block = LP_METADATA_GEOMETRY_SIZE / LP_SECTOR_SIZE;
+ metadata_blob_ = SerializeMetadata(metadata_);
+ for (size_t i = 0; i < geometry_.metadata_slot_count; i++) {
+ if (!AddData(metadata_blob_, metadata_block)) {
+ return false;
+ }
+ metadata_block += geometry_.metadata_max_size / LP_SECTOR_SIZE;
+ }
+
+ // The backup area contains all metadata slots, and then geometry. Similar
+ // to before we write the metadata to every slot.
+ int64_t backup_offset = GetBackupMetadataOffset(geometry_, 0);
+ uint64_t backups_start = geometry_.block_device_size + backup_offset;
+ uint64_t backup_sector = backups_start / LP_SECTOR_SIZE;
+ for (size_t i = 0; i < geometry_.metadata_slot_count; i++) {
+ if (!AddData(metadata_blob_, backup_sector)) {
+ return false;
+ }
+ backup_sector += geometry_.metadata_max_size / LP_SECTOR_SIZE;
+ }
+ if (!AddData(geometry_blob_, backup_sector)) {
+ return false;
+ }
+ return true;
+}
+
+bool WriteToSparseFile(const char* file, const LpMetadata& metadata) {
+ uint64_t num_blocks =
+ AlignTo(metadata.geometry.block_device_size, LP_SECTOR_SIZE) / LP_SECTOR_SIZE;
+ if (num_blocks >= UINT_MAX) {
+ // libsparse counts blocks in unsigned 32-bit integers, but our block
+ // size is rather low (512 bytes), since we operate in sectors.
+ // Therefore the maximum block device size we can represent with a
+ // sparse file is 2TB for now.
+ LERROR << "Block device is too large to encode with libsparse.";
+ return false;
+ }
+
+ SparseBuilder builder(metadata);
+ if (!builder.IsValid()) {
+ LERROR << "Could not allocate sparse file of size " << metadata.geometry.block_device_size;
+ return false;
+ }
+ if (!builder.Build()) {
+ return false;
+ }
+
+ return builder.Export(file);
+}
+
+} // namespace fs_mgr
+} // namespace android
diff --git a/fs_mgr/liblp/images.h b/fs_mgr/liblp/images.h
new file mode 100644
index 0000000..3a999b8
--- /dev/null
+++ b/fs_mgr/liblp/images.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2018 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 <liblp/liblp.h>
+
+namespace android {
+namespace fs_mgr {
+
+// Helper function to serialize geometry and metadata to a normal file, for
+// flashing or debugging.
+std::unique_ptr<LpMetadata> ReadFromImageFile(int fd);
+bool WriteToImageFile(const char* file, const LpMetadata& metadata);
+bool WriteToImageFile(int fd, const LpMetadata& metadata);
+
+} // namespace fs_mgr
+} // namespace android
diff --git a/fs_mgr/liblp/include/liblp/builder.h b/fs_mgr/liblp/include/liblp/builder.h
index 3cd95ae..8bde313 100644
--- a/fs_mgr/liblp/include/liblp/builder.h
+++ b/fs_mgr/liblp/include/liblp/builder.h
@@ -23,7 +23,7 @@
#include <map>
#include <memory>
-#include "metadata_format.h"
+#include "liblp.h"
namespace android {
namespace fs_mgr {
diff --git a/fs_mgr/liblp/include/liblp/liblp.h b/fs_mgr/liblp/include/liblp/liblp.h
new file mode 100644
index 0000000..c8d34d9
--- /dev/null
+++ b/fs_mgr/liblp/include/liblp/liblp.h
@@ -0,0 +1,76 @@
+//
+// Copyright (C) 2018 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 LIBLP_LIBLP_H
+#define LIBLP_LIBLP_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+
+#include "metadata_format.h"
+
+namespace android {
+namespace fs_mgr {
+
+// Helper structure for easily interpreting deserialized metadata, or
+// re-serializing metadata.
+struct LpMetadata {
+ LpMetadataGeometry geometry;
+ LpMetadataHeader header;
+ std::vector<LpMetadataPartition> partitions;
+ std::vector<LpMetadataExtent> extents;
+};
+
+// 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);
+
+// 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);
+
+// Read logical partition metadata from its predetermined location on a block
+// device. If readback fails, we also attempt to load from a backup copy.
+std::unique_ptr<LpMetadata> ReadMetadata(const char* block_device, uint32_t slot_number);
+
+// Read/Write logical partition metadata to an image file, for diagnostics or
+// flashing.
+bool WriteToSparseFile(const char* file, const LpMetadata& metadata);
+bool WriteToImageFile(const char* file, const LpMetadata& metadata);
+std::unique_ptr<LpMetadata> ReadFromImageFile(const char* file);
+
+// Helper to extract safe C++ strings from partition info.
+std::string GetPartitionName(const LpMetadataPartition& partition);
+std::string GetPartitionGuid(const LpMetadataPartition& partition);
+
+// Helper to return a slot number for a slot suffix.
+uint32_t SlotNumberForSlotSuffix(const std::string& suffix);
+
+} // namespace fs_mgr
+} // namespace android
+
+#endif // LIBLP_LIBLP_H
diff --git a/fs_mgr/liblp/include/liblp/metadata_format.h b/fs_mgr/liblp/include/liblp/metadata_format.h
index 27602ac..e1323e1 100644
--- a/fs_mgr/liblp/include/liblp/metadata_format.h
+++ b/fs_mgr/liblp/include/liblp/metadata_format.h
@@ -67,7 +67,7 @@
* | Geometry Backup |
* +--------------------+
*/
-#define LP_METADATA_PARTITION_NAME "android"
+#define LP_METADATA_PARTITION_NAME "super"
/* Size of a sector is always 512 bytes for compatibility with the Linux kernel. */
#define LP_SECTOR_SIZE 512
@@ -86,7 +86,9 @@
/* 8: SHA256 checksum of this struct, with this field set to 0. */
uint8_t checksum[32];
- /* 40: Maximum amount of space a single copy of the metadata can use. */
+ /* 40: Maximum amount of space a single copy of the metadata can use. This
+ * must be a multiple of LP_SECTOR_SIZE.
+ */
uint32_t metadata_max_size;
/* 44: Number of copies of the metadata to keep. For A/B devices, this
@@ -129,6 +131,11 @@
* If it cannot be determined, it is assumed to be 0.
*/
uint32_t alignment_offset;
+
+ /* 72: Block device size, as specified when the metadata was created. This
+ * can be used to verify the geometry against a target device.
+ */
+ uint64_t block_device_size;
} __attribute__((packed)) LpMetadataGeometry;
/* The logical partition metadata has a number of tables; they are described
@@ -262,28 +269,4 @@
} /* extern "C" */
#endif
-#ifdef __cplusplus
-namespace android {
-namespace fs_mgr {
-
-// Helper structure for easily interpreting deserialized metadata, or
-// re-serializing metadata.
-struct LpMetadata {
- LpMetadataGeometry geometry;
- LpMetadataHeader header;
- std::vector<LpMetadataPartition> partitions;
- std::vector<LpMetadataExtent> extents;
-};
-
-// Helper to extract safe C++ strings from partition info.
-std::string GetPartitionName(const LpMetadataPartition& partition);
-std::string GetPartitionGuid(const LpMetadataPartition& partition);
-
-// Helper to return a slot number for a slot suffix.
-uint32_t SlotNumberForSlotSuffix(const std::string& suffix);
-
-} // namespace fs_mgr
-} // namespace android
-#endif
-
#endif /* LOGICAL_PARTITION_METADATA_FORMAT_H_ */
diff --git a/fs_mgr/liblp/include/liblp/reader.h b/fs_mgr/liblp/include/liblp/reader.h
deleted file mode 100644
index 982fe65..0000000
--- a/fs_mgr/liblp/include/liblp/reader.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2018 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 LIBLP_READER_H_
-#define LIBLP_READER_H_
-
-#include <stddef.h>
-
-#include <memory>
-
-#include "metadata_format.h"
-
-namespace android {
-namespace fs_mgr {
-
-// Read logical partition metadata from its predetermined location on a block
-// device. If readback fails, we also attempt to load from a backup copy.
-std::unique_ptr<LpMetadata> ReadMetadata(const char* block_device, uint32_t slot_number);
-std::unique_ptr<LpMetadata> ReadMetadata(int fd, uint32_t slot_number);
-
-// Read and validate the logical partition geometry from a block device.
-bool ReadLogicalPartitionGeometry(const char* block_device, LpMetadataGeometry* geometry);
-bool ReadLogicalPartitionGeometry(int fd, LpMetadataGeometry* geometry);
-
-// Read logical partition metadata from an image file that was created with
-// WriteToImageFile().
-std::unique_ptr<LpMetadata> ReadFromImageFile(const char* file);
-std::unique_ptr<LpMetadata> ReadFromImageFile(int fd);
-
-} // namespace fs_mgr
-} // namespace android
-
-#endif /* LIBLP_READER_H_ */
diff --git a/fs_mgr/liblp/include/liblp/writer.h b/fs_mgr/liblp/include/liblp/writer.h
deleted file mode 100644
index efa409d..0000000
--- a/fs_mgr/liblp/include/liblp/writer.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2018 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 LIBLP_WRITER_H
-#define LIBLP_WRITER_H
-
-#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
-};
-
-// 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);
-
-// Helper function to serialize geometry and metadata to a normal file, for
-// flashing or debugging.
-bool WriteToImageFile(const char* file, const LpMetadata& metadata);
-bool WriteToImageFile(int fd, const LpMetadata& metadata);
-
-} // namespace fs_mgr
-} // namespace android
-
-#endif /* LIBLP_WRITER_H */
diff --git a/fs_mgr/liblp/io_test.cpp b/fs_mgr/liblp/io_test.cpp
index 2595654..bbbedc7 100644
--- a/fs_mgr/liblp/io_test.cpp
+++ b/fs_mgr/liblp/io_test.cpp
@@ -23,10 +23,11 @@
#include <android-base/unique_fd.h>
#include <gtest/gtest.h>
#include <liblp/builder.h>
-#include <liblp/reader.h>
-#include <liblp/writer.h>
+#include "images.h"
+#include "reader.h"
#include "utility.h"
+#include "writer.h"
using namespace std;
using namespace android::fs_mgr;
@@ -102,7 +103,7 @@
if (!exported) {
return {};
}
- if (!WritePartitionTable(fd, *exported.get(), SyncMode::Flash, 0)) {
+ if (!FlashPartitionTable(fd, *exported.get(), 0)) {
return {};
}
return fd;
@@ -131,7 +132,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 +147,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 +196,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 +232,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 +247,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 +354,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 +365,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 +394,130 @@
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) {
+ write_count_++;
+ 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 {
+ if (!android::base::WriteFully(fd, blob.data(), blob.size())) {
+ return false;
+ }
+ return fail_after_write_ != write_count_;
+ }
+ }
+ void Reset() {
+ fail_on_write_ = 0;
+ fail_after_write_ = 0;
+ write_count_ = 0;
+ }
+ void FailOnWrite(int number) {
+ Reset();
+ fail_on_write_ = number;
+ }
+ void FailAfterWrite(int number) {
+ Reset();
+ fail_after_write_ = number;
+ }
+
+ private:
+ int fail_on_write_ = 0;
+ int fail_after_write_ = 0;
+ int write_count_ = 0;
+};
+
+// Test that an interrupted flash operation on the "primary" copy of metadata
+// is not fatal.
+TEST(liblp, UpdatePrimaryMetadataFailure) {
+ 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(3);
+ 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, UpdateBackupMetadataFailure) {
+ 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.
+ writer.FailOnWrite(2);
+ ASSERT_FALSE(UpdatePartitionTable(fd, *imported.get(), 0, writer));
+ imported = ReadMetadata(fd, 0);
+ ASSERT_NE(imported, nullptr);
+}
+
+// Test that an interrupted write *in between* writing metadata will read
+// the correct metadata copy. The primary is always considered newer than
+// the backup.
+TEST(liblp, UpdateMetadataCleanFailure) {
+ unique_fd fd = CreateFlashedDisk();
+ ASSERT_GE(fd, 0);
+
+ BadWriter writer;
+
+ // Change the name of the existing partition.
+ unique_ptr<LpMetadata> new_table = ReadMetadata(fd, 0);
+ ASSERT_NE(new_table, nullptr);
+ ASSERT_GE(new_table->partitions.size(), 1);
+ new_table->partitions[0].name[0]++;
+
+ // Flash it, but fail to write the backup copy.
+ writer.FailAfterWrite(2);
+ ASSERT_FALSE(UpdatePartitionTable(fd, *new_table.get(), 0, writer));
+
+ // When we read back, we should get the updated primary copy.
+ unique_ptr<LpMetadata> imported = ReadMetadata(fd, 0);
+ ASSERT_NE(imported, nullptr);
+ ASSERT_GE(new_table->partitions.size(), 1);
+ ASSERT_EQ(GetPartitionName(new_table->partitions[0]), GetPartitionName(imported->partitions[0]));
+
+ // Flash again. After, the backup and primary copy should be coherent.
+ // Note that the sync step should have used the primary to sync, not
+ // the backup.
+ writer.Reset();
+ ASSERT_TRUE(UpdatePartitionTable(fd, *new_table.get(), 0, writer));
+
+ imported = ReadMetadata(fd, 0);
+ ASSERT_NE(imported, nullptr);
+ ASSERT_GE(new_table->partitions.size(), 1);
+ ASSERT_EQ(GetPartitionName(new_table->partitions[0]), GetPartitionName(imported->partitions[0]));
+}
diff --git a/fs_mgr/liblp/reader.cpp b/fs_mgr/liblp/reader.cpp
index a0eeec9..117da59 100644
--- a/fs_mgr/liblp/reader.cpp
+++ b/fs_mgr/liblp/reader.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "liblp/reader.h"
+#include "reader.h"
#include <stddef.h>
#include <stdlib.h>
@@ -68,6 +68,10 @@
LERROR << "Logical partition metadata has invalid slot count.";
return false;
}
+ if (geometry->metadata_max_size % LP_SECTOR_SIZE != 0) {
+ LERROR << "Metadata max size is not sector-aligned.";
+ return false;
+ }
// Check that the metadata area and logical partition areas don't overlap.
int64_t end_of_metadata =
@@ -111,16 +115,6 @@
return ParseGeometry(buffer.get(), geometry);
}
-// Helper function to read geometry from a device without an open descriptor.
-bool ReadLogicalPartitionGeometry(const char* block_device, LpMetadataGeometry* geometry) {
- android::base::unique_fd fd(open(block_device, O_RDONLY));
- if (fd < 0) {
- PERROR << __PRETTY_FUNCTION__ << "open failed: " << block_device;
- return false;
- }
- return ReadLogicalPartitionGeometry(fd, geometry);
-}
-
static bool ValidateTableBounds(const LpMetadataHeader& header,
const LpMetadataTableDescriptor& table) {
if (table.offset > header.tables_size) {
@@ -175,11 +169,9 @@
return true;
}
-using ReadMetadataFn = std::function<bool(void* buffer, size_t num_bytes)>;
-
// Parse and validate all metadata at the current position in the given file
// descriptor.
-static std::unique_ptr<LpMetadata> ParseMetadata(int fd) {
+std::unique_ptr<LpMetadata> ParseMetadata(int fd) {
// First read and validate the header.
std::unique_ptr<LpMetadata> metadata = std::make_unique<LpMetadata>();
if (!android::base::ReadFully(fd, &metadata->header, sizeof(metadata->header))) {
@@ -243,6 +235,26 @@
return metadata;
}
+std::unique_ptr<LpMetadata> ReadPrimaryMetadata(int fd, const LpMetadataGeometry& geometry,
+ uint32_t slot_number) {
+ int64_t offset = GetPrimaryMetadataOffset(geometry, slot_number);
+ if (SeekFile64(fd, offset, SEEK_SET) < 0) {
+ PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset " << offset;
+ return nullptr;
+ }
+ return ParseMetadata(fd);
+}
+
+std::unique_ptr<LpMetadata> ReadBackupMetadata(int fd, const LpMetadataGeometry& geometry,
+ uint32_t slot_number) {
+ int64_t offset = GetBackupMetadataOffset(geometry, slot_number);
+ if (SeekFile64(fd, offset, SEEK_END) < 0) {
+ PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset " << offset;
+ return nullptr;
+ }
+ return ParseMetadata(fd);
+}
+
std::unique_ptr<LpMetadata> ReadMetadata(int fd, uint32_t slot_number) {
LpMetadataGeometry geometry;
if (!ReadLogicalPartitionGeometry(fd, &geometry)) {
@@ -254,24 +266,11 @@
return nullptr;
}
- // First try the primary copy.
- int64_t offset = GetPrimaryMetadataOffset(geometry, slot_number);
- if (SeekFile64(fd, offset, SEEK_SET) < 0) {
- PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset " << offset;
- return nullptr;
- }
- std::unique_ptr<LpMetadata> metadata = ParseMetadata(fd);
-
- // If the primary copy failed, try the backup copy.
+ // Read the priamry copy, and if that fails, try the backup.
+ std::unique_ptr<LpMetadata> metadata = ReadPrimaryMetadata(fd, geometry, slot_number);
if (!metadata) {
- offset = GetBackupMetadataOffset(geometry, slot_number);
- if (SeekFile64(fd, offset, SEEK_END) < 0) {
- PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset " << offset;
- return nullptr;
- }
- metadata = ParseMetadata(fd);
+ metadata = ReadBackupMetadata(fd, geometry, slot_number);
}
-
if (metadata) {
metadata->geometry = geometry;
}
@@ -287,32 +286,6 @@
return ReadMetadata(fd, slot_number);
}
-std::unique_ptr<LpMetadata> ReadFromImageFile(int fd) {
- LpMetadataGeometry geometry;
- if (!ReadLogicalPartitionGeometry(fd, &geometry)) {
- return nullptr;
- }
- if (SeekFile64(fd, LP_METADATA_GEOMETRY_SIZE, SEEK_SET) < 0) {
- PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset " << LP_METADATA_GEOMETRY_SIZE;
- return nullptr;
- }
- std::unique_ptr<LpMetadata> metadata = ParseMetadata(fd);
- if (!metadata) {
- return nullptr;
- }
- metadata->geometry = geometry;
- return metadata;
-}
-
-std::unique_ptr<LpMetadata> ReadFromImageFile(const char* file) {
- android::base::unique_fd fd(open(file, O_RDONLY));
- if (fd < 0) {
- PERROR << __PRETTY_FUNCTION__ << "open failed: " << file;
- return nullptr;
- }
- return ReadFromImageFile(fd);
-}
-
static std::string NameFromFixedArray(const char* name, size_t buffer_size) {
// If the end of the buffer has a null character, it's safe to assume the
// buffer is null terminated. Otherwise, we cap the string to the input
diff --git a/fs_mgr/liblp/reader.h b/fs_mgr/liblp/reader.h
new file mode 100644
index 0000000..843b2f2
--- /dev/null
+++ b/fs_mgr/liblp/reader.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2018 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 LIBLP_READER_H_
+#define LIBLP_READER_H_
+
+#include <stddef.h>
+
+#include <memory>
+
+#include <liblp/liblp.h>
+
+namespace android {
+namespace fs_mgr {
+
+std::unique_ptr<LpMetadata> ReadMetadata(int fd, uint32_t slot_number);
+
+// Helper functions for manually reading geometry and metadata.
+bool ReadLogicalPartitionGeometry(int fd, LpMetadataGeometry* geometry);
+std::unique_ptr<LpMetadata> ParseMetadata(int fd);
+
+// These functions assume a valid geometry and slot number.
+std::unique_ptr<LpMetadata> ReadPrimaryMetadata(int fd, const LpMetadataGeometry& geometry,
+ uint32_t slot_number);
+std::unique_ptr<LpMetadata> ReadBackupMetadata(int fd, const LpMetadataGeometry& geometry,
+ uint32_t slot_number);
+
+} // namespace fs_mgr
+} // namespace android
+
+#endif /* LIBLP_READER_H_ */
diff --git a/fs_mgr/liblp/utility_test.cpp b/fs_mgr/liblp/utility_test.cpp
index dcc569e..092dbf1 100644
--- a/fs_mgr/liblp/utility_test.cpp
+++ b/fs_mgr/liblp/utility_test.cpp
@@ -14,8 +14,10 @@
* limitations under the License.
*/
-#include "utility.h"
#include <gtest/gtest.h>
+#include <liblp/liblp.h>
+
+#include "utility.h"
using namespace android;
using namespace android::fs_mgr;
@@ -29,8 +31,16 @@
}
TEST(liblp, GetMetadataOffset) {
- LpMetadataGeometry geometry = {
- LP_METADATA_GEOMETRY_MAGIC, sizeof(geometry), {0}, 16384, 4, 10000, 80000, 0, 0};
+ LpMetadataGeometry geometry = {LP_METADATA_GEOMETRY_MAGIC,
+ sizeof(geometry),
+ {0},
+ 16384,
+ 4,
+ 10000,
+ 80000,
+ 0,
+ 0,
+ 1024 * 1024};
EXPECT_EQ(GetPrimaryMetadataOffset(geometry, 0), 4096);
EXPECT_EQ(GetPrimaryMetadataOffset(geometry, 1), 4096 + 16384);
EXPECT_EQ(GetPrimaryMetadataOffset(geometry, 2), 4096 + 16384 * 2);
diff --git a/fs_mgr/liblp/writer.cpp b/fs_mgr/liblp/writer.cpp
index 89cbabd..74c03bf 100644
--- a/fs_mgr/liblp/writer.cpp
+++ b/fs_mgr/liblp/writer.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include "writer.h"
+
#include <inttypes.h>
#include <unistd.h>
@@ -22,14 +24,13 @@
#include <android-base/file.h>
#include <android-base/unique_fd.h>
-#include "liblp/reader.h"
-#include "liblp/writer.h"
+#include "reader.h"
#include "utility.h"
namespace android {
namespace fs_mgr {
-static std::string SerializeGeometry(const LpMetadataGeometry& input) {
+std::string SerializeGeometry(const LpMetadataGeometry& input) {
LpMetadataGeometry geometry = input;
memset(geometry.checksum, 0, sizeof(geometry.checksum));
SHA256(&geometry, sizeof(geometry), geometry.checksum);
@@ -43,7 +44,7 @@
g1.last_logical_sector == g2.last_logical_sector;
}
-static std::string SerializeMetadata(const LpMetadata& input) {
+std::string SerializeMetadata(const LpMetadata& input) {
LpMetadata metadata = input;
LpMetadataHeader& header = metadata.header;
@@ -73,8 +74,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 +90,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;
}
@@ -101,6 +108,11 @@
LERROR << "Not enough space to backup all logical partition metadata slots.";
return false;
}
+ if (blockdevice_size != metadata.geometry.block_device_size) {
+ LERROR << "Block device size " << blockdevice_size
+ << " does not match metadata requested size " << metadata.geometry.block_device_size;
+ return false;
+ }
// Make sure all partition entries reference valid extents.
for (const auto& partition : metadata.partitions) {
@@ -124,75 +136,24 @@
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;
- }
-
- 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;
- }
- }
-
- // 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.
+static bool WritePrimaryMetadata(int fd, const LpMetadataGeometry& geometry, uint32_t slot_number,
+ const std::string& blob,
+ const std::function<bool(int, const std::string&)>& writer) {
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;
}
+ return true;
+}
- // Write the backup copy of the metadata.
+static bool WriteBackupMetadata(int fd, const LpMetadataGeometry& geometry, uint32_t slot_number,
+ const std::string& blob,
+ const std::function<bool(int, const std::string&)>& writer) {
int64_t backup_offset = GetBackupMetadataOffset(geometry, slot_number);
int64_t abs_offset = SeekFile64(fd, backup_offset, SEEK_END);
if (abs_offset == (int64_t)-1) {
@@ -204,44 +165,157 @@
<< " 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,
- uint32_t slot_number) {
- android::base::unique_fd fd(open(block_device, O_RDWR | O_SYNC));
- if (fd < 0) {
- PERROR << __PRETTY_FUNCTION__ << "open failed: " << block_device;
+static bool WriteMetadata(int fd, const LpMetadataGeometry& geometry, uint32_t slot_number,
+ const std::string& blob,
+ const 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;
}
- return WritePartitionTable(fd, metadata, sync_mode, slot_number);
-}
-
-bool WriteToImageFile(int fd, const LpMetadata& input) {
- std::string geometry = SerializeGeometry(input.geometry);
- std::string padding(LP_METADATA_GEOMETRY_SIZE - geometry.size(), '\0');
- std::string metadata = SerializeMetadata(input);
-
- std::string everything = geometry + padding + metadata;
-
- if (!android::base::WriteFully(fd, everything.data(), everything.size())) {
- PERROR << __PRETTY_FUNCTION__ << "write " << everything.size() << " bytes failed";
+ if (!WritePrimaryMetadata(fd, geometry, slot_number, blob, writer)) {
+ return false;
+ }
+ if (!WriteBackupMetadata(fd, geometry, slot_number, blob, writer)) {
return false;
}
return true;
}
-bool WriteToImageFile(const char* file, const LpMetadata& input) {
- android::base::unique_fd fd(open(file, O_CREAT | O_RDWR | O_TRUNC, 0644));
- if (fd < 0) {
- PERROR << __PRETTY_FUNCTION__ << "open failed: " << file;
+static bool DefaultWriter(int fd, const std::string& blob) {
+ return android::base::WriteFully(fd, blob.data(), blob.size());
+}
+
+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;
}
- return WriteToImageFile(fd, input);
+
+ // 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);
+}
+
+static bool CompareMetadata(const LpMetadata& a, const LpMetadata& b) {
+ return !memcmp(a.header.header_checksum, b.header.header_checksum,
+ sizeof(a.header.header_checksum));
+}
+
+bool UpdatePartitionTable(int fd, const LpMetadata& metadata, uint32_t slot_number,
+ const 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;
+ }
+
+ // Validate the slot number now, before we call Read*Metadata.
+ if (slot_number >= geometry.metadata_slot_count) {
+ LERROR << "Invalid logical partition metadata slot number.";
+ return false;
+ }
+
+ // Try to read both existing copies of the metadata, if any.
+ std::unique_ptr<LpMetadata> primary = ReadPrimaryMetadata(fd, geometry, slot_number);
+ std::unique_ptr<LpMetadata> backup = ReadBackupMetadata(fd, geometry, slot_number);
+
+ if (primary && (!backup || !CompareMetadata(*primary.get(), *backup.get()))) {
+ // If the backup copy does not match the primary copy, we first
+ // synchronize the backup copy. This guarantees that a partial write
+ // still leaves one copy intact.
+ std::string old_blob;
+ if (!ValidateAndSerializeMetadata(fd, *primary.get(), &old_blob)) {
+ LERROR << "Error serializing primary metadata to repair corrupted backup";
+ return false;
+ }
+ if (!WriteBackupMetadata(fd, geometry, slot_number, old_blob, writer)) {
+ LERROR << "Error writing primary metadata to repair corrupted backup";
+ return false;
+ }
+ } else if (backup && !primary) {
+ // The backup copy is coherent, and the primary is not. Sync it for
+ // safety.
+ std::string old_blob;
+ if (!ValidateAndSerializeMetadata(fd, *backup.get(), &old_blob)) {
+ LERROR << "Error serializing primary metadata to repair corrupted backup";
+ return false;
+ }
+ if (!WritePrimaryMetadata(fd, geometry, slot_number, old_blob, writer)) {
+ LERROR << "Error writing primary metadata to repair corrupted backup";
+ return false;
+ }
+ }
+
+ // Both copies should now be in sync, so we can continue the update.
+ 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.c_str(), O_RDWR | O_SYNC));
+ if (fd < 0) {
+ PERROR << __PRETTY_FUNCTION__ << "open failed: " << block_device;
+ return false;
+ }
+ 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);
}
} // namespace fs_mgr
diff --git a/fs_mgr/liblp/writer.h b/fs_mgr/liblp/writer.h
new file mode 100644
index 0000000..adbbebf
--- /dev/null
+++ b/fs_mgr/liblp/writer.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2018 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 LIBLP_WRITER_H
+#define LIBLP_WRITER_H
+
+#include <functional>
+#include <string>
+
+#include <liblp/liblp.h>
+
+namespace android {
+namespace fs_mgr {
+
+std::string SerializeGeometry(const LpMetadataGeometry& input);
+std::string SerializeMetadata(const LpMetadata& input);
+
+// 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,
+ const std::function<bool(int, const std::string&)>& writer);
+
+} // namespace fs_mgr
+} // namespace android
+
+#endif /* LIBLP_WRITER_H */
diff --git a/healthd/Android.bp b/healthd/Android.bp
index 56f5148..7269b62 100644
--- a/healthd/Android.bp
+++ b/healthd/Android.bp
@@ -5,3 +5,16 @@
header_libs: ["libbatteryservice_headers"],
export_header_lib_headers: ["libbatteryservice_headers"],
}
+
+cc_library_static {
+ name: "libbatterymonitor",
+ srcs: ["BatteryMonitor.cpp"],
+ vendor_available: true,
+ export_include_dirs: ["include"],
+ shared_libs: [
+ "libutils",
+ "libbase",
+ ],
+ header_libs: ["libhealthd_headers"],
+ export_header_lib_headers: ["libhealthd_headers"],
+}
diff --git a/healthd/Android.mk b/healthd/Android.mk
index 6c8fecf..1244903 100644
--- a/healthd/Android.mk
+++ b/healthd/Android.mk
@@ -3,14 +3,6 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
-LOCAL_SRC_FILES := BatteryMonitor.cpp
-LOCAL_MODULE := libbatterymonitor
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-LOCAL_STATIC_LIBRARIES := libutils libbase libbinder
-include $(BUILD_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
healthd_mode_android.cpp \
BatteryPropertiesRegistrar.cpp
diff --git a/healthd/include/healthd/BatteryMonitor.h b/healthd/include/healthd/BatteryMonitor.h
index 194e667..97435c7 100644
--- a/healthd/include/healthd/BatteryMonitor.h
+++ b/healthd/include/healthd/BatteryMonitor.h
@@ -18,7 +18,6 @@
#define HEALTHD_BATTERYMONITOR_H
#include <batteryservice/BatteryService.h>
-#include <binder/IInterface.h>
#include <utils/String8.h>
#include <utils/Vector.h>
diff --git a/init/service.cpp b/init/service.cpp
index 95b37ab..4c2747e 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -130,7 +130,7 @@
if (umount2("/sys", MNT_DETACH) == -1) {
return ErrnoError() << "Could not umount(/sys)";
}
- if (mount("", "/sys", "sys", kSafeFlags, "") == -1) {
+ if (mount("", "/sys", "sysfs", kSafeFlags, "") == -1) {
return ErrnoError() << "Could not mount(/sys)";
}
}
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..37afb98 100644
--- a/libcutils/Android.bp
+++ b/libcutils/Android.bp
@@ -20,6 +20,7 @@
libcutils_nonwindows_sources = [
"android_get_control_file.cpp",
"fs.cpp",
+ "hashmap.cpp",
"multiuser.cpp",
"socket_inaddr_any_server_unix.cpp",
"socket_local_client_unix.cpp",
@@ -61,11 +62,9 @@
"config_utils.cpp",
"fs_config.cpp",
"canned_fs_config.cpp",
- "hashmap.cpp",
"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..57d6006 100644
--- a/libcutils/hashmap.cpp
+++ b/libcutils/hashmap.cpp
@@ -18,7 +18,7 @@
#include <assert.h>
#include <errno.h>
-#include <cutils/threads.h>
+#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
@@ -36,7 +36,7 @@
size_t bucketCount;
int (*hash)(void* key);
bool (*equals)(void* keyA, void* keyB);
- mutex_t lock;
+ pthread_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);
-
+
+ pthread_mutex_init(&map->lock, nullptr);
+
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++) {
@@ -133,11 +129,11 @@
}
void hashmapLock(Hashmap* map) {
- mutex_lock(&map->lock);
+ pthread_mutex_lock(&map->lock);
}
void hashmapUnlock(Hashmap* map) {
- mutex_unlock(&map->lock);
+ pthread_mutex_unlock(&map->lock);
}
void hashmapFree(Hashmap* map) {
@@ -151,7 +147,7 @@
}
}
free(map->buckets);
- mutex_destroy(&map->lock);
+ pthread_mutex_destroy(&map->lock);
free(map);
}
@@ -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/cutils/threads.h b/libcutils/include/cutils/threads.h
index 5727494..ba4846e 100644
--- a/libcutils/include/cutils/threads.h
+++ b/libcutils/include/cutils/threads.h
@@ -29,16 +29,16 @@
extern "C" {
#endif
-/***********************************************************************/
-/***********************************************************************/
-/***** *****/
-/***** local thread storage *****/
-/***** *****/
-/***********************************************************************/
-/***********************************************************************/
+//
+// Deprecated: use android::base::GetThreadId instead, which doesn't truncate on Mac/Windows.
+//
extern pid_t gettid();
+//
+// Deprecated: use `_Thread_local` in C or `thread_local` in C++.
+//
+
#if !defined(_WIN32)
typedef struct {
@@ -70,77 +70,6 @@
void* value,
thread_store_destruct_t destroy);
-/***********************************************************************/
-/***********************************************************************/
-/***** *****/
-/***** mutexes *****/
-/***** *****/
-/***********************************************************************/
-/***********************************************************************/
-
-#if !defined(_WIN32)
-
-typedef pthread_mutex_t mutex_t;
-
-#define MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
-
-static __inline__ void mutex_lock(mutex_t* lock)
-{
- pthread_mutex_lock(lock);
-}
-static __inline__ void mutex_unlock(mutex_t* lock)
-{
- pthread_mutex_unlock(lock);
-}
-static __inline__ int mutex_init(mutex_t* lock)
-{
- return pthread_mutex_init(lock, NULL);
-}
-static __inline__ void mutex_destroy(mutex_t* lock)
-{
- pthread_mutex_destroy(lock);
-}
-
-#else // !defined(_WIN32)
-
-typedef struct {
- int init;
- CRITICAL_SECTION lock[1];
-} mutex_t;
-
-#define MUTEX_INITIALIZER { 0, {{ NULL, 0, 0, NULL, NULL, 0 }} }
-
-static __inline__ void mutex_lock(mutex_t* lock)
-{
- if (!lock->init) {
- lock->init = 1;
- InitializeCriticalSection( lock->lock );
- lock->init = 2;
- } else while (lock->init != 2)
- Sleep(10);
-
- EnterCriticalSection(lock->lock);
-}
-
-static __inline__ void mutex_unlock(mutex_t* lock)
-{
- LeaveCriticalSection(lock->lock);
-}
-static __inline__ int mutex_init(mutex_t* lock)
-{
- InitializeCriticalSection(lock->lock);
- lock->init = 2;
- return 0;
-}
-static __inline__ void mutex_destroy(mutex_t* lock)
-{
- if (lock->init) {
- lock->init = 0;
- DeleteCriticalSection(lock->lock);
- }
-}
-#endif // !defined(_WIN32)
-
#ifdef __cplusplus
}
#endif
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/liblog/include/log/log_read.h b/liblog/include/log/log_read.h
index d118563..93b9d4e 100644
--- a/liblog/include/log/log_read.h
+++ b/liblog/include/log/log_read.h
@@ -184,7 +184,7 @@
hdr_size = sizeof(entry_v1);
}
if ((hdr_size < sizeof(entry_v1)) || (hdr_size > sizeof(entry))) {
- return NULL;
+ return nullptr;
}
return reinterpret_cast<char*>(buf) + hdr_size;
}
diff --git a/liblog/include/private/android_logger.h b/liblog/include/private/android_logger.h
index 965de37..b927b46 100644
--- a/liblog/include/private/android_logger.h
+++ b/liblog/include/private/android_logger.h
@@ -173,7 +173,7 @@
#if defined(_USING_LIBCXX)
operator std::string() {
if (ret) return std::string("");
- const char* cp = NULL;
+ const char* cp = nullptr;
ssize_t len = android_log_write_list_buffer(ctx, &cp);
if (len < 0) ret = len;
if (!cp || (len <= 0)) return std::string("");
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/libnativeloader/include/nativeloader/native_loader.h b/libnativeloader/include/nativeloader/native_loader.h
index 3563fc1..19a1783 100644
--- a/libnativeloader/include/nativeloader/native_loader.h
+++ b/libnativeloader/include/nativeloader/native_loader.h
@@ -53,8 +53,21 @@
#if defined(__ANDROID__)
// Look up linker namespace by class_loader. Returns nullptr if
// there is no namespace associated with the class_loader.
+// TODO(b/79940628): move users to FindNativeLoaderNamespaceByClassLoader and remove this function.
__attribute__((visibility("default")))
android_namespace_t* FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader);
+// That version works with native bridge namespaces, but requires use of OpenNativeLibrary.
+class NativeLoaderNamespace;
+__attribute__((visibility("default")))
+NativeLoaderNamespace* FindNativeLoaderNamespaceByClassLoader(
+ JNIEnv* env, jobject class_loader);
+// Load library. Unlinke OpenNativeLibrary above couldn't create namespace on demand, but does
+// not require access to JNIEnv either.
+__attribute__((visibility("default")))
+void* OpenNativeLibrary(NativeLoaderNamespace* ns,
+ const char* path,
+ bool* needs_native_bridge,
+ std::string* error_msg);
#endif
__attribute__((visibility("default")))
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
index 7fef106..67c1c10 100644
--- a/libnativeloader/native_loader.cpp
+++ b/libnativeloader/native_loader.cpp
@@ -29,6 +29,7 @@
#include "nativebridge/native_bridge.h"
#include <algorithm>
+#include <list>
#include <memory>
#include <mutex>
#include <string>
@@ -150,15 +151,14 @@
public:
LibraryNamespaces() : initialized_(false) { }
- bool Create(JNIEnv* env,
- uint32_t target_sdk_version,
- jobject class_loader,
- bool is_shared,
- bool is_for_vendor,
- jstring java_library_path,
- jstring java_permitted_path,
- NativeLoaderNamespace* ns,
- std::string* error_msg) {
+ NativeLoaderNamespace* Create(JNIEnv* env,
+ uint32_t target_sdk_version,
+ jobject class_loader,
+ bool is_shared,
+ bool is_for_vendor,
+ jstring java_library_path,
+ jstring java_permitted_path,
+ std::string* error_msg) {
std::string library_path; // empty string by default.
if (java_library_path != nullptr) {
@@ -182,10 +182,10 @@
}
if (!initialized_ && !InitPublicNamespace(library_path.c_str(), error_msg)) {
- return false;
+ return nullptr;
}
- bool found = FindNamespaceByClassLoader(env, class_loader, nullptr);
+ bool found = FindNamespaceByClassLoader(env, class_loader);
LOG_ALWAYS_FATAL_IF(found,
"There is already a namespace associated with this classloader");
@@ -199,13 +199,12 @@
namespace_type |= ANDROID_NAMESPACE_TYPE_GREYLIST_ENABLED;
}
- NativeLoaderNamespace parent_ns;
- bool found_parent_namespace = FindParentNamespaceByClassLoader(env, class_loader, &parent_ns);
+ NativeLoaderNamespace* parent_ns = FindParentNamespaceByClassLoader(env, class_loader);
bool is_native_bridge = false;
- if (found_parent_namespace) {
- is_native_bridge = !parent_ns.is_android_namespace();
+ if (parent_ns != nullptr) {
+ is_native_bridge = !parent_ns->is_android_namespace();
} else if (!library_path.empty()) {
is_native_bridge = NativeBridgeIsPathSupported(library_path.c_str());
}
@@ -251,15 +250,17 @@
NativeLoaderNamespace native_loader_ns;
if (!is_native_bridge) {
+ android_namespace_t* android_parent_ns =
+ parent_ns == nullptr ? nullptr : parent_ns->get_android_ns();
android_namespace_t* ns = android_create_namespace(namespace_name,
nullptr,
library_path.c_str(),
namespace_type,
permitted_path.c_str(),
- parent_ns.get_android_ns());
+ android_parent_ns);
if (ns == nullptr) {
*error_msg = dlerror();
- return false;
+ return nullptr;
}
// Note that when vendor_ns is not configured this function will return nullptr
@@ -269,49 +270,50 @@
if (!android_link_namespaces(ns, nullptr, system_exposed_libraries.c_str())) {
*error_msg = dlerror();
- return false;
+ return nullptr;
}
if (vndk_ns != nullptr && !system_vndksp_libraries_.empty()) {
// vendor apks are allowed to use VNDK-SP libraries.
if (!android_link_namespaces(ns, vndk_ns, system_vndksp_libraries_.c_str())) {
*error_msg = dlerror();
- return false;
+ return nullptr;
}
}
if (!vendor_public_libraries_.empty()) {
if (!android_link_namespaces(ns, vendor_ns, vendor_public_libraries_.c_str())) {
*error_msg = dlerror();
- return false;
+ return nullptr;
}
}
native_loader_ns = NativeLoaderNamespace(ns);
} else {
+ native_bridge_namespace_t* native_bridge_parent_namespace =
+ parent_ns == nullptr ? nullptr : parent_ns->get_native_bridge_ns();
native_bridge_namespace_t* ns = NativeBridgeCreateNamespace(namespace_name,
nullptr,
library_path.c_str(),
namespace_type,
permitted_path.c_str(),
- parent_ns.get_native_bridge_ns());
-
+ native_bridge_parent_namespace);
if (ns == nullptr) {
*error_msg = NativeBridgeGetError();
- return false;
+ return nullptr;
}
native_bridge_namespace_t* vendor_ns = NativeBridgeGetVendorNamespace();
if (!NativeBridgeLinkNamespaces(ns, nullptr, system_exposed_libraries.c_str())) {
*error_msg = NativeBridgeGetError();
- return false;
+ return nullptr;
}
if (!vendor_public_libraries_.empty()) {
if (!NativeBridgeLinkNamespaces(ns, vendor_ns, vendor_public_libraries_.c_str())) {
*error_msg = NativeBridgeGetError();
- return false;
+ return nullptr;
}
}
@@ -320,24 +322,19 @@
namespaces_.push_back(std::make_pair(env->NewWeakGlobalRef(class_loader), native_loader_ns));
- *ns = native_loader_ns;
- return true;
+ return &(namespaces_.back().second);
}
- bool FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader, NativeLoaderNamespace* ns) {
+ NativeLoaderNamespace* FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
auto it = std::find_if(namespaces_.begin(), namespaces_.end(),
[&](const std::pair<jweak, NativeLoaderNamespace>& value) {
return env->IsSameObject(value.first, class_loader);
});
if (it != namespaces_.end()) {
- if (ns != nullptr) {
- *ns = it->second;
- }
-
- return true;
+ return &it->second;
}
- return false;
+ return nullptr;
}
void Initialize() {
@@ -557,24 +554,23 @@
return env->CallObjectMethod(class_loader, get_parent);
}
- bool FindParentNamespaceByClassLoader(JNIEnv* env,
- jobject class_loader,
- NativeLoaderNamespace* ns) {
+ NativeLoaderNamespace* FindParentNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
jobject parent_class_loader = GetParentClassLoader(env, class_loader);
while (parent_class_loader != nullptr) {
- if (FindNamespaceByClassLoader(env, parent_class_loader, ns)) {
- return true;
+ NativeLoaderNamespace* ns;
+ if ((ns = FindNamespaceByClassLoader(env, parent_class_loader)) != nullptr) {
+ return ns;
}
parent_class_loader = GetParentClassLoader(env, parent_class_loader);
}
- return false;
+ return nullptr;
}
bool initialized_;
- std::vector<std::pair<jweak, NativeLoaderNamespace>> namespaces_;
+ std::list<std::pair<jweak, NativeLoaderNamespace>> namespaces_;
std::string system_public_libraries_;
std::string vendor_public_libraries_;
std::string oem_public_libraries_;
@@ -614,7 +610,6 @@
std::lock_guard<std::mutex> guard(g_namespaces_mutex);
std::string error_msg;
- NativeLoaderNamespace ns;
bool success = g_namespaces->Create(env,
target_sdk_version,
class_loader,
@@ -622,8 +617,7 @@
is_for_vendor,
library_path,
permitted_path,
- &ns,
- &error_msg);
+ &error_msg) != nullptr;
if (!success) {
return env->NewStringUTF(error_msg.c_str());
}
@@ -649,43 +643,24 @@
}
std::lock_guard<std::mutex> guard(g_namespaces_mutex);
- NativeLoaderNamespace ns;
+ NativeLoaderNamespace* ns;
- if (!g_namespaces->FindNamespaceByClassLoader(env, class_loader, &ns)) {
+ if ((ns = g_namespaces->FindNamespaceByClassLoader(env, class_loader)) == nullptr) {
// This is the case where the classloader was not created by ApplicationLoaders
// In this case we create an isolated not-shared namespace for it.
- if (!g_namespaces->Create(env,
- target_sdk_version,
- class_loader,
- false /* is_shared */,
- false /* is_for_vendor */,
- library_path,
- nullptr,
- &ns,
- error_msg)) {
+ if ((ns = g_namespaces->Create(env,
+ target_sdk_version,
+ class_loader,
+ false /* is_shared */,
+ false /* is_for_vendor */,
+ library_path,
+ nullptr,
+ error_msg)) == nullptr) {
return nullptr;
}
}
- if (ns.is_android_namespace()) {
- android_dlextinfo extinfo;
- extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
- extinfo.library_namespace = ns.get_android_ns();
-
- void* handle = android_dlopen_ext(path, RTLD_NOW, &extinfo);
- if (handle == nullptr) {
- *error_msg = dlerror();
- }
- *needs_native_bridge = false;
- return handle;
- } else {
- void* handle = NativeBridgeLoadLibraryExt(path, RTLD_NOW, ns.get_native_bridge_ns());
- if (handle == nullptr) {
- *error_msg = NativeBridgeGetError();
- }
- *needs_native_bridge = true;
- return handle;
- }
+ return OpenNativeLibrary(ns, path, needs_native_bridge, error_msg);
#else
UNUSED(env, target_sdk_version, class_loader);
@@ -741,18 +716,45 @@
}
#if defined(__ANDROID__)
+void* OpenNativeLibrary(NativeLoaderNamespace* ns, const char* path, bool* needs_native_bridge,
+ std::string* error_msg) {
+ if (ns->is_android_namespace()) {
+ android_dlextinfo extinfo;
+ extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
+ extinfo.library_namespace = ns->get_android_ns();
+
+ void* handle = android_dlopen_ext(path, RTLD_NOW, &extinfo);
+ if (handle == nullptr) {
+ *error_msg = dlerror();
+ }
+ *needs_native_bridge = false;
+ return handle;
+ } else {
+ void* handle = NativeBridgeLoadLibraryExt(path, RTLD_NOW, ns->get_native_bridge_ns());
+ if (handle == nullptr) {
+ *error_msg = NativeBridgeGetError();
+ }
+ *needs_native_bridge = true;
+ return handle;
+ }
+}
+
// native_bridge_namespaces are not supported for callers of this function.
// This function will return nullptr in the case when application is running
// on native bridge.
android_namespace_t* FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
std::lock_guard<std::mutex> guard(g_namespaces_mutex);
- NativeLoaderNamespace ns;
- if (g_namespaces->FindNamespaceByClassLoader(env, class_loader, &ns)) {
- return ns.is_android_namespace() ? ns.get_android_ns() : nullptr;
+ NativeLoaderNamespace* ns = g_namespaces->FindNamespaceByClassLoader(env, class_loader);
+ if (ns != nullptr) {
+ return ns->is_android_namespace() ? ns->get_android_ns() : nullptr;
}
return nullptr;
}
+NativeLoaderNamespace* FindNativeLoaderNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
+ std::lock_guard<std::mutex> guard(g_namespaces_mutex);
+ return g_namespaces->FindNamespaceByClassLoader(env, class_loader);
+}
#endif
}; // android namespace
diff --git a/libunwindstack/ElfInterface.cpp b/libunwindstack/ElfInterface.cpp
index 915cddb..2c00456 100644
--- a/libunwindstack/ElfInterface.cpp
+++ b/libunwindstack/ElfInterface.cpp
@@ -204,49 +204,19 @@
uint64_t offset = ehdr.e_phoff;
for (size_t i = 0; i < ehdr.e_phnum; i++, offset += ehdr.e_phentsize) {
PhdrType phdr;
- if (!memory_->ReadField(offset, &phdr, &phdr.p_type, sizeof(phdr.p_type))) {
+ if (!memory_->ReadFully(offset, &phdr, sizeof(phdr))) {
last_error_.code = ERROR_MEMORY_INVALID;
- last_error_.address =
- offset + reinterpret_cast<uintptr_t>(&phdr.p_type) - reinterpret_cast<uintptr_t>(&phdr);
+ last_error_.address = offset;
return false;
}
- if (HandleType(offset, phdr.p_type)) {
- continue;
- }
-
switch (phdr.p_type) {
case PT_LOAD:
{
- // Get the flags first, if this isn't an executable header, ignore it.
- if (!memory_->ReadField(offset, &phdr, &phdr.p_flags, sizeof(phdr.p_flags))) {
- last_error_.code = ERROR_MEMORY_INVALID;
- last_error_.address = offset + reinterpret_cast<uintptr_t>(&phdr.p_flags) -
- reinterpret_cast<uintptr_t>(&phdr);
- return false;
- }
if ((phdr.p_flags & PF_X) == 0) {
continue;
}
- if (!memory_->ReadField(offset, &phdr, &phdr.p_vaddr, sizeof(phdr.p_vaddr))) {
- last_error_.code = ERROR_MEMORY_INVALID;
- last_error_.address = offset + reinterpret_cast<uintptr_t>(&phdr.p_vaddr) -
- reinterpret_cast<uintptr_t>(&phdr);
- return false;
- }
- if (!memory_->ReadField(offset, &phdr, &phdr.p_offset, sizeof(phdr.p_offset))) {
- last_error_.code = ERROR_MEMORY_INVALID;
- last_error_.address = offset + reinterpret_cast<uintptr_t>(&phdr.p_offset) -
- reinterpret_cast<uintptr_t>(&phdr);
- return false;
- }
- if (!memory_->ReadField(offset, &phdr, &phdr.p_memsz, sizeof(phdr.p_memsz))) {
- last_error_.code = ERROR_MEMORY_INVALID;
- last_error_.address = offset + reinterpret_cast<uintptr_t>(&phdr.p_memsz) -
- reinterpret_cast<uintptr_t>(&phdr);
- return false;
- }
pt_loads_[phdr.p_offset] = LoadInfo{phdr.p_offset, phdr.p_vaddr,
static_cast<size_t>(phdr.p_memsz)};
if (phdr.p_offset == 0) {
@@ -256,46 +226,20 @@
}
case PT_GNU_EH_FRAME:
- if (!memory_->ReadField(offset, &phdr, &phdr.p_offset, sizeof(phdr.p_offset))) {
- last_error_.code = ERROR_MEMORY_INVALID;
- last_error_.address = offset + reinterpret_cast<uintptr_t>(&phdr.p_offset) -
- reinterpret_cast<uintptr_t>(&phdr);
- return false;
- }
// This is really the pointer to the .eh_frame_hdr section.
eh_frame_hdr_offset_ = phdr.p_offset;
- if (!memory_->ReadField(offset, &phdr, &phdr.p_memsz, sizeof(phdr.p_memsz))) {
- last_error_.code = ERROR_MEMORY_INVALID;
- last_error_.address = offset + reinterpret_cast<uintptr_t>(&phdr.p_memsz) -
- reinterpret_cast<uintptr_t>(&phdr);
- return false;
- }
eh_frame_hdr_size_ = phdr.p_memsz;
break;
case PT_DYNAMIC:
- if (!memory_->ReadField(offset, &phdr, &phdr.p_offset, sizeof(phdr.p_offset))) {
- last_error_.code = ERROR_MEMORY_INVALID;
- last_error_.address = offset + reinterpret_cast<uintptr_t>(&phdr.p_offset) -
- reinterpret_cast<uintptr_t>(&phdr);
- return false;
- }
dynamic_offset_ = phdr.p_offset;
- if (!memory_->ReadField(offset, &phdr, &phdr.p_vaddr, sizeof(phdr.p_vaddr))) {
- last_error_.code = ERROR_MEMORY_INVALID;
- last_error_.address = offset + reinterpret_cast<uintptr_t>(&phdr.p_vaddr) -
- reinterpret_cast<uintptr_t>(&phdr);
- return false;
- }
dynamic_vaddr_ = phdr.p_vaddr;
- if (!memory_->ReadField(offset, &phdr, &phdr.p_memsz, sizeof(phdr.p_memsz))) {
- last_error_.code = ERROR_MEMORY_INVALID;
- last_error_.address = offset + reinterpret_cast<uintptr_t>(&phdr.p_memsz) -
- reinterpret_cast<uintptr_t>(&phdr);
- return false;
- }
dynamic_size_ = phdr.p_memsz;
break;
+
+ default:
+ HandleUnknownType(phdr.p_type, phdr.p_offset, phdr.p_filesz);
+ break;
}
}
return true;
@@ -313,8 +257,7 @@
ShdrType shdr;
if (ehdr.e_shstrndx < ehdr.e_shnum) {
uint64_t sh_offset = offset + ehdr.e_shstrndx * ehdr.e_shentsize;
- if (memory_->ReadField(sh_offset, &shdr, &shdr.sh_offset, sizeof(shdr.sh_offset)) &&
- memory_->ReadField(sh_offset, &shdr, &shdr.sh_size, sizeof(shdr.sh_size))) {
+ if (memory_->ReadFully(sh_offset, &shdr, sizeof(shdr))) {
sec_offset = shdr.sh_offset;
sec_size = shdr.sh_size;
}
diff --git a/libunwindstack/ElfInterfaceArm.cpp b/libunwindstack/ElfInterfaceArm.cpp
index a3244e8..3dd5d54 100644
--- a/libunwindstack/ElfInterfaceArm.cpp
+++ b/libunwindstack/ElfInterfaceArm.cpp
@@ -87,23 +87,17 @@
#define PT_ARM_EXIDX 0x70000001
#endif
-bool ElfInterfaceArm::HandleType(uint64_t offset, uint32_t type) {
+void ElfInterfaceArm::HandleUnknownType(uint32_t type, uint64_t ph_offset, uint64_t ph_filesz) {
if (type != PT_ARM_EXIDX) {
- return false;
- }
-
- Elf32_Phdr phdr;
- if (!memory_->ReadFully(offset, &phdr, sizeof(phdr))) {
- return true;
+ return;
}
// The offset already takes into account the load bias.
- start_offset_ = phdr.p_offset;
+ start_offset_ = ph_offset;
// Always use filesz instead of memsz. In most cases they are the same,
// but some shared libraries wind up setting one correctly and not the other.
- total_entries_ = phdr.p_filesz / 8;
- return true;
+ total_entries_ = ph_filesz / 8;
}
bool ElfInterfaceArm::Step(uint64_t pc, Regs* regs, Memory* process_memory, bool* finished) {
diff --git a/libunwindstack/ElfInterfaceArm.h b/libunwindstack/ElfInterfaceArm.h
index 3bee9cf..4c3a0c3 100644
--- a/libunwindstack/ElfInterfaceArm.h
+++ b/libunwindstack/ElfInterfaceArm.h
@@ -70,7 +70,7 @@
bool FindEntry(uint32_t pc, uint64_t* entry_offset);
- bool HandleType(uint64_t offset, uint32_t type) override;
+ void HandleUnknownType(uint32_t type, uint64_t ph_offset, uint64_t ph_filesz) override;
bool Step(uint64_t pc, Regs* regs, Memory* process_memory, bool* finished) override;
diff --git a/libunwindstack/include/unwindstack/ElfInterface.h b/libunwindstack/include/unwindstack/ElfInterface.h
index 0c588da..5c1210d 100644
--- a/libunwindstack/include/unwindstack/ElfInterface.h
+++ b/libunwindstack/include/unwindstack/ElfInterface.h
@@ -118,7 +118,7 @@
template <typename SymType>
bool GetGlobalVariableWithTemplate(const std::string& name, uint64_t* memory_address);
- virtual bool HandleType(uint64_t, uint32_t) { return false; }
+ virtual void HandleUnknownType(uint32_t, uint64_t, uint64_t) {}
template <typename EhdrType>
static void GetMaxSizeWithTemplate(Memory* memory, uint64_t* size);
diff --git a/libunwindstack/include/unwindstack/Memory.h b/libunwindstack/include/unwindstack/Memory.h
index c0c07f4..dee5e98 100644
--- a/libunwindstack/include/unwindstack/Memory.h
+++ b/libunwindstack/include/unwindstack/Memory.h
@@ -41,18 +41,6 @@
bool ReadFully(uint64_t addr, void* dst, size_t size);
- inline bool ReadField(uint64_t addr, void* start, void* field, size_t size) {
- if (reinterpret_cast<uintptr_t>(field) < reinterpret_cast<uintptr_t>(start)) {
- return false;
- }
- uint64_t offset = reinterpret_cast<uintptr_t>(field) - reinterpret_cast<uintptr_t>(start);
- if (__builtin_add_overflow(addr, offset, &offset)) {
- return false;
- }
- // The read will check if offset + size overflows.
- return ReadFully(offset, field, size);
- }
-
inline bool Read32(uint64_t addr, uint32_t* dst) {
return ReadFully(addr, dst, sizeof(uint32_t));
}
diff --git a/libunwindstack/tests/ElfInterfaceArmTest.cpp b/libunwindstack/tests/ElfInterfaceArmTest.cpp
index a8bb4aa..43c6a97 100644
--- a/libunwindstack/tests/ElfInterfaceArmTest.cpp
+++ b/libunwindstack/tests/ElfInterfaceArmTest.cpp
@@ -242,44 +242,21 @@
ASSERT_EQ(0xa020U, entries[4]);
}
-TEST_F(ElfInterfaceArmTest, HandleType_not_arm_exidx) {
+TEST_F(ElfInterfaceArmTest, HandleUnknownType_arm_exidx) {
ElfInterfaceArmFake interface(&memory_);
- ASSERT_FALSE(interface.HandleType(0x1000, PT_NULL));
- ASSERT_FALSE(interface.HandleType(0x1000, PT_LOAD));
- ASSERT_FALSE(interface.HandleType(0x1000, PT_DYNAMIC));
- ASSERT_FALSE(interface.HandleType(0x1000, PT_INTERP));
- ASSERT_FALSE(interface.HandleType(0x1000, PT_NOTE));
- ASSERT_FALSE(interface.HandleType(0x1000, PT_SHLIB));
- ASSERT_FALSE(interface.HandleType(0x1000, PT_PHDR));
- ASSERT_FALSE(interface.HandleType(0x1000, PT_TLS));
- ASSERT_FALSE(interface.HandleType(0x1000, PT_LOOS));
- ASSERT_FALSE(interface.HandleType(0x1000, PT_HIOS));
- ASSERT_FALSE(interface.HandleType(0x1000, PT_LOPROC));
- ASSERT_FALSE(interface.HandleType(0x1000, PT_HIPROC));
- ASSERT_FALSE(interface.HandleType(0x1000, PT_GNU_EH_FRAME));
- ASSERT_FALSE(interface.HandleType(0x1000, PT_GNU_STACK));
-}
-
-TEST_F(ElfInterfaceArmTest, HandleType_arm_exidx) {
- ElfInterfaceArmFake interface(&memory_);
-
- Elf32_Phdr phdr = {};
interface.FakeSetStartOffset(0x1000);
interface.FakeSetTotalEntries(100);
- phdr.p_offset = 0x2000;
- phdr.p_filesz = 0xa00;
- // Verify that if reads fail, we don't set the values but still get true.
- ASSERT_TRUE(interface.HandleType(0x1000, 0x70000001));
+ // Verify that if the type is not the one we want, we don't set the values.
+ interface.HandleUnknownType(0x70000000, 0x2000, 320);
ASSERT_EQ(0x1000U, interface.start_offset());
ASSERT_EQ(100U, interface.total_entries());
// Everything is correct and present.
- memory_.SetMemory(0x1000, &phdr, sizeof(phdr));
- ASSERT_TRUE(interface.HandleType(0x1000, 0x70000001));
+ interface.HandleUnknownType(0x70000001, 0x2000, 320);
ASSERT_EQ(0x2000U, interface.start_offset());
- ASSERT_EQ(320U, interface.total_entries());
+ ASSERT_EQ(40U, interface.total_entries());
}
TEST_F(ElfInterfaceArmTest, StepExidx) {
diff --git a/libunwindstack/tests/MemoryTest.cpp b/libunwindstack/tests/MemoryTest.cpp
index 4a9ed9f..3655984 100644
--- a/libunwindstack/tests/MemoryTest.cpp
+++ b/libunwindstack/tests/MemoryTest.cpp
@@ -51,40 +51,6 @@
uint64_t four;
};
-TEST(MemoryTest, read_field) {
- MemoryFakeAlwaysReadZero memory;
-
- FakeStruct data;
- memset(&data, 0xff, sizeof(data));
- ASSERT_TRUE(memory.ReadField(0, &data, &data.one, sizeof(data.one)));
- ASSERT_EQ(0, data.one);
-
- memset(&data, 0xff, sizeof(data));
- ASSERT_TRUE(memory.ReadField(0, &data, &data.two, sizeof(data.two)));
- ASSERT_FALSE(data.two);
-
- memset(&data, 0xff, sizeof(data));
- ASSERT_TRUE(memory.ReadField(0, &data, &data.three, sizeof(data.three)));
- ASSERT_EQ(0U, data.three);
-
- memset(&data, 0xff, sizeof(data));
- ASSERT_TRUE(memory.ReadField(0, &data, &data.four, sizeof(data.four)));
- ASSERT_EQ(0U, data.four);
-}
-
-TEST(MemoryTest, read_field_fails) {
- MemoryFakeAlwaysReadZero memory;
-
- FakeStruct data;
- memset(&data, 0xff, sizeof(data));
-
- ASSERT_FALSE(memory.ReadField(UINT64_MAX, &data, &data.three, sizeof(data.three)));
-
- // Field and start reversed, should fail.
- ASSERT_FALSE(memory.ReadField(100, &data.two, &data, sizeof(data.two)));
- ASSERT_FALSE(memory.ReadField(0, &data.two, &data, sizeof(data.two)));
-}
-
TEST(MemoryTest, read_string) {
std::string name("string_in_memory");
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/libutils/include/utils/AndroidThreads.h b/libutils/include/utils/AndroidThreads.h
index dab888d..a8d7851 100644
--- a/libutils/include/utils/AndroidThreads.h
+++ b/libutils/include/utils/AndroidThreads.h
@@ -106,7 +106,7 @@
const char* threadName = "android:unnamed_thread",
int32_t threadPriority = PRIORITY_DEFAULT,
size_t threadStackSize = 0,
- thread_id_t *threadId = 0)
+ thread_id_t *threadId = nullptr)
{
return androidCreateThreadEtc(entryFunction, userData, threadName,
threadPriority, threadStackSize, threadId) ? true : false;
diff --git a/libutils/include/utils/CallStack.h b/libutils/include/utils/CallStack.h
index 9622142..0c1b875 100644
--- a/libutils/include/utils/CallStack.h
+++ b/libutils/include/utils/CallStack.h
@@ -49,13 +49,13 @@
// Dump a stack trace to the log using the supplied logtag.
void log(const char* logtag,
android_LogPriority priority = ANDROID_LOG_DEBUG,
- const char* prefix = 0) const;
+ const char* prefix = nullptr) const;
// Dump a stack trace to the specified file descriptor.
- void dump(int fd, int indent = 0, const char* prefix = 0) const;
+ void dump(int fd, int indent = 0, const char* prefix = nullptr) const;
// Return a string (possibly very long) containing the complete stack trace.
- String8 toString(const char* prefix = 0) const;
+ String8 toString(const char* prefix = nullptr) const;
// Dump a serialized representation of the stack trace to the specified printer.
void print(Printer& printer) const;
diff --git a/libutils/include/utils/Looper.h b/libutils/include/utils/Looper.h
index a62e67f..4509d75 100644
--- a/libutils/include/utils/Looper.h
+++ b/libutils/include/utils/Looper.h
@@ -262,7 +262,7 @@
*/
int pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData);
inline int pollOnce(int timeoutMillis) {
- return pollOnce(timeoutMillis, NULL, NULL, NULL);
+ return pollOnce(timeoutMillis, nullptr, nullptr, nullptr);
}
/**
@@ -272,7 +272,7 @@
*/
int pollAll(int timeoutMillis, int* outFd, int* outEvents, void** outData);
inline int pollAll(int timeoutMillis) {
- return pollAll(timeoutMillis, NULL, NULL, NULL);
+ return pollAll(timeoutMillis, nullptr, nullptr, nullptr);
}
/**
diff --git a/libutils/include/utils/Mutex.h b/libutils/include/utils/Mutex.h
index 1228df4..29c2e8c 100644
--- a/libutils/include/utils/Mutex.h
+++ b/libutils/include/utils/Mutex.h
@@ -100,7 +100,7 @@
Mutex();
explicit Mutex(const char* name);
- explicit Mutex(int type, const char* name = NULL);
+ explicit Mutex(int type, const char* name = nullptr);
~Mutex();
// lock or unlock the mutex
@@ -160,10 +160,10 @@
#if !defined(_WIN32)
inline Mutex::Mutex() {
- pthread_mutex_init(&mMutex, NULL);
+ pthread_mutex_init(&mMutex, nullptr);
}
inline Mutex::Mutex(__attribute__((unused)) const char* name) {
- pthread_mutex_init(&mMutex, NULL);
+ pthread_mutex_init(&mMutex, nullptr);
}
inline Mutex::Mutex(int type, __attribute__((unused)) const char* name) {
if (type == SHARED) {
@@ -173,7 +173,7 @@
pthread_mutex_init(&mMutex, &attr);
pthread_mutexattr_destroy(&attr);
} else {
- pthread_mutex_init(&mMutex, NULL);
+ pthread_mutex_init(&mMutex, nullptr);
}
}
inline Mutex::~Mutex() {
diff --git a/libutils/include/utils/RWLock.h b/libutils/include/utils/RWLock.h
index 7d43e69..64e370e 100644
--- a/libutils/include/utils/RWLock.h
+++ b/libutils/include/utils/RWLock.h
@@ -48,7 +48,7 @@
RWLock();
explicit RWLock(const char* name);
- explicit RWLock(int type, const char* name = NULL);
+ explicit RWLock(int type, const char* name = nullptr);
~RWLock();
status_t readLock();
@@ -82,10 +82,10 @@
};
inline RWLock::RWLock() {
- pthread_rwlock_init(&mRWLock, NULL);
+ pthread_rwlock_init(&mRWLock, nullptr);
}
inline RWLock::RWLock(__attribute__((unused)) const char* name) {
- pthread_rwlock_init(&mRWLock, NULL);
+ pthread_rwlock_init(&mRWLock, nullptr);
}
inline RWLock::RWLock(int type, __attribute__((unused)) const char* name) {
if (type == SHARED) {
@@ -95,7 +95,7 @@
pthread_rwlock_init(&mRWLock, &attr);
pthread_rwlockattr_destroy(&attr);
} else {
- pthread_rwlock_init(&mRWLock, NULL);
+ pthread_rwlock_init(&mRWLock, nullptr);
}
}
inline RWLock::~RWLock() {
diff --git a/libutils/include/utils/RefBase.h b/libutils/include/utils/RefBase.h
index e817ee4..13b6a2b 100644
--- a/libutils/include/utils/RefBase.h
+++ b/libutils/include/utils/RefBase.h
@@ -354,7 +354,7 @@
public:
typedef typename RefBase::weakref_type weakref_type;
- inline wp() : m_ptr(0) { }
+ inline wp() : m_ptr(nullptr) { }
wp(T* other); // NOLINT(implicit)
wp(const wp<T>& other);
@@ -505,7 +505,7 @@
wp<T>& wp<T>::operator = (T* other)
{
weakref_type* newRefs =
- other ? other->createWeak(this) : 0;
+ other ? other->createWeak(this) : nullptr;
if (m_ptr) m_refs->decWeak(this);
m_ptr = other;
m_refs = newRefs;
@@ -528,7 +528,7 @@
wp<T>& wp<T>::operator = (const sp<T>& other)
{
weakref_type* newRefs =
- other != NULL ? other->createWeak(this) : 0;
+ other != nullptr ? other->createWeak(this) : nullptr;
T* otherPtr(other.m_ptr);
if (m_ptr) m_refs->decWeak(this);
m_ptr = otherPtr;
diff --git a/libutils/include/utils/Singleton.h b/libutils/include/utils/Singleton.h
index 2dd5a47..44d8ad7 100644
--- a/libutils/include/utils/Singleton.h
+++ b/libutils/include/utils/Singleton.h
@@ -51,7 +51,7 @@
static TYPE& getInstance() {
Mutex::Autolock _l(sLock);
TYPE* instance = sInstance;
- if (instance == 0) {
+ if (instance == nullptr) {
instance = new TYPE();
sInstance = instance;
}
@@ -60,7 +60,7 @@
static bool hasInstance() {
Mutex::Autolock _l(sLock);
- return sInstance != 0;
+ return sInstance != nullptr;
}
protected:
@@ -90,7 +90,7 @@
#define ANDROID_SINGLETON_STATIC_INSTANCE(TYPE) \
template<> ::android::Mutex \
(::android::Singleton< TYPE >::sLock)(::android::Mutex::PRIVATE); \
- template<> TYPE* ::android::Singleton< TYPE >::sInstance(0); /* NOLINT */ \
+ template<> TYPE* ::android::Singleton< TYPE >::sInstance(nullptr); /* NOLINT */ \
template class ::android::Singleton< TYPE >;
diff --git a/libutils/include/utils/String8.h b/libutils/include/utils/String8.h
index 94ac32f..c8f584e 100644
--- a/libutils/include/utils/String8.h
+++ b/libutils/include/utils/String8.h
@@ -187,7 +187,7 @@
* "/tmp" --> "tmp" (remain = "")
* "bar.c" --> "bar.c" (remain = "")
*/
- String8 walkPath(String8* outRemains = NULL) const;
+ String8 walkPath(String8* outRemains = nullptr) const;
/*
* Return the filename extension. This is the last '.' and any number
diff --git a/libutils/include/utils/StrongPointer.h b/libutils/include/utils/StrongPointer.h
index 9cd278f1..360fce5 100644
--- a/libutils/include/utils/StrongPointer.h
+++ b/libutils/include/utils/StrongPointer.h
@@ -52,7 +52,7 @@
template<typename T>
class sp {
public:
- inline sp() : m_ptr(0) { }
+ inline sp() : m_ptr(nullptr) { }
sp(T* other); // NOLINT(implicit)
sp(const sp<T>& other);
@@ -230,7 +230,7 @@
void sp<T>::clear() {
if (m_ptr) {
m_ptr->decStrong(this);
- m_ptr = 0;
+ m_ptr = nullptr;
}
}
diff --git a/libutils/include/utils/VectorImpl.h b/libutils/include/utils/VectorImpl.h
index 55d5d98..41b9f33 100644
--- a/libutils/include/utils/VectorImpl.h
+++ b/libutils/include/utils/VectorImpl.h
@@ -157,7 +157,7 @@
virtual int do_compare(const void* lhs, const void* rhs) const = 0;
private:
- ssize_t _indexOrderOf(const void* item, size_t* order = 0) const;
+ ssize_t _indexOrderOf(const void* item, size_t* order = nullptr) const;
// these are made private, because they can't be used on a SortedVector
// (they don't have an implementation either)
diff --git a/logd/CommandListener.cpp b/logd/CommandListener.cpp
index 06c0ab5..7a843d8 100644
--- a/logd/CommandListener.cpp
+++ b/logd/CommandListener.cpp
@@ -288,9 +288,9 @@
uid = AID_ROOT;
}
- const char* name = NULL;
- const char* format = NULL;
- const char* id = NULL;
+ const char* name = nullptr;
+ const char* format = nullptr;
+ const char* id = nullptr;
for (int i = 1; i < argc; ++i) {
static const char _name[] = "name=";
if (!strncmp(argv[i], _name, strlen(_name))) {
diff --git a/logd/FlushCommand.cpp b/logd/FlushCommand.cpp
old mode 100755
new mode 100644
index 70ecbe0..658e079
--- a/logd/FlushCommand.cpp
+++ b/logd/FlushCommand.cpp
@@ -36,7 +36,7 @@
// reference counts are used to ensure that individual
// LogTimeEntry lifetime is managed when not protected.
void FlushCommand::runSocketCommand(SocketClient* client) {
- LogTimeEntry* entry = NULL;
+ LogTimeEntry* entry = nullptr;
LastLogTimes& times = mReader.logbuf().mTimes;
LogTimeEntry::wrlock();
diff --git a/logd/FlushCommand.h b/logd/FlushCommand.h
old mode 100755
new mode 100644
diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp
old mode 100755
new mode 100644
index 27cd9a8..4ea7877
--- a/logd/LogAudit.cpp
+++ b/logd/LogAudit.cpp
@@ -171,13 +171,13 @@
}
int LogAudit::logPrint(const char* fmt, ...) {
- if (fmt == NULL) {
+ if (fmt == nullptr) {
return -EINVAL;
}
va_list args;
- char* str = NULL;
+ char* str = nullptr;
va_start(args, fmt);
int rc = vasprintf(&str, fmt, args);
va_end(args);
@@ -228,7 +228,7 @@
static char* last_str;
static bool last_info;
- if (last_str != NULL) {
+ if (last_str != nullptr) {
static const char avc[] = "): avc: ";
char* avcl = strstr(last_str, avc);
bool skip = false;
@@ -265,10 +265,10 @@
writev(fdDmesg, iov, arraysize(iov));
free(last_str);
- last_str = NULL;
+ last_str = nullptr;
}
}
- if (last_str == NULL) {
+ if (last_str == nullptr) {
count = 0;
last_str = strdup(str);
last_info = info;
@@ -357,7 +357,7 @@
static const char comm_str[] = " comm=\"";
const char* comm = strstr(str, comm_str);
const char* estr = str + strlen(str);
- const char* commfree = NULL;
+ const char* commfree = nullptr;
if (comm) {
estr = comm;
comm += sizeof(comm_str) - 1;
diff --git a/logd/LogBufferElement.cpp b/logd/LogBufferElement.cpp
index f20ac45..2d627b9 100644
--- a/logd/LogBufferElement.cpp
+++ b/logd/LogBufferElement.cpp
@@ -91,7 +91,7 @@
// caller must own and free character string
char* android::tidToName(pid_t tid) {
- char* retval = NULL;
+ char* retval = nullptr;
char buffer[256];
snprintf(buffer, sizeof(buffer), "/proc/%u/comm", tid);
int fd = open(buffer, O_RDONLY);
@@ -114,7 +114,7 @@
char* name = android::pidToName(tid);
if (!retval) {
retval = name;
- name = NULL;
+ name = nullptr;
}
// check if comm is truncated, see if cmdline has full representation
@@ -162,15 +162,15 @@
if (!strncmp(name + 1, commName + 1, len)) {
if (commName[len + 1] == '\0') {
free(const_cast<char*>(commName));
- commName = NULL;
+ commName = nullptr;
} else {
free(const_cast<char*>(name));
- name = NULL;
+ name = nullptr;
}
}
}
if (name) {
- char* buf = NULL;
+ char* buf = nullptr;
asprintf(&buf, "(%s)", name);
if (buf) {
free(const_cast<char*>(name));
@@ -178,7 +178,7 @@
}
}
if (commName) {
- char* buf = NULL;
+ char* buf = nullptr;
asprintf(&buf, " %s", commName);
if (buf) {
free(const_cast<char*>(commName));
@@ -187,7 +187,7 @@
}
// identical to below to calculate the buffer size required
const char* type = lastSame ? "identical" : "expire";
- size_t len = snprintf(NULL, 0, format_uid, mUid, name ? name : "",
+ size_t len = snprintf(nullptr, 0, format_uid, mUid, name ? name : "",
commName ? commName : "", type, getDropped(),
(getDropped() > 1) ? "s" : "");
@@ -247,7 +247,7 @@
iovec[0].iov_base = &entry;
iovec[0].iov_len = entry.hdr_size;
- char* buffer = NULL;
+ char* buffer = nullptr;
if (mDropped) {
entry.len = populateDroppedMessage(buffer, parent, lastSame);
diff --git a/logd/LogCommand.cpp b/logd/LogCommand.cpp
index 6d7c0a5..8bff9da 100644
--- a/logd/LogCommand.cpp
+++ b/logd/LogCommand.cpp
@@ -44,9 +44,9 @@
char* ptr;
static const char ws[] = " \n";
- for (buf = strtok_r(buf, ws, &ptr); buf; buf = strtok_r(NULL, ws, &ptr)) {
+ for (buf = strtok_r(buf, ws, &ptr); buf; buf = strtok_r(nullptr, ws, &ptr)) {
errno = 0;
- gid_t Gid = strtol(buf, NULL, 10);
+ gid_t Gid = strtol(buf, nullptr, 10);
if (errno != 0) {
return false;
}
@@ -98,7 +98,7 @@
continue;
}
- char* line = NULL;
+ char* line = nullptr;
size_t len = 0;
while (getline(&line, &len, file) > 0) {
static const char groups_string[] = "Groups:\t";
diff --git a/logd/LogKlog.cpp b/logd/LogKlog.cpp
old mode 100755
new mode 100644
diff --git a/logd/LogListener.cpp b/logd/LogListener.cpp
old mode 100755
new mode 100644
index fc51dcf..e568ddc
--- a/logd/LogListener.cpp
+++ b/logd/LogListener.cpp
@@ -50,7 +50,7 @@
alignas(4) char control[CMSG_SPACE(sizeof(struct ucred))];
struct msghdr hdr = {
- NULL, 0, &iov, 1, control, sizeof(control), 0,
+ nullptr, 0, &iov, 1, control, sizeof(control), 0,
};
int socket = cli->getSocket();
@@ -66,10 +66,10 @@
buffer[n] = 0;
- struct ucred* cred = NULL;
+ struct ucred* cred = nullptr;
struct cmsghdr* cmsg = CMSG_FIRSTHDR(&hdr);
- while (cmsg != NULL) {
+ while (cmsg != nullptr) {
if (cmsg->cmsg_level == SOL_SOCKET &&
cmsg->cmsg_type == SCM_CREDENTIALS) {
cred = (struct ucred*)CMSG_DATA(cmsg);
@@ -79,7 +79,7 @@
}
struct ucred fake_cred;
- if (cred == NULL) {
+ if (cred == nullptr) {
cred = &fake_cred;
cred->pid = 0;
cred->uid = DEFAULT_OVERFLOWUID;
diff --git a/logd/LogReader.cpp b/logd/LogReader.cpp
old mode 100755
new mode 100644
diff --git a/logd/LogReader.h b/logd/LogReader.h
old mode 100755
new mode 100644
diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp
index af59ddc..cefacf7 100644
--- a/logd/LogStatistics.cpp
+++ b/logd/LogStatistics.cpp
@@ -56,7 +56,7 @@
// caller must own and free character string
char* pidToName(pid_t pid) {
- char* retval = NULL;
+ char* retval = nullptr;
if (pid == 0) { // special case from auditd/klogd for kernel
retval = strdup("logd");
} else {
@@ -286,7 +286,7 @@
name = strdup(nameTmp);
} else if (fastcmp<strcmp>(name, nameTmp)) {
free(const_cast<char*>(name));
- name = NULL;
+ name = nullptr;
break;
}
}
@@ -872,7 +872,7 @@
pidTable_t& writablePidTable = const_cast<pidTable_t&>(pidTable);
const char* name = writablePidTable.add(pid)->second.getName();
if (!name) {
- return NULL;
+ return nullptr;
}
return strdup(name);
}
diff --git a/logd/LogTags.cpp b/logd/LogTags.cpp
index ff7e762..1ab9dd1 100644
--- a/logd/LogTags.cpp
+++ b/logd/LogTags.cpp
@@ -91,7 +91,7 @@
fd = TEMP_FAILURE_RETRY(open(
filename, O_WRONLY | O_TRUNC | O_CLOEXEC | O_NOFOLLOW | O_BINARY));
if (fd >= 0) {
- time_t now = time(NULL);
+ time_t now = time(nullptr);
struct tm tm;
localtime_r(&now, &tm);
char timebuf[20];
@@ -208,7 +208,7 @@
} else if (lineStart) {
if (*cp == '#') {
/* comment; just scan to end */
- lineStart = NULL;
+ lineStart = nullptr;
} else if (isdigit(*cp)) {
unsigned long Tag = strtoul(cp, &cp, 10);
if (warn && (Tag > emptyTag)) {
@@ -235,7 +235,7 @@
if (hasAlpha &&
((cp >= endp) || (*cp == '#') || isspace(*cp))) {
if (Tag > emptyTag) {
- if (*cp != '\n') lineStart = NULL;
+ if (*cp != '\n') lineStart = nullptr;
continue;
}
while ((cp < endp) && (*cp != '\n') && isspace(*cp))
@@ -245,14 +245,14 @@
while ((cp < endp) && (*cp != '\n')) {
if (*cp == '#') {
uid = sniffUid(cp, endp);
- lineStart = NULL;
+ lineStart = nullptr;
break;
}
++cp;
}
while ((cp > format) && isspace(cp[-1])) {
--cp;
- lineStart = NULL;
+ lineStart = nullptr;
}
std::string Format(format, cp - format);
@@ -263,7 +263,7 @@
android::prdebug("tag name invalid %.*s",
(int)(cp - name + 1), name);
}
- lineStart = NULL;
+ lineStart = nullptr;
}
} else if (!isspace(*cp)) {
break;
@@ -364,7 +364,7 @@
android::RWLock::AutoRLock readLock(const_cast<android::RWLock&>(rwlock));
it = tag2name.find(tag);
- if ((it == tag2name.end()) || (it->second.length() == 0)) return NULL;
+ if ((it == tag2name.end()) || (it->second.length() == 0)) return nullptr;
return it->second.c_str();
}
@@ -383,7 +383,7 @@
const char* android::tagToName(uint32_t tag) {
LogTags* me = logtags;
- if (!me) return NULL;
+ if (!me) return nullptr;
me->WritePmsgEventLogTags(tag);
return me->tagToName(tag);
}
@@ -412,7 +412,7 @@
android::RWLock::AutoRLock readLock(const_cast<android::RWLock&>(rwlock));
iform = tag2format.find(tag);
- if (iform == tag2format.end()) return NULL;
+ if (iform == tag2format.end()) return nullptr;
return iform->second.c_str();
}
@@ -441,7 +441,7 @@
bool& unique) {
key2tag_const_iterator ik;
- bool write = format != NULL;
+ bool write = format != nullptr;
unique = write;
if (!write) {
@@ -679,7 +679,7 @@
// are in readonly mode.
uint32_t LogTags::nameToTag(uid_t uid, const char* name, const char* format) {
std::string Name = std::string(name);
- bool write = format != NULL;
+ bool write = format != nullptr;
bool updateUid = uid != AID_ROOT;
bool updateFormat = format && *format;
bool unique;
@@ -848,7 +848,7 @@
if (!list) {
// switch to read entry only if format == "*"
- if (format && (format[0] == '*') && !format[1]) format = NULL;
+ if (format && (format[0] == '*') && !format[1]) format = nullptr;
// WAI: for null format, only works for a single entry, we can have
// multiple entries, one for each format, so we find first entry
diff --git a/logd/LogTags.h b/logd/LogTags.h
index 203318d..e4d165a 100644
--- a/logd/LogTags.h
+++ b/logd/LogTags.h
@@ -87,14 +87,14 @@
bool RebuildFileEventLogTags(const char* filename, bool warn = true);
void AddEventLogTags(uint32_t tag, uid_t uid, const std::string& Name,
- const std::string& Format, const char* source = NULL,
+ const std::string& Format, const char* source = nullptr,
bool warn = false);
void WriteDynamicEventLogTags(uint32_t tag, uid_t uid);
void WriteDebugEventLogTags(uint32_t tag, uid_t uid);
// push tag details to persistent storage
void WritePersistEventLogTags(uint32_t tag, uid_t uid = AID_ROOT,
- const char* source = NULL);
+ const char* source = nullptr);
static const uint32_t emptyTag = uint32_t(-1);
diff --git a/logd/LogTimes.cpp b/logd/LogTimes.cpp
old mode 100755
new mode 100644
diff --git a/logd/LogTimes.h b/logd/LogTimes.h
old mode 100755
new mode 100644
diff --git a/logd/LogWhiteBlackList.cpp b/logd/LogWhiteBlackList.cpp
index 4b8b080..9d762dc 100644
--- a/logd/LogWhiteBlackList.cpp
+++ b/logd/LogWhiteBlackList.cpp
@@ -51,7 +51,7 @@
}
PruneList::PruneList() {
- init(NULL);
+ init(nullptr);
}
PruneList::~PruneList() {
@@ -79,7 +79,7 @@
// default here means take ro.logd.filter, persist.logd.filter then
// internal default in that order.
if (str && !strcmp(str, _default)) {
- str = NULL;
+ str = nullptr;
}
static const char _disable[] = "disable";
if (str && !strcmp(str, _disable)) {
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