Merge changes from topic "revert-1665499-revert-1660531-max-boot-level-crypto-KFMCEDKSIV-WPIHELCRFI"
* changes:
Revert^2 "Set earlyBootEnded before apex starts"
Revert^2 "Expose AID_KEYSTORE"
diff --git a/fastboot/Android.bp b/fastboot/Android.bp
index 43b2ddd..ce702a0 100644
--- a/fastboot/Android.bp
+++ b/fastboot/Android.bp
@@ -183,6 +183,7 @@
],
static_libs: [
+ "libc++fs",
"libgtest_prod",
"libhealthhalutils",
"libsnapshot_cow",
diff --git a/fastboot/device/flashing.cpp b/fastboot/device/flashing.cpp
index 333ca50..ee0aa58 100644
--- a/fastboot/device/flashing.cpp
+++ b/fastboot/device/flashing.cpp
@@ -27,6 +27,7 @@
#include <android-base/file.h>
#include <android-base/logging.h>
+#include <android-base/properties.h>
#include <android-base/strings.h>
#include <ext4_utils/ext4_utils.h>
#include <fs_mgr_overlayfs.h>
@@ -162,7 +163,9 @@
partition_name == "boot_b")) {
CopyAVBFooter(&data, block_device_size);
}
- WipeOverlayfsForPartition(device, partition_name);
+ if (android::base::GetProperty("ro.system.build.type", "") != "user") {
+ WipeOverlayfsForPartition(device, partition_name);
+ }
int result = FlashBlockDevice(handle.fd(), data);
sync();
return result;
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 700d4bd..e5319a5 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -411,6 +411,13 @@
" gsi wipe|disable Wipe or disable a GSI installation (fastbootd only).\n"
" wipe-super [SUPER_EMPTY] Wipe the super partition. This will reset it to\n"
" contain an empty set of default dynamic partitions.\n"
+ " create-logical-partition NAME SIZE\n"
+ " Create a logical partition with the given name and\n"
+ " size, in the super partition.\n"
+ " delete-logical-partition NAME\n"
+ " Delete a logical partition with the given name.\n"
+ " resize-logical-partition NAME SIZE\n"
+ " Change the size of the named logical partition.\n"
" snapshot-update cancel On devices that support snapshot-based updates, cancel\n"
" an in-progress update. This may make the device\n"
" unbootable until it is reflashed.\n"
@@ -673,7 +680,7 @@
return fd;
}
-static void CheckRequirement(const std::string& cur_product, const std::string& var,
+static bool CheckRequirement(const std::string& cur_product, const std::string& var,
const std::string& product, bool invert,
const std::vector<std::string>& options) {
Status("Checking '" + var + "'");
@@ -685,7 +692,7 @@
double split = now();
fprintf(stderr, "IGNORE, product is %s required only for %s [%7.3fs]\n",
cur_product.c_str(), product.c_str(), (split - start));
- return;
+ return true;
}
}
@@ -694,7 +701,7 @@
fprintf(stderr, "FAILED\n\n");
fprintf(stderr, "Could not getvar for '%s' (%s)\n\n", var.c_str(),
fb->Error().c_str());
- die("requirements not met!");
+ return false;
}
bool match = false;
@@ -714,7 +721,7 @@
if (match) {
double split = now();
fprintf(stderr, "OKAY [%7.3fs]\n", (split - start));
- return;
+ return true;
}
fprintf(stderr, "FAILED\n\n");
@@ -724,7 +731,7 @@
fprintf(stderr, " or '%s'", it->c_str());
}
fprintf(stderr, ".\n\n");
- die("requirements not met!");
+ return false;
}
bool ParseRequirementLine(const std::string& line, std::string* name, std::string* product,
@@ -788,7 +795,7 @@
}
}
-static void CheckRequirements(const std::string& data) {
+static void CheckRequirements(const std::string& data, bool force_flash) {
std::string cur_product;
if (fb->GetVar("product", &cur_product) != fastboot::SUCCESS) {
fprintf(stderr, "getvar:product FAILED (%s)\n", fb->Error().c_str());
@@ -812,7 +819,14 @@
if (name == "partition-exists") {
HandlePartitionExists(options);
} else {
- CheckRequirement(cur_product, name, product, invert, options);
+ bool met = CheckRequirement(cur_product, name, product, invert, options);
+ if (!met) {
+ if (!force_flash) {
+ die("requirements not met!");
+ } else {
+ fprintf(stderr, "requirements not met! but proceeding due to --force\n");
+ }
+ }
}
}
}
@@ -1405,7 +1419,8 @@
class FlashAllTool {
public:
- FlashAllTool(const ImageSource& source, const std::string& slot_override, bool skip_secondary, bool wipe);
+ FlashAllTool(const ImageSource& source, const std::string& slot_override, bool skip_secondary,
+ bool wipe, bool force_flash);
void Flash();
@@ -1421,16 +1436,19 @@
std::string slot_override_;
bool skip_secondary_;
bool wipe_;
+ bool force_flash_;
std::string secondary_slot_;
std::vector<std::pair<const Image*, std::string>> boot_images_;
std::vector<std::pair<const Image*, std::string>> os_images_;
};
-FlashAllTool::FlashAllTool(const ImageSource& source, const std::string& slot_override, bool skip_secondary, bool wipe)
+FlashAllTool::FlashAllTool(const ImageSource& source, const std::string& slot_override,
+ bool skip_secondary, bool wipe, bool force_flash)
: source_(source),
slot_override_(slot_override),
skip_secondary_(skip_secondary),
- wipe_(wipe)
+ wipe_(wipe),
+ force_flash_(force_flash)
{
}
@@ -1478,7 +1496,7 @@
if (!source_.ReadFile("android-info.txt", &contents)) {
die("could not read android-info.txt");
}
- ::CheckRequirements({contents.data(), contents.size()});
+ ::CheckRequirements({contents.data(), contents.size()}, force_flash_);
}
void FlashAllTool::DetermineSecondarySlot() {
@@ -1598,14 +1616,15 @@
return unzip_to_file(zip_, name.c_str());
}
-static void do_update(const char* filename, const std::string& slot_override, bool skip_secondary) {
+static void do_update(const char* filename, const std::string& slot_override, bool skip_secondary,
+ bool force_flash) {
ZipArchiveHandle zip;
int error = OpenArchive(filename, &zip);
if (error != 0) {
die("failed to open zip file '%s': %s", filename, ErrorCodeString(error));
}
- FlashAllTool tool(ZipImageSource(zip), slot_override, skip_secondary, false);
+ FlashAllTool tool(ZipImageSource(zip), slot_override, skip_secondary, false, force_flash);
tool.Flash();
CloseArchive(zip);
@@ -1630,8 +1649,9 @@
return unique_fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_BINARY)));
}
-static void do_flashall(const std::string& slot_override, bool skip_secondary, bool wipe) {
- FlashAllTool tool(LocalImageSource(), slot_override, skip_secondary, wipe);
+static void do_flashall(const std::string& slot_override, bool skip_secondary, bool wipe,
+ bool force_flash) {
+ FlashAllTool tool(LocalImageSource(), slot_override, skip_secondary, wipe, force_flash);
tool.Flash();
}
@@ -2179,9 +2199,9 @@
} else if (command == "flashall") {
if (slot_override == "all") {
fprintf(stderr, "Warning: slot set to 'all'. Secondary slots will not be flashed.\n");
- do_flashall(slot_override, true, wants_wipe);
+ do_flashall(slot_override, true, wants_wipe, force_flash);
} else {
- do_flashall(slot_override, skip_secondary, wants_wipe);
+ do_flashall(slot_override, skip_secondary, wants_wipe, force_flash);
}
wants_reboot = true;
} else if (command == "update") {
@@ -2193,7 +2213,7 @@
if (!args.empty()) {
filename = next_arg(&args);
}
- do_update(filename.c_str(), slot_override, skip_secondary || slot_all);
+ do_update(filename.c_str(), slot_override, skip_secondary || slot_all, force_flash);
wants_reboot = true;
} else if (command == FB_CMD_SET_ACTIVE) {
std::string slot = verify_slot(next_arg(&args), false);
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 6952cdf..bbbb7e8 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -647,6 +647,46 @@
return sb == cpu_to_le32(F2FS_SUPER_MAGIC);
}
+static void SetReadAheadSize(const std::string& entry_block_device, off64_t size_kb) {
+ std::string block_device;
+ if (!Realpath(entry_block_device, &block_device)) {
+ PERROR << "Failed to realpath " << entry_block_device;
+ return;
+ }
+
+ static constexpr std::string_view kDevBlockPrefix("/dev/block/");
+ if (!android::base::StartsWith(block_device, kDevBlockPrefix)) {
+ LWARNING << block_device << " is not a block device";
+ return;
+ }
+
+ DeviceMapper& dm = DeviceMapper::Instance();
+ while (true) {
+ std::string block_name = block_device;
+ if (android::base::StartsWith(block_device, kDevBlockPrefix)) {
+ block_name = block_device.substr(kDevBlockPrefix.length());
+ }
+ std::string sys_partition =
+ android::base::StringPrintf("/sys/class/block/%s/partition", block_name.c_str());
+ struct stat info;
+ if (lstat(sys_partition.c_str(), &info) == 0) {
+ // it has a partition like "sda12".
+ block_name += "/..";
+ }
+ std::string sys_ra = android::base::StringPrintf("/sys/class/block/%s/queue/read_ahead_kb",
+ block_name.c_str());
+ std::string size = android::base::StringPrintf("%llu", (long long)size_kb);
+ android::base::WriteStringToFile(size, sys_ra.c_str());
+ LINFO << "Set readahead_kb: " << size << " on " << sys_ra;
+
+ auto parent = dm.GetParentBlockDeviceByPath(block_device);
+ if (!parent) {
+ return;
+ }
+ block_device = *parent;
+ }
+}
+
//
// Prepare the filesystem on the given block device to be mounted.
//
@@ -667,6 +707,11 @@
}
mkdir(mount_point.c_str(), 0755);
+ // Don't need to return error, since it's a salt
+ if (entry.readahead_size_kb != -1) {
+ SetReadAheadSize(blk_device, entry.readahead_size_kb);
+ }
+
int fs_stat = 0;
if (is_extfs(entry.fs_type)) {
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index ad48dd1..42bf356 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -255,6 +255,13 @@
} else {
entry->reserved_size = static_cast<off64_t>(size);
}
+ } else if (StartsWith(flag, "readahead_size_kb=")) {
+ int val;
+ if (ParseInt(arg, &val, 0, 16 * 1024)) {
+ entry->readahead_size_kb = val;
+ } else {
+ LWARNING << "Warning: readahead_size_kb= flag malformed (0 ~ 16MB): " << arg;
+ }
} else if (StartsWith(flag, "eraseblk=")) {
// The erase block size flag is followed by an = and the flash erase block size. Get it,
// check that it is a power of 2 and at least 4096, and return it.
diff --git a/fs_mgr/include_fstab/fstab/fstab.h b/fs_mgr/include_fstab/fstab/fstab.h
index 8ecf41b..2704e47 100644
--- a/fs_mgr/include_fstab/fstab/fstab.h
+++ b/fs_mgr/include_fstab/fstab/fstab.h
@@ -47,6 +47,7 @@
int max_comp_streams = 0;
off64_t zram_size = 0;
off64_t reserved_size = 0;
+ off64_t readahead_size_kb = -1;
std::string encryption_options;
off64_t erase_blk_size = 0;
off64_t logical_blk_size = 0;
diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp
index ea92d25..3cb4123 100644
--- a/fs_mgr/libsnapshot/Android.bp
+++ b/fs_mgr/libsnapshot/Android.bp
@@ -264,6 +264,7 @@
"android.hardware.boot@1.0",
"android.hardware.boot@1.1",
"libbrotli",
+ "libc++fs",
"libfs_mgr",
"libgsi",
"libgmock",
@@ -297,6 +298,7 @@
],
static_libs: [
"libbrotli",
+ "libc++fs",
"libfstab",
"libsnapshot",
"libsnapshot_cow",
@@ -326,6 +328,7 @@
"power_test.cpp",
],
static_libs: [
+ "libc++fs",
"libsnapshot",
"update_metadata-protos",
],
@@ -355,6 +358,7 @@
static_libs: [
"libbase",
"libbrotli",
+ "libc++fs",
"libchrome",
"libcrypto_static",
"libcutils",
@@ -416,7 +420,7 @@
"snapuserd_server.cpp",
"snapuserd.cpp",
"snapuserd_daemon.cpp",
- "snapuserd_worker.cpp",
+ "snapuserd_worker.cpp",
],
cflags: [
diff --git a/fs_mgr/libsnapshot/cow_api_test.cpp b/fs_mgr/libsnapshot/cow_api_test.cpp
index 5d63220..b75b154 100644
--- a/fs_mgr/libsnapshot/cow_api_test.cpp
+++ b/fs_mgr/libsnapshot/cow_api_test.cpp
@@ -25,6 +25,10 @@
#include <libsnapshot/cow_reader.h>
#include <libsnapshot/cow_writer.h>
+using testing::AssertionFailure;
+using testing::AssertionResult;
+using testing::AssertionSuccess;
+
namespace android {
namespace snapshot {
@@ -781,6 +785,202 @@
ASSERT_TRUE(reader.Parse(cow_->fd));
}
+AssertionResult WriteDataBlock(CowWriter* writer, uint64_t new_block, std::string data) {
+ data.resize(writer->options().block_size, '\0');
+ if (!writer->AddRawBlocks(new_block, data.data(), data.size())) {
+ return AssertionFailure() << "Failed to add raw block";
+ }
+ return AssertionSuccess();
+}
+
+AssertionResult CompareDataBlock(CowReader* reader, const CowOperation& op,
+ const std::string& data) {
+ CowHeader header;
+ reader->GetHeader(&header);
+
+ std::string cmp = data;
+ cmp.resize(header.block_size, '\0');
+
+ StringSink sink;
+ if (!reader->ReadData(op, &sink)) {
+ return AssertionFailure() << "Failed to read data block";
+ }
+ if (cmp != sink.stream()) {
+ return AssertionFailure() << "Data blocks did not match, expected " << cmp << ", got "
+ << sink.stream();
+ }
+
+ return AssertionSuccess();
+}
+
+TEST_F(CowTest, ResumeMidCluster) {
+ CowOptions options;
+ options.cluster_ops = 7;
+ auto writer = std::make_unique<CowWriter>(options);
+ ASSERT_TRUE(writer->Initialize(cow_->fd));
+
+ ASSERT_TRUE(WriteDataBlock(writer.get(), 1, "Block 1"));
+ ASSERT_TRUE(WriteDataBlock(writer.get(), 2, "Block 2"));
+ ASSERT_TRUE(WriteDataBlock(writer.get(), 3, "Block 3"));
+ ASSERT_TRUE(writer->AddLabel(1));
+ ASSERT_TRUE(writer->Finalize());
+ ASSERT_TRUE(WriteDataBlock(writer.get(), 4, "Block 4"));
+ ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
+
+ writer = std::make_unique<CowWriter>(options);
+ ASSERT_TRUE(writer->InitializeAppend(cow_->fd, 1));
+ ASSERT_TRUE(WriteDataBlock(writer.get(), 4, "Block 4"));
+ ASSERT_TRUE(WriteDataBlock(writer.get(), 5, "Block 5"));
+ ASSERT_TRUE(WriteDataBlock(writer.get(), 6, "Block 6"));
+ ASSERT_TRUE(WriteDataBlock(writer.get(), 7, "Block 7"));
+ ASSERT_TRUE(WriteDataBlock(writer.get(), 8, "Block 8"));
+ ASSERT_TRUE(writer->AddLabel(2));
+ ASSERT_TRUE(writer->Finalize());
+ ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
+
+ CowReader reader;
+ ASSERT_TRUE(reader.Parse(cow_->fd));
+
+ auto iter = reader.GetOpIter();
+ size_t num_replace = 0;
+ size_t max_in_cluster = 0;
+ size_t num_in_cluster = 0;
+ size_t num_clusters = 0;
+ while (!iter->Done()) {
+ const auto& op = iter->Get();
+
+ num_in_cluster++;
+ max_in_cluster = std::max(max_in_cluster, num_in_cluster);
+
+ if (op.type == kCowReplaceOp) {
+ num_replace++;
+
+ ASSERT_EQ(op.new_block, num_replace);
+ ASSERT_TRUE(CompareDataBlock(&reader, op, "Block " + std::to_string(num_replace)));
+ } else if (op.type == kCowClusterOp) {
+ num_in_cluster = 0;
+ num_clusters++;
+ }
+
+ iter->Next();
+ }
+ ASSERT_EQ(num_replace, 8);
+ ASSERT_EQ(max_in_cluster, 7);
+ ASSERT_EQ(num_clusters, 2);
+}
+
+TEST_F(CowTest, ResumeEndCluster) {
+ CowOptions options;
+ int cluster_ops = 5;
+ options.cluster_ops = cluster_ops;
+ auto writer = std::make_unique<CowWriter>(options);
+ ASSERT_TRUE(writer->Initialize(cow_->fd));
+
+ ASSERT_TRUE(WriteDataBlock(writer.get(), 1, "Block 1"));
+ ASSERT_TRUE(WriteDataBlock(writer.get(), 2, "Block 2"));
+ ASSERT_TRUE(WriteDataBlock(writer.get(), 3, "Block 3"));
+ ASSERT_TRUE(writer->AddLabel(1));
+ ASSERT_TRUE(writer->Finalize());
+ ASSERT_TRUE(WriteDataBlock(writer.get(), 4, "Block 4"));
+ ASSERT_TRUE(WriteDataBlock(writer.get(), 5, "Block 5"));
+ ASSERT_TRUE(WriteDataBlock(writer.get(), 6, "Block 6"));
+ ASSERT_TRUE(WriteDataBlock(writer.get(), 7, "Block 7"));
+ ASSERT_TRUE(WriteDataBlock(writer.get(), 8, "Block 8"));
+ ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
+
+ writer = std::make_unique<CowWriter>(options);
+ ASSERT_TRUE(writer->InitializeAppend(cow_->fd, 1));
+ ASSERT_TRUE(WriteDataBlock(writer.get(), 4, "Block 4"));
+ ASSERT_TRUE(WriteDataBlock(writer.get(), 5, "Block 5"));
+ ASSERT_TRUE(WriteDataBlock(writer.get(), 6, "Block 6"));
+ ASSERT_TRUE(WriteDataBlock(writer.get(), 7, "Block 7"));
+ ASSERT_TRUE(WriteDataBlock(writer.get(), 8, "Block 8"));
+ ASSERT_TRUE(writer->AddLabel(2));
+ ASSERT_TRUE(writer->Finalize());
+ ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
+
+ CowReader reader;
+ ASSERT_TRUE(reader.Parse(cow_->fd));
+
+ auto iter = reader.GetOpIter();
+ size_t num_replace = 0;
+ size_t max_in_cluster = 0;
+ size_t num_in_cluster = 0;
+ size_t num_clusters = 0;
+ while (!iter->Done()) {
+ const auto& op = iter->Get();
+
+ num_in_cluster++;
+ max_in_cluster = std::max(max_in_cluster, num_in_cluster);
+
+ if (op.type == kCowReplaceOp) {
+ num_replace++;
+
+ ASSERT_EQ(op.new_block, num_replace);
+ ASSERT_TRUE(CompareDataBlock(&reader, op, "Block " + std::to_string(num_replace)));
+ } else if (op.type == kCowClusterOp) {
+ num_in_cluster = 0;
+ num_clusters++;
+ }
+
+ iter->Next();
+ }
+ ASSERT_EQ(num_replace, 8);
+ ASSERT_EQ(max_in_cluster, cluster_ops);
+ ASSERT_EQ(num_clusters, 3);
+}
+
+TEST_F(CowTest, DeleteMidCluster) {
+ CowOptions options;
+ options.cluster_ops = 7;
+ auto writer = std::make_unique<CowWriter>(options);
+ ASSERT_TRUE(writer->Initialize(cow_->fd));
+
+ ASSERT_TRUE(WriteDataBlock(writer.get(), 1, "Block 1"));
+ ASSERT_TRUE(WriteDataBlock(writer.get(), 2, "Block 2"));
+ ASSERT_TRUE(WriteDataBlock(writer.get(), 3, "Block 3"));
+ ASSERT_TRUE(writer->AddLabel(1));
+ ASSERT_TRUE(writer->Finalize());
+ ASSERT_TRUE(WriteDataBlock(writer.get(), 4, "Block 4"));
+ ASSERT_TRUE(WriteDataBlock(writer.get(), 5, "Block 5"));
+ ASSERT_TRUE(WriteDataBlock(writer.get(), 6, "Block 6"));
+ ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
+
+ writer = std::make_unique<CowWriter>(options);
+ ASSERT_TRUE(writer->InitializeAppend(cow_->fd, 1));
+ ASSERT_TRUE(writer->Finalize());
+ ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
+
+ CowReader reader;
+ ASSERT_TRUE(reader.Parse(cow_->fd));
+
+ auto iter = reader.GetOpIter();
+ size_t num_replace = 0;
+ size_t max_in_cluster = 0;
+ size_t num_in_cluster = 0;
+ size_t num_clusters = 0;
+ while (!iter->Done()) {
+ const auto& op = iter->Get();
+
+ num_in_cluster++;
+ max_in_cluster = std::max(max_in_cluster, num_in_cluster);
+ if (op.type == kCowReplaceOp) {
+ num_replace++;
+
+ ASSERT_EQ(op.new_block, num_replace);
+ ASSERT_TRUE(CompareDataBlock(&reader, op, "Block " + std::to_string(num_replace)));
+ } else if (op.type == kCowClusterOp) {
+ num_in_cluster = 0;
+ num_clusters++;
+ }
+
+ iter->Next();
+ }
+ ASSERT_EQ(num_replace, 3);
+ ASSERT_EQ(max_in_cluster, 5); // 3 data, 1 label, 1 cluster op
+ ASSERT_EQ(num_clusters, 1);
+}
+
} // namespace snapshot
} // namespace android
diff --git a/fs_mgr/libsnapshot/cow_writer.cpp b/fs_mgr/libsnapshot/cow_writer.cpp
index 59f6d6f..645ae9d 100644
--- a/fs_mgr/libsnapshot/cow_writer.cpp
+++ b/fs_mgr/libsnapshot/cow_writer.cpp
@@ -232,15 +232,11 @@
// Free reader so we own the descriptor position again.
reader = nullptr;
- // Remove excess data
- if (!Truncate(next_op_pos_)) {
- return false;
- }
if (lseek(fd_.get(), next_op_pos_, SEEK_SET) < 0) {
PLOG(ERROR) << "lseek failed";
return false;
}
- return true;
+ return EmitClusterIfNeeded();
}
bool CowWriter::EmitCopy(uint64_t new_block, uint64_t old_block) {
@@ -319,6 +315,14 @@
return WriteOperation(op);
}
+bool CowWriter::EmitClusterIfNeeded() {
+ // If there isn't room for another op and the cluster end op, end the current cluster
+ if (cluster_size_ && cluster_size_ < current_cluster_size_ + 2 * sizeof(CowOperation)) {
+ if (!EmitCluster()) return false;
+ }
+ return true;
+}
+
std::basic_string<uint8_t> CowWriter::Compress(const void* data, size_t length) {
switch (compression_) {
case kCowCompressGz: {
@@ -379,6 +383,21 @@
auto continue_num_ops = footer_.op.num_ops;
bool extra_cluster = false;
+ // Blank out extra ops, in case we're in append mode and dropped ops.
+ if (cluster_size_) {
+ auto unused_cluster_space = cluster_size_ - current_cluster_size_;
+ std::string clr;
+ clr.resize(unused_cluster_space, '\0');
+ if (lseek(fd_.get(), next_op_pos_, SEEK_SET) < 0) {
+ PLOG(ERROR) << "Failed to seek to footer position.";
+ return false;
+ }
+ if (!android::base::WriteFully(fd_, clr.data(), clr.size())) {
+ PLOG(ERROR) << "clearing unused cluster area failed";
+ return false;
+ }
+ }
+
// Footer should be at the end of a file, so if there is data after the current block, end it
// and start a new cluster.
if (cluster_size_ && current_data_size_ > 0) {
@@ -403,6 +422,17 @@
return false;
}
+ // Remove excess data, if we're in append mode and threw away more data
+ // than we wrote before.
+ off_t offs = lseek(fd_.get(), 0, SEEK_CUR);
+ if (offs < 0) {
+ PLOG(ERROR) << "Failed to lseek to find current position";
+ return false;
+ }
+ if (!Truncate(offs)) {
+ return false;
+ }
+
// Reposition for additional Writing
if (extra_cluster) {
current_cluster_size_ = continue_cluster_size;
@@ -445,12 +475,7 @@
if (!WriteRawData(data, size)) return false;
}
AddOperation(op);
- // If there isn't room for another op and the cluster end op, end the current cluster
- if (cluster_size_ && op.type != kCowClusterOp &&
- cluster_size_ < current_cluster_size_ + 2 * sizeof(op)) {
- if (!EmitCluster()) return false;
- }
- return true;
+ return EmitClusterIfNeeded();
}
void CowWriter::AddOperation(const CowOperation& op) {
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h
index 6ffd5d8..a9efad8 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h
@@ -115,6 +115,7 @@
private:
bool EmitCluster();
+ bool EmitClusterIfNeeded();
void SetupHeaders();
bool ParseOptions();
bool OpenForWrite();
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot_merge_stats.h b/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot_merge_stats.h
new file mode 100644
index 0000000..ac2c787
--- /dev/null
+++ b/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot_merge_stats.h
@@ -0,0 +1,48 @@
+//
+// Copyright (C) 2021 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.
+//
+
+#pragma once
+
+#include <memory>
+
+#include <gmock/gmock.h>
+#include <libsnapshot/snapshot_stats.h>
+
+namespace android::snapshot {
+
+class MockSnapshotMergeStats final : public ISnapshotMergeStats {
+ public:
+ virtual ~MockSnapshotMergeStats() = default;
+ // Called when merge starts or resumes.
+ MOCK_METHOD(bool, Start, (), (override));
+ MOCK_METHOD(void, set_state, (android::snapshot::UpdateState, bool), (override));
+ MOCK_METHOD(void, set_cow_file_size, (uint64_t), ());
+ MOCK_METHOD(void, set_total_cow_size_bytes, (uint64_t), (override));
+ MOCK_METHOD(void, set_estimated_cow_size_bytes, (uint64_t), (override));
+ MOCK_METHOD(void, set_boot_complete_time_ms, (uint32_t), (override));
+ MOCK_METHOD(void, set_boot_complete_to_merge_start_time_ms, (uint32_t), (override));
+ MOCK_METHOD(uint64_t, cow_file_size, (), (override));
+ MOCK_METHOD(uint64_t, total_cow_size_bytes, (), (override));
+ MOCK_METHOD(uint64_t, estimated_cow_size_bytes, (), (override));
+ MOCK_METHOD(uint32_t, boot_complete_time_ms, (), (override));
+ MOCK_METHOD(uint32_t, boot_complete_to_merge_start_time_ms, (), (override));
+ MOCK_METHOD(std::unique_ptr<Result>, Finish, (), (override));
+
+ using ISnapshotMergeStats::Result;
+ // Return nullptr if any failure.
+};
+
+} // namespace android::snapshot
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
index 7e74fac..126e1a0 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
@@ -493,6 +493,9 @@
// Unmap a COW image device previously mapped with MapCowImage().
bool UnmapCowImage(const std::string& name);
+ // Unmap a COW and remove it from a MetadataBuilder.
+ void UnmapAndDeleteCowPartition(MetadataBuilder* current_metadata);
+
// Unmap and remove all known snapshots.
bool RemoveAllSnapshots(LockedFile* lock);
@@ -738,6 +741,10 @@
// Helper of UpdateUsesCompression
bool UpdateUsesCompression(LockedFile* lock);
+ // Wrapper around libdm, with diagnostics.
+ bool DeleteDeviceIfExists(const std::string& name,
+ const std::chrono::milliseconds& timeout_ms = {});
+
std::string gsid_dir_;
std::string metadata_dir_;
std::unique_ptr<IDeviceInfo> device_;
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index a0a1e4f..c504355 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -21,6 +21,7 @@
#include <sys/types.h>
#include <sys/unistd.h>
+#include <filesystem>
#include <optional>
#include <thread>
#include <unordered_set>
@@ -587,8 +588,7 @@
bool SnapshotManager::UnmapSnapshot(LockedFile* lock, const std::string& name) {
CHECK(lock);
- auto& dm = DeviceMapper::Instance();
- if (!dm.DeleteDeviceIfExists(name)) {
+ if (!DeleteDeviceIfExists(name)) {
LOG(ERROR) << "Could not delete snapshot device: " << name;
return false;
}
@@ -1252,25 +1252,6 @@
return true;
}
-static bool DeleteDmDevice(const std::string& name, const std::chrono::milliseconds& timeout_ms) {
- auto start = std::chrono::steady_clock::now();
- auto& dm = DeviceMapper::Instance();
- while (true) {
- if (dm.DeleteDeviceIfExists(name)) {
- break;
- }
- auto now = std::chrono::steady_clock::now();
- auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - start);
- if (elapsed >= timeout_ms) {
- LOG(ERROR) << "DeleteDevice timeout: " << name;
- return false;
- }
- std::this_thread::sleep_for(400ms);
- }
-
- return true;
-}
-
bool SnapshotManager::CollapseSnapshotDevice(const std::string& name,
const SnapshotStatus& status) {
auto& dm = DeviceMapper::Instance();
@@ -1326,11 +1307,11 @@
UnmapDmUserDevice(name);
}
auto base_name = GetBaseDeviceName(name);
- if (!dm.DeleteDeviceIfExists(base_name)) {
+ if (!DeleteDeviceIfExists(base_name)) {
LOG(ERROR) << "Unable to delete base device for snapshot: " << base_name;
}
- if (!DeleteDmDevice(GetSourceDeviceName(name), 4000ms)) {
+ if (!DeleteDeviceIfExists(GetSourceDeviceName(name), 4000ms)) {
LOG(ERROR) << "Unable to delete source device for snapshot: " << GetSourceDeviceName(name);
}
@@ -2083,15 +2064,14 @@
return false;
}
- auto& dm = DeviceMapper::Instance();
auto base_name = GetBaseDeviceName(target_partition_name);
- if (!dm.DeleteDeviceIfExists(base_name)) {
+ if (!DeleteDeviceIfExists(base_name)) {
LOG(ERROR) << "Cannot delete base device: " << base_name;
return false;
}
auto source_name = GetSourceDeviceName(target_partition_name);
- if (!dm.DeleteDeviceIfExists(source_name)) {
+ if (!DeleteDeviceIfExists(source_name)) {
LOG(ERROR) << "Cannot delete source device: " << source_name;
return false;
}
@@ -2181,7 +2161,7 @@
return false;
}
- if (!DeleteDmDevice(GetCowName(name), 4000ms)) {
+ if (!DeleteDeviceIfExists(GetCowName(name), 4000ms)) {
LOG(ERROR) << "Cannot unmap: " << GetCowName(name);
return false;
}
@@ -2202,7 +2182,7 @@
return true;
}
- if (!dm.DeleteDeviceIfExists(dm_user_name)) {
+ if (!DeleteDeviceIfExists(dm_user_name)) {
LOG(ERROR) << "Cannot unmap " << dm_user_name;
return false;
}
@@ -2593,11 +2573,10 @@
return true;
}
-static void UnmapAndDeleteCowPartition(MetadataBuilder* current_metadata) {
- auto& dm = DeviceMapper::Instance();
+void SnapshotManager::UnmapAndDeleteCowPartition(MetadataBuilder* current_metadata) {
std::vector<std::string> to_delete;
for (auto* existing_cow_partition : current_metadata->ListPartitionsInGroup(kCowGroupName)) {
- if (!dm.DeleteDeviceIfExists(existing_cow_partition->name())) {
+ if (!DeleteDeviceIfExists(existing_cow_partition->name())) {
LOG(WARNING) << existing_cow_partition->name()
<< " cannot be unmapped and its space cannot be reclaimed";
continue;
@@ -3626,5 +3605,71 @@
stats->set_estimated_cow_size_bytes(estimated_cow_size);
}
+bool SnapshotManager::DeleteDeviceIfExists(const std::string& name,
+ const std::chrono::milliseconds& timeout_ms) {
+ auto& dm = DeviceMapper::Instance();
+ auto start = std::chrono::steady_clock::now();
+ while (true) {
+ if (dm.DeleteDeviceIfExists(name)) {
+ return true;
+ }
+ auto now = std::chrono::steady_clock::now();
+ auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - start);
+ if (elapsed >= timeout_ms) {
+ break;
+ }
+ std::this_thread::sleep_for(400ms);
+ }
+
+ // Try to diagnose why this failed. First get the actual device path.
+ std::string full_path;
+ if (!dm.GetDmDevicePathByName(name, &full_path)) {
+ LOG(ERROR) << "Unable to diagnose DM_DEV_REMOVE failure.";
+ return false;
+ }
+
+ // Check for child dm-devices.
+ std::string block_name = android::base::Basename(full_path);
+ std::string sysfs_holders = "/sys/class/block/" + block_name + "/holders";
+
+ std::error_code ec;
+ std::filesystem::directory_iterator dir_iter(sysfs_holders, ec);
+ if (auto begin = std::filesystem::begin(dir_iter); begin != std::filesystem::end(dir_iter)) {
+ LOG(ERROR) << "Child device-mapper device still mapped: " << begin->path();
+ return false;
+ }
+
+ // Check for mounted partitions.
+ android::fs_mgr::Fstab fstab;
+ android::fs_mgr::ReadFstabFromFile("/proc/mounts", &fstab);
+ for (const auto& entry : fstab) {
+ if (android::base::Basename(entry.blk_device) == block_name) {
+ LOG(ERROR) << "Partition still mounted: " << entry.mount_point;
+ return false;
+ }
+ }
+
+ // Check for detached mounted partitions.
+ for (const auto& fs : std::filesystem::directory_iterator("/sys/fs", ec)) {
+ std::string fs_type = android::base::Basename(fs.path().c_str());
+ if (!(fs_type == "ext4" || fs_type == "f2fs")) {
+ continue;
+ }
+
+ std::string path = fs.path().c_str() + "/"s + block_name;
+ if (access(path.c_str(), F_OK) == 0) {
+ LOG(ERROR) << "Block device was lazily unmounted and is still in-use: " << full_path
+ << "; possibly open file descriptor or attached loop device.";
+ return false;
+ }
+ }
+
+ LOG(ERROR) << "Device-mapper device " << name << "(" << full_path << ")"
+ << " still in use."
+ << " Probably a file descriptor was leaked or held open, or a loop device is"
+ << " attached.";
+ return false;
+}
+
} // namespace snapshot
} // namespace android
diff --git a/fs_mgr/tests/fs_mgr_test.cpp b/fs_mgr/tests/fs_mgr_test.cpp
index 5887641..9adb6bd 100644
--- a/fs_mgr/tests/fs_mgr_test.cpp
+++ b/fs_mgr/tests/fs_mgr_test.cpp
@@ -1097,3 +1097,59 @@
ASSERT_NE(nullptr, fs_mgr_get_mounted_entry_for_userdata(&fstab, block_device))
<< "/data wasn't mounted from default fstab";
}
+
+TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_Readahead_Size_KB) {
+ TemporaryFile tf;
+ ASSERT_TRUE(tf.fd != -1);
+ std::string fstab_contents = R"fs(
+source none0 swap defaults readahead_size_kb=blah
+source none1 swap defaults readahead_size_kb=128
+source none2 swap defaults readahead_size_kb=5%
+source none3 swap defaults readahead_size_kb=5kb
+source none4 swap defaults readahead_size_kb=16385
+source none5 swap defaults readahead_size_kb=-128
+source none6 swap defaults readahead_size_kb=0
+)fs";
+ ASSERT_TRUE(android::base::WriteStringToFile(fstab_contents, tf.path));
+
+ Fstab fstab;
+ EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab));
+ ASSERT_EQ(7U, fstab.size());
+
+ FstabEntry::FsMgrFlags flags = {};
+
+ auto entry = fstab.begin();
+ EXPECT_EQ("none0", entry->mount_point);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
+ EXPECT_EQ(-1, entry->readahead_size_kb);
+ entry++;
+
+ EXPECT_EQ("none1", entry->mount_point);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
+ EXPECT_EQ(128, entry->readahead_size_kb);
+ entry++;
+
+ EXPECT_EQ("none2", entry->mount_point);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
+ EXPECT_EQ(-1, entry->readahead_size_kb);
+ entry++;
+
+ EXPECT_EQ("none3", entry->mount_point);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
+ EXPECT_EQ(-1, entry->readahead_size_kb);
+ entry++;
+
+ EXPECT_EQ("none4", entry->mount_point);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
+ EXPECT_EQ(-1, entry->readahead_size_kb);
+ entry++;
+
+ EXPECT_EQ("none5", entry->mount_point);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
+ EXPECT_EQ(-1, entry->readahead_size_kb);
+ entry++;
+
+ EXPECT_EQ("none6", entry->mount_point);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
+ EXPECT_EQ(0, entry->readahead_size_kb);
+}
diff --git a/init/init.cpp b/init/init.cpp
index 7264b22..a7325ca 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -849,21 +849,6 @@
auto is_installed = android::gsi::IsGsiInstalled() ? "1" : "0";
SetProperty(gsi::kGsiInstalledProp, is_installed);
- /*
- * For debug builds of S launching devices, init mounts debugfs for
- * enabling vendor debug data collection setup at boot time. Init will unmount it on
- * boot-complete after vendor code has performed the required initializations
- * during boot. Dumpstate will then mount debugfs in order to read data
- * from the same using the dumpstate HAL during bugreport creation.
- * Dumpstate will also unmount debugfs after bugreport creation.
- * first_api_level comparison is done here instead
- * of init.rc since init.rc parser does not support >/< operators.
- */
- auto api_level = android::base::GetIntProperty("ro.product.first_api_level", 0);
- bool is_debuggable = android::base::GetBoolProperty("ro.debuggable", false);
- auto mount_debugfs = (is_debuggable && (api_level >= 31)) ? "1" : "0";
- SetProperty("init.mount_debugfs", mount_debugfs);
-
am.QueueBuiltinAction(SetupCgroupsAction, "SetupCgroups");
am.QueueBuiltinAction(SetKptrRestrictAction, "SetKptrRestrict");
am.QueueBuiltinAction(TestPerfEventSelinuxAction, "TestPerfEventSelinux");
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 0dc8159..17c36bb 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -1187,8 +1187,6 @@
if (StartsWith(key, ANDROIDBOOT_PREFIX)) {
InitPropertySet("ro.boot." + key.substr(ANDROIDBOOT_PREFIX.size()), value);
} else if (StartsWith(key, qemu_prefix)) {
- InitPropertySet("ro.kernel." + key, value); // emulator specific, deprecated
-
// emulator specific, should be retired once emulator migrates to
// androidboot.
const auto new_name =
@@ -1200,6 +1198,22 @@
// emulator specific, should be retired once emulator migrates to
// androidboot.
InitPropertySet("ro.boot." + key, value);
+ } else if (key == "android.bootanim" && value == "0") {
+ // emulator specific, should be retired once emulator migrates to
+ // androidboot.
+ InitPropertySet("ro.boot.debug.sf.nobootanimation", "1");
+ } else if (key == "android.checkjni") {
+ // emulator specific, should be retired once emulator migrates to
+ // androidboot.
+ std::string value_bool;
+ if (value == "0") {
+ value_bool = "false";
+ } else if (value == "1") {
+ value_bool = "true";
+ } else {
+ value_bool = value;
+ }
+ InitPropertySet("ro.boot.dalvik.vm.checkjni", value_bool);
}
});
}
diff --git a/init/selinux.cpp b/init/selinux.cpp
index 2d3e06e..35a96f9 100644
--- a/init/selinux.cpp
+++ b/init/selinux.cpp
@@ -372,6 +372,12 @@
system_ext_mapping_file.clear();
}
+ std::string system_ext_compat_cil_file("/system_ext/etc/selinux/mapping/" + vend_plat_vers +
+ ".compat.cil");
+ if (access(system_ext_compat_cil_file.c_str(), F_OK) == -1) {
+ system_ext_compat_cil_file.clear();
+ }
+
std::string product_policy_cil_file("/product/etc/selinux/product_sepolicy.cil");
if (access(product_policy_cil_file.c_str(), F_OK) == -1) {
product_policy_cil_file.clear();
@@ -426,6 +432,9 @@
if (!system_ext_mapping_file.empty()) {
compile_args.push_back(system_ext_mapping_file.c_str());
}
+ if (!system_ext_compat_cil_file.empty()) {
+ compile_args.push_back(system_ext_compat_cil_file.c_str());
+ }
if (!product_policy_cil_file.empty()) {
compile_args.push_back(product_policy_cil_file.c_str());
}
diff --git a/libprocessgroup/profiles/task_profiles.json b/libprocessgroup/profiles/task_profiles.json
index 5b57bdd..bd94621 100644
--- a/libprocessgroup/profiles/task_profiles.json
+++ b/libprocessgroup/profiles/task_profiles.json
@@ -70,11 +70,11 @@
"Name": "Frozen",
"Actions": [
{
- "Name": "JoinCgroup",
+ "Name": "SetAttribute",
"Params":
{
- "Controller": "freezer",
- "Path": ""
+ "Name": "FreezerState",
+ "Value": "1"
}
}
]
@@ -83,11 +83,11 @@
"Name": "Unfrozen",
"Actions": [
{
- "Name": "JoinCgroup",
+ "Name": "SetAttribute",
"Params":
{
- "Controller": "freezer",
- "Path": "../"
+ "Name": "FreezerState",
+ "Value": "0"
}
}
]
@@ -558,32 +558,6 @@
}
]
},
- {
- "Name": "FreezerDisabled",
- "Actions": [
- {
- "Name": "SetAttribute",
- "Params":
- {
- "Name": "FreezerState",
- "Value": "0"
- }
- }
- ]
- },
- {
- "Name": "FreezerEnabled",
- "Actions": [
- {
- "Name": "SetAttribute",
- "Params":
- {
- "Name": "FreezerState",
- "Value": "1"
- }
- }
- ]
- }
],
"AggregateProfiles": [
diff --git a/libprocessgroup/task_profiles.cpp b/libprocessgroup/task_profiles.cpp
index f13a681..db00a49 100644
--- a/libprocessgroup/task_profiles.cpp
+++ b/libprocessgroup/task_profiles.cpp
@@ -518,10 +518,10 @@
std::string attr_filepath = params_val["FilePath"].asString();
std::string attr_value = params_val["Value"].asString();
if (!attr_filepath.empty() && !attr_value.empty()) {
- const Json::Value& logfailures = params_val["LogFailures"];
- bool attr_logfailures = logfailures.isNull() || logfailures.asBool();
+ std::string attr_logfailures = params_val["LogFailures"].asString();
+ bool logfailures = attr_logfailures.empty() || attr_logfailures == "true";
profile->Add(std::make_unique<WriteFileAction>(attr_filepath, attr_value,
- attr_logfailures));
+ logfailures));
} else if (attr_filepath.empty()) {
LOG(WARNING) << "WriteFile: invalid parameter: "
<< "empty filepath";
diff --git a/libutils/RefBase_test.cpp b/libutils/RefBase_test.cpp
index dcc469e..93f9654 100644
--- a/libutils/RefBase_test.cpp
+++ b/libutils/RefBase_test.cpp
@@ -242,12 +242,12 @@
}
TEST(RefBase, AssertWeakRefExistsSuccess) {
- // uses some other refcounting method, or non at all
bool isDeleted;
sp<Foo> foo = sp<Foo>::make(&isDeleted);
wp<Foo> weakFoo = foo;
EXPECT_EQ(weakFoo, wp<Foo>::fromExisting(foo.get()));
+ EXPECT_EQ(weakFoo.unsafe_get(), wp<Foo>::fromExisting(foo.get()).unsafe_get());
EXPECT_FALSE(isDeleted);
foo = nullptr;
@@ -255,7 +255,7 @@
}
TEST(RefBase, AssertWeakRefExistsDeath) {
- // uses some other refcounting method, or non at all
+ // uses some other refcounting method, or none at all
bool isDeleted;
Foo* foo = new Foo(&isDeleted);
diff --git a/libutils/String16.cpp b/libutils/String16.cpp
index 70bf5a0..e3e5f11 100644
--- a/libutils/String16.cpp
+++ b/libutils/String16.cpp
@@ -390,28 +390,6 @@
return static_cast<size_t>(*(p - 1));
}
-status_t String16::makeLower()
-{
- const size_t N = size();
- const char16_t* str = string();
- char16_t* edited = nullptr;
- for (size_t i=0; i<N; i++) {
- const char16_t v = str[i];
- if (v >= 'A' && v <= 'Z') {
- if (!edited) {
- SharedBuffer* buf = static_cast<SharedBuffer*>(edit());
- if (!buf) {
- return NO_MEMORY;
- }
- edited = (char16_t*)buf->data();
- mString = str = edited;
- }
- edited[i] = tolower((char)v);
- }
- }
- return OK;
-}
-
status_t String16::replaceAll(char16_t replaceThis, char16_t withThis)
{
const size_t N = size();
diff --git a/libutils/String16_fuzz.cpp b/libutils/String16_fuzz.cpp
index 63c2800..defa0f5 100644
--- a/libutils/String16_fuzz.cpp
+++ b/libutils/String16_fuzz.cpp
@@ -34,11 +34,6 @@
str1.size();
}),
- // Casing
- ([](FuzzedDataProvider&, android::String16 str1, android::String16) -> void {
- str1.makeLower();
- }),
-
// Comparison
([](FuzzedDataProvider&, android::String16 str1, android::String16 str2) -> void {
str1.startsWith(str2);
diff --git a/libutils/String16_test.cpp b/libutils/String16_test.cpp
index 2505f44..c2e9b02 100644
--- a/libutils/String16_test.cpp
+++ b/libutils/String16_test.cpp
@@ -97,13 +97,6 @@
EXPECT_STR16EQ(u" m", tmp);
}
-TEST(String16Test, MakeLower) {
- String16 tmp("Verify Me!");
- tmp.makeLower();
- EXPECT_EQ(10U, tmp.size());
- EXPECT_STR16EQ(u"verify me!", tmp);
-}
-
TEST(String16Test, ReplaceAll) {
String16 tmp("Verify verify Verify");
tmp.replaceAll(u'r', u'!');
@@ -176,14 +169,6 @@
EXPECT_FALSE(tmp.isStaticString());
}
-TEST(String16Test, StaticStringMakeLower) {
- StaticString16 tmp(u"Verify me!");
- tmp.makeLower();
- EXPECT_EQ(10U, tmp.size());
- EXPECT_STR16EQ(u"verify me!", tmp);
- EXPECT_FALSE(tmp.isStaticString());
-}
-
TEST(String16Test, StaticStringReplaceAll) {
StaticString16 tmp(u"Verify verify Verify");
tmp.replaceAll(u'r', u'!');
diff --git a/libutils/String8.cpp b/libutils/String8.cpp
index 3dc2026..2974aa3 100644
--- a/libutils/String8.cpp
+++ b/libutils/String8.cpp
@@ -415,50 +415,15 @@
void String8::toLower()
{
- toLower(0, size());
-}
+ const size_t length = size();
+ if (length == 0) return;
-void String8::toLower(size_t start, size_t length)
-{
- const size_t len = size();
- if (start >= len) {
- return;
- }
- if (start+length > len) {
- length = len-start;
- }
- char* buf = lockBuffer(len);
- buf += start;
- while (length > 0) {
+ char* buf = lockBuffer(length);
+ for (size_t i = length; i > 0; --i) {
*buf = static_cast<char>(tolower(*buf));
buf++;
- length--;
}
- unlockBuffer(len);
-}
-
-void String8::toUpper()
-{
- toUpper(0, size());
-}
-
-void String8::toUpper(size_t start, size_t length)
-{
- const size_t len = size();
- if (start >= len) {
- return;
- }
- if (start+length > len) {
- length = len-start;
- }
- char* buf = lockBuffer(len);
- buf += start;
- while (length > 0) {
- *buf = static_cast<char>(toupper(*buf));
- buf++;
- length--;
- }
- unlockBuffer(len);
+ unlockBuffer(length);
}
// ---------------------------------------------------------------------------
diff --git a/libutils/String8_fuzz.cpp b/libutils/String8_fuzz.cpp
index b02683c..a45d675 100644
--- a/libutils/String8_fuzz.cpp
+++ b/libutils/String8_fuzz.cpp
@@ -42,9 +42,6 @@
// Casing
[](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
- str1->toUpper();
- },
- [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
str1->toLower();
},
[](FuzzedDataProvider*, android::String8* str1, android::String8* str2) -> void {
diff --git a/libutils/include/utils/RefBase.h b/libutils/include/utils/RefBase.h
index 5a5bd56..e07f574 100644
--- a/libutils/include/utils/RefBase.h
+++ b/libutils/include/utils/RefBase.h
@@ -416,13 +416,16 @@
wp(std::nullptr_t) : wp() {}
#else
wp(T* other); // NOLINT(implicit)
+ template <typename U>
+ wp(U* other); // NOLINT(implicit)
+ wp& operator=(T* other);
+ template <typename U>
+ wp& operator=(U* other);
#endif
+
wp(const wp<T>& other);
explicit wp(const sp<T>& other);
-#if !defined(ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION)
- template<typename U> wp(U* other); // NOLINT(implicit)
-#endif
template<typename U> wp(const sp<U>& other); // NOLINT(implicit)
template<typename U> wp(const wp<U>& other); // NOLINT(implicit)
@@ -430,15 +433,9 @@
// Assignment
-#if !defined(ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION)
- wp& operator = (T* other);
-#endif
wp& operator = (const wp<T>& other);
wp& operator = (const sp<T>& other);
-#if !defined(ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION)
- template<typename U> wp& operator = (U* other);
-#endif
template<typename U> wp& operator = (const wp<U>& other);
template<typename U> wp& operator = (const sp<U>& other);
@@ -547,6 +544,7 @@
refs->incWeakRequireWeak(other);
wp<T> ret;
+ ret.m_ptr = other;
ret.m_refs = refs;
return ret;
}
@@ -558,6 +556,31 @@
{
m_refs = other ? m_refs = other->createWeak(this) : nullptr;
}
+
+template <typename T>
+template <typename U>
+wp<T>::wp(U* other) : m_ptr(other) {
+ m_refs = other ? other->createWeak(this) : nullptr;
+}
+
+template <typename T>
+wp<T>& wp<T>::operator=(T* other) {
+ weakref_type* newRefs = other ? other->createWeak(this) : nullptr;
+ if (m_ptr) m_refs->decWeak(this);
+ m_ptr = other;
+ m_refs = newRefs;
+ return *this;
+}
+
+template <typename T>
+template <typename U>
+wp<T>& wp<T>::operator=(U* other) {
+ weakref_type* newRefs = other ? other->createWeak(this) : 0;
+ if (m_ptr) m_refs->decWeak(this);
+ m_ptr = other;
+ m_refs = newRefs;
+ return *this;
+}
#endif
template<typename T>
@@ -574,15 +597,6 @@
m_refs = m_ptr ? m_ptr->createWeak(this) : nullptr;
}
-#if !defined(ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION)
-template<typename T> template<typename U>
-wp<T>::wp(U* other)
- : m_ptr(other)
-{
- m_refs = other ? other->createWeak(this) : nullptr;
-}
-#endif
-
template<typename T> template<typename U>
wp<T>::wp(const wp<U>& other)
: m_ptr(other.m_ptr)
@@ -608,19 +622,6 @@
if (m_ptr) m_refs->decWeak(this);
}
-#if !defined(ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION)
-template<typename T>
-wp<T>& wp<T>::operator = (T* other)
-{
- weakref_type* newRefs =
- other ? other->createWeak(this) : nullptr;
- if (m_ptr) m_refs->decWeak(this);
- m_ptr = other;
- m_refs = newRefs;
- return *this;
-}
-#endif
-
template<typename T>
wp<T>& wp<T>::operator = (const wp<T>& other)
{
@@ -645,19 +646,6 @@
return *this;
}
-#if !defined(ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION)
-template<typename T> template<typename U>
-wp<T>& wp<T>::operator = (U* other)
-{
- weakref_type* newRefs =
- other ? other->createWeak(this) : 0;
- if (m_ptr) m_refs->decWeak(this);
- m_ptr = other;
- m_refs = newRefs;
- return *this;
-}
-#endif
-
template<typename T> template<typename U>
wp<T>& wp<T>::operator = (const wp<U>& other)
{
diff --git a/libutils/include/utils/String16.h b/libutils/include/utils/String16.h
index 1a4b47e..5ce48c6 100644
--- a/libutils/include/utils/String16.h
+++ b/libutils/include/utils/String16.h
@@ -85,8 +85,6 @@
bool contains(const char16_t* chrs) const;
- status_t makeLower();
-
status_t replaceAll(char16_t replaceThis,
char16_t withThis);
diff --git a/libutils/include/utils/String8.h b/libutils/include/utils/String8.h
index 0bcb716..cee5dc6 100644
--- a/libutils/include/utils/String8.h
+++ b/libutils/include/utils/String8.h
@@ -130,9 +130,6 @@
bool removeAll(const char* other);
void toLower();
- void toLower(size_t start, size_t numChars);
- void toUpper();
- void toUpper(size_t start, size_t numChars);
/*
diff --git a/libutils/include/utils/StrongPointer.h b/libutils/include/utils/StrongPointer.h
index 1f07052..bb1941b 100644
--- a/libutils/include/utils/StrongPointer.h
+++ b/libutils/include/utils/StrongPointer.h
@@ -62,31 +62,34 @@
sp(std::nullptr_t) : sp() {}
#else
sp(T* other); // NOLINT(implicit)
+ template <typename U>
+ sp(U* other); // NOLINT(implicit)
+ sp& operator=(T* other);
+ template <typename U>
+ sp& operator=(U* other);
#endif
+
sp(const sp<T>& other);
sp(sp<T>&& other) noexcept;
-#if !defined(ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION)
- template<typename U> sp(U* other); // NOLINT(implicit)
-#endif
template<typename U> sp(const sp<U>& other); // NOLINT(implicit)
template<typename U> sp(sp<U>&& other); // NOLINT(implicit)
+ // Cast a strong pointer directly from one type to another. Constructors
+ // allow changing types, but only if they are pointer-compatible. This does
+ // a static_cast internally.
+ template <typename U>
+ static inline sp<T> cast(const sp<U>& other);
+
~sp();
// Assignment
-#if !defined(ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION)
- sp& operator = (T* other);
-#endif
sp& operator = (const sp<T>& other);
sp& operator=(sp<T>&& other) noexcept;
template<typename U> sp& operator = (const sp<U>& other);
template<typename U> sp& operator = (sp<U>&& other);
-#if !defined(ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION)
- template<typename U> sp& operator = (U* other);
-#endif
//! Special optimization for use by ProcessState (and nobody else).
void force_set(T* other);
@@ -241,6 +244,28 @@
other->incStrong(this);
}
}
+
+template <typename T>
+template <typename U>
+sp<T>::sp(U* other) : m_ptr(other) {
+ if (other) {
+ check_not_on_stack(other);
+ (static_cast<T*>(other))->incStrong(this);
+ }
+}
+
+template <typename T>
+sp<T>& sp<T>::operator=(T* other) {
+ T* oldPtr(*const_cast<T* volatile*>(&m_ptr));
+ if (other) {
+ check_not_on_stack(other);
+ other->incStrong(this);
+ }
+ if (oldPtr) oldPtr->decStrong(this);
+ if (oldPtr != *const_cast<T* volatile*>(&m_ptr)) sp_report_race();
+ m_ptr = other;
+ return *this;
+}
#endif
template<typename T>
@@ -255,17 +280,6 @@
other.m_ptr = nullptr;
}
-#if !defined(ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION)
-template<typename T> template<typename U>
-sp<T>::sp(U* other)
- : m_ptr(other) {
- if (other) {
- check_not_on_stack(other);
- (static_cast<T*>(other))->incStrong(this);
- }
-}
-#endif
-
template<typename T> template<typename U>
sp<T>::sp(const sp<U>& other)
: m_ptr(other.m_ptr) {
@@ -279,6 +293,12 @@
other.m_ptr = nullptr;
}
+template <typename T>
+template <typename U>
+sp<T> sp<T>::cast(const sp<U>& other) {
+ return sp<T>::fromExisting(static_cast<T*>(other.get()));
+}
+
template<typename T>
sp<T>::~sp() {
if (m_ptr)
@@ -307,21 +327,6 @@
return *this;
}
-#if !defined(ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION)
-template<typename T>
-sp<T>& sp<T>::operator =(T* other) {
- T* oldPtr(*const_cast<T* volatile*>(&m_ptr));
- if (other) {
- check_not_on_stack(other);
- other->incStrong(this);
- }
- if (oldPtr) oldPtr->decStrong(this);
- if (oldPtr != *const_cast<T* volatile*>(&m_ptr)) sp_report_race();
- m_ptr = other;
- return *this;
-}
-#endif
-
template<typename T> template<typename U>
sp<T>& sp<T>::operator =(const sp<U>& other) {
T* oldPtr(*const_cast<T* volatile*>(&m_ptr));
diff --git a/rootdir/Android.bp b/rootdir/Android.bp
index 6a80808..ae21633 100644
--- a/rootdir/Android.bp
+++ b/rootdir/Android.bp
@@ -20,7 +20,10 @@
name: "init.rc",
src: "init.rc",
sub_dir: "init/hw",
- required: ["fsverity_init"],
+ required: [
+ "fsverity_init",
+ "platform-bootclasspath",
+ ],
}
prebuilt_etc {
@@ -35,3 +38,11 @@
src: "etc/linker.config.json",
installable: false,
}
+
+// TODO(b/185211376) Scope the native APIs that microdroid will provide to the app payload
+prebuilt_etc {
+ name: "public.libraries.android.txt",
+ src: "etc/public.libraries.android.txt",
+ filename: "public.libraries.txt",
+ installable: false,
+}
\ No newline at end of file
diff --git a/rootdir/etc/linker.config.json b/rootdir/etc/linker.config.json
index 83cb6ff..d9f5526 100644
--- a/rootdir/etc/linker.config.json
+++ b/rootdir/etc/linker.config.json
@@ -1,8 +1,7 @@
{
"requireLibs": [
- // Keep in sync with the "platform" namespace in art/build/apex/ld.config.txt.
- "libdexfile_external.so",
- "libdexfiled_external.so",
+ "libdexfile.so",
+ "libdexfiled.so",
"libnativebridge.so",
"libnativehelper.so",
"libnativeloader.so",
diff --git a/rootdir/init-debug.rc b/rootdir/init-debug.rc
index 435d4cb..cac88fd 100644
--- a/rootdir/init-debug.rc
+++ b/rootdir/init-debug.rc
@@ -6,3 +6,10 @@
on property:persist.mmc.cache_size=*
write /sys/block/mmcblk0/cache_size ${persist.mmc.cache_size}
+
+on early-init && property:ro.product.enforce_debugfs_restrictions=true
+ mount debugfs debugfs /sys/kernel/debug
+ chmod 0755 /sys/kernel/debug
+
+on property:sys.boot_completed=1 && property:ro.product.enforce_debugfs_restrictions=true
+ umount /sys/kernel/debug
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 0ac2dee..08de882 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -767,6 +767,8 @@
mkdir /data/misc/snapshotctl_log 0755 root root
# create location to store pre-reboot information
mkdir /data/misc/prereboot 0700 system system
+ # directory used for on-device refresh metrics file.
+ mkdir /data/misc/odrefresh 0777 system system
# directory used for on-device signing key blob
mkdir /data/misc/odsign 0700 root root
@@ -996,9 +998,6 @@
write /proc/sys/vm/dirty_expire_centisecs 200
write /proc/sys/vm/dirty_background_ratio 5
-on property:sys.boot_completed=1 && property:init.mount_debugfs=1
- umount /sys/kernel/debug
-
on boot
# basic network init
ifup lo
@@ -1274,10 +1273,6 @@
on property:sys.boot_completed=1 && property:sys.init.userspace_reboot.in_progress=1
setprop sys.init.userspace_reboot.in_progress ""
-on early-init && property:init.mount_debugfs=1
- mount debugfs debugfs /sys/kernel/debug
- chmod 0755 /sys/kernel/debug
-
# Migrate tasks again in case kernel threads are created during boot
on property:sys.boot_completed=1
copy_per_line /dev/cpuctl/tasks /dev/cpuctl/system/tasks
diff --git a/rootdir/ueventd.rc b/rootdir/ueventd.rc
index 65e29c1..56e774b 100644
--- a/rootdir/ueventd.rc
+++ b/rootdir/ueventd.rc
@@ -67,6 +67,10 @@
# CDMA radio interface MUX
/dev/ppp 0660 radio vpn
+# Virtualisation is managed by Virt Manager
+/dev/kvm 0600 virtmanager root
+/dev/vhost-vsock 0600 virtmanager root
+
# sysfs properties
/sys/devices/platform/trusty.* trusty_version 0440 root log
/sys/devices/virtual/input/input* enable 0660 root input
diff --git a/trusty/fuzz/include/trusty/fuzz/utils.h b/trusty/fuzz/include/trusty/fuzz/utils.h
index bca84e9..c906412 100644
--- a/trusty/fuzz/include/trusty/fuzz/utils.h
+++ b/trusty/fuzz/include/trusty/fuzz/utils.h
@@ -34,6 +34,7 @@
android::base::Result<void> Connect();
android::base::Result<void> Read(void* buf, size_t len);
android::base::Result<void> Write(const void* buf, size_t len);
+ void Disconnect();
android::base::Result<int> GetRawFd();
diff --git a/trusty/fuzz/tipc_fuzzer.cpp b/trusty/fuzz/tipc_fuzzer.cpp
index 3258944..f265ced 100644
--- a/trusty/fuzz/tipc_fuzzer.cpp
+++ b/trusty/fuzz/tipc_fuzzer.cpp
@@ -41,6 +41,7 @@
#error "Binary file name must be parameterized using -DTRUSTY_APP_FILENAME."
#endif
+static TrustyApp kTrustyApp(TIPC_DEV, TRUSTY_APP_PORT);
static std::unique_ptr<CoverageRecord> record;
extern "C" int LLVMFuzzerInitialize(int* /* argc */, char*** /* argv */) {
@@ -52,8 +53,7 @@
}
/* Make sure lazy-loaded TAs have started and connected to coverage service. */
- TrustyApp ta(TIPC_DEV, TRUSTY_APP_PORT);
- auto ret = ta.Connect();
+ auto ret = kTrustyApp.Connect();
if (!ret.ok()) {
std::cerr << ret.error() << std::endl;
exit(-1);
@@ -79,22 +79,18 @@
ExtraCounters counters(record.get());
counters.Reset();
- TrustyApp ta(TIPC_DEV, TRUSTY_APP_PORT);
- auto ret = ta.Connect();
+ auto ret = kTrustyApp.Write(data, size);
+ if (ret.ok()) {
+ ret = kTrustyApp.Read(&buf, sizeof(buf));
+ }
+
+ // Reconnect to ensure that the service is still up
+ kTrustyApp.Disconnect();
+ ret = kTrustyApp.Connect();
if (!ret.ok()) {
std::cerr << ret.error() << std::endl;
android::trusty::fuzz::Abort();
}
- ret = ta.Write(data, size);
- if (!ret.ok()) {
- return -1;
- }
-
- ret = ta.Read(&buf, sizeof(buf));
- if (!ret.ok()) {
- return -1;
- }
-
- return 0;
+ return ret.ok() ? 0 : -1;
}
diff --git a/trusty/fuzz/utils.cpp b/trusty/fuzz/utils.cpp
index 3526337..bb096be 100644
--- a/trusty/fuzz/utils.cpp
+++ b/trusty/fuzz/utils.cpp
@@ -127,6 +127,10 @@
return ta_fd_;
}
+void TrustyApp::Disconnect() {
+ ta_fd_.reset();
+}
+
void Abort() {
PrintTrustyLog();
exit(-1);