Merge "Restore lost .dm support of adb install-multiple"
diff --git a/fastboot/device/commands.cpp b/fastboot/device/commands.cpp
index b02d968..6c0aba1 100644
--- a/fastboot/device/commands.cpp
+++ b/fastboot/device/commands.cpp
@@ -27,6 +27,7 @@
#include <android-base/unique_fd.h>
#include <cutils/android_reboot.h>
#include <ext4_utils/wipe.h>
+#include <fs_mgr.h>
#include <liblp/builder.h>
#include <liblp/liblp.h>
#include <uuid/uuid.h>
@@ -310,7 +311,7 @@
};
PartitionBuilder::PartitionBuilder(FastbootDevice* device) {
- auto super_device = FindPhysicalPartition(LP_METADATA_PARTITION_NAME);
+ auto super_device = FindPhysicalPartition(fs_mgr_get_super_partition_name());
if (!super_device) {
return;
}
@@ -353,13 +354,7 @@
return device->WriteFail("Partition already exists");
}
- // Make a random UUID, since they're not currently used.
- uuid_t uuid;
- char uuid_str[37];
- uuid_generate_random(uuid);
- uuid_unparse(uuid, uuid_str);
-
- Partition* partition = builder->AddPartition(partition_name, uuid_str, 0);
+ Partition* partition = builder->AddPartition(partition_name, 0);
if (!partition) {
return device->WriteFail("Failed to add partition");
}
diff --git a/fastboot/device/flashing.cpp b/fastboot/device/flashing.cpp
index a383c54..4fc3d1d 100644
--- a/fastboot/device/flashing.cpp
+++ b/fastboot/device/flashing.cpp
@@ -146,8 +146,7 @@
if (builder->FindPartition(name)) {
continue;
}
- std::string guid = GetPartitionGuid(partition);
- if (!builder->AddPartition(name, guid, partition.attributes)) {
+ if (!builder->AddPartition(name, partition.attributes)) {
return device->WriteFail("Unable to add partition: " + name);
}
}
diff --git a/fastboot/device/utility.cpp b/fastboot/device/utility.cpp
index 02f6f2c..528abec 100644
--- a/fastboot/device/utility.cpp
+++ b/fastboot/device/utility.cpp
@@ -23,6 +23,7 @@
#include <android-base/file.h>
#include <android-base/logging.h>
+#include <fs_mgr.h>
#include <fs_mgr_dm_linear.h>
#include <liblp/liblp.h>
@@ -44,7 +45,7 @@
static bool OpenLogicalPartition(const std::string& name, const std::string& slot,
PartitionHandle* handle) {
- std::optional<std::string> path = FindPhysicalPartition(LP_METADATA_PARTITION_NAME);
+ std::optional<std::string> path = FindPhysicalPartition(fs_mgr_get_super_partition_name());
if (!path) {
return false;
}
@@ -100,7 +101,7 @@
bool LogicalPartitionExists(const std::string& name, const std::string& slot_suffix,
bool* is_zero_length) {
- auto path = FindPhysicalPartition(LP_METADATA_PARTITION_NAME);
+ auto path = FindPhysicalPartition(fs_mgr_get_super_partition_name());
if (!path) {
return false;
}
@@ -149,7 +150,7 @@
}
// Next get logical partitions.
- if (auto path = FindPhysicalPartition(LP_METADATA_PARTITION_NAME)) {
+ if (auto path = FindPhysicalPartition(fs_mgr_get_super_partition_name())) {
uint32_t slot_number = SlotNumberForSlotSuffix(device->GetCurrentSlot());
if (auto metadata = ReadMetadata(path->c_str(), slot_number)) {
for (const auto& partition : metadata->partitions) {
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index d29ccf4..3ab9732 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -55,6 +55,7 @@
#include <ext4_utils/wipe.h>
#include <fs_mgr_overlayfs.h>
#include <libdm/dm.h>
+#include <liblp/metadata_format.h>
#include <linux/fs.h>
#include <linux/loop.h>
#include <linux/magic.h>
@@ -529,8 +530,18 @@
errno = 0;
ret = mount(source, target, rec->fs_type, mountflags, rec->fs_options);
save_errno = errno;
- PINFO << __FUNCTION__ << "(source=" << source << ",target=" << target
- << ",type=" << rec->fs_type << ")=" << ret;
+ const char* target_missing = "";
+ const char* source_missing = "";
+ if (save_errno == ENOENT) {
+ if (access(target, F_OK)) {
+ target_missing = "(missing)";
+ } else if (access(source, F_OK)) {
+ source_missing = "(missing)";
+ }
+ errno = save_errno;
+ }
+ PINFO << __FUNCTION__ << "(source=" << source << source_missing << ",target=" << target
+ << target_missing << ",type=" << rec->fs_type << ")=" << ret;
if ((ret == 0) && (mountflags & MS_RDONLY) != 0) {
fs_mgr_set_blk_ro(source);
}
@@ -840,7 +851,7 @@
}
bool fs_mgr_update_checkpoint_partition(struct fstab_rec* rec) {
- if (fs_mgr_is_checkpoint(rec)) {
+ if (fs_mgr_is_checkpoint_fs(rec)) {
if (!strcmp(rec->fs_type, "f2fs")) {
std::string opts(rec->fs_options);
@@ -850,9 +861,42 @@
} else {
LERROR << rec->fs_type << " does not implement checkpoints.";
}
- } else if (rec->fs_mgr_flags & MF_CHECKPOINT_BLK) {
- LERROR << "Block based checkpoint not implemented.";
- return false;
+ } else if (fs_mgr_is_checkpoint_blk(rec)) {
+ call_vdc({"checkpoint", "restoreCheckpoint", rec->blk_device});
+
+ android::base::unique_fd fd(
+ TEMP_FAILURE_RETRY(open(rec->blk_device, O_RDONLY | O_CLOEXEC)));
+ if (!fd) {
+ PERROR << "Cannot open device " << rec->blk_device;
+ return false;
+ }
+
+ uint64_t size = get_block_device_size(fd) / 512;
+ if (!size) {
+ PERROR << "Cannot get device size";
+ return false;
+ }
+
+ android::dm::DmTable table;
+ if (!table.AddTarget(
+ std::make_unique<android::dm::DmTargetBow>(0, size, rec->blk_device))) {
+ LERROR << "Failed to add Bow target";
+ return false;
+ }
+
+ DeviceMapper& dm = DeviceMapper::Instance();
+ if (!dm.CreateDevice("bow", table)) {
+ PERROR << "Failed to create bow device";
+ return false;
+ }
+
+ std::string name;
+ if (!dm.GetDmDevicePathByName("bow", &name)) {
+ PERROR << "Failed to get bow device name";
+ return false;
+ }
+
+ rec->blk_device = strdup(name.c_str());
}
return true;
}
@@ -1300,29 +1344,25 @@
* on a system (all the memory comes from the same pool) so
* we can assume the device number is 0.
*/
- FILE *zram_fp;
- FILE *zram_mcs_fp;
-
if (fstab->recs[i].max_comp_streams >= 0) {
- zram_mcs_fp = fopen(ZRAM_CONF_MCS, "r+");
- if (zram_mcs_fp == NULL) {
- LERROR << "Unable to open zram conf comp device "
- << ZRAM_CONF_MCS;
- ret = -1;
- continue;
- }
- fprintf(zram_mcs_fp, "%d\n", fstab->recs[i].max_comp_streams);
- fclose(zram_mcs_fp);
+ auto zram_mcs_fp = std::unique_ptr<FILE, decltype(&fclose)>{
+ fopen(ZRAM_CONF_MCS, "re"), fclose};
+ if (zram_mcs_fp == NULL) {
+ LERROR << "Unable to open zram conf comp device " << ZRAM_CONF_MCS;
+ ret = -1;
+ continue;
+ }
+ fprintf(zram_mcs_fp.get(), "%d\n", fstab->recs[i].max_comp_streams);
}
- zram_fp = fopen(ZRAM_CONF_DEV, "r+");
+ auto zram_fp =
+ std::unique_ptr<FILE, decltype(&fclose)>{fopen(ZRAM_CONF_DEV, "re+"), fclose};
if (zram_fp == NULL) {
LERROR << "Unable to open zram conf device " << ZRAM_CONF_DEV;
ret = -1;
continue;
}
- fprintf(zram_fp, "%u\n", fstab->recs[i].zram_size);
- fclose(zram_fp);
+ fprintf(zram_fp.get(), "%u\n", fstab->recs[i].zram_size);
}
if (fstab->recs[i].fs_mgr_flags & MF_WAIT &&
@@ -1501,3 +1541,7 @@
return true;
}
+
+std::string fs_mgr_get_super_partition_name(int /* slot */) {
+ return LP_METADATA_DEFAULT_PARTITION_NAME;
+}
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index 250793a..fc3a05c 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -732,21 +732,19 @@
struct fstab *fs_mgr_read_fstab(const char *fstab_path)
{
- FILE *fstab_file;
struct fstab *fstab;
- fstab_file = fopen(fstab_path, "r");
+ auto fstab_file = std::unique_ptr<FILE, decltype(&fclose)>{fopen(fstab_path, "re"), fclose};
if (!fstab_file) {
PERROR << __FUNCTION__<< "(): cannot open file: '" << fstab_path << "'";
return nullptr;
}
- fstab = fs_mgr_read_fstab_file(fstab_file, !strcmp("/proc/mounts", fstab_path));
+ fstab = fs_mgr_read_fstab_file(fstab_file.get(), !strcmp("/proc/mounts", fstab_path));
if (!fstab) {
LERROR << __FUNCTION__ << "(): failed to load fstab from : '" << fstab_path << "'";
}
- fclose(fstab_file);
return fstab;
}
diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp
index 07b2a7a..ee63d60 100644
--- a/fs_mgr/fs_mgr_overlayfs.cpp
+++ b/fs_mgr/fs_mgr_overlayfs.cpp
@@ -344,6 +344,50 @@
return ret;
}
+bool fs_mgr_overlayfs_teardown_one(const std::string& overlay, const std::string& mount_point,
+ bool* change) {
+ const auto top = overlay + kOverlayTopDir;
+ auto save_errno = errno;
+ auto missing = access(top.c_str(), F_OK);
+ errno = save_errno;
+ if (missing) return false;
+
+ const auto oldpath = top + (mount_point.empty() ? "" : ("/"s + mount_point));
+ const auto newpath = oldpath + ".teardown";
+ auto ret = fs_mgr_rm_all(newpath);
+ save_errno = errno;
+ if (!rename(oldpath.c_str(), newpath.c_str())) {
+ if (change) *change = true;
+ } else if (errno != ENOENT) {
+ ret = false;
+ PERROR << "mv " << oldpath << " " << newpath;
+ } else {
+ errno = save_errno;
+ }
+ ret &= fs_mgr_rm_all(newpath, change);
+ save_errno = errno;
+ if (!rmdir(newpath.c_str())) {
+ if (change) *change = true;
+ } else if (errno != ENOENT) {
+ ret = false;
+ PERROR << "rmdir " << newpath;
+ } else {
+ errno = save_errno;
+ }
+ if (!mount_point.empty()) {
+ save_errno = errno;
+ if (!rmdir(top.c_str())) {
+ if (change) *change = true;
+ } else if ((errno != ENOENT) && (errno != ENOTEMPTY)) {
+ ret = false;
+ PERROR << "rmdir " << top;
+ } else {
+ errno = save_errno;
+ }
+ }
+ return ret;
+}
+
bool fs_mgr_overlayfs_mount(const std::string& mount_point) {
auto options = fs_mgr_get_overlayfs_options(mount_point);
if (options.empty()) return false;
@@ -475,41 +519,7 @@
fs_mgr_read_fstab_default(), fs_mgr_free_fstab)
.get(),
mount_point);
- auto ret = true;
- const auto overlay = kOverlayMountPoint + kOverlayTopDir;
- const auto oldpath = overlay + (mount_point ? "/"s + mount_point : ""s);
- const auto newpath = oldpath + ".teardown";
- ret &= fs_mgr_rm_all(newpath);
- auto save_errno = errno;
- if (!rename(oldpath.c_str(), newpath.c_str())) {
- if (change) *change = true;
- } else if (errno != ENOENT) {
- ret = false;
- PERROR << "mv " << oldpath << " " << newpath;
- } else {
- errno = save_errno;
- }
- ret &= fs_mgr_rm_all(newpath, change);
- save_errno = errno;
- if (!rmdir(newpath.c_str())) {
- if (change) *change = true;
- } else if (errno != ENOENT) {
- ret = false;
- PERROR << "rmdir " << newpath;
- } else {
- errno = save_errno;
- }
- if (mount_point) {
- save_errno = errno;
- if (!rmdir(overlay.c_str())) {
- if (change) *change = true;
- } else if ((errno != ENOENT) && (errno != ENOTEMPTY)) {
- ret = false;
- PERROR << "rmdir " << overlay;
- } else {
- errno = save_errno;
- }
- }
+ auto ret = fs_mgr_overlayfs_teardown_one(kOverlayMountPoint, mount_point ?: "", change);
if (!fs_mgr_wants_overlayfs()) {
// After obligatory teardown to make sure everything is clean, but if
// we didn't want overlayfs in the the first place, we do not want to
diff --git a/fs_mgr/fs_mgr_verity.cpp b/fs_mgr/fs_mgr_verity.cpp
index 5fb4ebb..2727a6d 100644
--- a/fs_mgr/fs_mgr_verity.cpp
+++ b/fs_mgr/fs_mgr_verity.cpp
@@ -89,24 +89,21 @@
{
uint8_t key_data[ANDROID_PUBKEY_ENCODED_SIZE];
- FILE* f = fopen(path, "r");
+ auto f = std::unique_ptr<FILE, decltype(&fclose)>{fopen(path, "re"), fclose};
if (!f) {
LERROR << "Can't open " << path;
- return NULL;
+ return nullptr;
}
- if (!fread(key_data, sizeof(key_data), 1, f)) {
+ if (!fread(key_data, sizeof(key_data), 1, f.get())) {
LERROR << "Could not read key!";
- fclose(f);
- return NULL;
+ return nullptr;
}
- fclose(f);
-
- RSA* key = NULL;
+ RSA* key = nullptr;
if (!android_pubkey_decode(key_data, sizeof(key_data), &key)) {
LERROR << "Could not parse key!";
- return NULL;
+ return nullptr;
}
return key;
@@ -368,7 +365,6 @@
static int metadata_find(const char *fname, const char *stag,
unsigned int slength, off64_t *offset)
{
- FILE *fp = NULL;
char tag[METADATA_TAG_MAX_LENGTH + 1];
int rc = -1;
int n;
@@ -380,75 +376,64 @@
return -1;
}
- fp = fopen(fname, "r+");
+ auto fp = std::unique_ptr<FILE, decltype(&fclose)>{fopen(fname, "re+"), fclose};
if (!fp) {
PERROR << "Failed to open " << fname;
- goto out;
+ return -1;
}
/* check magic */
- if (fseek(fp, start, SEEK_SET) < 0 ||
- fread(&magic, sizeof(magic), 1, fp) != 1) {
+ if (fseek(fp.get(), start, SEEK_SET) < 0 || fread(&magic, sizeof(magic), 1, fp.get()) != 1) {
PERROR << "Failed to read magic from " << fname;
- goto out;
+ return -1;
}
if (magic != METADATA_MAGIC) {
magic = METADATA_MAGIC;
- if (fseek(fp, start, SEEK_SET) < 0 ||
- fwrite(&magic, sizeof(magic), 1, fp) != 1) {
+ if (fseek(fp.get(), start, SEEK_SET) < 0 ||
+ fwrite(&magic, sizeof(magic), 1, fp.get()) != 1) {
PERROR << "Failed to write magic to " << fname;
- goto out;
+ return -1;
}
- rc = metadata_add(fp, start + sizeof(magic), stag, slength, offset);
+ rc = metadata_add(fp.get(), start + sizeof(magic), stag, slength, offset);
if (rc < 0) {
PERROR << "Failed to add metadata to " << fname;
}
- goto out;
+ return rc;
}
start += sizeof(magic);
while (1) {
- n = fscanf(fp, "%" STRINGIFY(METADATA_TAG_MAX_LENGTH) "s %u\n",
- tag, &length);
+ n = fscanf(fp.get(), "%" STRINGIFY(METADATA_TAG_MAX_LENGTH) "s %u\n", tag, &length);
if (n == 2 && strcmp(tag, METADATA_EOD)) {
/* found a tag */
- start = ftell(fp);
+ start = ftell(fp.get());
if (!strcmp(tag, stag) && length == slength) {
*offset = start;
- rc = 0;
- goto out;
+ return 0;
}
start += length;
- if (fseek(fp, length, SEEK_CUR) < 0) {
+ if (fseek(fp.get(), length, SEEK_CUR) < 0) {
PERROR << "Failed to seek " << fname;
- goto out;
+ return -1;
}
} else {
- rc = metadata_add(fp, start, stag, slength, offset);
+ rc = metadata_add(fp.get(), start, stag, slength, offset);
if (rc < 0) {
PERROR << "Failed to write metadata to " << fname;
}
- goto out;
+ return rc;
}
- }
-
-out:
- if (fp) {
- fflush(fp);
- fclose(fp);
}
-
- return rc;
}
static int write_verity_state(const char *fname, off64_t offset, int32_t mode)
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index cee069b..a4544b2 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -23,6 +23,7 @@
#include <linux/dm-ioctl.h>
#include <functional>
+#include <string>
#include <fstab/fstab.h>
@@ -89,4 +90,9 @@
#define FS_MGR_SETUP_VERITY_SUCCESS 0
int fs_mgr_setup_verity(struct fstab_rec *fstab, bool wait_for_verity_dev);
+// Return the name of the super partition if it exists. If a slot number is
+// specified, the super partition for the corresponding metadata slot will be
+// returned. Otherwise, it will use the current slot.
+std::string fs_mgr_get_super_partition_name(int slot = -1);
+
#endif /* __CORE_FS_MGR_H */
diff --git a/fs_mgr/libdm/include/libdm/dm_target.h b/fs_mgr/libdm/include/libdm/dm_target.h
index aab89e5..175b0f0 100644
--- a/fs_mgr/libdm/include/libdm/dm_target.h
+++ b/fs_mgr/libdm/include/libdm/dm_target.h
@@ -156,6 +156,20 @@
std::string target_string_;
};
+// dm-bow is the backup on write target that can provide checkpoint capability
+// for file systems that do not support checkpoints natively
+class DmTargetBow final : public DmTarget {
+ public:
+ DmTargetBow(uint64_t start, uint64_t length, const std::string& target_string)
+ : DmTarget(start, length), target_string_(target_string) {}
+
+ std::string name() const override { return "bow"; }
+ std::string GetParameterString() const override { return target_string_; }
+
+ private:
+ std::string target_string_;
+};
+
} // namespace dm
} // namespace android
diff --git a/fs_mgr/liblp/Android.bp b/fs_mgr/liblp/Android.bp
index 89282db..69dc065 100644
--- a/fs_mgr/liblp/Android.bp
+++ b/fs_mgr/liblp/Android.bp
@@ -35,7 +35,6 @@
"libcrypto",
"libcrypto_utils",
"libsparse",
- "libext2_uuid",
"libext4_utils",
"libz",
],
diff --git a/fs_mgr/liblp/builder.cpp b/fs_mgr/liblp/builder.cpp
index 352647b..97b15bd 100644
--- a/fs_mgr/liblp/builder.cpp
+++ b/fs_mgr/liblp/builder.cpp
@@ -25,7 +25,6 @@
#include <algorithm>
#include <android-base/unique_fd.h>
-#include <uuid/uuid.h>
#include "liblp/liblp.h"
#include "reader.h"
@@ -79,8 +78,8 @@
out->extents.push_back(LpMetadataExtent{num_sectors_, LP_TARGET_TYPE_ZERO, 0});
}
-Partition::Partition(const std::string& name, const std::string& guid, uint32_t attributes)
- : name_(name), guid_(guid), attributes_(attributes), size_(0) {}
+Partition::Partition(const std::string& name, const std::string& group_name, uint32_t attributes)
+ : name_(name), group_name_(group_name), attributes_(attributes), size_(0) {}
void Partition::AddExtent(std::unique_ptr<Extent>&& extent) {
size_ += extent->num_sectors() * LP_SECTOR_SIZE;
@@ -128,6 +127,17 @@
DCHECK(size_ == aligned_size);
}
+uint64_t Partition::BytesOnDisk() const {
+ uint64_t sectors = 0;
+ for (const auto& extent : extents_) {
+ if (!extent->AsLinearExtent()) {
+ continue;
+ }
+ sectors += extent->num_sectors();
+ }
+ return sectors * LP_SECTOR_SIZE;
+}
+
std::unique_ptr<MetadataBuilder> MetadataBuilder::New(const std::string& block_device,
uint32_t slot_number) {
std::unique_ptr<LpMetadata> metadata = ReadMetadata(block_device.c_str(), slot_number);
@@ -175,14 +185,23 @@
header_.header_size = sizeof(header_);
header_.partitions.entry_size = sizeof(LpMetadataPartition);
header_.extents.entry_size = sizeof(LpMetadataExtent);
+ header_.groups.entry_size = sizeof(LpMetadataPartitionGroup);
}
bool MetadataBuilder::Init(const LpMetadata& metadata) {
geometry_ = metadata.geometry;
+ for (const auto& group : metadata.groups) {
+ std::string group_name = GetPartitionGroupName(group);
+ if (!AddGroup(group_name, group.maximum_size)) {
+ return false;
+ }
+ }
+
for (const auto& partition : metadata.partitions) {
- Partition* builder = AddPartition(GetPartitionName(partition), GetPartitionGuid(partition),
- partition.attributes);
+ std::string group_name = GetPartitionGroupName(metadata.groups[partition.group_index]);
+ Partition* builder =
+ AddPartition(GetPartitionName(partition), group_name, partition.attributes);
if (!builder) {
return false;
}
@@ -292,10 +311,27 @@
geometry_.alignment_offset = device_info_.alignment_offset;
geometry_.block_device_size = device_info_.size;
geometry_.logical_block_size = device_info.logical_block_size;
+
+ if (!AddGroup("default", 0)) {
+ return false;
+ }
return true;
}
-Partition* MetadataBuilder::AddPartition(const std::string& name, const std::string& guid,
+bool MetadataBuilder::AddGroup(const std::string& group_name, uint64_t maximum_size) {
+ if (FindGroup(group_name)) {
+ LERROR << "Group already exists: " << group_name;
+ return false;
+ }
+ groups_.push_back(std::make_unique<PartitionGroup>(group_name, maximum_size));
+ return true;
+}
+
+Partition* MetadataBuilder::AddPartition(const std::string& name, uint32_t attributes) {
+ return AddPartition(name, "default", attributes);
+}
+
+Partition* MetadataBuilder::AddPartition(const std::string& name, const std::string& group_name,
uint32_t attributes) {
if (name.empty()) {
LERROR << "Partition must have a non-empty name.";
@@ -305,7 +341,11 @@
LERROR << "Attempting to create duplication partition with name: " << name;
return nullptr;
}
- partitions_.push_back(std::make_unique<Partition>(name, guid, attributes));
+ if (!FindGroup(group_name)) {
+ LERROR << "Could not find partition group: " << group_name;
+ return nullptr;
+ }
+ partitions_.push_back(std::make_unique<Partition>(name, group_name, attributes));
return partitions_.back().get();
}
@@ -318,6 +358,26 @@
return nullptr;
}
+PartitionGroup* MetadataBuilder::FindGroup(const std::string& group_name) const {
+ for (const auto& group : groups_) {
+ if (group->name() == group_name) {
+ return group.get();
+ }
+ }
+ return nullptr;
+}
+
+uint64_t MetadataBuilder::TotalSizeOfGroup(PartitionGroup* group) const {
+ uint64_t total = 0;
+ for (const auto& partition : partitions_) {
+ if (partition->group_name() != group->name()) {
+ continue;
+ }
+ total += partition->BytesOnDisk();
+ }
+ return total;
+}
+
void MetadataBuilder::RemovePartition(const std::string& name) {
for (auto iter = partitions_.begin(); iter != partitions_.end(); iter++) {
if ((*iter)->name() == name) {
@@ -328,8 +388,23 @@
}
bool MetadataBuilder::GrowPartition(Partition* partition, uint64_t aligned_size) {
- // Figure out how much we need to allocate.
+ PartitionGroup* group = FindGroup(partition->group_name());
+ CHECK(group);
+
+ // Figure out how much we need to allocate, and whether our group has
+ // enough space remaining.
uint64_t space_needed = aligned_size - partition->size();
+ if (group->maximum_size() > 0) {
+ uint64_t group_size = TotalSizeOfGroup(group);
+ if (group_size >= group->maximum_size() ||
+ group->maximum_size() - group_size < space_needed) {
+ LERROR << "Partition " << partition->name() << " is part of group " << group->name()
+ << " which does not have enough space free (" << space_needed << "requested, "
+ << group_size << " used out of " << group->maximum_size();
+ return false;
+ }
+ }
+
uint64_t sectors_needed = space_needed / LP_SECTOR_SIZE;
DCHECK(sectors_needed * LP_SECTOR_SIZE == space_needed);
@@ -441,6 +516,20 @@
metadata->header = header_;
metadata->geometry = geometry_;
+ std::map<std::string, size_t> group_indices;
+ for (const auto& group : groups_) {
+ LpMetadataPartitionGroup out = {};
+
+ if (group->name().size() > sizeof(out.name)) {
+ LERROR << "Partition group name is too long: " << group->name();
+ return nullptr;
+ }
+ strncpy(out.name, group->name().c_str(), sizeof(out.name));
+ out.maximum_size = group->maximum_size();
+
+ metadata->groups.push_back(out);
+ }
+
// Flatten the partition and extent structures into an LpMetadata, which
// makes it very easy to validate, serialize, or pass on to device-mapper.
for (const auto& partition : partitions_) {
@@ -457,12 +546,6 @@
}
strncpy(part.name, partition->name().c_str(), sizeof(part.name));
- if (uuid_parse(partition->guid().c_str(), part.guid) != 0) {
- LERROR << "Could not parse guid " << partition->guid() << " for partition "
- << partition->name();
- return nullptr;
- }
-
part.first_extent_index = static_cast<uint32_t>(metadata->extents.size());
part.num_extents = static_cast<uint32_t>(partition->extents().size());
part.attributes = partition->attributes();
@@ -475,6 +558,7 @@
metadata->header.partitions.num_entries = static_cast<uint32_t>(metadata->partitions.size());
metadata->header.extents.num_entries = static_cast<uint32_t>(metadata->extents.size());
+ metadata->header.groups.num_entries = static_cast<uint32_t>(metadata->groups.size());
return metadata;
}
@@ -530,8 +614,10 @@
ShrinkPartition(partition, aligned_size);
}
- LINFO << "Partition " << partition->name() << " will resize from " << old_size << " bytes to "
- << aligned_size << " bytes";
+ if (partition->size() != old_size) {
+ LINFO << "Partition " << partition->name() << " will resize from " << old_size
+ << " bytes to " << aligned_size << " bytes";
+ }
return true;
}
diff --git a/fs_mgr/liblp/builder_test.cpp b/fs_mgr/liblp/builder_test.cpp
index 0c7e43d..c916b44 100644
--- a/fs_mgr/liblp/builder_test.cpp
+++ b/fs_mgr/liblp/builder_test.cpp
@@ -22,16 +22,12 @@
using namespace std;
using namespace android::fs_mgr;
-static const char* TEST_GUID = "A799D1D6-669F-41D8-A3F0-EBB7572D8302";
-static const char* TEST_GUID2 = "A799D1D6-669F-41D8-A3F0-EBB7572D8303";
-
TEST(liblp, BuildBasic) {
unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(1024 * 1024, 1024, 2);
- Partition* partition = builder->AddPartition("system", TEST_GUID, LP_PARTITION_ATTR_READONLY);
+ Partition* partition = builder->AddPartition("system", LP_PARTITION_ATTR_READONLY);
ASSERT_NE(partition, nullptr);
EXPECT_EQ(partition->name(), "system");
- EXPECT_EQ(partition->guid(), TEST_GUID);
EXPECT_EQ(partition->attributes(), LP_PARTITION_ATTR_READONLY);
EXPECT_EQ(partition->size(), 0);
EXPECT_EQ(builder->FindPartition("system"), partition);
@@ -43,7 +39,7 @@
TEST(liblp, ResizePartition) {
unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(1024 * 1024, 1024, 2);
- Partition* system = builder->AddPartition("system", TEST_GUID, LP_PARTITION_ATTR_READONLY);
+ Partition* system = builder->AddPartition("system", LP_PARTITION_ATTR_READONLY);
ASSERT_NE(system, nullptr);
EXPECT_EQ(builder->ResizePartition(system, 65536), true);
EXPECT_EQ(system->size(), 65536);
@@ -94,7 +90,7 @@
unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(1024 * 1024, 1024, 2);
// Test that we align up to one sector.
- Partition* system = builder->AddPartition("system", TEST_GUID, LP_PARTITION_ATTR_READONLY);
+ Partition* system = builder->AddPartition("system", LP_PARTITION_ATTR_READONLY);
ASSERT_NE(system, nullptr);
EXPECT_EQ(builder->ResizePartition(system, 10000), true);
EXPECT_EQ(system->size(), 12288);
@@ -171,9 +167,9 @@
BlockDeviceInfo device_info(512 * 1024 * 1024, 768 * 1024, 753664, 4096);
unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(device_info, 32 * 1024, 2);
- Partition* a = builder->AddPartition("a", TEST_GUID, 0);
+ Partition* a = builder->AddPartition("a", 0);
ASSERT_NE(a, nullptr);
- Partition* b = builder->AddPartition("b", TEST_GUID2, 0);
+ Partition* b = builder->AddPartition("b", 0);
ASSERT_NE(b, nullptr);
// Add a bunch of small extents to each, interleaving.
@@ -214,7 +210,7 @@
EXPECT_EQ(builder->AllocatableSpace(), allocatable);
EXPECT_EQ(builder->UsedSpace(), 0);
- Partition* system = builder->AddPartition("system", TEST_GUID, LP_PARTITION_ATTR_READONLY);
+ Partition* system = builder->AddPartition("system", LP_PARTITION_ATTR_READONLY);
ASSERT_NE(system, nullptr);
EXPECT_EQ(builder->ResizePartition(system, allocatable), true);
EXPECT_EQ(system->size(), allocatable);
@@ -229,8 +225,8 @@
TEST(liblp, BuildComplex) {
unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(1024 * 1024, 1024, 2);
- Partition* system = builder->AddPartition("system", TEST_GUID, LP_PARTITION_ATTR_READONLY);
- Partition* vendor = builder->AddPartition("vendor", TEST_GUID2, LP_PARTITION_ATTR_READONLY);
+ Partition* system = builder->AddPartition("system", LP_PARTITION_ATTR_READONLY);
+ Partition* vendor = builder->AddPartition("vendor", LP_PARTITION_ATTR_READONLY);
ASSERT_NE(system, nullptr);
ASSERT_NE(vendor, nullptr);
EXPECT_EQ(builder->ResizePartition(system, 65536), true);
@@ -263,15 +259,15 @@
TEST(liblp, AddInvalidPartition) {
unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(1024 * 1024, 1024, 2);
- Partition* partition = builder->AddPartition("system", TEST_GUID, LP_PARTITION_ATTR_READONLY);
+ Partition* partition = builder->AddPartition("system", LP_PARTITION_ATTR_READONLY);
ASSERT_NE(partition, nullptr);
// Duplicate name.
- partition = builder->AddPartition("system", TEST_GUID, LP_PARTITION_ATTR_READONLY);
+ partition = builder->AddPartition("system", LP_PARTITION_ATTR_READONLY);
EXPECT_EQ(partition, nullptr);
// Empty name.
- partition = builder->AddPartition("", TEST_GUID, LP_PARTITION_ATTR_READONLY);
+ partition = builder->AddPartition("", LP_PARTITION_ATTR_READONLY);
EXPECT_EQ(partition, nullptr);
}
@@ -282,8 +278,8 @@
unique_ptr<MetadataBuilder> builder =
MetadataBuilder::New(kDiskSize, kMetadataSize, kMetadataSlots);
- Partition* system = builder->AddPartition("system", TEST_GUID, LP_PARTITION_ATTR_READONLY);
- Partition* vendor = builder->AddPartition("vendor", TEST_GUID2, LP_PARTITION_ATTR_READONLY);
+ Partition* system = builder->AddPartition("system", LP_PARTITION_ATTR_READONLY);
+ Partition* vendor = builder->AddPartition("vendor", LP_PARTITION_ATTR_READONLY);
ASSERT_NE(system, nullptr);
ASSERT_NE(vendor, nullptr);
EXPECT_EQ(builder->ResizePartition(system, 65536), true);
@@ -322,7 +318,6 @@
for (const auto& partition : exported->partitions) {
Partition* original = builder->FindPartition(GetPartitionName(partition));
ASSERT_NE(original, nullptr);
- EXPECT_EQ(original->guid(), GetPartitionGuid(partition));
for (size_t i = 0; i < partition.num_extents; i++) {
const auto& extent = exported->extents[partition.first_extent_index + i];
LinearExtent* original_extent = original->extents()[i]->AsLinearExtent();
@@ -337,8 +332,8 @@
TEST(liblp, BuilderImport) {
unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(1024 * 1024, 1024, 2);
- Partition* system = builder->AddPartition("system", TEST_GUID, LP_PARTITION_ATTR_READONLY);
- Partition* vendor = builder->AddPartition("vendor", TEST_GUID2, LP_PARTITION_ATTR_READONLY);
+ Partition* system = builder->AddPartition("system", LP_PARTITION_ATTR_READONLY);
+ Partition* vendor = builder->AddPartition("vendor", LP_PARTITION_ATTR_READONLY);
ASSERT_NE(system, nullptr);
ASSERT_NE(vendor, nullptr);
EXPECT_EQ(builder->ResizePartition(system, 65536), true);
@@ -357,11 +352,9 @@
EXPECT_EQ(system->size(), 98304);
ASSERT_EQ(system->extents().size(), 2);
- EXPECT_EQ(system->guid(), TEST_GUID);
EXPECT_EQ(system->attributes(), LP_PARTITION_ATTR_READONLY);
EXPECT_EQ(vendor->size(), 32768);
ASSERT_EQ(vendor->extents().size(), 1);
- EXPECT_EQ(vendor->guid(), TEST_GUID2);
EXPECT_EQ(vendor->attributes(), LP_PARTITION_ATTR_READONLY);
LinearExtent* system1 = system->extents()[0]->AsLinearExtent();
@@ -378,17 +371,7 @@
unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(1024 * 1024, 1024, 2);
std::string name = "abcdefghijklmnopqrstuvwxyz0123456789";
- Partition* system = builder->AddPartition(name + name, TEST_GUID, LP_PARTITION_ATTR_READONLY);
- EXPECT_NE(system, nullptr);
-
- unique_ptr<LpMetadata> exported = builder->Export();
- EXPECT_EQ(exported, nullptr);
-}
-
-TEST(liblp, ExportInvalidGuid) {
- unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(1024 * 1024, 1024, 2);
-
- Partition* system = builder->AddPartition("system", "bad", LP_PARTITION_ATTR_READONLY);
+ Partition* system = builder->AddPartition(name + name, LP_PARTITION_ATTR_READONLY);
EXPECT_NE(system, nullptr);
unique_ptr<LpMetadata> exported = builder->Export();
@@ -483,7 +466,7 @@
unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(device_info, 1024, 1);
ASSERT_NE(builder, nullptr);
- Partition* partition = builder->AddPartition("system", TEST_GUID, 0);
+ Partition* partition = builder->AddPartition("system", 0);
ASSERT_NE(partition, nullptr);
ASSERT_TRUE(builder->ResizePartition(partition, 512));
EXPECT_EQ(partition->size(), 4096);
@@ -495,3 +478,28 @@
unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(device_info, 512, 1);
ASSERT_EQ(builder, nullptr);
}
+
+TEST(liblp, HasDefaultGroup) {
+ BlockDeviceInfo device_info(1024 * 1024, 0, 0, 4096);
+ unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(device_info, 1024, 1);
+ ASSERT_NE(builder, nullptr);
+
+ EXPECT_FALSE(builder->AddGroup("default", 0));
+}
+
+TEST(liblp, GroupSizeLimits) {
+ BlockDeviceInfo device_info(1024 * 1024, 0, 0, 4096);
+ unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(device_info, 1024, 1);
+ ASSERT_NE(builder, nullptr);
+
+ ASSERT_TRUE(builder->AddGroup("google", 16384));
+
+ Partition* partition = builder->AddPartition("system", "google", 0);
+ ASSERT_NE(partition, nullptr);
+ EXPECT_TRUE(builder->ResizePartition(partition, 8192));
+ EXPECT_EQ(partition->size(), 8192);
+ EXPECT_TRUE(builder->ResizePartition(partition, 16384));
+ EXPECT_EQ(partition->size(), 16384);
+ EXPECT_FALSE(builder->ResizePartition(partition, 32768));
+ EXPECT_EQ(partition->size(), 16384);
+}
diff --git a/fs_mgr/liblp/include/liblp/builder.h b/fs_mgr/liblp/include/liblp/builder.h
index 2780825..a6044d0 100644
--- a/fs_mgr/liblp/include/liblp/builder.h
+++ b/fs_mgr/liblp/include/liblp/builder.h
@@ -95,11 +95,24 @@
void AddTo(LpMetadata* out) const override;
};
+class PartitionGroup final {
+ public:
+ explicit PartitionGroup(const std::string& name, uint64_t maximum_size)
+ : name_(name), maximum_size_(maximum_size) {}
+
+ const std::string& name() const { return name_; }
+ uint64_t maximum_size() const { return maximum_size_; }
+
+ private:
+ std::string name_;
+ uint64_t maximum_size_;
+};
+
class Partition final {
friend class MetadataBuilder;
public:
- Partition(const std::string& name, const std::string& guid, uint32_t attributes);
+ Partition(const std::string& name, const std::string& group_name, uint32_t attributes);
// Add a raw extent.
void AddExtent(std::unique_ptr<Extent>&& extent);
@@ -107,9 +120,13 @@
// Remove all extents from this partition.
void RemoveExtents();
+ // Compute the size used by linear extents. This is the same as size(),
+ // but does not factor in extents which do not take up space.
+ uint64_t BytesOnDisk() const;
+
const std::string& name() const { return name_; }
+ const std::string& group_name() const { return group_name_; }
uint32_t attributes() const { return attributes_; }
- const std::string& guid() const { return guid_; }
const std::vector<std::unique_ptr<Extent>>& extents() const { return extents_; }
uint64_t size() const { return size_; }
@@ -117,7 +134,7 @@
void ShrinkTo(uint64_t aligned_size);
std::string name_;
- std::string guid_;
+ std::string group_name_;
std::vector<std::unique_ptr<Extent>> extents_;
uint32_t attributes_;
uint64_t size_;
@@ -156,13 +173,25 @@
return New(device_info, metadata_max_size, metadata_slot_count);
}
+ // Define a new partition group. By default there is one group called
+ // "default", with an unrestricted size. A non-zero size will restrict the
+ // total space used by all partitions in the group.
+ //
+ // This can fail and return false if the group already exists.
+ bool AddGroup(const std::string& group_name, uint64_t maximum_size);
+
// Export metadata so it can be serialized to an image, to disk, or mounted
// via device-mapper.
std::unique_ptr<LpMetadata> Export();
// Add a partition, returning a handle so it can be sized as needed. If a
// partition with the given name already exists, nullptr is returned.
- Partition* AddPartition(const std::string& name, const std::string& guid, uint32_t attributes);
+ Partition* AddPartition(const std::string& name, const std::string& group_name,
+ uint32_t attributes);
+
+ // Same as AddPartition above, but uses the default partition group which
+ // has no size restrictions.
+ Partition* AddPartition(const std::string& name, uint32_t attributes);
// Delete a partition by name if it exists.
void RemovePartition(const std::string& name);
@@ -202,10 +231,13 @@
bool GrowPartition(Partition* partition, uint64_t aligned_size);
void ShrinkPartition(Partition* partition, uint64_t aligned_size);
uint64_t AlignSector(uint64_t sector);
+ PartitionGroup* FindGroup(const std::string& group_name) const;
+ uint64_t TotalSizeOfGroup(PartitionGroup* group) const;
LpMetadataGeometry geometry_;
LpMetadataHeader header_;
std::vector<std::unique_ptr<Partition>> partitions_;
+ std::vector<std::unique_ptr<PartitionGroup>> groups_;
BlockDeviceInfo device_info_;
};
diff --git a/fs_mgr/liblp/include/liblp/liblp.h b/fs_mgr/liblp/include/liblp/liblp.h
index 6da24f6..5f95dca 100644
--- a/fs_mgr/liblp/include/liblp/liblp.h
+++ b/fs_mgr/liblp/include/liblp/liblp.h
@@ -36,6 +36,7 @@
LpMetadataHeader header;
std::vector<LpMetadataPartition> partitions;
std::vector<LpMetadataExtent> extents;
+ std::vector<LpMetadataPartitionGroup> groups;
};
// Place an initial partition table on the device. This will overwrite the
@@ -67,7 +68,7 @@
// Helper to extract safe C++ strings from partition info.
std::string GetPartitionName(const LpMetadataPartition& partition);
-std::string GetPartitionGuid(const LpMetadataPartition& partition);
+std::string GetPartitionGroupName(const LpMetadataPartitionGroup& group);
// Helper to return a slot number for a slot suffix.
uint32_t SlotNumberForSlotSuffix(const std::string& suffix);
diff --git a/fs_mgr/liblp/include/liblp/metadata_format.h b/fs_mgr/liblp/include/liblp/metadata_format.h
index 52c80f7..7d1a2a9 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 1
+#define LP_METADATA_MAJOR_VERSION 3
#define LP_METADATA_MINOR_VERSION 0
/* Attributes for the LpMetadataPartition::attributes field.
@@ -67,7 +67,7 @@
* | Geometry Backup |
* +--------------------+
*/
-#define LP_METADATA_PARTITION_NAME "super"
+#define LP_METADATA_DEFAULT_PARTITION_NAME "super"
/* Size of a sector is always 512 bytes for compatibility with the Linux kernel. */
#define LP_SECTOR_SIZE 512
@@ -216,6 +216,8 @@
LpMetadataTableDescriptor partitions;
/* 92: Extent table descriptor. */
LpMetadataTableDescriptor extents;
+ /* 104: Updateable group descriptor. */
+ LpMetadataTableDescriptor groups;
} __attribute__((packed)) LpMetadataHeader;
/* This struct defines a logical partition entry, similar to what would be
@@ -230,21 +232,21 @@
*/
char name[36];
- /* 36: Globally unique identifier (GUID) of this partition. */
- uint8_t guid[16];
-
- /* 52: Attributes for the partition (see LP_PARTITION_ATTR_* flags above). */
+ /* 36: Attributes for the partition (see LP_PARTITION_ATTR_* flags above). */
uint32_t attributes;
- /* 56: Index of the first extent owned by this partition. The extent will
+ /* 40: Index of the first extent owned by this partition. The extent will
* start at logical sector 0. Gaps between extents are not allowed.
*/
uint32_t first_extent_index;
- /* 60: Number of extents in the partition. Every partition must have at
+ /* 44: Number of extents in the partition. Every partition must have at
* least one extent.
*/
uint32_t num_extents;
+
+ /* 48: Group this partition belongs to. */
+ uint32_t group_index;
} __attribute__((packed)) LpMetadataPartition;
/* This extent is a dm-linear target, and the index is an index into the
@@ -271,6 +273,19 @@
uint64_t target_data;
} __attribute__((packed)) LpMetadataExtent;
+/* This struct defines an entry in the groups table. Each group has a maximum
+ * size, and partitions in a group must not exceed that size. There is always
+ * a "default" group of unlimited size, which is used when not using update
+ * groups or when using overlayfs or fastbootd.
+ */
+typedef struct LpMetadataPartitionGroup {
+ /* 0: Name of this group. Any unused characters must be 0. */
+ char name[36];
+
+ /* 36: Maximum size in bytes. If 0, the group has no maximum size. */
+ uint64_t maximum_size;
+} LpMetadataPartitionGroup;
+
#ifdef __cplusplus
} /* extern "C" */
#endif
diff --git a/fs_mgr/liblp/io_test.cpp b/fs_mgr/liblp/io_test.cpp
index eda68fd..01de3ac 100644
--- a/fs_mgr/liblp/io_test.cpp
+++ b/fs_mgr/liblp/io_test.cpp
@@ -37,8 +37,6 @@
static const size_t kDiskSize = 131072;
static const size_t kMetadataSize = 512;
static const size_t kMetadataSlots = 2;
-static const char* TEST_GUID_BASE = "A799D1D6-669F-41D8-A3F0-EBB7572D830";
-static const char* TEST_GUID = "A799D1D6-669F-41D8-A3F0-EBB7572D8302";
// Helper function for creating an in-memory file descriptor. This lets us
// simulate read/writing logical partition metadata as if we had a block device
@@ -81,7 +79,7 @@
}
static bool AddDefaultPartitions(MetadataBuilder* builder) {
- Partition* system = builder->AddPartition("system", TEST_GUID, LP_PARTITION_ATTR_NONE);
+ Partition* system = builder->AddPartition("system", LP_PARTITION_ATTR_NONE);
if (!system) {
return false;
}
@@ -171,7 +169,6 @@
// Check partition tables.
ASSERT_EQ(exported->partitions.size(), imported->partitions.size());
EXPECT_EQ(GetPartitionName(exported->partitions[0]), GetPartitionName(imported->partitions[0]));
- EXPECT_EQ(GetPartitionGuid(exported->partitions[0]), GetPartitionGuid(imported->partitions[0]));
EXPECT_EQ(exported->partitions[0].attributes, imported->partitions[0].attributes);
EXPECT_EQ(exported->partitions[0].first_extent_index,
imported->partitions[0].first_extent_index);
@@ -331,21 +328,18 @@
unique_ptr<MetadataBuilder> builder = CreateDefaultBuilder();
ASSERT_NE(builder, nullptr);
- // Compute the maximum number of partitions we can fit in 1024 bytes of metadata.
- size_t max_partitions = (kMetadataSize - sizeof(LpMetadataHeader)) / sizeof(LpMetadataPartition);
- EXPECT_LT(max_partitions, 10);
+ // Compute the maximum number of partitions we can fit in 512 bytes of
+ // metadata. By default there is the header, and one partition group.
+ static const size_t kMaxPartitionTableSize =
+ kMetadataSize - sizeof(LpMetadataHeader) - sizeof(LpMetadataPartitionGroup);
+ size_t max_partitions = kMaxPartitionTableSize / sizeof(LpMetadataPartition);
// Add this number of partitions.
Partition* partition = nullptr;
for (size_t i = 0; i < max_partitions; i++) {
- std::string guid = std::string(TEST_GUID) + to_string(i);
- partition = builder->AddPartition(to_string(i), TEST_GUID, LP_PARTITION_ATTR_NONE);
+ partition = builder->AddPartition(to_string(i), LP_PARTITION_ATTR_NONE);
ASSERT_NE(partition, nullptr);
}
- ASSERT_NE(partition, nullptr);
- // Add one extent to any partition to fill up more space - we're at 508
- // bytes after this, out of 512.
- ASSERT_TRUE(builder->ResizePartition(partition, 1024));
unique_ptr<LpMetadata> exported = builder->Export();
ASSERT_NE(exported, nullptr);
@@ -357,7 +351,7 @@
ASSERT_TRUE(FlashPartitionTable(fd, *exported.get()));
// Check that adding one more partition overflows the metadata allotment.
- partition = builder->AddPartition("final", TEST_GUID, LP_PARTITION_ATTR_NONE);
+ partition = builder->AddPartition("final", LP_PARTITION_ATTR_NONE);
EXPECT_NE(partition, nullptr);
exported = builder->Export();
diff --git a/fs_mgr/liblp/reader.cpp b/fs_mgr/liblp/reader.cpp
index 190c650..005d493 100644
--- a/fs_mgr/liblp/reader.cpp
+++ b/fs_mgr/liblp/reader.cpp
@@ -188,7 +188,8 @@
return false;
}
if (!ValidateTableBounds(header, header.partitions) ||
- !ValidateTableBounds(header, header.extents)) {
+ !ValidateTableBounds(header, header.extents) ||
+ !ValidateTableBounds(header, header.groups)) {
LERROR << "Logical partition metadata has invalid table bounds.";
return false;
}
@@ -202,6 +203,10 @@
LERROR << "Logical partition metadata has invalid extent table entry size.";
return false;
}
+ if (header.groups.entry_size != sizeof(LpMetadataPartitionGroup)) {
+ LERROR << "Logical partition metadata has invalid group table entry size.";
+ return false;
+ }
return true;
}
@@ -257,6 +262,10 @@
LERROR << "Logical partition has invalid extent list.";
return nullptr;
}
+ if (partition.group_index >= header.groups.num_entries) {
+ LERROR << "Logical partition has invalid group index.";
+ return nullptr;
+ }
metadata->partitions.push_back(partition);
}
@@ -269,6 +278,16 @@
metadata->extents.push_back(extent);
}
+
+ cursor = buffer.get() + header.groups.offset;
+ for (size_t i = 0; i < header.groups.num_entries; i++) {
+ LpMetadataPartitionGroup group = {};
+ memcpy(&group, cursor, sizeof(group));
+ cursor += header.groups.entry_size;
+
+ metadata->groups.push_back(group);
+ }
+
return metadata;
}
@@ -345,5 +364,9 @@
return NameFromFixedArray(partition.name, sizeof(partition.name));
}
+std::string GetPartitionGroupName(const LpMetadataPartitionGroup& group) {
+ return NameFromFixedArray(group.name, sizeof(group.name));
+}
+
} // namespace fs_mgr
} // namespace android
diff --git a/fs_mgr/liblp/utility.cpp b/fs_mgr/liblp/utility.cpp
index a590037..b08f96c 100644
--- a/fs_mgr/liblp/utility.cpp
+++ b/fs_mgr/liblp/utility.cpp
@@ -23,7 +23,6 @@
#include <android-base/file.h>
#include <ext4_utils/ext4_utils.h>
#include <openssl/sha.h>
-#include <uuid/uuid.h>
#include "utility.h"
@@ -80,15 +79,6 @@
SHA256_Final(out, &c);
}
-std::string GetPartitionGuid(const LpMetadataPartition& partition) {
- // 32 hex characters, four hyphens. Unfortunately libext2_uuid provides no
- // macro to assist with buffer sizing.
- static const size_t kGuidLen = 36;
- char buffer[kGuidLen + 1];
- uuid_unparse_upper(partition.guid, buffer);
- return buffer;
-}
-
uint32_t SlotNumberForSlotSuffix(const std::string& suffix) {
if (suffix.empty()) {
return 0;
diff --git a/fs_mgr/liblp/writer.cpp b/fs_mgr/liblp/writer.cpp
index 9dd2745..2415629 100644
--- a/fs_mgr/liblp/writer.cpp
+++ b/fs_mgr/liblp/writer.cpp
@@ -56,14 +56,17 @@
metadata.partitions.size() * sizeof(LpMetadataPartition));
std::string extents(reinterpret_cast<const char*>(metadata.extents.data()),
metadata.extents.size() * sizeof(LpMetadataExtent));
+ std::string groups(reinterpret_cast<const char*>(metadata.groups.data()),
+ metadata.groups.size() * sizeof(LpMetadataPartitionGroup));
// Compute positions of tables.
header.partitions.offset = 0;
header.extents.offset = header.partitions.offset + partitions.size();
- header.tables_size = header.extents.offset + extents.size();
+ header.groups.offset = header.extents.offset + extents.size();
+ header.tables_size = header.groups.offset + groups.size();
// Compute payload checksum.
- std::string tables = partitions + extents;
+ std::string tables = partitions + extents + groups;
SHA256(tables.data(), tables.size(), header.tables_checksum);
// Compute header checksum.
diff --git a/fs_mgr/tests/fs_mgr_test.cpp b/fs_mgr/tests/fs_mgr_test.cpp
index 8b1c55a..db01c1e 100644
--- a/fs_mgr/tests/fs_mgr_test.cpp
+++ b/fs_mgr/tests/fs_mgr_test.cpp
@@ -139,7 +139,7 @@
auto fstab = fs_mgr_read_fstab("/proc/mounts");
ASSERT_NE(fstab, nullptr);
- std::unique_ptr<std::FILE, int (*)(std::FILE*)> mounts(setmntent("/proc/mounts", "r"),
+ std::unique_ptr<std::FILE, int (*)(std::FILE*)> mounts(setmntent("/proc/mounts", "re"),
endmntent);
ASSERT_NE(mounts, nullptr);
diff --git a/fs_mgr/tools/dmctl.cpp b/fs_mgr/tools/dmctl.cpp
index 879ba21..f78093b 100644
--- a/fs_mgr/tools/dmctl.cpp
+++ b/fs_mgr/tools/dmctl.cpp
@@ -42,6 +42,7 @@
using DmTargetLinear = ::android::dm::DmTargetLinear;
using DmTargetZero = ::android::dm::DmTargetZero;
using DmTargetAndroidVerity = ::android::dm::DmTargetAndroidVerity;
+using DmTargetBow = ::android::dm::DmTargetBow;
using DmTargetTypeInfo = ::android::dm::DmTargetTypeInfo;
using DmBlockDevice = ::android::dm::DeviceMapper::DmBlockDevice;
@@ -108,6 +109,13 @@
std::string block_device = NextArg();
return std::make_unique<DmTargetAndroidVerity>(start_sector, num_sectors, keyid,
block_device);
+ } else if (target_type == "bow") {
+ if (!HasArgs(1)) {
+ std::cerr << "Expected \"bow\" <block_device>" << std::endl;
+ return nullptr;
+ }
+ std::string block_device = NextArg();
+ return std::make_unique<DmTargetBow>(start_sector, num_sectors, block_device);
} else {
std::cerr << "Unrecognized target type: " << target_type << std::endl;
return nullptr;
diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp
index 71a8e0d..684bf1f 100644
--- a/init/first_stage_mount.cpp
+++ b/init/first_stage_mount.cpp
@@ -68,6 +68,7 @@
bool CreateLogicalPartitions();
bool MountPartition(fstab_rec* fstab_rec);
bool MountPartitions();
+ bool IsDmLinearEnabled();
bool GetBackingDmLinearDevices();
virtual ListenerAction UeventCallback(const Uevent& uevent);
@@ -82,6 +83,7 @@
std::string lp_metadata_partition_;
std::vector<fstab_rec*> mount_fstab_recs_;
std::set<std::string> required_devices_partition_names_;
+ std::string super_partition_name_;
std::unique_ptr<DeviceHandler> device_handler_;
UeventListener uevent_listener_;
};
@@ -134,22 +136,6 @@
return !ForceNormalBoot() && access("/system/bin/recovery", F_OK) == 0;
}
-static inline bool IsDmLinearEnabled() {
- static bool checked = false;
- static bool enabled = false;
- if (checked) {
- return enabled;
- }
- import_kernel_cmdline(false,
- [](const std::string& key, const std::string& value, bool in_qemu) {
- if (key == "androidboot.logical_partitions" && value == "1") {
- enabled = true;
- }
- });
- checked = true;
- return enabled;
-}
-
// Class Definitions
// -----------------
FirstStageMount::FirstStageMount()
@@ -168,6 +154,8 @@
device_handler_ = std::make_unique<DeviceHandler>(
std::vector<Permissions>{}, std::vector<SysfsPermissions>{}, std::vector<Subsystem>{},
std::move(boot_devices), false);
+
+ super_partition_name_ = fs_mgr_get_super_partition_name();
}
std::unique_ptr<FirstStageMount> FirstStageMount::Create() {
@@ -198,13 +186,20 @@
return GetBackingDmLinearDevices() && GetDmVerityDevices() && InitRequiredDevices();
}
+bool FirstStageMount::IsDmLinearEnabled() {
+ for (auto fstab_rec : mount_fstab_recs_) {
+ if (fs_mgr_is_logical(fstab_rec)) return true;
+ }
+ return false;
+}
+
bool FirstStageMount::GetBackingDmLinearDevices() {
// Add any additional devices required for dm-linear mappings.
if (!IsDmLinearEnabled()) {
return true;
}
- required_devices_partition_names_.emplace(LP_METADATA_PARTITION_NAME);
+ required_devices_partition_names_.emplace(super_partition_name_);
return true;
}
@@ -270,7 +265,7 @@
if (lp_metadata_partition_.empty()) {
LOG(ERROR) << "Could not locate logical partition tables in partition "
- << LP_METADATA_PARTITION_NAME;
+ << super_partition_name_;
return false;
}
return android::fs_mgr::CreateLogicalPartitions(lp_metadata_partition_);
@@ -283,7 +278,7 @@
auto iter = required_devices_partition_names_.find(name);
if (iter != required_devices_partition_names_.end()) {
LOG(VERBOSE) << __PRETTY_FUNCTION__ << ": found partition: " << *iter;
- if (IsDmLinearEnabled() && name == LP_METADATA_PARTITION_NAME) {
+ if (IsDmLinearEnabled() && name == super_partition_name_) {
std::vector<std::string> links = device_handler_->GetBlockDeviceSymlinks(uevent);
lp_metadata_partition_ = links[0];
}
diff --git a/init/reboot.cpp b/init/reboot.cpp
index b84bfd3..866f40e 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -162,7 +162,7 @@
*/
static bool FindPartitionsToUmount(std::vector<MountEntry>* blockDevPartitions,
std::vector<MountEntry>* emulatedPartitions, bool dump) {
- std::unique_ptr<std::FILE, int (*)(std::FILE*)> fp(setmntent("/proc/mounts", "r"), endmntent);
+ std::unique_ptr<std::FILE, int (*)(std::FILE*)> fp(setmntent("/proc/mounts", "re"), endmntent);
if (fp == nullptr) {
PLOG(ERROR) << "Failed to open /proc/mounts";
return false;
diff --git a/libbacktrace/Android.bp b/libbacktrace/Android.bp
index c42ae49..43bcd98 100644
--- a/libbacktrace/Android.bp
+++ b/libbacktrace/Android.bp
@@ -27,15 +27,6 @@
enabled: false,
},
},
-
- multilib: {
- lib32: {
- suffix: "32",
- },
- lib64: {
- suffix: "64",
- },
- },
}
libbacktrace_sources = [
@@ -108,7 +99,7 @@
whole_static_libs: ["libdemangle"],
}
-cc_library_shared {
+cc_test_library {
name: "libbacktrace_test",
defaults: ["libbacktrace_common"],
host_supported: true,
@@ -121,6 +112,21 @@
shared_libs: [
"libunwindstack",
],
+ relative_install_path: "backtrace_test_libs",
+
+ target: {
+ linux_glibc: {
+ // The host uses rosegment, which isn't supported yet.
+ ldflags: [
+ "-Wl,--no-rosegment",
+ ],
+ // This forces the creation of eh_frame with unwind information
+ // for host.
+ cflags: [
+ "-fcxx-exceptions"
+ ],
+ },
+ },
}
//-------------------------------------------------------------------------
@@ -128,12 +134,12 @@
//-------------------------------------------------------------------------
cc_test {
name: "backtrace_test",
+ isolated: true,
defaults: ["libbacktrace_common"],
host_supported: true,
srcs: [
"backtrace_offline_test.cpp",
"backtrace_test.cpp",
- "GetPss.cpp",
],
cflags: [
@@ -143,7 +149,6 @@
],
shared_libs: [
- "libbacktrace_test",
"libbacktrace",
"libbase",
"liblog",
@@ -152,17 +157,10 @@
group_static_libs: true,
- target: {
- android: {
- cflags: ["-DENABLE_PSS_TESTS"],
- shared_libs: [
- "libutils",
- ],
- },
- linux_glibc: {
- static_libs: ["libutils"],
- },
- },
+ // So that the dlopen can find the libbacktrace_test.so.
+ ldflags: [
+ "-Wl,--rpath,${ORIGIN}/../backtrace_test_libs",
+ ],
test_suites: ["device-tests"],
data: [
diff --git a/libbacktrace/BacktraceTest.h b/libbacktrace/BacktraceTest.h
new file mode 100644
index 0000000..c38af04
--- /dev/null
+++ b/libbacktrace/BacktraceTest.h
@@ -0,0 +1,78 @@
+/*
+ * 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_BACKTRACE_TEST_H
+#define _LIBBACKTRACE_BACKTRACE_TEST_H
+
+#include <dlfcn.h>
+
+#include <gtest/gtest.h>
+
+class BacktraceTest : public ::testing::Test {
+ protected:
+ static void SetUpTestCase() {
+ dl_handle_ = dlopen("libbacktrace_test.so", RTLD_NOW | RTLD_LOCAL);
+
+ test_level_one_ = reinterpret_cast<int (*)(int, int, int, int, void (*)(void*), void*)>(
+ dlsym(dl_handle_, "test_level_one"));
+
+ test_level_two_ = reinterpret_cast<int (*)(int, int, int, int, void (*)(void*), void*)>(
+ dlsym(dl_handle_, "test_level_two"));
+
+ test_level_three_ = reinterpret_cast<int (*)(int, int, int, int, void (*)(void*), void*)>(
+ dlsym(dl_handle_, "test_level_three"));
+
+ test_level_four_ = reinterpret_cast<int (*)(int, int, int, int, void (*)(void*), void*)>(
+ dlsym(dl_handle_, "test_level_four"));
+
+ test_recursive_call_ = reinterpret_cast<int (*)(int, void (*)(void*), void*)>(
+ dlsym(dl_handle_, "test_recursive_call"));
+
+ test_get_context_and_wait_ = reinterpret_cast<void (*)(void*, volatile int*)>(
+ dlsym(dl_handle_, "test_get_context_and_wait"));
+
+ test_signal_action_ =
+ reinterpret_cast<void (*)(int, siginfo_t*, void*)>(dlsym(dl_handle_, "test_signal_action"));
+
+ test_signal_handler_ =
+ reinterpret_cast<void (*)(int)>(dlsym(dl_handle_, "test_signal_handler"));
+ }
+
+ void SetUp() override {
+ ASSERT_TRUE(dl_handle_ != nullptr);
+ ASSERT_TRUE(test_level_one_ != nullptr);
+ ASSERT_TRUE(test_level_two_ != nullptr);
+ ASSERT_TRUE(test_level_three_ != nullptr);
+ ASSERT_TRUE(test_level_four_ != nullptr);
+ ASSERT_TRUE(test_recursive_call_ != nullptr);
+ ASSERT_TRUE(test_get_context_and_wait_ != nullptr);
+ ASSERT_TRUE(test_signal_action_ != nullptr);
+ ASSERT_TRUE(test_signal_handler_ != nullptr);
+ }
+
+ public:
+ static void* dl_handle_;
+ static int (*test_level_one_)(int, int, int, int, void (*)(void*), void*);
+ static int (*test_level_two_)(int, int, int, int, void (*)(void*), void*);
+ static int (*test_level_three_)(int, int, int, int, void (*)(void*), void*);
+ static int (*test_level_four_)(int, int, int, int, void (*)(void*), void*);
+ static int (*test_recursive_call_)(int, void (*)(void*), void*);
+ static void (*test_get_context_and_wait_)(void*, volatile int*);
+ static void (*test_signal_action_)(int, siginfo_t*, void*);
+ static void (*test_signal_handler_)(int);
+};
+
+#endif // _LIBBACKTRACE_BACKTRACE_TEST_H
diff --git a/libbacktrace/GetPss.cpp b/libbacktrace/GetPss.cpp
deleted file mode 100644
index 6d750ea..0000000
--- a/libbacktrace/GetPss.cpp
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) 2014 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 <inttypes.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <fcntl.h>
-
-// This is an extremely simplified version of libpagemap.
-
-#define _BITS(x, offset, bits) (((x) >> (offset)) & ((1LL << (bits)) - 1))
-
-#define PAGEMAP_PRESENT(x) (_BITS(x, 63, 1))
-#define PAGEMAP_SWAPPED(x) (_BITS(x, 62, 1))
-#define PAGEMAP_SHIFT(x) (_BITS(x, 55, 6))
-#define PAGEMAP_PFN(x) (_BITS(x, 0, 55))
-#define PAGEMAP_SWAP_OFFSET(x) (_BITS(x, 5, 50))
-#define PAGEMAP_SWAP_TYPE(x) (_BITS(x, 0, 5))
-
-static bool ReadData(int fd, off_t place, uint64_t *data) {
- if (lseek(fd, place * sizeof(uint64_t), SEEK_SET) < 0) {
- return false;
- }
- if (read(fd, (void*)data, sizeof(uint64_t)) != (ssize_t)sizeof(uint64_t)) {
- return false;
- }
- return true;
-}
-
-size_t GetPssBytes() {
- FILE* maps = fopen("/proc/self/maps", "r");
- if (maps == nullptr) {
- return 0;
- }
-
- int pagecount_fd = open("/proc/kpagecount", O_RDONLY);
- if (pagecount_fd == -1) {
- fclose(maps);
- return 0;
- }
-
- int pagemap_fd = open("/proc/self/pagemap", O_RDONLY);
- if (pagemap_fd == -1) {
- fclose(maps);
- close(pagecount_fd);
- return 0;
- }
-
- char line[4096];
- size_t total_pss = 0;
- int pagesize = getpagesize();
- while (fgets(line, sizeof(line), maps)) {
- uintptr_t start, end;
- if (sscanf(line, "%" SCNxPTR "-%" SCNxPTR " ", &start, &end) != 2) {
- total_pss = 0;
- break;
- }
- for (off_t page = static_cast<off_t>(start/pagesize);
- page < static_cast<off_t>(end/pagesize); page++) {
- uint64_t data;
- if (ReadData(pagemap_fd, page, &data)) {
- if (PAGEMAP_PRESENT(data) && !PAGEMAP_SWAPPED(data)) {
- uint64_t count;
- if (ReadData(pagecount_fd, static_cast<off_t>(PAGEMAP_PFN(data)), &count)) {
- total_pss += (count >= 1) ? pagesize / count : 0;
- }
- }
- }
- }
- }
-
- fclose(maps);
-
- close(pagecount_fd);
- close(pagemap_fd);
-
- return total_pss;
-}
diff --git a/libbacktrace/GetPss.h b/libbacktrace/GetPss.h
deleted file mode 100644
index 787c33d..0000000
--- a/libbacktrace/GetPss.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (C) 2014 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_GET_PSS_H
-#define _LIBBACKTRACE_GET_PSS_H
-
-size_t GetPssBytes();
-
-#endif // _LIBBACKTRACE_GET_PSS_H
diff --git a/libbacktrace/backtrace_offline_test.cpp b/libbacktrace/backtrace_offline_test.cpp
index 7d1027e..662fb99 100644
--- a/libbacktrace/backtrace_offline_test.cpp
+++ b/libbacktrace/backtrace_offline_test.cpp
@@ -37,15 +37,7 @@
#include <gtest/gtest.h>
-extern "C" {
-// Prototypes for functions in the test library.
-int test_level_one(int, int, int, int, void (*)(void*), void*);
-int test_level_two(int, int, int, int, void (*)(void*), void*);
-int test_level_three(int, int, int, int, void (*)(void*), void*);
-int test_level_four(int, int, int, int, void (*)(void*), void*);
-int test_recursive_call(int, void (*)(void*), void*);
-void test_get_context_and_wait(void* context, volatile int* exit_flag);
-}
+#include "BacktraceTest.h"
struct FunctionSymbol {
std::string name;
@@ -56,12 +48,13 @@
static std::vector<FunctionSymbol> GetFunctionSymbols() {
std::vector<FunctionSymbol> symbols = {
{"unknown_start", 0, 0},
- {"test_level_one", reinterpret_cast<uint64_t>(&test_level_one), 0},
- {"test_level_two", reinterpret_cast<uint64_t>(&test_level_two), 0},
- {"test_level_three", reinterpret_cast<uint64_t>(&test_level_three), 0},
- {"test_level_four", reinterpret_cast<uint64_t>(&test_level_four), 0},
- {"test_recursive_call", reinterpret_cast<uint64_t>(&test_recursive_call), 0},
- {"test_get_context_and_wait", reinterpret_cast<uint64_t>(&test_get_context_and_wait), 0},
+ {"test_level_one", reinterpret_cast<uint64_t>(&BacktraceTest::test_level_one_), 0},
+ {"test_level_two", reinterpret_cast<uint64_t>(&BacktraceTest::test_level_two_), 0},
+ {"test_level_three", reinterpret_cast<uint64_t>(&BacktraceTest::test_level_three_), 0},
+ {"test_level_four", reinterpret_cast<uint64_t>(&BacktraceTest::test_level_four_), 0},
+ {"test_recursive_call", reinterpret_cast<uint64_t>(&BacktraceTest::test_recursive_call_), 0},
+ {"test_get_context_and_wait",
+ reinterpret_cast<uint64_t>(&BacktraceTest::test_get_context_and_wait_), 0},
{"unknown_end", static_cast<uint64_t>(-1), static_cast<uint64_t>(-1)},
};
std::sort(
@@ -100,7 +93,7 @@
static void* OfflineThreadFunc(void* arg) {
OfflineThreadArg* fn_arg = reinterpret_cast<OfflineThreadArg*>(arg);
fn_arg->tid = android::base::GetThreadId();
- test_get_context_and_wait(&fn_arg->ucontext, &fn_arg->exit_flag);
+ BacktraceTest::test_get_context_and_wait_(&fn_arg->ucontext, &fn_arg->exit_flag);
return nullptr;
}
@@ -109,7 +102,7 @@
}
// This test is disable because it is for generating test data.
-TEST(libbacktrace, DISABLED_generate_offline_testdata) {
+TEST_F(BacktraceTest, DISABLED_generate_offline_testdata) {
// Create a thread to generate the needed stack and registers information.
const size_t stack_size = 16 * 1024;
void* stack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
@@ -304,22 +297,22 @@
}
// For now, these tests can only run on the given architectures.
-TEST(libbacktrace, offline_eh_frame) {
+TEST_F(BacktraceTest, offline_eh_frame) {
BacktraceOfflineTest("arm64", "libbacktrace_test_eh_frame.so");
BacktraceOfflineTest("x86_64", "libbacktrace_test_eh_frame.so");
}
-TEST(libbacktrace, offline_debug_frame) {
+TEST_F(BacktraceTest, offline_debug_frame) {
BacktraceOfflineTest("arm", "libbacktrace_test_debug_frame.so");
BacktraceOfflineTest("x86", "libbacktrace_test_debug_frame.so");
}
-TEST(libbacktrace, offline_gnu_debugdata) {
+TEST_F(BacktraceTest, offline_gnu_debugdata) {
BacktraceOfflineTest("arm", "libbacktrace_test_gnu_debugdata.so");
BacktraceOfflineTest("x86", "libbacktrace_test_gnu_debugdata.so");
}
-TEST(libbacktrace, offline_arm_exidx) {
+TEST_F(BacktraceTest, offline_arm_exidx) {
BacktraceOfflineTest("arm", "libbacktrace_test_arm_exidx.so");
}
@@ -373,32 +366,32 @@
// This test tests the situation that ranges of functions covered by .eh_frame and .ARM.exidx
// overlap with each other, which appears in /system/lib/libart.so.
-TEST(libbacktrace, offline_unwind_mix_eh_frame_and_arm_exidx) {
+TEST_F(BacktraceTest, offline_unwind_mix_eh_frame_and_arm_exidx) {
LibUnwindingTest("arm", "offline_testdata_for_libart", "libart.so");
}
-TEST(libbacktrace, offline_debug_frame_with_load_bias) {
+TEST_F(BacktraceTest, offline_debug_frame_with_load_bias) {
LibUnwindingTest("arm", "offline_testdata_for_libandroid_runtime", "libandroid_runtime.so");
}
-TEST(libbacktrace, offline_try_armexidx_after_debug_frame) {
+TEST_F(BacktraceTest, offline_try_armexidx_after_debug_frame) {
LibUnwindingTest("arm", "offline_testdata_for_libGLESv2_adreno", "libGLESv2_adreno.so");
}
-TEST(libbacktrace, offline_cie_with_P_augmentation) {
+TEST_F(BacktraceTest, offline_cie_with_P_augmentation) {
// Make sure we can unwind through functions with CIE entry containing P augmentation, which
// makes unwinding library reading personality handler from memory. One example is
// /system/lib64/libskia.so.
LibUnwindingTest("arm64", "offline_testdata_for_libskia", "libskia.so");
}
-TEST(libbacktrace, offline_empty_eh_frame_hdr) {
+TEST_F(BacktraceTest, offline_empty_eh_frame_hdr) {
// Make sure we can unwind through libraries with empty .eh_frame_hdr section. One example is
// /vendor/lib64/egl/eglSubDriverAndroid.so.
LibUnwindingTest("arm64", "offline_testdata_for_eglSubDriverAndroid", "eglSubDriverAndroid.so");
}
-TEST(libbacktrace, offline_max_frames_limit) {
+TEST_F(BacktraceTest, offline_max_frames_limit) {
// The length of callchain can reach 256 when recording an application.
ASSERT_GE(MAX_BACKTRACE_FRAMES, 256);
}
diff --git a/libbacktrace/backtrace_test.cpp b/libbacktrace/backtrace_test.cpp
index 06a32c7..f4191b9 100644
--- a/libbacktrace/backtrace_test.cpp
+++ b/libbacktrace/backtrace_test.cpp
@@ -20,6 +20,7 @@
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
+#include <malloc.h>
#include <pthread.h>
#include <signal.h>
#include <stdint.h>
@@ -55,6 +56,7 @@
// For the THREAD_SIGNAL definition.
#include "BacktraceCurrent.h"
+#include "BacktraceTest.h"
#include "backtrace_testlib.h"
// Number of microseconds per milliseconds.
@@ -95,6 +97,23 @@
static void VerifyMaxDump(Backtrace* backtrace, create_func_t create_func = nullptr,
map_create_func_t map_func = nullptr);
+void* BacktraceTest::dl_handle_;
+int (*BacktraceTest::test_level_one_)(int, int, int, int, void (*)(void*), void*);
+int (*BacktraceTest::test_level_two_)(int, int, int, int, void (*)(void*), void*);
+int (*BacktraceTest::test_level_three_)(int, int, int, int, void (*)(void*), void*);
+int (*BacktraceTest::test_level_four_)(int, int, int, int, void (*)(void*), void*);
+int (*BacktraceTest::test_recursive_call_)(int, void (*)(void*), void*);
+void (*BacktraceTest::test_get_context_and_wait_)(void*, volatile int*);
+void (*BacktraceTest::test_signal_action_)(int, siginfo_t*, void*);
+void (*BacktraceTest::test_signal_handler_)(int);
+
+extern "C" bool GetInitialArgs(const char*** args, size_t* num_args) {
+ static const char* initial_args[] = {"--slow_threshold_ms=8000", "--deadline_threshold_ms=15000"};
+ *args = initial_args;
+ *num_args = 2;
+ return true;
+}
+
static uint64_t NanoTime() {
struct timespec t = { 0, 0 };
clock_gettime(CLOCK_MONOTONIC, &t);
@@ -250,7 +269,7 @@
return false;
}
-TEST(libbacktrace, local_no_unwind_frames) {
+TEST_F(BacktraceTest, local_no_unwind_frames) {
// Verify that a local unwind does not include any frames within
// libunwind or libbacktrace.
std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), getpid()));
@@ -270,7 +289,7 @@
}
}
-TEST(libbacktrace, local_unwind_frames) {
+TEST_F(BacktraceTest, local_unwind_frames) {
// Verify that a local unwind with the skip frames disabled does include
// frames within the backtrace libraries.
std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), getpid()));
@@ -302,8 +321,8 @@
<< DumpFrames(backtrace.get());
}
-TEST(libbacktrace, local_trace) {
- ASSERT_NE(test_level_one(1, 2, 3, 4, VerifyLevelBacktrace, nullptr), 0);
+TEST_F(BacktraceTest, local_trace) {
+ ASSERT_NE(test_level_one_(1, 2, 3, 4, VerifyLevelBacktrace, nullptr), 0);
}
static void VerifyIgnoreFrames(Backtrace* bt_all, Backtrace* bt_ign1, Backtrace* bt_ign2,
@@ -357,12 +376,12 @@
VerifyIgnoreFrames(all.get(), ign1.get(), ign2.get(), "VerifyLevelIgnoreFrames");
}
-TEST(libbacktrace, local_trace_ignore_frames) {
- ASSERT_NE(test_level_one(1, 2, 3, 4, VerifyLevelIgnoreFrames, nullptr), 0);
+TEST_F(BacktraceTest, local_trace_ignore_frames) {
+ ASSERT_NE(test_level_one_(1, 2, 3, 4, VerifyLevelIgnoreFrames, nullptr), 0);
}
-TEST(libbacktrace, local_max_trace) {
- ASSERT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, VerifyMaxBacktrace, nullptr), 0);
+TEST_F(BacktraceTest, local_max_trace) {
+ ASSERT_NE(test_recursive_call_(MAX_BACKTRACE_FRAMES + 10, VerifyMaxBacktrace, nullptr), 0);
}
static void VerifyProcTest(pid_t pid, pid_t tid, bool (*ReadyFunc)(Backtrace*),
@@ -402,10 +421,10 @@
ASSERT_TRUE(verified) << "Last backtrace:\n" << last_dump;
}
-TEST(libbacktrace, ptrace_trace) {
+TEST_F(BacktraceTest, ptrace_trace) {
pid_t pid;
if ((pid = fork()) == 0) {
- ASSERT_NE(test_level_one(1, 2, 3, 4, nullptr, nullptr), 0);
+ ASSERT_NE(test_level_one_(1, 2, 3, 4, nullptr, nullptr), 0);
_exit(1);
}
VerifyProcTest(pid, BACKTRACE_CURRENT_THREAD, ReadyLevelBacktrace, VerifyLevelDump,
@@ -416,10 +435,10 @@
ASSERT_EQ(waitpid(pid, &status, 0), pid);
}
-TEST(libbacktrace, ptrace_max_trace) {
+TEST_F(BacktraceTest, ptrace_max_trace) {
pid_t pid;
if ((pid = fork()) == 0) {
- ASSERT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, nullptr, nullptr), 0);
+ ASSERT_NE(test_recursive_call_(MAX_BACKTRACE_FRAMES + 10, nullptr, nullptr), 0);
_exit(1);
}
VerifyProcTest(pid, BACKTRACE_CURRENT_THREAD, ReadyMaxBacktrace, VerifyMaxDump, Backtrace::Create,
@@ -446,10 +465,10 @@
VerifyIgnoreFrames(bt_all, ign1.get(), ign2.get(), nullptr);
}
-TEST(libbacktrace, ptrace_ignore_frames) {
+TEST_F(BacktraceTest, ptrace_ignore_frames) {
pid_t pid;
if ((pid = fork()) == 0) {
- ASSERT_NE(test_level_one(1, 2, 3, 4, nullptr, nullptr), 0);
+ ASSERT_NE(test_level_one_(1, 2, 3, 4, nullptr, nullptr), 0);
_exit(1);
}
VerifyProcTest(pid, BACKTRACE_CURRENT_THREAD, ReadyLevelBacktrace, VerifyProcessIgnoreFrames,
@@ -462,7 +481,7 @@
// Create a process with multiple threads and dump all of the threads.
static void* PtraceThreadLevelRun(void*) {
- EXPECT_NE(test_level_one(1, 2, 3, 4, nullptr, nullptr), 0);
+ EXPECT_NE(BacktraceTest::test_level_one_(1, 2, 3, 4, nullptr, nullptr), 0);
return nullptr;
}
@@ -483,7 +502,7 @@
}
}
-TEST(libbacktrace, ptrace_threads) {
+TEST_F(BacktraceTest, ptrace_threads) {
pid_t pid;
if ((pid = fork()) == 0) {
for (size_t i = 0; i < NUM_PTRACE_THREADS; i++) {
@@ -494,7 +513,7 @@
pthread_t thread;
ASSERT_TRUE(pthread_create(&thread, &attr, PtraceThreadLevelRun, nullptr) == 0);
}
- ASSERT_NE(test_level_one(1, 2, 3, 4, nullptr, nullptr), 0);
+ ASSERT_NE(test_level_one_(1, 2, 3, 4, nullptr, nullptr), 0);
_exit(1);
}
@@ -532,8 +551,8 @@
VerifyLevelDump(backtrace.get());
}
-TEST(libbacktrace, thread_current_level) {
- ASSERT_NE(test_level_one(1, 2, 3, 4, VerifyLevelThread, nullptr), 0);
+TEST_F(BacktraceTest, thread_current_level) {
+ ASSERT_NE(test_level_one_(1, 2, 3, 4, VerifyLevelThread, nullptr), 0);
}
static void VerifyMaxThread(void*) {
@@ -545,19 +564,19 @@
VerifyMaxDump(backtrace.get());
}
-TEST(libbacktrace, thread_current_max) {
- ASSERT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, VerifyMaxThread, nullptr), 0);
+TEST_F(BacktraceTest, thread_current_max) {
+ ASSERT_NE(test_recursive_call_(MAX_BACKTRACE_FRAMES + 10, VerifyMaxThread, nullptr), 0);
}
static void* ThreadLevelRun(void* data) {
thread_t* thread = reinterpret_cast<thread_t*>(data);
thread->tid = android::base::GetThreadId();
- EXPECT_NE(test_level_one(1, 2, 3, 4, ThreadSetState, data), 0);
+ EXPECT_NE(BacktraceTest::test_level_one_(1, 2, 3, 4, ThreadSetState, data), 0);
return nullptr;
}
-TEST(libbacktrace, thread_level_trace) {
+TEST_F(BacktraceTest, thread_level_trace) {
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
@@ -607,7 +626,7 @@
EXPECT_EQ(cur_action.sa_flags, new_action.sa_flags);
}
-TEST(libbacktrace, thread_ignore_frames) {
+TEST_F(BacktraceTest, thread_ignore_frames) {
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
@@ -644,11 +663,12 @@
thread_t* thread = reinterpret_cast<thread_t*>(data);
thread->tid = android::base::GetThreadId();
- EXPECT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, ThreadSetState, data), 0);
+ EXPECT_NE(BacktraceTest::test_recursive_call_(MAX_BACKTRACE_FRAMES + 10, ThreadSetState, data),
+ 0);
return nullptr;
}
-TEST(libbacktrace, thread_max_trace) {
+TEST_F(BacktraceTest, thread_max_trace) {
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
@@ -742,17 +762,17 @@
}
}
-TEST(libbacktrace, thread_multiple_dump) {
+TEST_F(BacktraceTest, thread_multiple_dump) {
MultipleThreadDumpTest(false);
}
-TEST(libbacktrace, thread_multiple_dump_same_map) {
+TEST_F(BacktraceTest, thread_multiple_dump_same_map) {
MultipleThreadDumpTest(true);
}
// This test is for UnwindMaps that should share the same map cursor when
// multiple maps are created for the current process at the same time.
-TEST(libbacktrace, simultaneous_maps) {
+TEST_F(BacktraceTest, simultaneous_maps) {
BacktraceMap* map1 = BacktraceMap::Create(getpid());
BacktraceMap* map2 = BacktraceMap::Create(getpid());
BacktraceMap* map3 = BacktraceMap::Create(getpid());
@@ -779,7 +799,7 @@
delete map3;
}
-TEST(libbacktrace, fillin_erases) {
+TEST_F(BacktraceTest, fillin_erases) {
BacktraceMap* back_map = BacktraceMap::Create(getpid());
backtrace_map_t map;
@@ -798,7 +818,7 @@
ASSERT_EQ("", map.name);
}
-TEST(libbacktrace, format_test) {
+TEST_F(BacktraceTest, format_test) {
std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), BACKTRACE_CURRENT_THREAD));
ASSERT_TRUE(backtrace.get() != nullptr);
@@ -969,7 +989,7 @@
ASSERT_TRUE(test_it == test_maps.end());
}
-TEST(libbacktrace, verify_map_remote) {
+TEST_F(BacktraceTest, verify_map_remote) {
pid_t pid;
CreateRemoteProcess(&pid);
@@ -1069,7 +1089,7 @@
delete[] expected;
}
-TEST(libbacktrace, thread_read) {
+TEST_F(BacktraceTest, thread_read) {
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
@@ -1120,7 +1140,7 @@
}
}
-TEST(libbacktrace, process_read) {
+TEST_F(BacktraceTest, process_read) {
g_ready = 0;
pid_t pid;
if ((pid = fork()) == 0) {
@@ -1187,29 +1207,23 @@
}
static void CopySharedLibrary(const char* tmp_dir, std::string* tmp_so_name) {
- std::string system_dir;
-
-#if defined(__BIONIC__)
- system_dir = "/system/lib";
-#else
- const char* host_out_env = getenv("ANDROID_HOST_OUT");
- ASSERT_TRUE(host_out_env != nullptr);
- system_dir = std::string(host_out_env) + "/lib";
-#endif
-
-#if defined(__LP64__)
- system_dir += "64";
-#endif
+ std::string test_lib(testing::internal::GetArgvs()[0]);
+ auto const value = test_lib.find_last_of('/');
+ if (value == std::string::npos) {
+ test_lib = "../backtrace_test_libs/";
+ } else {
+ test_lib = test_lib.substr(0, value + 1) + "../backtrace_test_libs/";
+ }
+ test_lib += "libbacktrace_test.so";
*tmp_so_name = std::string(tmp_dir) + "/libbacktrace_test.so";
- std::string cp_cmd =
- android::base::StringPrintf("cp %s/libbacktrace_test.so %s", system_dir.c_str(), tmp_dir);
+ std::string cp_cmd = android::base::StringPrintf("cp %s %s", test_lib.c_str(), tmp_dir);
// Copy the shared so to a tempory directory.
ASSERT_EQ(0, system(cp_cmd.c_str()));
}
-TEST(libbacktrace, check_unreadable_elf_local) {
+TEST_F(BacktraceTest, check_unreadable_elf_local) {
TemporaryDir td;
std::string tmp_so_name;
ASSERT_NO_FATAL_FAILURE(CopySharedLibrary(td.path, &tmp_so_name));
@@ -1251,7 +1265,7 @@
VerifyFunctionsFound(found_functions);
}
-TEST(libbacktrace, check_unreadable_elf_remote) {
+TEST_F(BacktraceTest, check_unreadable_elf_remote) {
TemporaryDir td;
std::string tmp_so_name;
ASSERT_NO_FATAL_FAILURE(CopySharedLibrary(td.path, &tmp_so_name));
@@ -1390,7 +1404,7 @@
typedef int (*test_func_t)(int, int, int, int, void (*)(void*), void*);
-TEST(libbacktrace, unwind_through_unreadable_elf_local) {
+TEST_F(BacktraceTest, unwind_through_unreadable_elf_local) {
TemporaryDir td;
std::string tmp_so_name;
ASSERT_NO_FATAL_FAILURE(CopySharedLibrary(td.path, &tmp_so_name));
@@ -1405,11 +1419,9 @@
ASSERT_NE(test_func(1, 2, 3, 4, VerifyUnreadableElfBacktrace, reinterpret_cast<void*>(test_func)),
0);
-
- ASSERT_TRUE(dlclose(lib_handle) == 0);
}
-TEST(libbacktrace, unwind_through_unreadable_elf_remote) {
+TEST_F(BacktraceTest, unwind_through_unreadable_elf_remote) {
TemporaryDir td;
std::string tmp_so_name;
ASSERT_NO_FATAL_FAILURE(CopySharedLibrary(td.path, &tmp_so_name));
@@ -1428,7 +1440,6 @@
exit(0);
}
ASSERT_TRUE(pid > 0);
- ASSERT_TRUE(dlclose(lib_handle) == 0);
uint64_t start = NanoTime();
bool done = false;
@@ -1465,7 +1476,7 @@
ASSERT_TRUE(done) << "Test function never found in unwind.";
}
-TEST(libbacktrace, unwind_thread_doesnt_exist) {
+TEST_F(BacktraceTest, unwind_thread_doesnt_exist) {
std::unique_ptr<Backtrace> backtrace(
Backtrace::Create(BACKTRACE_CURRENT_PROCESS, 99999999));
ASSERT_TRUE(backtrace.get() != nullptr);
@@ -1473,18 +1484,18 @@
ASSERT_EQ(BACKTRACE_UNWIND_ERROR_THREAD_DOESNT_EXIST, backtrace->GetError().error_code);
}
-TEST(libbacktrace, local_get_function_name_before_unwind) {
+TEST_F(BacktraceTest, local_get_function_name_before_unwind) {
std::unique_ptr<Backtrace> backtrace(
Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD));
ASSERT_TRUE(backtrace.get() != nullptr);
// Verify that trying to get a function name before doing an unwind works.
- uint64_t cur_func_offset = reinterpret_cast<uint64_t>(&test_level_one) + 1;
+ uint64_t cur_func_offset = reinterpret_cast<uint64_t>(test_level_one_) + 1;
uint64_t offset;
ASSERT_NE(std::string(""), backtrace->GetFunctionName(cur_func_offset, &offset));
}
-TEST(libbacktrace, remote_get_function_name_before_unwind) {
+TEST_F(BacktraceTest, remote_get_function_name_before_unwind) {
pid_t pid;
CreateRemoteProcess(&pid);
@@ -1492,7 +1503,7 @@
std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, pid));
// Verify that trying to get a function name before doing an unwind works.
- uint64_t cur_func_offset = reinterpret_cast<uint64_t>(&test_level_one) + 1;
+ uint64_t cur_func_offset = reinterpret_cast<uint64_t>(test_level_one_) + 1;
uint64_t offset;
ASSERT_NE(std::string(""), backtrace->GetFunctionName(cur_func_offset, &offset));
@@ -1579,7 +1590,7 @@
ASSERT_EQ(std::string(""), backtrace->GetFunctionName(device_map_uint, &offset, &map));
ASSERT_EQ(std::string(""), backtrace->GetFunctionName(0, &offset));
- uint64_t cur_func_offset = reinterpret_cast<uint64_t>(&test_level_one) + 1;
+ uint64_t cur_func_offset = reinterpret_cast<uint64_t>(BacktraceTest::test_level_one_) + 1;
// Now verify the device map flag actually causes the function name to be empty.
backtrace->FillInMap(cur_func_offset, &map);
ASSERT_TRUE((map.flags & PROT_DEVICE_MAP) == 0);
@@ -1628,7 +1639,7 @@
ASSERT_EQ(0U, backtrace->NumFrames());
}
-TEST(libbacktrace, unwind_disallow_device_map_local) {
+TEST_F(BacktraceTest, unwind_disallow_device_map_local) {
void* device_map;
SetupDeviceMap(&device_map);
@@ -1642,7 +1653,7 @@
munmap(device_map, DEVICE_MAP_SIZE);
}
-TEST(libbacktrace, unwind_disallow_device_map_remote) {
+TEST_F(BacktraceTest, unwind_disallow_device_map_remote) {
void* device_map;
SetupDeviceMap(&device_map);
@@ -1698,13 +1709,13 @@
pid_t pid;
if ((pid = fork()) == 0) {
if (use_action) {
- ScopedSignalHandler ssh(SIGUSR1, test_signal_action);
+ ScopedSignalHandler ssh(SIGUSR1, BacktraceTest::test_signal_action_);
- test_level_one(1, 2, 3, 4, SetValueAndLoop, const_cast<int*>(&value));
+ BacktraceTest::test_level_one_(1, 2, 3, 4, SetValueAndLoop, const_cast<int*>(&value));
} else {
- ScopedSignalHandler ssh(SIGUSR1, test_signal_handler);
+ ScopedSignalHandler ssh(SIGUSR1, BacktraceTest::test_signal_handler_);
- test_level_one(1, 2, 3, 4, SetValueAndLoop, const_cast<int*>(&value));
+ BacktraceTest::test_level_one_(1, 2, 3, 4, SetValueAndLoop, const_cast<int*>(&value));
}
}
ASSERT_NE(-1, pid);
@@ -1805,11 +1816,11 @@
FinishRemoteProcess(pid);
}
-TEST(libbacktrace, unwind_remote_through_signal_using_handler) {
+TEST_F(BacktraceTest, unwind_remote_through_signal_using_handler) {
UnwindThroughSignal(false, Backtrace::Create, BacktraceMap::Create);
}
-TEST(libbacktrace, unwind_remote_through_signal_using_action) {
+TEST_F(BacktraceTest, unwind_remote_through_signal_using_action) {
UnwindThroughSignal(true, Backtrace::Create, BacktraceMap::Create);
}
@@ -1822,49 +1833,41 @@
ASSERT_EQ(0U, backtrace->GetFrame(0)->num);
}
-TEST(libbacktrace, unwind_frame_skip_numbering) {
+TEST_F(BacktraceTest, unwind_frame_skip_numbering) {
TestFrameSkipNumbering(Backtrace::Create, BacktraceMap::Create);
}
-#if defined(ENABLE_PSS_TESTS)
-#include "GetPss.h"
-
#define MAX_LEAK_BYTES (32*1024UL)
static void CheckForLeak(pid_t pid, pid_t tid) {
std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(pid));
- // Do a few runs to get the PSS stable.
- for (size_t i = 0; i < 100; i++) {
- Backtrace* backtrace = Backtrace::Create(pid, tid, map.get());
- ASSERT_TRUE(backtrace != nullptr);
- ASSERT_TRUE(backtrace->Unwind(0));
- VERIFY_NO_ERROR(backtrace->GetError().error_code);
- delete backtrace;
- }
- size_t stable_pss = GetPssBytes();
- ASSERT_TRUE(stable_pss != 0);
-
// Loop enough that even a small leak should be detectable.
+ size_t first_allocated_bytes = 0;
+ size_t last_allocated_bytes = 0;
for (size_t i = 0; i < 4096; i++) {
Backtrace* backtrace = Backtrace::Create(pid, tid, map.get());
ASSERT_TRUE(backtrace != nullptr);
ASSERT_TRUE(backtrace->Unwind(0));
VERIFY_NO_ERROR(backtrace->GetError().error_code);
delete backtrace;
- }
- size_t new_pss = GetPssBytes();
- ASSERT_TRUE(new_pss != 0);
- if (new_pss > stable_pss) {
- ASSERT_LE(new_pss - stable_pss, MAX_LEAK_BYTES);
+
+ size_t allocated_bytes = mallinfo().uordblks;
+ if (first_allocated_bytes == 0) {
+ first_allocated_bytes = allocated_bytes;
+ } else if (last_allocated_bytes > first_allocated_bytes) {
+ // Check that the memory did not increase too much over the first loop.
+ ASSERT_LE(last_allocated_bytes - first_allocated_bytes, MAX_LEAK_BYTES);
+ }
+ last_allocated_bytes = allocated_bytes;
}
}
-TEST(libbacktrace, check_for_leak_local) {
+TEST_F(BacktraceTest, check_for_leak_local) {
CheckForLeak(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD);
}
-TEST(libbacktrace, check_for_leak_local_thread) {
+TEST_F(BacktraceTest, check_for_leak_local_thread) {
thread_t thread_data = { 0, 0, 0, nullptr };
pthread_t thread;
ASSERT_TRUE(pthread_create(&thread, nullptr, ThreadLevelRun, &thread_data) == 0);
@@ -1880,7 +1883,7 @@
ASSERT_TRUE(pthread_join(thread, nullptr) == 0);
}
-TEST(libbacktrace, check_for_leak_remote) {
+TEST_F(BacktraceTest, check_for_leak_remote) {
pid_t pid;
CreateRemoteProcess(&pid);
@@ -1888,4 +1891,3 @@
FinishRemoteProcess(pid);
}
-#endif
diff --git a/liblog/include/log/log_main.h b/liblog/include/log/log_main.h
index e7b1728..53653de 100644
--- a/liblog/include/log/log_main.h
+++ b/liblog/include/log/log_main.h
@@ -56,15 +56,24 @@
/*
* Use __VA_ARGS__ if running a static analyzer,
* to avoid warnings of unused variables in __VA_ARGS__.
- * __FAKE_USE_VA_ARGS is undefined at link time,
- * so don't link with __clang_analyzer__ defined.
+ * Use contexpr function in C++ mode, so these macros can be used
+ * in other constexpr functions without warning.
*/
#ifdef __clang_analyzer__
-extern void __fake_use_va_args(int, ...);
-#define __FAKE_USE_VA_ARGS(...) __fake_use_va_args(0, ##__VA_ARGS__)
+#ifdef __cplusplus
+extern "C++" {
+template <typename... Ts>
+constexpr int __fake_use_va_args(Ts...) {
+ return 0;
+}
+}
+#else
+extern int __fake_use_va_args(int, ...);
+#endif /* __cplusplus */
+#define __FAKE_USE_VA_ARGS(...) ((void)__fake_use_va_args(0, ##__VA_ARGS__))
#else
#define __FAKE_USE_VA_ARGS(...) ((void)(0))
-#endif
+#endif /* __clang_analyzer__ */
#ifndef __predict_false
#define __predict_false(exp) __builtin_expect((exp) != 0, 0)
diff --git a/libstats/include/stats_event_list.h b/libstats/include/stats_event_list.h
index 5d174ae..a9832db 100644
--- a/libstats/include/stats_event_list.h
+++ b/libstats/include/stats_event_list.h
@@ -24,6 +24,8 @@
#endif
void reset_log_context(android_log_context ctx);
int write_to_logger(android_log_context context, log_id_t id);
+void note_log_drop();
+void stats_log_close();
#ifdef __cplusplus
}
diff --git a/libstats/stats_event_list.c b/libstats/stats_event_list.c
index 3d746db..735088a 100644
--- a/libstats/stats_event_list.c
+++ b/libstats/stats_event_list.c
@@ -119,6 +119,18 @@
return retValue;
}
+void note_log_drop() {
+ statsdLoggerWrite.noteDrop();
+}
+
+void stats_log_close() {
+ statsd_writer_init_lock();
+ if (statsdLoggerWrite.close) {
+ (*statsdLoggerWrite.close)();
+ }
+ statsd_writer_init_unlock();
+}
+
/* log_init_lock assumed */
static int __write_to_statsd_initialize_locked() {
if (!statsdLoggerWrite.open || ((*statsdLoggerWrite.open)() < 0)) {
diff --git a/libstats/statsd_writer.c b/libstats/statsd_writer.c
index 9953bba..afe401f 100644
--- a/libstats/statsd_writer.c
+++ b/libstats/statsd_writer.c
@@ -38,6 +38,7 @@
#define min(x, y) ((y) ^ (((x) ^ (y)) & -((x) < (y))))
static pthread_mutex_t log_init_lock = PTHREAD_MUTEX_INITIALIZER;
+static atomic_int dropped = 0;
void statsd_writer_init_lock() {
/*
@@ -59,14 +60,16 @@
static int statsdOpen();
static void statsdClose();
static int statsdWrite(struct timespec* ts, struct iovec* vec, size_t nr);
+static void statsdNoteDrop();
struct android_log_transport_write statsdLoggerWrite = {
- .name = "statsd",
- .sock = -EBADF,
- .available = statsdAvailable,
- .open = statsdOpen,
- .close = statsdClose,
- .write = statsdWrite,
+ .name = "statsd",
+ .sock = -EBADF,
+ .available = statsdAvailable,
+ .open = statsdOpen,
+ .close = statsdClose,
+ .write = statsdWrite,
+ .noteDrop = statsdNoteDrop,
};
/* log_init_lock assumed */
@@ -131,6 +134,10 @@
return 1;
}
+static void statsdNoteDrop() {
+ atomic_fetch_add_explicit(&dropped, 1, memory_order_relaxed);
+}
+
static int statsdWrite(struct timespec* ts, struct iovec* vec, size_t nr) {
ssize_t ret;
int sock;
@@ -138,7 +145,6 @@
struct iovec newVec[nr + headerLength];
android_log_header_t header;
size_t i, payloadSize;
- static atomic_int dropped;
sock = atomic_load(&statsdLoggerWrite.sock);
if (sock < 0) switch (sock) {
@@ -252,8 +258,6 @@
if (ret > (ssize_t)sizeof(header)) {
ret -= sizeof(header);
- } else if (ret == -EAGAIN) {
- atomic_fetch_add_explicit(&dropped, 1, memory_order_relaxed);
}
return ret;
diff --git a/libstats/statsd_writer.h b/libstats/statsd_writer.h
index 82e14e0..7289441 100644
--- a/libstats/statsd_writer.h
+++ b/libstats/statsd_writer.h
@@ -38,6 +38,8 @@
void (*close)(); /* free up resources */
/* write log to transport, returns number of bytes propagated, or -errno */
int (*write)(struct timespec* ts, struct iovec* vec, size_t nr);
+ /* note one log drop */
+ void (*noteDrop)();
};
#endif // ANDROID_STATS_LOG_STATS_WRITER_H
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index b68dc34..a4c3955 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -77,7 +77,7 @@
#
# create some directories (some are mount points) and symlinks
LOCAL_POST_INSTALL_CMD := mkdir -p $(addprefix $(TARGET_ROOT_OUT)/, \
- sbin dev proc sys system data odm oem acct config storage mnt $(BOARD_ROOT_EXTRA_FOLDERS)); \
+ sbin dev proc sys system data odm oem acct config storage mnt apex $(BOARD_ROOT_EXTRA_FOLDERS)); \
ln -sf /system/bin $(TARGET_ROOT_OUT)/bin; \
ln -sf /system/etc $(TARGET_ROOT_OUT)/etc; \
ln -sf /data/user_de/0/com.android.shell/files/bugreports $(TARGET_ROOT_OUT)/bugreports; \
diff --git a/rootdir/init.rc b/rootdir/init.rc
index f39ea7c..6a6a8f9 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -269,6 +269,12 @@
# that they can be chown'd to system:system later on boot
write /sys/class/leds/vibrator/trigger "transient"
+ # Setup APEX mount point and its security context
+ mount tmpfs tmpfs /apex nodev noexec nosuid
+ chmod 0755 /apex
+ chown root root /apex
+ restorecon /apex
+
# 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
@@ -400,6 +406,7 @@
# Make sure we have the device encryption key.
start vold
+ exec - system system -- /system/bin/vdc checkpoint prepareDriveForCheckpoint /data
installkey /data
# Start bootcharting as soon as possible after the data partition is
@@ -523,6 +530,8 @@
mkdir /data/anr 0775 system system
+ mkdir /data/apex 0770 root root
+
# NFC: create data/nfc for nv storage
mkdir /data/nfc 0770 nfc nfc
mkdir /data/nfc/param 0770 nfc nfc