Merge "libmeminfo: librank optimization using maps instead of vectors"
diff --git a/adb/benchmark_device.py b/adb/benchmark_device.py
index e56ef5a..4d0cf49 100755
--- a/adb/benchmark_device.py
+++ b/adb/benchmark_device.py
@@ -17,6 +17,8 @@
import os
import statistics
+import subprocess
+import tempfile
import time
import adb
@@ -56,6 +58,41 @@
msg = "%s: %d runs: median %.2f MiB/s, mean %.2f MiB/s, stddev: %.2f MiB/s"
print(msg % (name, len(speeds), median, mean, stddev))
+def benchmark_sink(device=None, size_mb=100):
+ if device == None:
+ device = adb.get_device()
+
+ speeds = list()
+ cmd = device.adb_cmd + ["raw", "sink:%d" % (size_mb * 1024 * 1024)]
+
+ with tempfile.TemporaryFile() as tmpfile:
+ tmpfile.truncate(size_mb * 1024 * 1024)
+
+ for _ in range(0, 10):
+ tmpfile.seek(0)
+ begin = time.time()
+ subprocess.check_call(cmd, stdin=tmpfile)
+ end = time.time()
+ speeds.append(size_mb / float(end - begin))
+
+ analyze("sink %dMiB" % size_mb, speeds)
+
+def benchmark_source(device=None, size_mb=100):
+ if device == None:
+ device = adb.get_device()
+
+ speeds = list()
+ cmd = device.adb_cmd + ["raw", "source:%d" % (size_mb * 1024 * 1024)]
+
+ with open(os.devnull, 'w') as devnull:
+ for _ in range(0, 10):
+ begin = time.time()
+ subprocess.check_call(cmd, stdout=devnull)
+ end = time.time()
+ speeds.append(size_mb / float(end - begin))
+
+ analyze("source %dMiB" % size_mb, speeds)
+
def benchmark_push(device=None, file_size_mb=100):
if device == None:
device = adb.get_device()
@@ -110,6 +147,8 @@
def main():
device = adb.get_device()
unlock(device)
+ benchmark_sink(device)
+ benchmark_source(device)
benchmark_push(device)
benchmark_pull(device)
diff --git a/adb/daemon/usb.cpp b/adb/daemon/usb.cpp
index 83ff221..598f2cd 100644
--- a/adb/daemon/usb.cpp
+++ b/adb/daemon/usb.cpp
@@ -57,11 +57,11 @@
// We can't find out whether we have support for AIO on ffs endpoints until we submit a read.
static std::optional<bool> gFfsAioSupported;
-static constexpr size_t kUsbReadQueueDepth = 16;
-static constexpr size_t kUsbReadSize = 16384;
+static constexpr size_t kUsbReadQueueDepth = 32;
+static constexpr size_t kUsbReadSize = 8 * PAGE_SIZE;
-static constexpr size_t kUsbWriteQueueDepth = 16;
-static constexpr size_t kUsbWriteSize = 16 * PAGE_SIZE;
+static constexpr size_t kUsbWriteQueueDepth = 32;
+static constexpr size_t kUsbWriteSize = 8 * PAGE_SIZE;
static const char* to_string(enum usb_functionfs_event_type type) {
switch (type) {
@@ -260,7 +260,6 @@
// until it dies, and then report failure to the transport via HandleError, which will
// eventually result in the transport being destroyed, which will result in UsbFfsConnection
// being destroyed, which unblocks the open thread and restarts this entire process.
- static constexpr int kInterruptionSignal = SIGUSR1;
static std::once_flag handler_once;
std::call_once(handler_once, []() { signal(kInterruptionSignal, [](int) {}); });
@@ -286,6 +285,7 @@
} else if (rc == 0) {
// Something in the kernel presumably went wrong.
// Close our endpoints, wait for a bit, and then try again.
+ StopWorker();
aio_context_.reset();
read_fd_.reset();
write_fd_.reset();
@@ -311,7 +311,7 @@
switch (event.type) {
case FUNCTIONFS_BIND:
- CHECK(!started) << "received FUNCTIONFS_ENABLE while already bound?";
+ CHECK(!bound) << "received FUNCTIONFS_BIND while already bound?";
bound = true;
break;
@@ -327,28 +327,7 @@
}
}
- pthread_t worker_thread_handle = worker_thread_.native_handle();
- while (true) {
- int rc = pthread_kill(worker_thread_handle, kInterruptionSignal);
- if (rc != 0) {
- LOG(ERROR) << "failed to send interruption signal to worker: " << strerror(rc);
- break;
- }
-
- std::this_thread::sleep_for(100ms);
-
- rc = pthread_kill(worker_thread_handle, 0);
- if (rc == 0) {
- continue;
- } else if (rc == ESRCH) {
- break;
- } else {
- LOG(ERROR) << "failed to send interruption signal to worker: " << strerror(rc);
- }
- }
-
- worker_thread_.join();
-
+ StopWorker();
aio_context_.reset();
read_fd_.reset();
write_fd_.reset();
@@ -379,6 +358,30 @@
});
}
+ void StopWorker() {
+ pthread_t worker_thread_handle = worker_thread_.native_handle();
+ while (true) {
+ int rc = pthread_kill(worker_thread_handle, kInterruptionSignal);
+ if (rc != 0) {
+ LOG(ERROR) << "failed to send interruption signal to worker: " << strerror(rc);
+ break;
+ }
+
+ std::this_thread::sleep_for(100ms);
+
+ rc = pthread_kill(worker_thread_handle, 0);
+ if (rc == 0) {
+ continue;
+ } else if (rc == ESRCH) {
+ break;
+ } else {
+ LOG(ERROR) << "failed to send interruption signal to worker: " << strerror(rc);
+ }
+ }
+
+ worker_thread_.join();
+ }
+
void PrepareReadBlock(IoBlock* block, uint64_t id) {
block->pending = false;
block->payload = std::make_shared<Block>(kUsbReadSize);
@@ -615,6 +618,8 @@
std::deque<std::unique_ptr<IoBlock>> write_requests_ GUARDED_BY(write_mutex_);
size_t next_write_id_ GUARDED_BY(write_mutex_) = 0;
size_t writes_submitted_ GUARDED_BY(write_mutex_) = 0;
+
+ static constexpr int kInterruptionSignal = SIGUSR1;
};
void usb_init_legacy();
diff --git a/bootstat/OWNERS b/bootstat/OWNERS
index 7fe0443..50b2097 100644
--- a/bootstat/OWNERS
+++ b/bootstat/OWNERS
@@ -1 +1,2 @@
jhawkins@google.com
+salyzyn@google.com
diff --git a/fastboot/fastboot_driver.cpp b/fastboot/fastboot_driver.cpp
index 65a5247..fea0a77 100644
--- a/fastboot/fastboot_driver.cpp
+++ b/fastboot/fastboot_driver.cpp
@@ -403,7 +403,7 @@
RetCode FastBootDriver::HandleResponse(std::string* response, std::vector<std::string>* info,
int* dsize) {
char status[FB_RESPONSE_SZ + 1];
- auto start = std::chrono::system_clock::now();
+ auto start = std::chrono::steady_clock::now();
auto set_response = [response](std::string s) {
if (response) *response = std::move(s);
@@ -414,7 +414,7 @@
// erase response
set_response("");
- while ((std::chrono::system_clock::now() - start) < std::chrono::seconds(RESP_TIMEOUT)) {
+ while ((std::chrono::steady_clock::now() - start) < std::chrono::seconds(RESP_TIMEOUT)) {
int r = transport_->Read(status, FB_RESPONSE_SZ);
if (r < 0) {
error_ = ErrnoStr("Status read failed");
@@ -427,6 +427,11 @@
std::string tmp = input.substr(strlen("INFO"));
info_(tmp);
add_info(std::move(tmp));
+ // We may receive one or more INFO packets during long operations,
+ // e.g. flash/erase if they are back by slow media like NAND/NOR
+ // flash. In that case, reset the timer since it's not a real
+ // timeout.
+ start = std::chrono::steady_clock::now();
} else if (android::base::StartsWith(input, "OKAY")) {
set_response(input.substr(strlen("OKAY")));
return SUCCESS;
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index 5d4a3cc..2f1e41f 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -307,6 +307,8 @@
} else {
entry->logical_blk_size = val;
}
+ } else if (StartsWith(flag, "avb_keys=")) { // must before the following "avb"
+ entry->avb_keys = arg;
} else if (StartsWith(flag, "avb")) {
entry->fs_mgr_flags.avb = true;
entry->vbmeta_partition = arg;
@@ -325,8 +327,6 @@
}
} else if (StartsWith(flag, "zram_backing_dev_path=")) {
entry->zram_backing_dev_path = arg;
- } else if (StartsWith(flag, "avb_keys=")) {
- entry->avb_keys = arg;
} else {
LWARNING << "Warning: unknown flag: " << flag;
}
diff --git a/fs_mgr/libfiemap_writer/fiemap_writer.cpp b/fs_mgr/libfiemap_writer/fiemap_writer.cpp
index 6b742e6..8b880e6 100644
--- a/fs_mgr/libfiemap_writer/fiemap_writer.cpp
+++ b/fs_mgr/libfiemap_writer/fiemap_writer.cpp
@@ -200,9 +200,8 @@
return false;
}
- if (file_size % sfs.f_bsize) {
- LOG(ERROR) << "File size " << file_size << " is not aligned to optimal block size "
- << sfs.f_bsize << " for file " << file_path;
+ if (!sfs.f_bsize) {
+ LOG(ERROR) << "Unsupported block size: " << sfs.f_bsize;
return false;
}
@@ -500,6 +499,11 @@
return nullptr;
}
+ // Align up to the nearest block size.
+ if (file_size % blocksz) {
+ file_size += blocksz - (file_size % blocksz);
+ }
+
if (create) {
if (!AllocateFile(file_fd, abs_path, blocksz, file_size, std::move(progress))) {
LOG(ERROR) << "Failed to allocate file: " << abs_path << " of size: " << file_size
diff --git a/fs_mgr/libfiemap_writer/fiemap_writer_test.cpp b/fs_mgr/libfiemap_writer/fiemap_writer_test.cpp
index 3e8381b..d1c0aad 100644
--- a/fs_mgr/libfiemap_writer/fiemap_writer_test.cpp
+++ b/fs_mgr/libfiemap_writer/fiemap_writer_test.cpp
@@ -22,6 +22,7 @@
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/types.h>
+#include <sys/vfs.h>
#include <unistd.h>
#include <string>
@@ -43,6 +44,7 @@
std::string gTestDir;
uint64_t testfile_size = 536870912; // default of 512MiB
+size_t gBlockSize = 0;
class FiemapWriterTest : public ::testing::Test {
protected:
@@ -71,16 +73,15 @@
// Try creating a file of size 4097 bytes which is guaranteed
// to be unaligned to all known block sizes. The creation must
// fail.
- FiemapUniquePtr fptr = FiemapWriter::Open(testfile, 4097);
- EXPECT_EQ(fptr, nullptr);
- EXPECT_EQ(access(testfile.c_str(), F_OK), -1);
- EXPECT_EQ(errno, ENOENT);
+ FiemapUniquePtr fptr = FiemapWriter::Open(testfile, gBlockSize + 1);
+ ASSERT_NE(fptr, nullptr);
+ ASSERT_EQ(fptr->size(), gBlockSize * 2);
}
TEST_F(FiemapWriterTest, CheckFilePath) {
- FiemapUniquePtr fptr = FiemapWriter::Open(testfile, 4096);
+ FiemapUniquePtr fptr = FiemapWriter::Open(testfile, gBlockSize);
ASSERT_NE(fptr, nullptr);
- EXPECT_EQ(fptr->size(), 4096);
+ EXPECT_EQ(fptr->size(), gBlockSize);
EXPECT_EQ(fptr->file_path(), testfile);
EXPECT_EQ(access(testfile.c_str(), F_OK), 0);
}
@@ -88,18 +89,18 @@
TEST_F(FiemapWriterTest, CheckProgress) {
std::vector<uint64_t> expected{
0,
- 4096,
+ gBlockSize,
};
size_t invocations = 0;
auto callback = [&](uint64_t done, uint64_t total) -> bool {
EXPECT_LT(invocations, expected.size());
EXPECT_EQ(done, expected[invocations]);
- EXPECT_EQ(total, 4096);
+ EXPECT_EQ(total, gBlockSize);
invocations++;
return true;
};
- auto ptr = FiemapWriter::Open(testfile, 4096, true, std::move(callback));
+ auto ptr = FiemapWriter::Open(testfile, gBlockSize, true, std::move(callback));
EXPECT_NE(ptr, nullptr);
EXPECT_EQ(invocations, 2);
}
@@ -111,8 +112,8 @@
}
TEST_F(FiemapWriterTest, CheckBlockDevicePath) {
- FiemapUniquePtr fptr = FiemapWriter::Open(testfile, 4096);
- EXPECT_EQ(fptr->size(), 4096);
+ FiemapUniquePtr fptr = FiemapWriter::Open(testfile, gBlockSize);
+ EXPECT_EQ(fptr->size(), gBlockSize);
EXPECT_EQ(fptr->bdev_path().find("/dev/block/"), size_t(0));
EXPECT_EQ(fptr->bdev_path().find("/dev/block/dm-"), string::npos);
}
@@ -139,44 +140,23 @@
EXPECT_GT(fptr->extents().size(), 0);
}
-class TestExistingFile : public ::testing::Test {
- protected:
- void SetUp() override {
- unaligned_file_ = gTestDir + "/unaligned_file";
- file_4k_ = gTestDir + "/file_4k";
- file_32k_ = gTestDir + "/file_32k";
-
- CleanupFiles();
- fptr_unaligned = FiemapWriter::Open(unaligned_file_, 4097);
- fptr_4k = FiemapWriter::Open(file_4k_, 4096);
- fptr_32k = FiemapWriter::Open(file_32k_, 32768);
+TEST_F(FiemapWriterTest, ExistingFile) {
+ // Create the file.
+ { ASSERT_NE(FiemapWriter::Open(testfile, gBlockSize), nullptr); }
+ // Test that we can still open it.
+ {
+ auto ptr = FiemapWriter::Open(testfile, 0, false);
+ ASSERT_NE(ptr, nullptr);
+ EXPECT_GT(ptr->extents().size(), 0);
}
+}
- void TearDown() { CleanupFiles(); }
-
- void CleanupFiles() {
- unlink(unaligned_file_.c_str());
- unlink(file_4k_.c_str());
- unlink(file_32k_.c_str());
- }
-
- std::string unaligned_file_;
- std::string file_4k_;
- std::string file_32k_;
- FiemapUniquePtr fptr_unaligned;
- FiemapUniquePtr fptr_4k;
- FiemapUniquePtr fptr_32k;
-};
-
-TEST_F(TestExistingFile, ErrorChecks) {
- EXPECT_EQ(fptr_unaligned, nullptr);
- EXPECT_NE(fptr_4k, nullptr);
- EXPECT_NE(fptr_32k, nullptr);
-
- EXPECT_EQ(fptr_4k->size(), 4096);
- EXPECT_EQ(fptr_32k->size(), 32768);
- EXPECT_GT(fptr_4k->extents().size(), 0);
- EXPECT_GT(fptr_32k->extents().size(), 0);
+TEST_F(FiemapWriterTest, FileDeletedOnError) {
+ auto callback = [](uint64_t, uint64_t) -> bool { return false; };
+ auto ptr = FiemapWriter::Open(testfile, gBlockSize, true, std::move(callback));
+ EXPECT_EQ(ptr, nullptr);
+ EXPECT_EQ(access(testfile.c_str(), F_OK), -1);
+ EXPECT_EQ(errno, ENOENT);
}
class VerifyBlockWritesExt4 : public ::testing::Test {
@@ -263,6 +243,21 @@
std::string fs_path;
};
+bool DetermineBlockSize() {
+ struct statfs s;
+ if (statfs(gTestDir.c_str(), &s)) {
+ std::cerr << "Could not call statfs: " << strerror(errno) << "\n";
+ return false;
+ }
+ if (!s.f_bsize) {
+ std::cerr << "Invalid block size: " << s.f_bsize << "\n";
+ return false;
+ }
+
+ gBlockSize = s.f_bsize;
+ return true;
+}
+
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
if (argc <= 1) {
@@ -275,7 +270,7 @@
std::string tempdir = argv[1] + "/XXXXXX"s;
if (!mkdtemp(tempdir.data())) {
- cerr << "unable to create tempdir on " << argv[1];
+ cerr << "unable to create tempdir on " << argv[1] << "\n";
exit(EXIT_FAILURE);
}
gTestDir = tempdir;
@@ -287,6 +282,10 @@
}
}
+ if (!DetermineBlockSize()) {
+ exit(EXIT_FAILURE);
+ }
+
auto result = RUN_ALL_TESTS();
std::string cmd = "rm -rf " + gTestDir;
diff --git a/fs_mgr/libfiemap_writer/include/libfiemap_writer/fiemap_writer.h b/fs_mgr/libfiemap_writer/include/libfiemap_writer/fiemap_writer.h
index b5472c9..3ba68e9 100644
--- a/fs_mgr/libfiemap_writer/include/libfiemap_writer/fiemap_writer.h
+++ b/fs_mgr/libfiemap_writer/include/libfiemap_writer/fiemap_writer.h
@@ -41,6 +41,9 @@
// invoked, if create is true, while the file is being initialized. It receives the bytes
// written and the number of total bytes. If the callback returns false, the operation will
// fail.
+ //
+ // Note: when create is true, the file size will be aligned up to the nearest file system
+ // block.
static FiemapUniquePtr Open(const std::string& file_path, uint64_t file_size,
bool create = true,
std::function<bool(uint64_t, uint64_t)> progress = {});
diff --git a/fs_mgr/liblp/builder.cpp b/fs_mgr/liblp/builder.cpp
index c39fbe7..ebd6997 100644
--- a/fs_mgr/liblp/builder.cpp
+++ b/fs_mgr/liblp/builder.cpp
@@ -550,11 +550,11 @@
}
bool MetadataBuilder::ValidatePartitionSizeChange(Partition* partition, uint64_t old_size,
- uint64_t new_size) {
+ uint64_t new_size, bool force_check) {
PartitionGroup* group = FindGroup(partition->group_name());
CHECK(group);
- if (new_size <= old_size) {
+ if (!force_check && new_size <= old_size) {
return true;
}
@@ -861,7 +861,7 @@
uint64_t aligned_size = AlignTo(requested_size, geometry_.logical_block_size);
uint64_t old_size = partition->size();
- if (!ValidatePartitionSizeChange(partition, old_size, aligned_size)) {
+ if (!ValidatePartitionSizeChange(partition, old_size, aligned_size, false)) {
return false;
}
@@ -973,7 +973,12 @@
ImportExtents(partition, metadata, source);
- if (!ValidatePartitionSizeChange(partition, 0, partition->size())) {
+ // Note: we've already increased the partition size by calling
+ // ImportExtents(). In order to figure out the size before that,
+ // we would have to iterate the extents and add up the linear
+ // segments. Instead, we just force ValidatePartitionSizeChange
+ // to check if the current configuration is acceptable.
+ if (!ValidatePartitionSizeChange(partition, partition->size(), partition->size(), true)) {
partition->RemoveExtents();
return false;
}
diff --git a/fs_mgr/liblp/builder_test.cpp b/fs_mgr/liblp/builder_test.cpp
index 69724f8..81305b3 100644
--- a/fs_mgr/liblp/builder_test.cpp
+++ b/fs_mgr/liblp/builder_test.cpp
@@ -835,3 +835,73 @@
EXPECT_EQ(exported->extents[1].target_data, 4608);
EXPECT_EQ(exported->extents[1].num_sectors, 1536);
}
+
+TEST_F(BuilderTest, UpdateSuper) {
+ // Build the on-disk metadata that we saw before flashing.
+ auto builder = MetadataBuilder::New(8145338368ULL, 65536, 3);
+ ASSERT_NE(builder, nullptr);
+
+ ASSERT_TRUE(builder->AddGroup("google_dynamic_partitions_a", 4068474880ULL));
+ ASSERT_TRUE(builder->AddGroup("google_dynamic_partitions_b", 4068474880ULL));
+
+ Partition* partition = builder->AddPartition("system_a", "google_dynamic_partitions_a",
+ LP_PARTITION_ATTR_READONLY);
+ ASSERT_NE(partition, nullptr);
+ ASSERT_TRUE(builder->AddLinearExtent(partition, "super", 1901568, 3608576));
+
+ partition = builder->AddPartition("vendor_a", "google_dynamic_partitions_a",
+ LP_PARTITION_ATTR_READONLY);
+ ASSERT_NE(partition, nullptr);
+ ASSERT_TRUE(builder->AddLinearExtent(partition, "super", 1521664, 5510144));
+
+ partition = builder->AddPartition("product_a", "google_dynamic_partitions_a",
+ LP_PARTITION_ATTR_READONLY);
+ ASSERT_NE(partition, nullptr);
+ ASSERT_TRUE(builder->AddLinearExtent(partition, "super", 3606528, 2048));
+
+ partition = builder->AddPartition("system_b", "google_dynamic_partitions_b",
+ LP_PARTITION_ATTR_READONLY);
+ ASSERT_NE(partition, nullptr);
+ ASSERT_TRUE(builder->AddLinearExtent(partition, "super", 1901568, 7955456));
+
+ partition = builder->AddPartition("vendor_b", "google_dynamic_partitions_b",
+ LP_PARTITION_ATTR_READONLY);
+ ASSERT_NE(partition, nullptr);
+ ASSERT_TRUE(builder->AddLinearExtent(partition, "super", 1521664, 9857024));
+
+ partition = builder->AddPartition("product_b", "google_dynamic_partitions_b",
+ LP_PARTITION_ATTR_READONLY);
+ ASSERT_NE(partition, nullptr);
+ ASSERT_TRUE(builder->AddLinearExtent(partition, "super", 3606528, 11378688));
+
+ auto on_disk = builder->Export();
+ ASSERT_NE(on_disk, nullptr);
+
+ // Build the super_empty from the new build.
+ builder = MetadataBuilder::New(8145338368ULL, 65536, 3);
+ ASSERT_NE(builder, nullptr);
+
+ ASSERT_TRUE(builder->AddGroup("google_dynamic_partitions_a", 4068474880ULL));
+ ASSERT_TRUE(builder->AddGroup("google_dynamic_partitions_b", 4068474880ULL));
+ ASSERT_NE(builder->AddPartition("system_a", "google_dynamic_partitions_a",
+ LP_PARTITION_ATTR_READONLY),
+ nullptr);
+ ASSERT_NE(builder->AddPartition("system_b", "google_dynamic_partitions_b",
+ LP_PARTITION_ATTR_READONLY),
+ nullptr);
+ ASSERT_NE(builder->AddPartition("vendor_a", "google_dynamic_partitions_a",
+ LP_PARTITION_ATTR_READONLY),
+ nullptr);
+ ASSERT_NE(builder->AddPartition("vendor_b", "google_dynamic_partitions_b",
+ LP_PARTITION_ATTR_READONLY),
+ nullptr);
+ ASSERT_NE(builder->AddPartition("product_a", "google_dynamic_partitions_a",
+ LP_PARTITION_ATTR_READONLY),
+ nullptr);
+ ASSERT_NE(builder->AddPartition("product_b", "google_dynamic_partitions_b",
+ LP_PARTITION_ATTR_READONLY),
+ nullptr);
+
+ std::set<std::string> partitions_to_keep{"system_a", "vendor_a", "product_a"};
+ ASSERT_TRUE(builder->ImportPartitions(*on_disk.get(), partitions_to_keep));
+}
diff --git a/fs_mgr/liblp/include/liblp/builder.h b/fs_mgr/liblp/include/liblp/builder.h
index 53f480f..486a71f 100644
--- a/fs_mgr/liblp/include/liblp/builder.h
+++ b/fs_mgr/liblp/include/liblp/builder.h
@@ -297,7 +297,8 @@
uint64_t TotalSizeOfGroup(PartitionGroup* group) const;
bool UpdateBlockDeviceInfo(size_t index, const BlockDeviceInfo& info);
bool FindBlockDeviceByName(const std::string& partition_name, uint32_t* index) const;
- bool ValidatePartitionSizeChange(Partition* partition, uint64_t old_size, uint64_t new_size);
+ bool ValidatePartitionSizeChange(Partition* partition, uint64_t old_size, uint64_t new_size,
+ bool force_check);
void ImportExtents(Partition* dest, const LpMetadata& metadata,
const LpMetadataPartition& source);
bool ImportPartition(const LpMetadata& metadata, const LpMetadataPartition& source);
diff --git a/fs_mgr/tests/fs_mgr_test.cpp b/fs_mgr/tests/fs_mgr_test.cpp
index 6afc8d2..72afa69 100644
--- a/fs_mgr/tests/fs_mgr_test.cpp
+++ b/fs_mgr/tests/fs_mgr_test.cpp
@@ -948,13 +948,14 @@
ASSERT_TRUE(tf.fd != -1);
std::string fstab_contents = R"fs(
source none0 swap defaults avb=vbmeta_partition
+source none1 swap defaults avb_keys=/path/to/test.avbpubkey
)fs";
ASSERT_TRUE(android::base::WriteStringToFile(fstab_contents, tf.path));
Fstab fstab;
EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab));
- ASSERT_EQ(1U, fstab.size());
+ ASSERT_EQ(2U, fstab.size());
auto entry = fstab.begin();
EXPECT_EQ("none0", entry->mount_point);
@@ -964,6 +965,12 @@
EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
EXPECT_EQ("vbmeta_partition", entry->vbmeta_partition);
+ entry++;
+
+ EXPECT_EQ("none1", entry->mount_point);
+ FstabEntry::FsMgrFlags empty_flags = {}; // no flags should be set for avb_keys.
+ EXPECT_TRUE(CompareFlags(empty_flags, entry->fs_mgr_flags));
+ EXPECT_EQ("/path/to/test.avbpubkey", entry->avb_keys);
}
TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_KeyDirectory) {
diff --git a/libprocessgroup/cgroup_map.cpp b/libprocessgroup/cgroup_map.cpp
index d094811..26d0754 100644
--- a/libprocessgroup/cgroup_map.cpp
+++ b/libprocessgroup/cgroup_map.cpp
@@ -45,6 +45,7 @@
using android::base::unique_fd;
static constexpr const char* CGROUPS_DESC_FILE = "/etc/cgroups.json";
+static constexpr const char* CGROUPS_DESC_VENDOR_FILE = "/vendor/etc/cgroups.json";
static constexpr const char* CGROUP_PROCS_FILE = "/cgroup.procs";
static constexpr const char* CGROUP_TASKS_FILE = "/tasks";
@@ -110,12 +111,13 @@
return true;
}
-static bool ReadDescriptors(std::map<std::string, CgroupDescriptor>* descriptors) {
+static bool ReadDescriptorsFromFile(const std::string& file_name,
+ std::map<std::string, CgroupDescriptor>* descriptors) {
std::vector<CgroupDescriptor> result;
std::string json_doc;
- if (!android::base::ReadFileToString(CGROUPS_DESC_FILE, &json_doc)) {
- LOG(ERROR) << "Failed to read task profiles from " << CGROUPS_DESC_FILE;
+ if (!android::base::ReadFileToString(file_name, &json_doc)) {
+ LOG(ERROR) << "Failed to read task profiles from " << file_name;
return false;
}
@@ -130,21 +132,46 @@
const Json::Value& cgroups = root["Cgroups"];
for (Json::Value::ArrayIndex i = 0; i < cgroups.size(); ++i) {
std::string name = cgroups[i]["Controller"].asString();
- descriptors->emplace(std::make_pair(
- name,
- CgroupDescriptor(1, name, cgroups[i]["Path"].asString(),
+ auto iter = descriptors->find(name);
+ if (iter == descriptors->end()) {
+ descriptors->emplace(name, CgroupDescriptor(1, name, cgroups[i]["Path"].asString(),
std::strtoul(cgroups[i]["Mode"].asString().c_str(), 0, 8),
- cgroups[i]["UID"].asString(), cgroups[i]["GID"].asString())));
+ cgroups[i]["UID"].asString(), cgroups[i]["GID"].asString()));
+ } else {
+ iter->second = CgroupDescriptor(1, name, cgroups[i]["Path"].asString(),
+ std::strtoul(cgroups[i]["Mode"].asString().c_str(), 0, 8),
+ cgroups[i]["UID"].asString(), cgroups[i]["GID"].asString());
+ }
}
}
if (root.isMember("Cgroups2")) {
const Json::Value& cgroups2 = root["Cgroups2"];
- descriptors->emplace(std::make_pair(
- CGROUPV2_CONTROLLER_NAME,
- CgroupDescriptor(2, CGROUPV2_CONTROLLER_NAME, cgroups2["Path"].asString(),
+ auto iter = descriptors->find(CGROUPV2_CONTROLLER_NAME);
+ if (iter == descriptors->end()) {
+ descriptors->emplace(CGROUPV2_CONTROLLER_NAME, CgroupDescriptor(2, CGROUPV2_CONTROLLER_NAME, cgroups2["Path"].asString(),
std::strtoul(cgroups2["Mode"].asString().c_str(), 0, 8),
- cgroups2["UID"].asString(), cgroups2["GID"].asString())));
+ cgroups2["UID"].asString(), cgroups2["GID"].asString()));
+ } else {
+ iter->second = CgroupDescriptor(2, CGROUPV2_CONTROLLER_NAME, cgroups2["Path"].asString(),
+ std::strtoul(cgroups2["Mode"].asString().c_str(), 0, 8),
+ cgroups2["UID"].asString(), cgroups2["GID"].asString());
+ }
+ }
+
+ return true;
+}
+
+static bool ReadDescriptors(std::map<std::string, CgroupDescriptor>* descriptors) {
+ // load system cgroup descriptors
+ if (!ReadDescriptorsFromFile(CGROUPS_DESC_FILE, descriptors)) {
+ return false;
+ }
+
+ // load vendor cgroup descriptors if the file exists
+ if (!access(CGROUPS_DESC_VENDOR_FILE, F_OK) &&
+ !ReadDescriptorsFromFile(CGROUPS_DESC_VENDOR_FILE, descriptors)) {
+ return false;
}
return true;
diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp
index 8505e61..8884650 100644
--- a/libprocessgroup/processgroup.cpp
+++ b/libprocessgroup/processgroup.cpp
@@ -170,8 +170,9 @@
return ret;
}
-static void RemoveUidProcessGroups(const std::string& uid_path) {
+static bool RemoveUidProcessGroups(const std::string& uid_path) {
std::unique_ptr<DIR, decltype(&closedir)> uid(opendir(uid_path.c_str()), closedir);
+ bool empty = true;
if (uid != NULL) {
dirent* dir;
while ((dir = readdir(uid.get())) != nullptr) {
@@ -185,9 +186,15 @@
auto path = StringPrintf("%s/%s", uid_path.c_str(), dir->d_name);
LOG(VERBOSE) << "Removing " << path;
- if (rmdir(path.c_str()) == -1) PLOG(WARNING) << "Failed to remove " << path;
+ if (rmdir(path.c_str()) == -1) {
+ if (errno != EBUSY) {
+ PLOG(WARNING) << "Failed to remove " << path;
+ }
+ empty = false;
+ }
}
}
+ return empty;
}
void removeAllProcessGroups() {
@@ -219,9 +226,14 @@
}
auto path = StringPrintf("%s/%s", cgroup_root_path.c_str(), dir->d_name);
- RemoveUidProcessGroups(path);
+ if (!RemoveUidProcessGroups(path)) {
+ LOG(VERBOSE) << "Skip removing " << path;
+ continue;
+ }
LOG(VERBOSE) << "Removing " << path;
- if (rmdir(path.c_str()) == -1) PLOG(WARNING) << "Failed to remove " << path;
+ if (rmdir(path.c_str()) == -1 && errno != EBUSY) {
+ PLOG(WARNING) << "Failed to remove " << path;
+ }
}
}
}
@@ -249,6 +261,10 @@
auto path = ConvertUidPidToPath(cgroup, uid, initialPid) + PROCESSGROUP_CGROUP_PROCS_FILE;
std::unique_ptr<FILE, decltype(&fclose)> fd(fopen(path.c_str(), "re"), fclose);
if (!fd) {
+ if (errno == ENOENT) {
+ // This happens when process is already dead
+ return 0;
+ }
PLOG(WARNING) << "Failed to open process cgroup uid " << uid << " pid " << initialPid;
return -1;
}
@@ -293,7 +309,7 @@
LOG(VERBOSE) << "Killing process group " << -pgid << " in uid " << uid
<< " as part of process cgroup " << initialPid;
- if (kill(-pgid, signal) == -1) {
+ if (kill(-pgid, signal) == -1 && errno != ESRCH) {
PLOG(WARNING) << "kill(" << -pgid << ", " << signal << ") failed";
}
}
@@ -303,7 +319,7 @@
LOG(VERBOSE) << "Killing pid " << pid << " in uid " << uid << " as part of process cgroup "
<< initialPid;
- if (kill(pid, signal) == -1) {
+ if (kill(pid, signal) == -1 && errno != ESRCH) {
PLOG(WARNING) << "kill(" << pid << ", " << signal << ") failed";
}
}
diff --git a/libprocessgroup/task_profiles.cpp b/libprocessgroup/task_profiles.cpp
index 8ec29d3..fded417 100644
--- a/libprocessgroup/task_profiles.cpp
+++ b/libprocessgroup/task_profiles.cpp
@@ -42,6 +42,7 @@
using android::base::WriteStringToFile;
#define TASK_PROFILE_DB_FILE "/etc/task_profiles.json"
+#define TASK_PROFILE_DB_VENDOR_FILE "/vendor/etc/task_profiles.json"
bool ProfileAttribute::GetPathForTask(int tid, std::string* path) const {
std::string subgroup;
@@ -288,16 +289,24 @@
}
TaskProfiles::TaskProfiles() {
- if (!Load(CgroupMap::GetInstance())) {
- LOG(ERROR) << "TaskProfiles::Load for [" << getpid() << "] failed";
+ // load system task profiles
+ if (!Load(CgroupMap::GetInstance(), TASK_PROFILE_DB_FILE)) {
+ LOG(ERROR) << "Loading " << TASK_PROFILE_DB_FILE << " for [" << getpid() << "] failed";
+ }
+
+ // load vendor task profiles if the file exists
+ if (!access(TASK_PROFILE_DB_VENDOR_FILE, F_OK) &&
+ !Load(CgroupMap::GetInstance(), TASK_PROFILE_DB_VENDOR_FILE)) {
+ LOG(ERROR) << "Loading " << TASK_PROFILE_DB_VENDOR_FILE << " for [" << getpid()
+ << "] failed";
}
}
-bool TaskProfiles::Load(const CgroupMap& cg_map) {
+bool TaskProfiles::Load(const CgroupMap& cg_map, const std::string& file_name) {
std::string json_doc;
- if (!android::base::ReadFileToString(TASK_PROFILE_DB_FILE, &json_doc)) {
- LOG(ERROR) << "Failed to read task profiles from " << TASK_PROFILE_DB_FILE;
+ if (!android::base::ReadFileToString(file_name, &json_doc)) {
+ LOG(ERROR) << "Failed to read task profiles from " << file_name;
return false;
}
@@ -308,18 +317,18 @@
return false;
}
- Json::Value attr = root["Attributes"];
+ const Json::Value& attr = root["Attributes"];
for (Json::Value::ArrayIndex i = 0; i < attr.size(); ++i) {
std::string name = attr[i]["Name"].asString();
- std::string ctrlName = attr[i]["Controller"].asString();
- std::string file_name = attr[i]["File"].asString();
+ std::string controller_name = attr[i]["Controller"].asString();
+ std::string file_attr = attr[i]["File"].asString();
if (attributes_.find(name) == attributes_.end()) {
- const CgroupController* controller = cg_map.FindController(ctrlName);
+ const CgroupController* controller = cg_map.FindController(controller_name);
if (controller) {
- attributes_[name] = std::make_unique<ProfileAttribute>(controller, file_name);
+ attributes_[name] = std::make_unique<ProfileAttribute>(controller, file_attr);
} else {
- LOG(WARNING) << "Controller " << ctrlName << " is not found";
+ LOG(WARNING) << "Controller " << controller_name << " is not found";
}
} else {
LOG(WARNING) << "Attribute " << name << " is already defined";
@@ -328,72 +337,72 @@
std::map<std::string, std::string> params;
- Json::Value profilesVal = root["Profiles"];
- for (Json::Value::ArrayIndex i = 0; i < profilesVal.size(); ++i) {
- Json::Value profileVal = profilesVal[i];
+ const Json::Value& profiles_val = root["Profiles"];
+ for (Json::Value::ArrayIndex i = 0; i < profiles_val.size(); ++i) {
+ const Json::Value& profile_val = profiles_val[i];
- std::string profileName = profileVal["Name"].asString();
- Json::Value actions = profileVal["Actions"];
+ std::string profile_name = profile_val["Name"].asString();
+ const Json::Value& actions = profile_val["Actions"];
auto profile = std::make_unique<TaskProfile>();
- for (Json::Value::ArrayIndex actIdx = 0; actIdx < actions.size(); ++actIdx) {
- Json::Value actionVal = actions[actIdx];
- std::string actionName = actionVal["Name"].asString();
- Json::Value paramsVal = actionVal["Params"];
- if (actionName == "JoinCgroup") {
- std::string ctrlName = paramsVal["Controller"].asString();
- std::string path = paramsVal["Path"].asString();
+ for (Json::Value::ArrayIndex act_idx = 0; act_idx < actions.size(); ++act_idx) {
+ const Json::Value& action_val = actions[act_idx];
+ std::string action_name = action_val["Name"].asString();
+ const Json::Value& params_val = action_val["Params"];
+ if (action_name == "JoinCgroup") {
+ std::string controller_name = params_val["Controller"].asString();
+ std::string path = params_val["Path"].asString();
- const CgroupController* controller = cg_map.FindController(ctrlName);
+ const CgroupController* controller = cg_map.FindController(controller_name);
if (controller) {
profile->Add(std::make_unique<SetCgroupAction>(controller, path));
} else {
- LOG(WARNING) << "JoinCgroup: controller " << ctrlName << " is not found";
+ LOG(WARNING) << "JoinCgroup: controller " << controller_name << " is not found";
}
- } else if (actionName == "SetTimerSlack") {
- std::string slackValue = paramsVal["Slack"].asString();
+ } else if (action_name == "SetTimerSlack") {
+ std::string slack_value = params_val["Slack"].asString();
char* end;
unsigned long slack;
- slack = strtoul(slackValue.c_str(), &end, 10);
- if (end > slackValue.c_str()) {
+ slack = strtoul(slack_value.c_str(), &end, 10);
+ if (end > slack_value.c_str()) {
profile->Add(std::make_unique<SetTimerSlackAction>(slack));
} else {
- LOG(WARNING) << "SetTimerSlack: invalid parameter: " << slackValue;
+ LOG(WARNING) << "SetTimerSlack: invalid parameter: " << slack_value;
}
- } else if (actionName == "SetAttribute") {
- std::string attrName = paramsVal["Name"].asString();
- std::string attrValue = paramsVal["Value"].asString();
+ } else if (action_name == "SetAttribute") {
+ std::string attr_name = params_val["Name"].asString();
+ std::string attr_value = params_val["Value"].asString();
- auto iter = attributes_.find(attrName);
+ auto iter = attributes_.find(attr_name);
if (iter != attributes_.end()) {
profile->Add(
- std::make_unique<SetAttributeAction>(iter->second.get(), attrValue));
+ std::make_unique<SetAttributeAction>(iter->second.get(), attr_value));
} else {
- LOG(WARNING) << "SetAttribute: unknown attribute: " << attrName;
+ LOG(WARNING) << "SetAttribute: unknown attribute: " << attr_name;
}
- } else if (actionName == "SetClamps") {
- std::string boostValue = paramsVal["Boost"].asString();
- std::string clampValue = paramsVal["Clamp"].asString();
+ } else if (action_name == "SetClamps") {
+ std::string boost_value = params_val["Boost"].asString();
+ std::string clamp_value = params_val["Clamp"].asString();
char* end;
unsigned long boost;
- boost = strtoul(boostValue.c_str(), &end, 10);
- if (end > boostValue.c_str()) {
- unsigned long clamp = strtoul(clampValue.c_str(), &end, 10);
- if (end > clampValue.c_str()) {
+ boost = strtoul(boost_value.c_str(), &end, 10);
+ if (end > boost_value.c_str()) {
+ unsigned long clamp = strtoul(clamp_value.c_str(), &end, 10);
+ if (end > clamp_value.c_str()) {
profile->Add(std::make_unique<SetClampsAction>(boost, clamp));
} else {
- LOG(WARNING) << "SetClamps: invalid parameter " << clampValue;
+ LOG(WARNING) << "SetClamps: invalid parameter " << clamp_value;
}
} else {
- LOG(WARNING) << "SetClamps: invalid parameter: " << boostValue;
+ LOG(WARNING) << "SetClamps: invalid parameter: " << boost_value;
}
} else {
- LOG(WARNING) << "Unknown profile action: " << actionName;
+ LOG(WARNING) << "Unknown profile action: " << action_name;
}
}
- profiles_[profileName] = std::move(profile);
+ profiles_[profile_name] = std::move(profile);
}
return true;
diff --git a/libprocessgroup/task_profiles.h b/libprocessgroup/task_profiles.h
index b2e39f9..9ee81c1 100644
--- a/libprocessgroup/task_profiles.h
+++ b/libprocessgroup/task_profiles.h
@@ -152,5 +152,5 @@
TaskProfiles();
- bool Load(const CgroupMap& cg_map);
+ bool Load(const CgroupMap& cg_map, const std::string& file_name);
};