Merge "Fix double-accounting bug in liblp."
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 f0e2861..598f2cd 100644
--- a/adb/daemon/usb.cpp
+++ b/adb/daemon/usb.cpp
@@ -29,6 +29,7 @@
 #include <linux/usb/functionfs.h>
 #include <sys/eventfd.h>
 
+#include <algorithm>
 #include <array>
 #include <future>
 #include <memory>
@@ -56,10 +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 kUsbWriteQueueDepth = 32;
+static constexpr size_t kUsbWriteSize = 8 * PAGE_SIZE;
 
 static const char* to_string(enum usb_functionfs_event_type type) {
     switch (type) {
@@ -115,7 +117,7 @@
 struct IoBlock {
     bool pending;
     struct iocb control;
-    Block payload;
+    std::shared_ptr<Block> payload;
 
     TransferId id() const { return TransferId::from_value(control.aio_data); }
 };
@@ -207,8 +209,20 @@
         std::lock_guard<std::mutex> lock(write_mutex_);
         write_requests_.push_back(CreateWriteBlock(std::move(header), next_write_id_++));
         if (!packet->payload.empty()) {
-            write_requests_.push_back(
-                    CreateWriteBlock(std::move(packet->payload), next_write_id_++));
+            // The kernel attempts to allocate a contiguous block of memory for each write,
+            // which can fail if the write is large and the kernel heap is fragmented.
+            // Split large writes into smaller chunks to avoid this.
+            std::shared_ptr<Block> payload = std::make_shared<Block>(std::move(packet->payload));
+            size_t offset = 0;
+            size_t len = payload->size();
+
+            while (len > 0) {
+                size_t write_size = std::min(kUsbWriteSize, len);
+                write_requests_.push_back(
+                        CreateWriteBlock(payload, offset, write_size, next_write_id_++));
+                len -= write_size;
+                offset += write_size;
+            }
         }
         SubmitWrites();
         return true;
@@ -246,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) {}); });
 
@@ -272,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();
@@ -297,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;
 
@@ -313,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();
@@ -365,12 +358,36 @@
         });
     }
 
+    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.resize(kUsbReadSize);
+        block->payload = std::make_shared<Block>(kUsbReadSize);
         block->control.aio_data = static_cast<uint64_t>(TransferId::read(id));
-        block->control.aio_buf = reinterpret_cast<uintptr_t>(block->payload.data());
-        block->control.aio_nbytes = block->payload.size();
+        block->control.aio_buf = reinterpret_cast<uintptr_t>(block->payload->data());
+        block->control.aio_nbytes = block->payload->size();
     }
 
     IoBlock CreateReadBlock(uint64_t id) {
@@ -421,7 +438,7 @@
         uint64_t read_idx = id.id % kUsbReadQueueDepth;
         IoBlock* block = &read_requests_[read_idx];
         block->pending = false;
-        block->payload.resize(size);
+        block->payload->resize(size);
 
         // Notification for completed reads can be received out of order.
         if (block->id().id != needed_read_id_) {
@@ -442,16 +459,16 @@
     }
 
     void ProcessRead(IoBlock* block) {
-        if (!block->payload.empty()) {
+        if (!block->payload->empty()) {
             if (!incoming_header_.has_value()) {
-                CHECK_EQ(sizeof(amessage), block->payload.size());
+                CHECK_EQ(sizeof(amessage), block->payload->size());
                 amessage msg;
-                memcpy(&msg, block->payload.data(), sizeof(amessage));
+                memcpy(&msg, block->payload->data(), sizeof(amessage));
                 LOG(DEBUG) << "USB read:" << dump_header(&msg);
                 incoming_header_ = msg;
             } else {
                 size_t bytes_left = incoming_header_->data_length - incoming_payload_.size();
-                Block payload = std::move(block->payload);
+                Block payload = std::move(*block->payload);
                 CHECK_LE(payload.size(), bytes_left);
                 incoming_payload_.append(std::make_unique<Block>(std::move(payload)));
             }
@@ -506,7 +523,8 @@
         SubmitWrites();
     }
 
-    std::unique_ptr<IoBlock> CreateWriteBlock(Block payload, uint64_t id) {
+    std::unique_ptr<IoBlock> CreateWriteBlock(std::shared_ptr<Block> payload, size_t offset,
+                                              size_t len, uint64_t id) {
         auto block = std::make_unique<IoBlock>();
         block->payload = std::move(payload);
         block->control.aio_data = static_cast<uint64_t>(TransferId::write(id));
@@ -514,14 +532,20 @@
         block->control.aio_lio_opcode = IOCB_CMD_PWRITE;
         block->control.aio_reqprio = 0;
         block->control.aio_fildes = write_fd_.get();
-        block->control.aio_buf = reinterpret_cast<uintptr_t>(block->payload.data());
-        block->control.aio_nbytes = block->payload.size();
+        block->control.aio_buf = reinterpret_cast<uintptr_t>(block->payload->data() + offset);
+        block->control.aio_nbytes = len;
         block->control.aio_offset = 0;
         block->control.aio_flags = IOCB_FLAG_RESFD;
         block->control.aio_resfd = worker_event_fd_.get();
         return block;
     }
 
+    std::unique_ptr<IoBlock> CreateWriteBlock(Block payload, uint64_t id) {
+        std::shared_ptr<Block> block = std::make_shared<Block>(std::move(payload));
+        size_t len = block->size();
+        return CreateWriteBlock(std::move(block), 0, len, id);
+    }
+
     void SubmitWrites() REQUIRES(write_mutex_) {
         if (writes_submitted_ == kUsbWriteQueueDepth) {
             return;
@@ -594,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/libfs_avb/avb_util.cpp b/fs_mgr/libfs_avb/avb_util.cpp
index 7d89902..f4e4d4e 100644
--- a/fs_mgr/libfs_avb/avb_util.cpp
+++ b/fs_mgr/libfs_avb/avb_util.cpp
@@ -326,7 +326,7 @@
     return false;
 }
 
-bool ValidatePublicKeyBlob(const std::string key_blob_to_validate,
+bool ValidatePublicKeyBlob(const std::string& key_blob_to_validate,
                            const std::vector<std::string>& allowed_key_paths) {
     std::string allowed_key_blob;
     if (key_blob_to_validate.empty()) {
diff --git a/fs_mgr/libfs_avb/avb_util.h b/fs_mgr/libfs_avb/avb_util.h
index 986a69a..09c786a 100644
--- a/fs_mgr/libfs_avb/avb_util.h
+++ b/fs_mgr/libfs_avb/avb_util.h
@@ -80,7 +80,7 @@
 
 bool ValidatePublicKeyBlob(const uint8_t* key, size_t length, const std::string& expected_key_blob);
 
-bool ValidatePublicKeyBlob(const std::string key_blob_to_validate,
+bool ValidatePublicKeyBlob(const std::string& key_blob_to_validate,
                            const std::vector<std::string>& expected_key_paths);
 
 // Detects if whether a partition contains a rollback image.
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/profiles/task_profiles.json b/libprocessgroup/profiles/task_profiles.json
index 985720f..74a39cd 100644
--- a/libprocessgroup/profiles/task_profiles.json
+++ b/libprocessgroup/profiles/task_profiles.json
@@ -56,10 +56,10 @@
   "Profiles": [
     {
       "Name": "HighEnergySaving",
-      "Actions" : [
+      "Actions": [
         {
-          "Name" : "JoinCgroup",
-          "Params" :
+          "Name": "JoinCgroup",
+          "Params":
           {
             "Controller": "schedtune",
             "Path": "background"
@@ -69,10 +69,10 @@
     },
     {
       "Name": "NormalPerformance",
-      "Actions" : [
+      "Actions": [
         {
-          "Name" : "JoinCgroup",
-          "Params" :
+          "Name": "JoinCgroup",
+          "Params":
           {
             "Controller": "schedtune",
             "Path": ""
@@ -82,10 +82,10 @@
     },
     {
       "Name": "HighPerformance",
-      "Actions" : [
+      "Actions": [
         {
-          "Name" : "JoinCgroup",
-          "Params" :
+          "Name": "JoinCgroup",
+          "Params":
           {
             "Controller": "schedtune",
             "Path": "foreground"
@@ -95,10 +95,10 @@
     },
     {
       "Name": "MaxPerformance",
-      "Actions" : [
+      "Actions": [
         {
-          "Name" : "JoinCgroup",
-          "Params" :
+          "Name": "JoinCgroup",
+          "Params":
           {
             "Controller": "schedtune",
             "Path": "top-app"
@@ -108,10 +108,10 @@
     },
     {
       "Name": "RealtimePerformance",
-      "Actions" : [
+      "Actions": [
         {
-          "Name" : "JoinCgroup",
-          "Params" :
+          "Name": "JoinCgroup",
+          "Params":
           {
             "Controller": "schedtune",
             "Path": "rt"
@@ -122,26 +122,26 @@
 
     {
       "Name": "CpuPolicySpread",
-      "Actions" : [
+      "Actions": [
         {
-          "Name" : "SetAttribute",
-          "Params" :
+          "Name": "SetAttribute",
+          "Params":
           {
-            "Name" : "STunePreferIdle",
-            "Value" : "1"
+            "Name": "STunePreferIdle",
+            "Value": "1"
           }
         }
       ]
     },
     {
       "Name": "CpuPolicyPack",
-      "Actions" : [
+      "Actions": [
         {
-          "Name" : "SetAttribute",
-          "Params" :
+          "Name": "SetAttribute",
+          "Params":
           {
-            "Name" : "STunePreferIdle",
-            "Value" : "0"
+            "Name": "STunePreferIdle",
+            "Value": "0"
           }
         }
       ]
@@ -149,10 +149,10 @@
 
     {
       "Name": "VrKernelCapacity",
-      "Actions" : [
+      "Actions": [
         {
-          "Name" : "JoinCgroup",
-          "Params" :
+          "Name": "JoinCgroup",
+          "Params":
           {
             "Controller": "cpuset",
             "Path": ""
@@ -162,10 +162,10 @@
     },
     {
       "Name": "VrServiceCapacityLow",
-      "Actions" : [
+      "Actions": [
         {
-          "Name" : "JoinCgroup",
-          "Params" :
+          "Name": "JoinCgroup",
+          "Params":
           {
             "Controller": "cpuset",
             "Path": "system/background"
@@ -175,10 +175,10 @@
     },
     {
       "Name": "VrServiceCapacityNormal",
-      "Actions" : [
+      "Actions": [
         {
-          "Name" : "JoinCgroup",
-          "Params" :
+          "Name": "JoinCgroup",
+          "Params":
           {
             "Controller": "cpuset",
             "Path": "system"
@@ -188,10 +188,10 @@
     },
     {
       "Name": "VrServiceCapacityHigh",
-      "Actions" : [
+      "Actions": [
         {
-          "Name" : "JoinCgroup",
-          "Params" :
+          "Name": "JoinCgroup",
+          "Params":
           {
             "Controller": "cpuset",
             "Path": "system/performance"
@@ -201,10 +201,10 @@
     },
     {
       "Name": "VrProcessCapacityLow",
-      "Actions" : [
+      "Actions": [
         {
-          "Name" : "JoinCgroup",
-          "Params" :
+          "Name": "JoinCgroup",
+          "Params":
           {
             "Controller": "cpuset",
             "Path": "application/background"
@@ -214,10 +214,10 @@
     },
     {
       "Name": "VrProcessCapacityNormal",
-      "Actions" : [
+      "Actions": [
         {
-          "Name" : "JoinCgroup",
-          "Params" :
+          "Name": "JoinCgroup",
+          "Params":
           {
             "Controller": "cpuset",
             "Path": "application"
@@ -227,10 +227,10 @@
     },
     {
       "Name": "VrProcessCapacityHigh",
-      "Actions" : [
+      "Actions": [
         {
-          "Name" : "JoinCgroup",
-          "Params" :
+          "Name": "JoinCgroup",
+          "Params":
           {
             "Controller": "cpuset",
             "Path": "application/performance"
@@ -241,10 +241,10 @@
 
     {
       "Name": "ProcessCapacityLow",
-      "Actions" : [
+      "Actions": [
         {
-          "Name" : "JoinCgroup",
-          "Params" :
+          "Name": "JoinCgroup",
+          "Params":
           {
             "Controller": "cpuset",
             "Path": "background"
@@ -254,10 +254,10 @@
     },
     {
       "Name": "ProcessCapacityNormal",
-      "Actions" : [
+      "Actions": [
         {
-          "Name" : "JoinCgroup",
-          "Params" :
+          "Name": "JoinCgroup",
+          "Params":
           {
             "Controller": "cpuset",
             "Path": ""
@@ -267,10 +267,10 @@
     },
     {
       "Name": "ProcessCapacityHigh",
-      "Actions" : [
+      "Actions": [
         {
-          "Name" : "JoinCgroup",
-          "Params" :
+          "Name": "JoinCgroup",
+          "Params":
           {
             "Controller": "cpuset",
             "Path": "foreground"
@@ -280,10 +280,10 @@
     },
     {
       "Name": "ProcessCapacityMax",
-      "Actions" : [
+      "Actions": [
         {
-          "Name" : "JoinCgroup",
-          "Params" :
+          "Name": "JoinCgroup",
+          "Params":
           {
             "Controller": "cpuset",
             "Path": "top-app"
@@ -294,10 +294,10 @@
 
     {
       "Name": "ServiceCapacityLow",
-      "Actions" : [
+      "Actions": [
         {
-          "Name" : "JoinCgroup",
-          "Params" :
+          "Name": "JoinCgroup",
+          "Params":
           {
             "Controller": "cpuset",
             "Path": "system-background"
@@ -307,10 +307,10 @@
     },
     {
       "Name": "ServiceCapacityRestricted",
-      "Actions" : [
+      "Actions": [
         {
-          "Name" : "JoinCgroup",
-          "Params" :
+          "Name": "JoinCgroup",
+          "Params":
           {
             "Controller": "cpuset",
             "Path": "restricted"
@@ -321,10 +321,10 @@
 
     {
       "Name": "CameraServiceCapacity",
-      "Actions" : [
+      "Actions": [
         {
-          "Name" : "JoinCgroup",
-          "Params" :
+          "Name": "JoinCgroup",
+          "Params":
           {
             "Controller": "cpuset",
             "Path": "camera-daemon"
@@ -335,10 +335,10 @@
 
     {
       "Name": "LowIoPriority",
-      "Actions" : [
+      "Actions": [
         {
-          "Name" : "JoinCgroup",
-          "Params" :
+          "Name": "JoinCgroup",
+          "Params":
           {
             "Controller": "blkio",
             "Path": "background"
@@ -348,10 +348,10 @@
     },
     {
       "Name": "NormalIoPriority",
-      "Actions" : [
+      "Actions": [
         {
-          "Name" : "JoinCgroup",
-          "Params" :
+          "Name": "JoinCgroup",
+          "Params":
           {
             "Controller": "blkio",
             "Path": ""
@@ -361,10 +361,10 @@
     },
     {
       "Name": "HighIoPriority",
-      "Actions" : [
+      "Actions": [
         {
-          "Name" : "JoinCgroup",
-          "Params" :
+          "Name": "JoinCgroup",
+          "Params":
           {
             "Controller": "blkio",
             "Path": ""
@@ -374,10 +374,10 @@
     },
     {
       "Name": "MaxIoPriority",
-      "Actions" : [
+      "Actions": [
         {
-          "Name" : "JoinCgroup",
-          "Params" :
+          "Name": "JoinCgroup",
+          "Params":
           {
             "Controller": "blkio",
             "Path": ""
@@ -388,10 +388,10 @@
 
     {
       "Name": "TimerSlackHigh",
-      "Actions" : [
+      "Actions": [
         {
-          "Name" : "SetTimerSlack",
-          "Params" :
+          "Name": "SetTimerSlack",
+          "Params":
           {
             "Slack": "40000000"
           }
@@ -400,10 +400,10 @@
     },
     {
       "Name": "TimerSlackNormal",
-      "Actions" : [
+      "Actions": [
         {
-          "Name" : "SetTimerSlack",
-          "Params" :
+          "Name": "SetTimerSlack",
+          "Params":
           {
             "Slack": "50000"
           }
@@ -413,26 +413,26 @@
 
     {
       "Name": "PerfBoost",
-      "Actions" : [
+      "Actions": [
         {
-          "Name" : "SetClamps",
-          "Params" :
+          "Name": "SetClamps",
+          "Params":
           {
-            "Boost" : "50%",
-            "Clamp" : "0"
+            "Boost": "50%",
+            "Clamp": "0"
           }
         }
       ]
     },
     {
       "Name": "PerfClamp",
-      "Actions" : [
+      "Actions": [
         {
-          "Name" : "SetClamps",
-          "Params" :
+          "Name": "SetClamps",
+          "Params":
           {
-            "Boost" : "0",
-            "Clamp" : "30%"
+            "Boost": "0",
+            "Clamp": "30%"
           }
         }
       ]
@@ -440,21 +440,21 @@
 
     {
       "Name": "LowMemoryUsage",
-      "Actions" : [
+      "Actions": [
         {
-          "Name" : "SetAttribute",
-          "Params" :
+          "Name": "SetAttribute",
+          "Params":
           {
-            "Name" : "MemSoftLimit",
-            "Value" : "16MB"
+            "Name": "MemSoftLimit",
+            "Value": "16MB"
           }
         },
         {
-          "Name" : "SetAttribute",
-          "Params" :
+          "Name": "SetAttribute",
+          "Params":
           {
-            "Name" : "MemSwappiness",
-            "Value" : "150"
+            "Name": "MemSwappiness",
+            "Value": "150"
 
           }
         }
@@ -462,31 +462,31 @@
     },
     {
       "Name": "HighMemoryUsage",
-      "Actions" : [
+      "Actions": [
         {
-          "Name" : "SetAttribute",
-          "Params" :
+          "Name": "SetAttribute",
+          "Params":
           {
-            "Name" : "MemSoftLimit",
-            "Value" : "512MB"
+            "Name": "MemSoftLimit",
+            "Value": "512MB"
           }
         },
         {
-          "Name" : "SetAttribute",
-          "Params" :
+          "Name": "SetAttribute",
+          "Params":
           {
-            "Name" : "MemSwappiness",
-            "Value" : "100"
+            "Name": "MemSwappiness",
+            "Value": "100"
           }
         }
       ]
     },
     {
       "Name": "SystemMemoryProcess",
-      "Actions" : [
+      "Actions": [
         {
-          "Name" : "JoinCgroup",
-          "Params" :
+          "Name": "JoinCgroup",
+          "Params":
           {
             "Controller": "memory",
             "Path": "system"
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);
 };