Merge "Make native metrics logger write to statsd socket"
diff --git a/adb/test_adb.py b/adb/test_adb.py
index 7e73818..430fc3d 100755
--- a/adb/test_adb.py
+++ b/adb/test_adb.py
@@ -31,6 +31,7 @@
import threading
import time
import unittest
+import warnings
@contextlib.contextmanager
@@ -229,6 +230,10 @@
stderr=subprocess.STDOUT)
try:
+ # We get warnings for unclosed files for the subprocess's pipes,
+ # and it's somewhat cumbersome to close them, so just ignore this.
+ warnings.simplefilter("ignore", ResourceWarning)
+
# Run the adb client and have it start the adb server.
proc = subprocess.Popen(["adb", "-P", str(port), "start-server"],
stdin=subprocess.PIPE,
diff --git a/fastboot/device/fastboot_device.cpp b/fastboot/device/fastboot_device.cpp
index 6cb4892..7be721a 100644
--- a/fastboot/device/fastboot_device.cpp
+++ b/fastboot/device/fastboot_device.cpp
@@ -137,7 +137,7 @@
std::string cmd_name;
if (android::base::StartsWith(command, "oem ")) {
args = {command};
- cmd_name = "oem";
+ cmd_name = FB_CMD_OEM;
} else {
args = android::base::Split(command, ":");
cmd_name = args[0];
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index e27a897..6b6e659 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -64,6 +64,7 @@
#include <ziparchive/zip_archive.h>
#include "bootimg_utils.h"
+#include "constants.h"
#include "diagnose_usb.h"
#include "fastboot_driver.h"
#include "fs.h"
@@ -1697,10 +1698,10 @@
while (!args.empty()) {
std::string command = next_arg(&args);
- if (command == "getvar") {
+ if (command == FB_CMD_GETVAR) {
std::string variable = next_arg(&args);
DisplayVarOrError(variable, variable);
- } else if (command == "erase") {
+ } else if (command == FB_CMD_ERASE) {
std::string partition = next_arg(&args);
auto erase = [&](const std::string& partition) {
std::string partition_type;
@@ -1742,7 +1743,7 @@
if (data.size() != 256) die("signature must be 256 bytes (got %zu)", data.size());
fb->Download("signature", data);
fb->RawCommand("signature", "installing signature");
- } else if (command == "reboot") {
+ } else if (command == FB_CMD_REBOOT) {
wants_reboot = true;
if (args.size() == 1) {
@@ -1762,15 +1763,15 @@
}
if (!args.empty()) syntax_error("junk after reboot command");
- } else if (command == "reboot-bootloader") {
+ } else if (command == FB_CMD_REBOOT_BOOTLOADER) {
wants_reboot_bootloader = true;
- } else if (command == "reboot-recovery") {
+ } else if (command == FB_CMD_REBOOT_RECOVERY) {
wants_reboot_recovery = true;
- } else if (command == "reboot-fastboot") {
+ } else if (command == FB_CMD_REBOOT_FASTBOOT) {
wants_reboot_fastboot = true;
- } else if (command == "continue") {
+ } else if (command == FB_CMD_CONTINUE) {
fb->Continue();
- } else if (command == "boot") {
+ } else if (command == FB_CMD_BOOT) {
std::string kernel = next_arg(&args);
std::string ramdisk;
if (!args.empty()) ramdisk = next_arg(&args);
@@ -1780,7 +1781,7 @@
auto data = LoadBootableImage(kernel, ramdisk, second_stage);
fb->Download("boot.img", data);
fb->Boot();
- } else if (command == "flash") {
+ } else if (command == FB_CMD_FLASH) {
std::string pname = next_arg(&args);
std::string fname;
@@ -1827,7 +1828,7 @@
}
do_update(filename.c_str(), slot_override, skip_secondary || slot_all);
wants_reboot = true;
- } else if (command == "set_active") {
+ } else if (command == FB_CMD_SET_ACTIVE) {
std::string slot = verify_slot(next_arg(&args), false);
fb->SetActive(slot);
} else if (command == "stage") {
@@ -1841,8 +1842,8 @@
} else if (command == "get_staged") {
std::string filename = next_arg(&args);
fb->Upload(filename);
- } else if (command == "oem") {
- do_oem_command("oem", &args);
+ } else if (command == FB_CMD_OEM) {
+ do_oem_command(FB_CMD_OEM, &args);
} else if (command == "flashing") {
if (args.empty()) {
syntax_error("missing 'flashing' command");
@@ -1854,14 +1855,14 @@
} else {
syntax_error("unknown 'flashing' command %s", args[0].c_str());
}
- } else if (command == "create-logical-partition") {
+ } else if (command == FB_CMD_CREATE_PARTITION) {
std::string partition = next_arg(&args);
std::string size = next_arg(&args);
fb->CreatePartition(partition, size);
- } else if (command == "delete-logical-partition") {
+ } else if (command == FB_CMD_DELETE_PARTITION) {
std::string partition = next_arg(&args);
fb->DeletePartition(partition);
- } else if (command == "resize-logical-partition") {
+ } else if (command == FB_CMD_RESIZE_PARTITION) {
std::string partition = next_arg(&args);
std::string size = next_arg(&args);
fb->ResizePartition(partition, size);
diff --git a/fastboot/fastboot_driver.h b/fastboot/fastboot_driver.h
index 62bbe52..af02637 100644
--- a/fastboot/fastboot_driver.h
+++ b/fastboot/fastboot_driver.h
@@ -37,15 +37,14 @@
#include <bootimg.h>
#include <inttypes.h>
#include <sparse/sparse.h>
+
+#include "constants.h"
#include "transport.h"
class Transport;
namespace fastboot {
-static constexpr int FB_COMMAND_SZ = 64;
-static constexpr int FB_RESPONSE_SZ = 64;
-
enum RetCode : int {
SUCCESS = 0,
BAD_ARG,
diff --git a/fastboot/fuzzy_fastboot/main.cpp b/fastboot/fuzzy_fastboot/main.cpp
index c02ab1c..479a06a 100644
--- a/fastboot/fuzzy_fastboot/main.cpp
+++ b/fastboot/fuzzy_fastboot/main.cpp
@@ -747,7 +747,7 @@
}
TEST_F(Fuzz, BadCommandTooLarge) {
- std::string s = RandomString(fastboot::FB_COMMAND_SZ + 1, rand_legal);
+ std::string s = RandomString(FB_COMMAND_SZ + 1, rand_legal);
EXPECT_EQ(fb->RawCommand(s), DEVICE_FAIL)
<< "Device did not respond with failure after sending length " << s.size()
<< " string of random ASCII chars";
diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp
index 4934f5a..767b73a 100644
--- a/fs_mgr/fs_mgr_overlayfs.cpp
+++ b/fs_mgr/fs_mgr_overlayfs.cpp
@@ -163,7 +163,7 @@
auto candidate = fs_mgr_get_overlayfs_candidate(mount_point);
if (candidate.empty()) return "";
- return "override_creds=off,"s + kLowerdirOption + mount_point + "," + kUpperdirOption +
+ return "override_creds=off," + kLowerdirOption + mount_point + "," + kUpperdirOption +
candidate + kUpperName + ",workdir=" + candidate + kWorkName;
}
@@ -261,7 +261,7 @@
return true;
}
-bool fs_mgr_rm_all(const std::string& path, bool* change = nullptr) {
+bool fs_mgr_rm_all(const std::string& path, bool* change = nullptr, int level = 0) {
auto save_errno = errno;
std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(path.c_str()), closedir);
if (!dir) {
@@ -269,7 +269,11 @@
errno = save_errno;
return true;
}
- PERROR << "opendir " << path;
+ PERROR << "opendir " << path << " depth=" << level;
+ if ((errno == EPERM) && (level != 0)) {
+ errno = save_errno;
+ return true;
+ }
return false;
}
dirent* entry;
@@ -279,23 +283,25 @@
auto file = path + "/" + entry->d_name;
if (entry->d_type == DT_UNKNOWN) {
struct stat st;
+ save_errno = errno;
if (!lstat(file.c_str(), &st) && (st.st_mode & S_IFDIR)) entry->d_type = DT_DIR;
+ errno = save_errno;
}
if (entry->d_type == DT_DIR) {
- ret &= fs_mgr_rm_all(file, change);
+ ret &= fs_mgr_rm_all(file, change, level + 1);
if (!rmdir(file.c_str())) {
if (change) *change = true;
} else {
- ret = false;
- PERROR << "rmdir " << file;
+ if (errno != ENOENT) ret = false;
+ PERROR << "rmdir " << file << " depth=" << level;
}
continue;
}
if (!unlink(file.c_str())) {
if (change) *change = true;
} else {
- ret = false;
- PERROR << "rm " << file;
+ if (errno != ENOENT) ret = false;
+ PERROR << "rm " << file << " depth=" << level;
}
}
return ret;
@@ -443,7 +449,7 @@
if (!fs_mgr_access(top)) return false;
auto cleanup_all = mount_point.empty();
- const auto oldpath = top + (cleanup_all ? "" : ("/"s + mount_point));
+ const auto oldpath = top + (cleanup_all ? "" : ("/" + mount_point));
const auto newpath = oldpath + ".teardown";
auto ret = fs_mgr_rm_all(newpath);
auto save_errno = errno;
@@ -583,8 +589,18 @@
fsrec->fs_type = strdup(mnt_type.c_str());
fsrec->flags = MS_RELATIME;
fsrec->fs_options = strdup("");
- auto mounted = fs_mgr_do_mount_one(fsrec) == 0;
auto save_errno = errno;
+ auto mounted = fs_mgr_do_mount_one(fsrec) == 0;
+ if (!mounted) {
+ free(fsrec->fs_type);
+ if (mnt_type == "f2fs") {
+ fsrec->fs_type = strdup("ext4");
+ } else {
+ fsrec->fs_type = strdup("f2fs");
+ }
+ mounted = fs_mgr_do_mount_one(fsrec) == 0;
+ if (!mounted) save_errno = errno;
+ }
setfscreatecon(nullptr);
if (!mounted) rmdir(kScratchMountPoint.c_str());
errno = save_errno;
@@ -594,6 +610,7 @@
const std::string kMkF2fs("/system/bin/make_f2fs");
const std::string kMkExt4("/system/bin/mke2fs");
+// Only a suggestion for _first_ try during mounting
std::string fs_mgr_overlayfs_scratch_mount_type() {
if (!access(kMkF2fs.c_str(), X_OK)) return "f2fs";
if (!access(kMkExt4.c_str(), X_OK)) return "ext4";
@@ -671,7 +688,7 @@
auto ret = system((mnt_type == "f2fs")
? ((kMkF2fs + " -d1 " + scratch_device).c_str())
- : ((kMkExt4 + " -b 4096 -t ext4 -m 0 -M "s + kScratchMountPoint +
+ : ((kMkExt4 + " -b 4096 -t ext4 -m 0 -M " + kScratchMountPoint +
" -O has_journal " + scratch_device)
.c_str()));
if (ret) {
diff --git a/fs_mgr/liblp/builder.cpp b/fs_mgr/liblp/builder.cpp
index 743a3fe..03fd5f9 100644
--- a/fs_mgr/liblp/builder.cpp
+++ b/fs_mgr/liblp/builder.cpp
@@ -268,39 +268,19 @@
}
// Compute the first free sector, factoring in alignment.
- uint64_t free_area =
+ uint64_t free_area_start =
AlignTo(total_reserved, device_info.alignment, device_info.alignment_offset);
- uint64_t first_sector = free_area / LP_SECTOR_SIZE;
+ uint64_t first_sector = free_area_start / LP_SECTOR_SIZE;
- // Compute the last free sector, which is inclusive. We subtract 1 to make
- // sure that logical partitions won't overlap with the same sector as the
- // backup metadata, which could happen if the block device was not aligned
- // to LP_SECTOR_SIZE.
- uint64_t last_sector = (device_info.size / LP_SECTOR_SIZE) - 1;
-
- // If this check fails, it means either (1) we did not have free space to
- // allocate a single sector, or (2) we did, but the alignment was high
- // enough to bump the first sector out of range. Either way, we cannot
- // continue.
- if (first_sector > last_sector) {
- LERROR << "Not enough space to allocate any partition tables.";
+ // There must be one logical block of free space remaining (enough for one partition).
+ uint64_t minimum_disk_size = (first_sector * LP_SECTOR_SIZE) + device_info.logical_block_size;
+ if (device_info.size < minimum_disk_size) {
+ LERROR << "Device must be at least " << minimum_disk_size << " bytes, only has "
+ << device_info.size;
return false;
}
- // Finally, the size of the allocatable space must be a multiple of the
- // logical block size. If we have no more free space after this
- // computation, then we abort. Note that the last sector is inclusive,
- // so we have to account for that.
- uint64_t num_free_sectors = last_sector - first_sector + 1;
- uint64_t sectors_per_block = device_info.logical_block_size / LP_SECTOR_SIZE;
- if (num_free_sectors < sectors_per_block) {
- LERROR << "Not enough space to allocate any partition tables.";
- return false;
- }
- last_sector = first_sector + (num_free_sectors / sectors_per_block) * sectors_per_block - 1;
-
geometry_.first_logical_sector = first_sector;
- geometry_.last_logical_sector = last_sector;
geometry_.metadata_max_size = metadata_max_size;
geometry_.metadata_slot_count = metadata_slot_count;
geometry_.alignment = device_info.alignment;
@@ -452,8 +432,10 @@
uint64_t last_free_extent_start =
extents.empty() ? geometry_.first_logical_sector : extents.back().end;
last_free_extent_start = AlignSector(last_free_extent_start);
- if (last_free_extent_start <= geometry_.last_logical_sector) {
- free_regions.emplace_back(last_free_extent_start, geometry_.last_logical_sector + 1);
+
+ uint64_t last_sector = geometry_.block_device_size / LP_SECTOR_SIZE;
+ if (last_free_extent_start < last_sector) {
+ free_regions.emplace_back(last_free_extent_start, last_sector);
}
const uint64_t sectors_per_block = geometry_.logical_block_size / LP_SECTOR_SIZE;
@@ -523,6 +505,7 @@
strncpy(out.name, group->name().c_str(), sizeof(out.name));
out.maximum_size = group->maximum_size();
+ group_indices[group->name()] = metadata->groups.size();
metadata->groups.push_back(out);
}
@@ -546,6 +529,14 @@
part.num_extents = static_cast<uint32_t>(partition->extents().size());
part.attributes = partition->attributes();
+ auto iter = group_indices.find(partition->group_name());
+ if (iter == group_indices.end()) {
+ LERROR << "Partition " << partition->name() << " is a member of unknown group "
+ << partition->group_name();
+ return nullptr;
+ }
+ part.group_index = iter->second;
+
for (const auto& extent : partition->extents()) {
extent->AddTo(metadata.get());
}
@@ -559,7 +550,7 @@
}
uint64_t MetadataBuilder::AllocatableSpace() const {
- return (geometry_.last_logical_sector - geometry_.first_logical_sector + 1) * LP_SECTOR_SIZE;
+ return geometry_.block_device_size - (geometry_.first_logical_sector * LP_SECTOR_SIZE);
}
uint64_t MetadataBuilder::UsedSpace() const {
diff --git a/fs_mgr/liblp/builder_test.cpp b/fs_mgr/liblp/builder_test.cpp
index ffa7d3b..eb65f89 100644
--- a/fs_mgr/liblp/builder_test.cpp
+++ b/fs_mgr/liblp/builder_test.cpp
@@ -127,7 +127,6 @@
unique_ptr<LpMetadata> exported = builder->Export();
ASSERT_NE(exported, nullptr);
EXPECT_EQ(exported->geometry.first_logical_sector, 1536);
- EXPECT_EQ(exported->geometry.last_logical_sector, 2047);
// Test a large alignment offset thrown in.
device_info.alignment_offset = 753664;
@@ -136,7 +135,6 @@
exported = builder->Export();
ASSERT_NE(exported, nullptr);
EXPECT_EQ(exported->geometry.first_logical_sector, 1472);
- EXPECT_EQ(exported->geometry.last_logical_sector, 2047);
// Alignment offset without alignment doesn't mean anything.
device_info.alignment = 0;
@@ -151,7 +149,6 @@
exported = builder->Export();
ASSERT_NE(exported, nullptr);
EXPECT_EQ(exported->geometry.first_logical_sector, 150);
- EXPECT_EQ(exported->geometry.last_logical_sector, 2045);
// Test a small alignment with no alignment offset.
device_info.alignment = 11 * 1024;
@@ -160,7 +157,6 @@
exported = builder->Export();
ASSERT_NE(exported, nullptr);
EXPECT_EQ(exported->geometry.first_logical_sector, 160);
- EXPECT_EQ(exported->geometry.last_logical_sector, 2047);
}
TEST(liblp, InternalPartitionAlignment) {
@@ -298,7 +294,6 @@
EXPECT_EQ(geometry.metadata_max_size, 1024);
EXPECT_EQ(geometry.metadata_slot_count, 2);
EXPECT_EQ(geometry.first_logical_sector, 24);
- EXPECT_EQ(geometry.last_logical_sector, 2047);
static const size_t kMetadataSpace =
((kMetadataSize * kMetadataSlots) + LP_METADATA_GEOMETRY_SIZE) * 2;
diff --git a/fs_mgr/liblp/include/liblp/metadata_format.h b/fs_mgr/liblp/include/liblp/metadata_format.h
index a4ff1a7..711ff95 100644
--- a/fs_mgr/liblp/include/liblp/metadata_format.h
+++ b/fs_mgr/liblp/include/liblp/metadata_format.h
@@ -38,7 +38,7 @@
#define LP_METADATA_HEADER_MAGIC 0x414C5030
/* Current metadata version. */
-#define LP_METADATA_MAJOR_VERSION 4
+#define LP_METADATA_MAJOR_VERSION 5
#define LP_METADATA_MINOR_VERSION 0
/* Attributes for the LpMetadataPartition::attributes field.
@@ -104,12 +104,6 @@
*/
uint64_t first_logical_sector;
- /* 56: Last usable sector, inclusive, for allocating logical partitions.
- * At the end of this sector will follow backup metadata slots and the
- * backup geometry block at the very end.
- */
- uint64_t last_logical_sector;
-
/* 64: Alignment for defining partitions or partition extents. For example,
* an alignment of 1MiB will require that all partitions have a size evenly
* divisible by 1MiB, and that the smallest unit the partition can grow by
diff --git a/fs_mgr/liblp/io_test.cpp b/fs_mgr/liblp/io_test.cpp
index 220d651..92696f5 100644
--- a/fs_mgr/liblp/io_test.cpp
+++ b/fs_mgr/liblp/io_test.cpp
@@ -161,7 +161,6 @@
EXPECT_EQ(exported->geometry.metadata_max_size, imported->geometry.metadata_max_size);
EXPECT_EQ(exported->geometry.metadata_slot_count, imported->geometry.metadata_slot_count);
EXPECT_EQ(exported->geometry.first_logical_sector, imported->geometry.first_logical_sector);
- EXPECT_EQ(exported->geometry.last_logical_sector, imported->geometry.last_logical_sector);
EXPECT_EQ(exported->header.major_version, imported->header.major_version);
EXPECT_EQ(exported->header.minor_version, imported->header.minor_version);
EXPECT_EQ(exported->header.header_size, imported->header.header_size);
@@ -207,13 +206,14 @@
ASSERT_EQ(imported->partitions.size(), 1);
EXPECT_EQ(GetPartitionName(imported->partitions[0]), "vendor");
+ uint64_t last_sector = imported->geometry.block_device_size / LP_SECTOR_SIZE;
+
// Verify that we didn't overwrite anything in the logical paritition area.
// We expect the disk to be filled with 0xcc on creation so we can read
// this back and compare it.
char expected[LP_SECTOR_SIZE];
memset(expected, 0xcc, sizeof(expected));
- for (uint64_t i = imported->geometry.first_logical_sector;
- i <= imported->geometry.last_logical_sector; i++) {
+ for (uint64_t i = imported->geometry.first_logical_sector; i < last_sector; i++) {
char buffer[LP_SECTOR_SIZE];
ASSERT_GE(lseek(fd, i * LP_SECTOR_SIZE, SEEK_SET), 0);
ASSERT_TRUE(android::base::ReadFully(fd, buffer, sizeof(buffer)));
@@ -261,8 +261,6 @@
imported = ReadMetadata(fd, 0);
ASSERT_NE(imported, nullptr);
- imported->geometry.last_logical_sector--;
- ASSERT_FALSE(UpdatePartitionTable(fd, *imported.get(), 1));
}
// Test that changing one bit of metadata is enough to break the checksum.
@@ -370,9 +368,6 @@
ASSERT_GE(lseek(fd, exported->geometry.first_logical_sector * LP_SECTOR_SIZE, SEEK_SET), 0);
ASSERT_TRUE(android::base::ReadFully(fd, buffer, sizeof(buffer)));
EXPECT_EQ(memcmp(expected, buffer, LP_SECTOR_SIZE), 0);
- ASSERT_GE(lseek(fd, exported->geometry.last_logical_sector * LP_SECTOR_SIZE, SEEK_SET), 0);
- ASSERT_TRUE(android::base::ReadFully(fd, buffer, sizeof(buffer)));
- EXPECT_EQ(memcmp(expected, buffer, LP_SECTOR_SIZE), 0);
}
// Test that we can read and write image files.
diff --git a/fs_mgr/liblp/utility_test.cpp b/fs_mgr/liblp/utility_test.cpp
index ff50e09..46ed2e6 100644
--- a/fs_mgr/liblp/utility_test.cpp
+++ b/fs_mgr/liblp/utility_test.cpp
@@ -37,7 +37,6 @@
16384,
4,
10000,
- 80000,
0,
0,
1024 * 1024,
diff --git a/fs_mgr/liblp/writer.cpp b/fs_mgr/liblp/writer.cpp
index 0c0cc49..5cf1a2c 100644
--- a/fs_mgr/liblp/writer.cpp
+++ b/fs_mgr/liblp/writer.cpp
@@ -43,8 +43,9 @@
static bool CompareGeometry(const LpMetadataGeometry& g1, const LpMetadataGeometry& g2) {
return g1.metadata_max_size == g2.metadata_max_size &&
g1.metadata_slot_count == g2.metadata_slot_count &&
- g1.first_logical_sector == g2.first_logical_sector &&
- g1.last_logical_sector == g2.last_logical_sector;
+ g1.block_device_size == g2.block_device_size &&
+ g1.logical_block_size == g2.logical_block_size &&
+ g1.first_logical_sector == g2.first_logical_sector;
}
std::string SerializeMetadata(const LpMetadata& input) {
@@ -86,15 +87,11 @@
return false;
}
- *blob = SerializeMetadata(metadata);
-
const LpMetadataHeader& header = metadata.header;
const LpMetadataGeometry& geometry = metadata.geometry;
- // Validate the usable sector range.
- if (geometry.first_logical_sector > geometry.last_logical_sector) {
- LERROR << "Logical partition metadata has invalid sector range.";
- return false;
- }
+
+ *blob = SerializeMetadata(metadata);
+
// Make sure we're writing within the space reserved.
if (blob->size() > geometry.metadata_max_size) {
LERROR << "Logical partition metadata is too large. " << blob->size() << " > "
@@ -128,11 +125,12 @@
}
// Make sure all linear extents have a valid range.
+ uint64_t last_sector = geometry.block_device_size / LP_SECTOR_SIZE;
for (const auto& extent : metadata.extents) {
if (extent.target_type == LP_TARGET_TYPE_LINEAR) {
uint64_t physical_sector = extent.target_data;
if (physical_sector < geometry.first_logical_sector ||
- physical_sector + extent.num_sectors > geometry.last_logical_sector) {
+ physical_sector + extent.num_sectors > last_sector) {
LERROR << "Extent table entry is out of bounds.";
return false;
}
@@ -167,7 +165,7 @@
}
if (abs_offset >= int64_t(geometry.first_logical_sector) * LP_SECTOR_SIZE) {
PERROR << __PRETTY_FUNCTION__ << "backup offset " << abs_offset
- << " is within logical partition bounds, sector " << geometry.last_logical_sector;
+ << " is within logical partition bounds, sector " << geometry.first_logical_sector;
return false;
}
if (!writer(fd, blob)) {
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index 970e05c..14f82c7 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -58,6 +58,7 @@
"Elf.cpp",
"ElfInterface.cpp",
"ElfInterfaceArm.cpp",
+ "Global.cpp",
"JitDebug.cpp",
"Log.cpp",
"MapInfo.cpp",
diff --git a/libunwindstack/DexFiles.cpp b/libunwindstack/DexFiles.cpp
index 17e2526..ac55fee 100644
--- a/libunwindstack/DexFiles.cpp
+++ b/libunwindstack/DexFiles.cpp
@@ -43,10 +43,10 @@
uint64_t dex_file;
};
-DexFiles::DexFiles(std::shared_ptr<Memory>& memory) : memory_(memory) {}
+DexFiles::DexFiles(std::shared_ptr<Memory>& memory) : Global(memory) {}
DexFiles::DexFiles(std::shared_ptr<Memory>& memory, std::vector<std::string>& search_libs)
- : memory_(memory), search_libs_(search_libs) {}
+ : Global(memory, search_libs) {}
DexFiles::~DexFiles() {
for (auto& entry : files_) {
@@ -117,6 +117,11 @@
return true;
}
+bool DexFiles::ReadVariableData(uint64_t ptr_offset) {
+ entry_addr_ = (this->*read_entry_ptr_func_)(ptr_offset);
+ return entry_addr_ != 0;
+}
+
void DexFiles::Init(Maps* maps) {
if (initialized_) {
return;
@@ -124,36 +129,7 @@
initialized_ = true;
entry_addr_ = 0;
- const std::string dex_debug_name("__dex_debug_descriptor");
- for (MapInfo* info : *maps) {
- if (!(info->flags & PROT_READ) || info->offset != 0) {
- continue;
- }
-
- if (!search_libs_.empty()) {
- bool found = false;
- const char* lib = basename(info->name.c_str());
- for (const std::string& name : search_libs_) {
- if (name == lib) {
- found = true;
- break;
- }
- }
- if (!found) {
- continue;
- }
- }
-
- Elf* elf = info->GetElf(memory_, true);
- uint64_t ptr;
- // Find first non-empty list (libart might be loaded multiple times).
- if (elf->GetGlobalVariable(dex_debug_name, &ptr) && ptr != 0) {
- entry_addr_ = (this->*read_entry_ptr_func_)(ptr + info->start);
- if (entry_addr_ != 0) {
- break;
- }
- }
- }
+ FindAndReadVariable(maps, "__dex_debug_descriptor");
}
DexFile* DexFiles::GetDexFile(uint64_t dex_file_offset, MapInfo* info) {
diff --git a/libunwindstack/Global.cpp b/libunwindstack/Global.cpp
new file mode 100644
index 0000000..b449c7e
--- /dev/null
+++ b/libunwindstack/Global.cpp
@@ -0,0 +1,96 @@
+/*
+ * 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 <stdint.h>
+#include <sys/mman.h>
+
+#include <string>
+#include <vector>
+
+#include <unwindstack/Global.h>
+#include <unwindstack/MapInfo.h>
+#include <unwindstack/Maps.h>
+#include <unwindstack/Memory.h>
+
+namespace unwindstack {
+
+Global::Global(std::shared_ptr<Memory>& memory) : memory_(memory) {}
+Global::Global(std::shared_ptr<Memory>& memory, std::vector<std::string>& search_libs)
+ : memory_(memory), search_libs_(search_libs) {}
+
+uint64_t Global::GetVariableOffset(MapInfo* info, const std::string& variable) {
+ if (!search_libs_.empty()) {
+ bool found = false;
+ const char* lib = basename(info->name.c_str());
+ for (const std::string& name : search_libs_) {
+ if (name == lib) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ return 0;
+ }
+ }
+
+ Elf* elf = info->GetElf(memory_, true);
+ uint64_t ptr;
+ // Find first non-empty list (libraries might be loaded multiple times).
+ if (elf->GetGlobalVariable(variable, &ptr) && ptr != 0) {
+ return ptr + info->start;
+ }
+ return 0;
+}
+
+void Global::FindAndReadVariable(Maps* maps, const char* var_str) {
+ std::string variable(var_str);
+ // When looking for global variables, do not arbitrarily search every
+ // readable map. Instead look for a specific pattern that must exist.
+ // The pattern should be a readable map, followed by a read-write
+ // map with a non-zero offset.
+ // For example:
+ // f0000-f1000 0 r-- /system/lib/libc.so
+ // f1000-f2000 1000 r-x /system/lib/libc.so
+ // f2000-f3000 2000 rw- /system/lib/libc.so
+ // This also works:
+ // f0000-f2000 0 r-- /system/lib/libc.so
+ // f2000-f3000 2000 rw- /system/lib/libc.so
+ MapInfo* map_start = nullptr;
+ for (MapInfo* info : *maps) {
+ if (map_start != nullptr) {
+ if (map_start->name == info->name) {
+ if (info->offset != 0 &&
+ (info->flags & (PROT_READ | PROT_WRITE)) == (PROT_READ | PROT_WRITE)) {
+ uint64_t ptr = GetVariableOffset(map_start, variable);
+ if (ptr != 0 && ReadVariableData(ptr)) {
+ break;
+ } else {
+ // Failed to find the global variable, do not bother trying again.
+ map_start = nullptr;
+ }
+ }
+ } else {
+ map_start = nullptr;
+ }
+ }
+ if (map_start == nullptr && (info->flags & PROT_READ) && info->offset == 0 &&
+ !info->name.empty()) {
+ map_start = info;
+ }
+ }
+}
+
+} // namespace unwindstack
diff --git a/libunwindstack/JitDebug.cpp b/libunwindstack/JitDebug.cpp
index 821aacf..fe680d7 100644
--- a/libunwindstack/JitDebug.cpp
+++ b/libunwindstack/JitDebug.cpp
@@ -69,10 +69,10 @@
uint64_t first_entry;
};
-JitDebug::JitDebug(std::shared_ptr<Memory>& memory) : memory_(memory) {}
+JitDebug::JitDebug(std::shared_ptr<Memory>& memory) : Global(memory) {}
JitDebug::JitDebug(std::shared_ptr<Memory>& memory, std::vector<std::string>& search_libs)
- : memory_(memory), search_libs_(search_libs) {}
+ : Global(memory, search_libs) {}
JitDebug::~JitDebug() {
for (auto* elf : elf_list_) {
@@ -165,6 +165,11 @@
}
}
+bool JitDebug::ReadVariableData(uint64_t ptr) {
+ entry_addr_ = (this->*read_descriptor_func_)(ptr);
+ return entry_addr_ != 0;
+}
+
void JitDebug::Init(Maps* maps) {
if (initialized_) {
return;
@@ -172,36 +177,7 @@
// Regardless of what happens below, consider the init finished.
initialized_ = true;
- const std::string descriptor_name("__jit_debug_descriptor");
- for (MapInfo* info : *maps) {
- if (!(info->flags & PROT_READ) || info->offset != 0) {
- continue;
- }
-
- if (!search_libs_.empty()) {
- bool found = false;
- const char* lib = basename(info->name.c_str());
- for (std::string& name : search_libs_) {
- if (strcmp(name.c_str(), lib) == 0) {
- found = true;
- break;
- }
- }
- if (!found) {
- continue;
- }
- }
-
- Elf* elf = info->GetElf(memory_, true);
- uint64_t descriptor_addr;
- // Find first non-empty entry (libart might be loaded multiple times).
- if (elf->GetGlobalVariable(descriptor_name, &descriptor_addr) && descriptor_addr != 0) {
- entry_addr_ = (this->*read_descriptor_func_)(descriptor_addr + info->start);
- if (entry_addr_ != 0) {
- break;
- }
- }
- }
+ FindAndReadVariable(maps, "__jit_debug_descriptor");
}
Elf* JitDebug::GetElf(Maps* maps, uint64_t pc) {
diff --git a/libunwindstack/include/unwindstack/DexFiles.h b/libunwindstack/include/unwindstack/DexFiles.h
index 26f5d35..c2fde74 100644
--- a/libunwindstack/include/unwindstack/DexFiles.h
+++ b/libunwindstack/include/unwindstack/DexFiles.h
@@ -25,16 +25,18 @@
#include <unordered_map>
#include <vector>
+#include <unwindstack/Global.h>
+#include <unwindstack/Memory.h>
+
namespace unwindstack {
// Forward declarations.
class DexFile;
class Maps;
struct MapInfo;
-class Memory;
enum ArchEnum : uint8_t;
-class DexFiles {
+class DexFiles : public Global {
public:
explicit DexFiles(std::shared_ptr<Memory>& memory);
DexFiles(std::shared_ptr<Memory>& memory, std::vector<std::string>& search_libs);
@@ -60,8 +62,7 @@
bool ReadEntry64();
- std::shared_ptr<Memory> memory_;
- std::vector<std::string> search_libs_;
+ bool ReadVariableData(uint64_t ptr_offset) override;
std::mutex lock_;
bool initialized_ = false;
diff --git a/libunwindstack/include/unwindstack/Global.h b/libunwindstack/include/unwindstack/Global.h
new file mode 100644
index 0000000..70e3ddd
--- /dev/null
+++ b/libunwindstack/include/unwindstack/Global.h
@@ -0,0 +1,54 @@
+/*
+ * 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 _LIBUNWINDSTACK_GLOBAL_H
+#define _LIBUNWINDSTACK_GLOBAL_H
+
+#include <stdint.h>
+
+#include <memory>
+#include <mutex>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include <unwindstack/Memory.h>
+
+namespace unwindstack {
+
+// Forward declarations.
+class Maps;
+struct MapInfo;
+
+class Global {
+ public:
+ explicit Global(std::shared_ptr<Memory>& memory);
+ Global(std::shared_ptr<Memory>& memory, std::vector<std::string>& search_libs);
+ virtual ~Global() = default;
+
+ protected:
+ uint64_t GetVariableOffset(MapInfo* info, const std::string& variable);
+ void FindAndReadVariable(Maps* maps, const char* variable);
+
+ virtual bool ReadVariableData(uint64_t offset) = 0;
+
+ std::shared_ptr<Memory> memory_;
+ std::vector<std::string> search_libs_;
+};
+
+} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_GLOBAL_H
diff --git a/libunwindstack/include/unwindstack/JitDebug.h b/libunwindstack/include/unwindstack/JitDebug.h
index 0bcd0b0..ccb473f 100644
--- a/libunwindstack/include/unwindstack/JitDebug.h
+++ b/libunwindstack/include/unwindstack/JitDebug.h
@@ -24,15 +24,17 @@
#include <string>
#include <vector>
+#include <unwindstack/Global.h>
+#include <unwindstack/Memory.h>
+
namespace unwindstack {
// Forward declarations.
class Elf;
class Maps;
-class Memory;
enum ArchEnum : uint8_t;
-class JitDebug {
+class JitDebug : public Global {
public:
explicit JitDebug(std::shared_ptr<Memory>& memory);
JitDebug(std::shared_ptr<Memory>& memory, std::vector<std::string>& search_libs);
@@ -45,11 +47,9 @@
private:
void Init(Maps* maps);
- std::shared_ptr<Memory> memory_;
uint64_t entry_addr_ = 0;
bool initialized_ = false;
std::vector<Elf*> elf_list_;
- std::vector<std::string> search_libs_;
std::mutex lock_;
@@ -62,6 +62,8 @@
uint64_t ReadEntry32Pack(uint64_t* start, uint64_t* size);
uint64_t ReadEntry32Pad(uint64_t* start, uint64_t* size);
uint64_t ReadEntry64(uint64_t* start, uint64_t* size);
+
+ bool ReadVariableData(uint64_t ptr_offset) override;
};
} // namespace unwindstack
diff --git a/libunwindstack/tests/DexFilesTest.cpp b/libunwindstack/tests/DexFilesTest.cpp
index c6d7f33..3ac3ca6 100644
--- a/libunwindstack/tests/DexFilesTest.cpp
+++ b/libunwindstack/tests/DexFilesTest.cpp
@@ -44,15 +44,15 @@
dex_files_->SetArch(ARCH_ARM);
maps_.reset(
- new BufferMaps("1000-4000 ---s 00000000 00:00 0\n"
- "4000-6000 r--s 00000000 00:00 0\n"
- "6000-8000 -wxs 00000000 00:00 0\n"
- "a000-c000 r--p 00000000 00:00 0\n"
- "c000-f000 rw-p 00000000 00:00 0\n"
- "f000-11000 r--p 00000000 00:00 0\n"
- "100000-110000 rw-p 0000000 00:00 0\n"
- "200000-210000 rw-p 0000000 00:00 0\n"
- "300000-400000 rw-p 0000000 00:00 0\n"));
+ new BufferMaps("1000-4000 ---s 00000000 00:00 0 /fake/elf\n"
+ "4000-6000 r--s 00000000 00:00 0 /fake/elf\n"
+ "6000-8000 -wxs 00000000 00:00 0 /fake/elf\n"
+ "a000-c000 r--p 00000000 00:00 0 /fake/elf2\n"
+ "c000-f000 rw-p 00001000 00:00 0 /fake/elf2\n"
+ "f000-11000 r--p 00000000 00:00 0 /fake/elf3\n"
+ "100000-110000 rw-p 0001000 00:00 0 /fake/elf3\n"
+ "200000-210000 rw-p 0002000 00:00 0 /fake/elf3\n"
+ "300000-400000 rw-p 0003000 00:00 0 /fake/elf3\n"));
ASSERT_TRUE(maps_->Parse());
// Global variable in a section that is not readable.
@@ -96,8 +96,9 @@
void WriteDex(uint64_t dex_file);
static constexpr size_t kMapGlobalNonReadable = 2;
- static constexpr size_t kMapGlobalSetToZero = 4;
+ static constexpr size_t kMapGlobalSetToZero = 3;
static constexpr size_t kMapGlobal = 5;
+ static constexpr size_t kMapGlobalRw = 6;
static constexpr size_t kMapDexFileEntries = 7;
static constexpr size_t kMapDexFiles = 8;
@@ -256,6 +257,9 @@
map_info->name = "/system/lib/libart.so";
dex_files_.reset(new DexFiles(process_memory_, libs));
dex_files_->SetArch(ARCH_ARM);
+ // Set the rw map to the same name or this will not scan this entry.
+ map_info = maps_->Get(kMapGlobalRw);
+ map_info->name = "/system/lib/libart.so";
// Make sure that clearing out copy of the libs doesn't affect the
// DexFiles object.
libs.clear();
@@ -271,7 +275,7 @@
MapInfo* info = maps_->Get(kMapDexFiles);
// First global variable found, but value is zero.
- WriteDescriptor32(0xc800, 0);
+ WriteDescriptor32(0xa800, 0);
WriteDescriptor32(0xf800, 0x200000);
WriteEntry32(0x200000, 0, 0, 0x300000);
@@ -286,7 +290,7 @@
dex_files_->SetArch(ARCH_ARM);
method_name = "fail";
method_offset = 0x123;
- WriteDescriptor32(0xc800, 0x100000);
+ WriteDescriptor32(0xa800, 0x100000);
dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
EXPECT_EQ("fail", method_name);
EXPECT_EQ(0x123U, method_offset);
@@ -298,7 +302,7 @@
MapInfo* info = maps_->Get(kMapDexFiles);
// First global variable found, but value is zero.
- WriteDescriptor64(0xc800, 0);
+ WriteDescriptor64(0xa800, 0);
WriteDescriptor64(0xf800, 0x200000);
WriteEntry64(0x200000, 0, 0, 0x300000);
@@ -314,7 +318,7 @@
dex_files_->SetArch(ARCH_ARM64);
method_name = "fail";
method_offset = 0x123;
- WriteDescriptor64(0xc800, 0x100000);
+ WriteDescriptor64(0xa800, 0x100000);
dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
EXPECT_EQ("fail", method_name);
EXPECT_EQ(0x123U, method_offset);
diff --git a/libunwindstack/tests/JitDebugTest.cpp b/libunwindstack/tests/JitDebugTest.cpp
index 66f0859..4598526 100644
--- a/libunwindstack/tests/JitDebugTest.cpp
+++ b/libunwindstack/tests/JitDebugTest.cpp
@@ -43,15 +43,16 @@
jit_debug_->SetArch(ARCH_ARM);
maps_.reset(
- new BufferMaps("1000-4000 ---s 00000000 00:00 0\n"
- "4000-6000 r--s 00000000 00:00 0\n"
- "6000-8000 -wxs 00000000 00:00 0\n"
- "a000-c000 --xp 00000000 00:00 0\n"
- "c000-f000 rw-p 00000000 00:00 0\n"
- "f000-11000 r--p 00000000 00:00 0\n"
- "12000-14000 r--p 00000000 00:00 0\n"
- "100000-110000 rw-p 0000000 00:00 0\n"
- "200000-210000 rw-p 0000000 00:00 0\n"));
+ new BufferMaps("1000-4000 ---s 00000000 00:00 0 /fake/elf1\n"
+ "4000-6000 r--s 00000000 00:00 0 /fake/elf1\n"
+ "6000-8000 -wxs 00000000 00:00 0 /fake/elf1\n"
+ "a000-c000 --xp 00000000 00:00 0 /fake/elf2\n"
+ "c000-f000 rw-p 00001000 00:00 0 /fake/elf2\n"
+ "f000-11000 r--p 00000000 00:00 0 /fake/elf3\n"
+ "11000-12000 rw-p 00001000 00:00 0 /fake/elf3\n"
+ "12000-14000 r--p 00000000 00:00 0 /fake/elf4\n"
+ "100000-110000 rw-p 0001000 00:00 0 /fake/elf4\n"
+ "200000-210000 rw-p 0002000 00:00 0 /fake/elf4\n"));
ASSERT_TRUE(maps_->Parse());
MapInfo* map_info = maps_->Get(3);
@@ -74,7 +75,7 @@
interface->FakeSetGlobalVariable("__jit_debug_descriptor", 0x800);
map_info->elf.reset(elf);
- map_info = maps_->Get(6);
+ map_info = maps_->Get(7);
ASSERT_TRUE(map_info != nullptr);
memory = new MemoryFake;
elf = new ElfFake(memory);
@@ -397,6 +398,8 @@
// Change the name of the map that includes the value and verify this works.
MapInfo* map_info = maps_->Get(5);
map_info->name = "/system/lib/libart.so";
+ map_info = maps_->Get(6);
+ map_info->name = "/system/lib/libart.so";
jit_debug_.reset(new JitDebug(process_memory_, libs));
// Make sure that clearing our copy of the libs doesn't affect the
// JitDebug object.
diff --git a/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/maps.txt b/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/maps.txt
index 55aaaf6..5657373 100644
--- a/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/maps.txt
+++ b/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/maps.txt
@@ -1,3 +1,4 @@
d0250000-d2600000 r-xp 0 00:00 0 <anonymous:d0250000>
e466e000-e4ae8000 r-xp 0 00:00 0 libart.so
+e4ae8000-e4ae9000 rw-p 1000 00:00 0 libart.so
e7d91000-e7e31000 r-xp 0 00:00 0 libc.so
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm/maps.txt b/libunwindstack/tests/files/offline/jit_debug_arm/maps.txt
index f25c781..3cd9d40 100644
--- a/libunwindstack/tests/files/offline/jit_debug_arm/maps.txt
+++ b/libunwindstack/tests/files/offline/jit_debug_arm/maps.txt
@@ -2,7 +2,9 @@
dfe4e000-dfe7b000 r-xp 0 00:00 0 libarttestd.so
e0447000-e0448000 r-xp 2000 00:00 0 137-cfi.odex
e2796000-e4796000 r-xp 0 00:00 0 anonymous:e2796000
-e648e000-e690f000 r-xp 00000000 00:00 0 libart.so
+e648e000-e690f000 r-xp 0 00:00 0 libart.so
+e690f000-e6910000 rw-p 1000 00:00 0 libart.so
ed306000-ed801000 r-xp 0 00:00 0 libartd.so
+ed801000-ed802000 rw-p 1000 00:00 0 libartd.so
eda88000-edb23000 r-xp 0 00:00 0 libc.so
ede4e000-ede50000 r-xp 0 00:00 0 anonymous:ede4e000
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86/maps.txt b/libunwindstack/tests/files/offline/jit_debug_x86/maps.txt
index db4f9f7..a8d215c 100644
--- a/libunwindstack/tests/files/offline/jit_debug_x86/maps.txt
+++ b/libunwindstack/tests/files/offline/jit_debug_x86/maps.txt
@@ -3,4 +3,5 @@
ec606000-ec607000 r-xp 2000 00:00 0 137-cfi.odex
ee74c000-f074c000 r-xp 0 00:00 0 anonymous:ee74c000
f6be1000-f732b000 r-xp 0 00:00 0 libartd.so
+f732b000-f732c000 rw-p 1000 00:00 0 libartd.so
f734b000-f74fc000 r-xp 0 00:00 0 libc.so
diff --git a/libutils/include/utils/Errors.h b/libutils/include/utils/Errors.h
index 7aafe42..1e03677 100644
--- a/libutils/include/utils/Errors.h
+++ b/libutils/include/utils/Errors.h
@@ -14,22 +14,19 @@
* limitations under the License.
*/
-#ifndef ANDROID_ERRORS_H
-#define ANDROID_ERRORS_H
+#pragma once
-#include <sys/types.h>
#include <errno.h>
+#include <stdint.h>
+#include <sys/types.h>
namespace android {
-// use this type to return error codes
-#ifdef _WIN32
-typedef int status_t;
-#else
-typedef int32_t status_t;
-#endif
-
-/* the MS C runtime lacks a few error codes */
+/**
+ * The type used to return success/failure from frameworks APIs.
+ * See the anonymous enum below for valid values.
+ */
+typedef int32_t status_t;
/*
* Error codes.
@@ -82,7 +79,3 @@
#endif
} // namespace android
-
-// ---------------------------------------------------------------------------
-
-#endif // ANDROID_ERRORS_H
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index e4e1650..393e204 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -124,6 +124,7 @@
LOCAL_POST_INSTALL_CMD += ; ln -sf /vendor/odm/lib64 $(TARGET_ROOT_OUT)/odm/lib64
LOCAL_POST_INSTALL_CMD += ; ln -sf /vendor/odm/overlay $(TARGET_ROOT_OUT)/odm/overlay
LOCAL_POST_INSTALL_CMD += ; ln -sf /vendor/odm/priv-app $(TARGET_ROOT_OUT)/odm/priv-app
+LOCAL_POST_INSTALL_CMD += ; ln -sf /vendor/odm/usr $(TARGET_ROOT_OUT)/odm/usr
ifdef BOARD_CACHEIMAGE_FILE_SYSTEM_TYPE
LOCAL_POST_INSTALL_CMD += ; mkdir -p $(TARGET_ROOT_OUT)/cache
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 21d234f..ea83ef9 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -275,6 +275,13 @@
chown root root /apex
restorecon /apex
+ # Start logd before any other services run to ensure we capture all of their logs.
+ start logd
+ # Start essential services.
+ start servicemanager
+ start hwservicemanager
+ start vndservicemanager
+
# Healthd can trigger a full boot from charger mode by signaling this
# property when the power button is held.
on property:sys.boot_from_charger_mode=1
@@ -331,11 +338,6 @@
# /vendor/build.prop and
# /factory/factory.prop
load_system_props
- # start essential services
- start logd
- start servicemanager
- start hwservicemanager
- start vndservicemanager
start vold
exec - system system -- /system/bin/vdc checkpoint markBootAttempt