Merge "Adding 'postinstall' root dir unconditionally."
diff --git a/fs_mgr/libsnapshot/cow_api_test.cpp b/fs_mgr/libsnapshot/cow_api_test.cpp
index 4db6584..35020f4 100644
--- a/fs_mgr/libsnapshot/cow_api_test.cpp
+++ b/fs_mgr/libsnapshot/cow_api_test.cpp
@@ -525,6 +525,165 @@
     ASSERT_TRUE(iter->Done());
 }
 
+TEST_F(CowTest, ClusterTest) {
+    CowOptions options;
+    options.cluster_ops = 4;
+    auto writer = std::make_unique<CowWriter>(options);
+    ASSERT_TRUE(writer->Initialize(cow_->fd));
+
+    std::string data = "This is some data, believe it";
+    data.resize(options.block_size, '\0');
+    ASSERT_TRUE(writer->AddRawBlocks(50, data.data(), data.size()));
+
+    ASSERT_TRUE(writer->AddLabel(4));
+
+    ASSERT_TRUE(writer->AddZeroBlocks(50, 2));  // Cluster split in middle
+
+    ASSERT_TRUE(writer->AddLabel(5));
+
+    ASSERT_TRUE(writer->AddCopy(5, 6));
+
+    // Cluster split
+
+    ASSERT_TRUE(writer->AddLabel(6));
+
+    ASSERT_TRUE(writer->Finalize());  // No data for cluster, so no cluster split needed
+
+    ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
+
+    // Read back all ops
+    CowReader reader;
+    ASSERT_TRUE(reader.Parse(cow_->fd));
+
+    StringSink sink;
+
+    auto iter = reader.GetOpIter();
+    ASSERT_NE(iter, nullptr);
+
+    ASSERT_FALSE(iter->Done());
+    auto op = &iter->Get();
+    ASSERT_EQ(op->type, kCowReplaceOp);
+    ASSERT_TRUE(reader.ReadData(*op, &sink));
+    ASSERT_EQ(sink.stream(), data.substr(0, options.block_size));
+
+    iter->Next();
+    sink.Reset();
+
+    ASSERT_FALSE(iter->Done());
+    op = &iter->Get();
+    ASSERT_EQ(op->type, kCowLabelOp);
+    ASSERT_EQ(op->source, 4);
+
+    iter->Next();
+
+    ASSERT_FALSE(iter->Done());
+    op = &iter->Get();
+    ASSERT_EQ(op->type, kCowZeroOp);
+
+    iter->Next();
+
+    ASSERT_FALSE(iter->Done());
+    op = &iter->Get();
+    ASSERT_EQ(op->type, kCowClusterOp);
+
+    iter->Next();
+
+    ASSERT_FALSE(iter->Done());
+    op = &iter->Get();
+    ASSERT_EQ(op->type, kCowZeroOp);
+
+    iter->Next();
+
+    ASSERT_FALSE(iter->Done());
+    op = &iter->Get();
+    ASSERT_EQ(op->type, kCowLabelOp);
+    ASSERT_EQ(op->source, 5);
+
+    iter->Next();
+
+    ASSERT_FALSE(iter->Done());
+    op = &iter->Get();
+    ASSERT_EQ(op->type, kCowCopyOp);
+
+    iter->Next();
+
+    ASSERT_FALSE(iter->Done());
+    op = &iter->Get();
+    ASSERT_EQ(op->type, kCowClusterOp);
+
+    iter->Next();
+
+    ASSERT_FALSE(iter->Done());
+    op = &iter->Get();
+    ASSERT_EQ(op->type, kCowLabelOp);
+    ASSERT_EQ(op->source, 6);
+
+    iter->Next();
+
+    ASSERT_TRUE(iter->Done());
+}
+
+TEST_F(CowTest, ClusterAppendTest) {
+    CowOptions options;
+    options.cluster_ops = 3;
+    auto writer = std::make_unique<CowWriter>(options);
+    ASSERT_TRUE(writer->Initialize(cow_->fd));
+
+    ASSERT_TRUE(writer->AddLabel(50));
+    ASSERT_TRUE(writer->Finalize());  // Adds a cluster op, should be dropped on append
+
+    ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
+
+    writer = std::make_unique<CowWriter>(options);
+    ASSERT_TRUE(writer->InitializeAppend(cow_->fd, 50));
+
+    std::string data2 = "More data!";
+    data2.resize(options.block_size, '\0');
+    ASSERT_TRUE(writer->AddRawBlocks(51, data2.data(), data2.size()));
+    ASSERT_TRUE(writer->Finalize());  // Adds a cluster op
+
+    ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
+
+    struct stat buf;
+    ASSERT_EQ(fstat(cow_->fd, &buf), 0);
+    ASSERT_EQ(buf.st_size, writer->GetCowSize());
+
+    // Read back both operations, plus cluster op at end
+    CowReader reader;
+    uint64_t label;
+    ASSERT_TRUE(reader.Parse(cow_->fd));
+    ASSERT_TRUE(reader.GetLastLabel(&label));
+    ASSERT_EQ(label, 50);
+
+    StringSink sink;
+
+    auto iter = reader.GetOpIter();
+    ASSERT_NE(iter, nullptr);
+
+    ASSERT_FALSE(iter->Done());
+    auto op = &iter->Get();
+    ASSERT_EQ(op->type, kCowLabelOp);
+    ASSERT_EQ(op->source, 50);
+
+    iter->Next();
+
+    ASSERT_FALSE(iter->Done());
+    op = &iter->Get();
+    ASSERT_EQ(op->type, kCowReplaceOp);
+    ASSERT_TRUE(reader.ReadData(*op, &sink));
+    ASSERT_EQ(sink.stream(), data2);
+
+    iter->Next();
+
+    ASSERT_FALSE(iter->Done());
+    op = &iter->Get();
+    ASSERT_EQ(op->type, kCowClusterOp);
+
+    iter->Next();
+
+    ASSERT_TRUE(iter->Done());
+}
+
 }  // namespace snapshot
 }  // namespace android
 
diff --git a/fs_mgr/libsnapshot/cow_format.cpp b/fs_mgr/libsnapshot/cow_format.cpp
index 49ba11f..0753c49 100644
--- a/fs_mgr/libsnapshot/cow_format.cpp
+++ b/fs_mgr/libsnapshot/cow_format.cpp
@@ -35,6 +35,10 @@
         os << "kCowFooterOp,  ";
     else if (op.type == kCowLabelOp)
         os << "kCowLabelOp,   ";
+    else if (op.type == kCowClusterOp)
+        os << "kCowClusterOp  ";
+    else if (op.type == kCowFooterOp)
+        os << "kCowFooterOp  ";
     else
         os << (int)op.type << "?,";
     os << "compression:";
@@ -52,11 +56,35 @@
     return os;
 }
 
-int64_t GetNextOpOffset(const CowOperation& op) {
-    if (op.type == kCowReplaceOp)
+int64_t GetNextOpOffset(const CowOperation& op, uint32_t cluster_ops) {
+    if (op.type == kCowClusterOp) {
+        return op.source;
+    } else if (op.type == kCowReplaceOp && cluster_ops == 0) {
         return op.data_length;
-    else
+    } else {
         return 0;
+    }
+}
+
+int64_t GetNextDataOffset(const CowOperation& op, uint32_t cluster_ops) {
+    if (op.type == kCowClusterOp) {
+        return cluster_ops * sizeof(CowOperation);
+    } else if (cluster_ops == 0) {
+        return sizeof(CowOperation);
+    } else {
+        return 0;
+    }
+}
+
+bool IsMetadataOp(const CowOperation& op) {
+    switch (op.type) {
+        case kCowLabelOp:
+        case kCowClusterOp:
+        case kCowFooterOp:
+            return true;
+        default:
+            return false;
+    }
 }
 
 }  // namespace snapshot
diff --git a/fs_mgr/libsnapshot/cow_reader.cpp b/fs_mgr/libsnapshot/cow_reader.cpp
index 0907032..3fbc5f3 100644
--- a/fs_mgr/libsnapshot/cow_reader.cpp
+++ b/fs_mgr/libsnapshot/cow_reader.cpp
@@ -81,6 +81,24 @@
                    << sizeof(CowFooter);
         return false;
     }
+    if (header_.op_size != sizeof(CowOperation)) {
+        LOG(ERROR) << "Operation size unknown, read " << header_.op_size << ", expected "
+                   << sizeof(CowOperation);
+        return false;
+    }
+    if (header_.cluster_ops == 1) {
+        LOG(ERROR) << "Clusters must contain at least two operations to function.";
+        return false;
+    }
+    if (header_.op_size != sizeof(CowOperation)) {
+        LOG(ERROR) << "Operation size unknown, read " << header_.op_size << ", expected "
+                   << sizeof(CowOperation);
+        return false;
+    }
+    if (header_.cluster_ops == 1) {
+        LOG(ERROR) << "Clusters must contain at least two operations to function.";
+        return false;
+    }
 
     if ((header_.major_version != kCowVersionMajor) ||
         (header_.minor_version != kCowVersionMinor)) {
@@ -103,45 +121,64 @@
     }
 
     auto ops_buffer = std::make_shared<std::vector<CowOperation>>();
+    uint64_t current_op_num = 0;
+    uint64_t cluster_ops = header_.cluster_ops ?: 1;
+    bool done = false;
 
-    // Alternating op and data
-    while (true) {
-        ops_buffer->emplace_back();
-        if (!android::base::ReadFully(fd_, &ops_buffer->back(), sizeof(CowOperation))) {
+    // Alternating op clusters and data
+    while (!done) {
+        uint64_t to_add = std::min(cluster_ops, (fd_size_ - pos) / sizeof(CowOperation));
+        if (to_add == 0) break;
+        ops_buffer->resize(current_op_num + to_add);
+        if (!android::base::ReadFully(fd_, &ops_buffer->data()[current_op_num],
+                                      to_add * sizeof(CowOperation))) {
             PLOG(ERROR) << "read op failed";
             return false;
         }
+        // Parse current cluster to find start of next cluster
+        while (current_op_num < ops_buffer->size()) {
+            auto& current_op = ops_buffer->data()[current_op_num];
+            current_op_num++;
+            pos += sizeof(CowOperation) + GetNextOpOffset(current_op, header_.cluster_ops);
 
-        auto& current_op = ops_buffer->back();
-        off_t offs = lseek(fd_.get(), GetNextOpOffset(current_op), SEEK_CUR);
-        if (offs < 0) {
+            if (current_op.type == kCowClusterOp) {
+                break;
+            } else if (current_op.type == kCowLabelOp) {
+                last_label_ = {current_op.source};
+
+                // If we reach the requested label, stop reading.
+                if (label && label.value() == current_op.source) {
+                    done = true;
+                    break;
+                }
+            } else if (current_op.type == kCowFooterOp) {
+                footer_.emplace();
+                CowFooter* footer = &footer_.value();
+                memcpy(&footer_->op, &current_op, sizeof(footer->op));
+                off_t offs = lseek(fd_.get(), pos, SEEK_SET);
+                if (offs < 0 || pos != static_cast<uint64_t>(offs)) {
+                    PLOG(ERROR) << "lseek next op failed";
+                    return false;
+                }
+                if (!android::base::ReadFully(fd_, &footer->data, sizeof(footer->data))) {
+                    LOG(ERROR) << "Could not read COW footer";
+                    return false;
+                }
+
+                // Drop the footer from the op stream.
+                current_op_num--;
+                done = true;
+                break;
+            }
+        }
+
+        // Position for next cluster read
+        off_t offs = lseek(fd_.get(), pos, SEEK_SET);
+        if (offs < 0 || pos != static_cast<uint64_t>(offs)) {
             PLOG(ERROR) << "lseek next op failed";
             return false;
         }
-        pos = static_cast<uint64_t>(offs);
-
-        if (current_op.type == kCowLabelOp) {
-            last_label_ = {current_op.source};
-
-            // If we reach the requested label, stop reading.
-            if (label && label.value() == current_op.source) {
-                break;
-            }
-        } else if (current_op.type == kCowFooterOp) {
-            footer_.emplace();
-
-            CowFooter* footer = &footer_.value();
-            memcpy(&footer_->op, &current_op, sizeof(footer->op));
-
-            if (!android::base::ReadFully(fd_, &footer->data, sizeof(footer->data))) {
-                LOG(ERROR) << "Could not read COW footer";
-                return false;
-            }
-
-            // Drop the footer from the op stream.
-            ops_buffer->pop_back();
-            break;
-        }
+        ops_buffer->resize(current_op_num);
     }
 
     // To successfully parse a COW file, we need either:
@@ -198,9 +235,7 @@
 
     // Remove all the metadata operations
     ops_->erase(std::remove_if(ops_.get()->begin(), ops_.get()->end(),
-                               [](CowOperation& op) {
-                                   return (op.type == kCowFooterOp || op.type == kCowLabelOp);
-                               }),
+                               [](CowOperation& op) { return IsMetadataOp(op); }),
                 ops_.get()->end());
 
     // We will re-arrange the vector in such a way that
diff --git a/fs_mgr/libsnapshot/cow_writer.cpp b/fs_mgr/libsnapshot/cow_writer.cpp
index f7cc6ff..8535252 100644
--- a/fs_mgr/libsnapshot/cow_writer.cpp
+++ b/fs_mgr/libsnapshot/cow_writer.cpp
@@ -90,8 +90,10 @@
     header_.minor_version = kCowVersionMinor;
     header_.header_size = sizeof(CowHeader);
     header_.footer_size = sizeof(CowFooter);
+    header_.op_size = sizeof(CowOperation);
     header_.block_size = options_.block_size;
     header_.num_merge_ops = 0;
+    header_.cluster_ops = options_.cluster_ops;
     footer_ = {};
     footer_.op.data_length = 64;
     footer_.op.type = kCowFooterOp;
@@ -108,6 +110,10 @@
         LOG(ERROR) << "unrecognized compression: " << options_.compression;
         return false;
     }
+    if (options_.cluster_ops == 1) {
+        LOG(ERROR) << "Clusters must contain at least two operations to function.";
+        return false;
+    }
     return true;
 }
 
@@ -165,6 +171,19 @@
     return OpenForAppend(label);
 }
 
+void CowWriter::InitPos() {
+    next_op_pos_ = sizeof(header_);
+    cluster_size_ = header_.cluster_ops * sizeof(CowOperation);
+    if (header_.cluster_ops) {
+        next_data_pos_ = next_op_pos_ + cluster_size_;
+    } else {
+        next_data_pos_ = next_op_pos_ + sizeof(CowOperation);
+    }
+    ops_.clear();
+    current_cluster_size_ = 0;
+    current_data_size_ = 0;
+}
+
 bool CowWriter::OpenForWrite() {
     // This limitation is tied to the data field size in CowOperation.
     if (header_.block_size > std::numeric_limits<uint16_t>::max()) {
@@ -184,7 +203,7 @@
         return false;
     }
 
-    next_op_pos_ = sizeof(header_);
+    InitPos();
     return true;
 }
 
@@ -197,13 +216,14 @@
     }
 
     options_.block_size = header_.block_size;
+    options_.cluster_ops = header_.cluster_ops;
 
     // Reset this, since we're going to reimport all operations.
     footer_.op.num_ops = 0;
-    next_op_pos_ = sizeof(header_);
-    ops_.resize(0);
+    InitPos();
 
     auto iter = reader->GetOpIter();
+
     while (!iter->Done()) {
         AddOperation(iter->Get());
         iter->Next();
@@ -234,14 +254,12 @@
 
 bool CowWriter::EmitRawBlocks(uint64_t new_block_start, const void* data, size_t size) {
     const uint8_t* iter = reinterpret_cast<const uint8_t*>(data);
-    uint64_t pos;
     CHECK(!merge_in_progress_);
     for (size_t i = 0; i < size / header_.block_size; i++) {
         CowOperation op = {};
         op.type = kCowReplaceOp;
         op.new_block = new_block_start + i;
-        GetDataPos(&pos);
-        op.source = pos + sizeof(op);
+        op.source = next_data_pos_;
 
         if (compression_) {
             auto data = Compress(iter, header_.block_size);
@@ -293,6 +311,14 @@
     return WriteOperation(op) && Sync();
 }
 
+bool CowWriter::EmitCluster() {
+    CowOperation op = {};
+    op.type = kCowClusterOp;
+    // Next cluster starts after remainder of current cluster and the next data block.
+    op.source = current_data_size_ + cluster_size_ - current_cluster_size_ - sizeof(CowOperation);
+    return WriteOperation(op);
+}
+
 std::basic_string<uint8_t> CowWriter::Compress(const void* data, size_t length) {
     switch (compression_) {
         case kCowCompressGz: {
@@ -345,11 +371,23 @@
 }
 
 bool CowWriter::Finalize() {
-    footer_.op.ops_size = ops_.size();
-    uint64_t pos;
+    auto continue_cluster_size = current_cluster_size_;
+    auto continue_data_size = current_data_size_;
+    auto continue_data_pos = next_data_pos_;
+    auto continue_op_pos = next_op_pos_;
+    auto continue_size = ops_.size();
+    bool extra_cluster = false;
 
-    if (!GetDataPos(&pos)) {
-        PLOG(ERROR) << "failed to get file position";
+    // 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) {
+        EmitCluster();
+        extra_cluster = true;
+    }
+
+    footer_.op.ops_size = ops_.size();
+    if (lseek(fd_.get(), next_op_pos_, SEEK_SET) < 0) {
+        PLOG(ERROR) << "Failed to seek to footer position.";
         return false;
     }
     memset(&footer_.data.ops_checksum, 0, sizeof(uint8_t) * 32);
@@ -364,16 +402,24 @@
         return false;
     }
 
-    // Re-position for any subsequent writes.
-    if (lseek(fd_.get(), pos, SEEK_SET) < 0) {
-        PLOG(ERROR) << "lseek ops failed";
-        return false;
+    // Reposition for additional Writing
+    if (extra_cluster) {
+        current_cluster_size_ = continue_cluster_size;
+        current_data_size_ = continue_data_size;
+        next_data_pos_ = continue_data_pos;
+        next_op_pos_ = continue_op_pos;
+        ops_.resize(continue_size);
     }
+
     return Sync();
 }
 
 uint64_t CowWriter::GetCowSize() {
-    return next_op_pos_ + sizeof(footer_);
+    if (current_data_size_ > 0) {
+        return next_data_pos_ + sizeof(footer_);
+    } else {
+        return next_op_pos_ + sizeof(footer_);
+    }
 }
 
 bool CowWriter::GetDataPos(uint64_t* pos) {
@@ -387,6 +433,15 @@
 }
 
 bool CowWriter::WriteOperation(const CowOperation& op, const void* data, size_t size) {
+    // If there isn't room for this 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;
+    }
+    if (lseek(fd_.get(), next_op_pos_, SEEK_SET) < 0) {
+        PLOG(ERROR) << "lseek failed for writing operation.";
+        return false;
+    }
     if (!android::base::WriteFully(fd_, reinterpret_cast<const uint8_t*>(&op), sizeof(op))) {
         return false;
     }
@@ -399,11 +454,26 @@
 
 void CowWriter::AddOperation(const CowOperation& op) {
     footer_.op.num_ops++;
-    next_op_pos_ += sizeof(CowOperation) + GetNextOpOffset(op);
+
+    if (op.type == kCowClusterOp) {
+        current_cluster_size_ = 0;
+        current_data_size_ = 0;
+    } else if (header_.cluster_ops) {
+        current_cluster_size_ += sizeof(op);
+        current_data_size_ += op.data_length;
+    }
+
+    next_data_pos_ += op.data_length + GetNextDataOffset(op, header_.cluster_ops);
+    next_op_pos_ += sizeof(CowOperation) + GetNextOpOffset(op, header_.cluster_ops);
     ops_.insert(ops_.size(), reinterpret_cast<const uint8_t*>(&op), sizeof(op));
 }
 
 bool CowWriter::WriteRawData(const void* data, size_t size) {
+    if (lseek(fd_.get(), next_data_pos_, SEEK_SET) < 0) {
+        PLOG(ERROR) << "lseek failed for writing data.";
+        return false;
+    }
+
     if (!android::base::WriteFully(fd_, data, size)) {
         return false;
     }
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h
index 80766ff..797b8ef 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h
@@ -57,9 +57,15 @@
     // Size of footer struct
     uint16_t footer_size;
 
+    // Size of op struct
+    uint16_t op_size;
+
     // The size of block operations, in bytes.
     uint32_t block_size;
 
+    // The number of ops to cluster together. 0 For no clustering. Cannot be 1.
+    uint32_t cluster_ops;
+
     // Tracks merge operations completed
     uint64_t num_merge_ops;
 } __attribute__((packed));
@@ -113,13 +119,15 @@
     // For copy operations, this is a block location in the source image.
     //
     // For replace operations, this is a byte offset within the COW's data
-    // section (eg, not landing within the header or metadata). It is an
+    // sections (eg, not landing within the header or metadata). It is an
     // absolute position within the image.
     //
     // For zero operations (replace with all zeroes), this is unused and must
     // be zero.
     //
     // For Label operations, this is the value of the applied label.
+    //
+    // For Cluster operations, this is the length of the following data region
     uint64_t source;
 } __attribute__((packed));
 
@@ -129,6 +137,7 @@
 static constexpr uint8_t kCowReplaceOp = 2;
 static constexpr uint8_t kCowZeroOp = 3;
 static constexpr uint8_t kCowLabelOp = 4;
+static constexpr uint8_t kCowClusterOp = 5;
 static constexpr uint8_t kCowFooterOp = -1;
 
 static constexpr uint8_t kCowCompressNone = 0;
@@ -142,7 +151,10 @@
 
 std::ostream& operator<<(std::ostream& os, CowOperation const& arg);
 
-int64_t GetNextOpOffset(const CowOperation& op);
+int64_t GetNextOpOffset(const CowOperation& op, uint32_t cluster_size);
+int64_t GetNextDataOffset(const CowOperation& op, uint32_t cluster_size);
+
+bool IsMetadataOp(const CowOperation& op);
 
 }  // namespace snapshot
 }  // namespace android
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h
index 36cd238..fd43cce 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h
@@ -33,6 +33,9 @@
 
     // Maximum number of blocks that can be written.
     std::optional<uint64_t> max_blocks;
+
+    // Number of CowOperations in a cluster. 0 for no clustering. Cannot be 1.
+    uint32_t cluster_ops = 0;
 };
 
 // Interface for writing to a snapuserd COW. All operations are ordered; merges
@@ -111,6 +114,7 @@
     virtual bool EmitLabel(uint64_t label) override;
 
   private:
+    bool EmitCluster();
     void SetupHeaders();
     bool ParseOptions();
     bool OpenForWrite();
@@ -120,6 +124,7 @@
     bool WriteOperation(const CowOperation& op, const void* data = nullptr, size_t size = 0);
     void AddOperation(const CowOperation& op);
     std::basic_string<uint8_t> Compress(const void* data, size_t length);
+    void InitPos();
 
     bool SetFd(android::base::borrowed_fd fd);
     bool Sync();
@@ -132,6 +137,10 @@
     CowFooter footer_{};
     int compression_ = 0;
     uint64_t next_op_pos_ = 0;
+    uint64_t next_data_pos_ = 0;
+    uint32_t cluster_size_ = 0;
+    uint32_t current_cluster_size_ = 0;
+    uint64_t current_data_size_ = 0;
     bool is_dev_null_ = false;
     bool merge_in_progress_ = false;
     bool is_block_device_ = false;
diff --git a/fs_mgr/libsnapshot/inspect_cow.cpp b/fs_mgr/libsnapshot/inspect_cow.cpp
index 6046bad..5ad61f3 100644
--- a/fs_mgr/libsnapshot/inspect_cow.cpp
+++ b/fs_mgr/libsnapshot/inspect_cow.cpp
@@ -14,6 +14,7 @@
 // limitations under the License.
 //
 #include <stdio.h>
+#include <unistd.h>
 
 #include <iostream>
 #include <string>
@@ -34,7 +35,11 @@
     }
 }
 
-static bool Inspect(const std::string& path) {
+static void usage(void) {
+    LOG(ERROR) << "Usage: inspect_cow [-s] <COW_FILE>";
+}
+
+static bool Inspect(const std::string& path, bool silent) {
     android::base::unique_fd fd(open(path.c_str(), O_RDONLY));
     if (fd < 0) {
         PLOG(ERROR) << "open failed: " << path;
@@ -52,19 +57,29 @@
         LOG(ERROR) << "could not get header: " << path;
         return false;
     }
+    CowFooter footer;
+    bool has_footer = false;
+    if (reader.GetFooter(&footer)) has_footer = true;
 
-    std::cout << "Major version: " << header.major_version << "\n";
-    std::cout << "Minor version: " << header.minor_version << "\n";
-    std::cout << "Header size: " << header.header_size << "\n";
-    std::cout << "Footer size: " << header.footer_size << "\n";
-    std::cout << "Block size: " << header.block_size << "\n";
-    std::cout << "\n";
+    if (!silent) {
+        std::cout << "Major version: " << header.major_version << "\n";
+        std::cout << "Minor version: " << header.minor_version << "\n";
+        std::cout << "Header size: " << header.header_size << "\n";
+        std::cout << "Footer size: " << header.footer_size << "\n";
+        std::cout << "Block size: " << header.block_size << "\n";
+        std::cout << "\n";
+        if (has_footer) {
+            std::cout << "Total Ops size: " << footer.op.ops_size << "\n";
+            std::cout << "Number of Ops: " << footer.op.num_ops << "\n";
+            std::cout << "\n";
+        }
+    }
 
     auto iter = reader.GetOpIter();
     while (!iter->Done()) {
         const CowOperation& op = iter->Get();
 
-        std::cout << op << "\n";
+        if (!silent) std::cout << op << "\n";
 
         iter->Next();
     }
@@ -76,14 +91,25 @@
 }  // namespace android
 
 int main(int argc, char** argv) {
+    int ch;
+    bool silent = false;
+    while ((ch = getopt(argc, argv, "s")) != -1) {
+        switch (ch) {
+            case 's':
+                silent = true;
+                break;
+            default:
+                android::snapshot::usage();
+        }
+    }
     android::base::InitLogging(argv, android::snapshot::MyLogger);
 
-    if (argc < 2) {
-        LOG(ERROR) << "Usage: inspect_cow <COW_FILE>";
+    if (argc < optind + 1) {
+        android::snapshot::usage();
         return 1;
     }
 
-    if (!android::snapshot::Inspect(argv[1])) {
+    if (!android::snapshot::Inspect(argv[optind], silent)) {
         return 1;
     }
     return 0;
diff --git a/fs_mgr/libsnapshot/make_cow_from_ab_ota.cpp b/fs_mgr/libsnapshot/make_cow_from_ab_ota.cpp
index d0b8f52..6a5754d 100644
--- a/fs_mgr/libsnapshot/make_cow_from_ab_ota.cpp
+++ b/fs_mgr/libsnapshot/make_cow_from_ab_ota.cpp
@@ -53,6 +53,7 @@
 
 DEFINE_string(source_tf, "", "Source target files (dir or zip file) for incremental payloads");
 DEFINE_string(compression, "gz", "Compression type to use (none or gz)");
+DEFINE_uint32(cluster_ops, 0, "Number of Cow Ops per cluster (0 or >1)");
 
 void MyLogger(android::base::LogId, android::base::LogSeverity severity, const char*, const char*,
               unsigned int, const char* message) {
@@ -189,6 +190,7 @@
     CowOptions options;
     options.block_size = kBlockSize;
     options.compression = FLAGS_compression;
+    options.cluster_ops = FLAGS_cluster_ops;
 
     writer_ = std::make_unique<CowWriter>(options);
     if (!writer_->Initialize(std::move(fd))) {
diff --git a/fs_mgr/libsnapshot/snapshot_reader.cpp b/fs_mgr/libsnapshot/snapshot_reader.cpp
index b56d879..5ee8e25 100644
--- a/fs_mgr/libsnapshot/snapshot_reader.cpp
+++ b/fs_mgr/libsnapshot/snapshot_reader.cpp
@@ -90,7 +90,7 @@
     op_iter_ = cow_->GetOpIter();
     while (!op_iter_->Done()) {
         const CowOperation* op = &op_iter_->Get();
-        if (op->type == kCowLabelOp || op->type == kCowFooterOp) {
+        if (IsMetadataOp(*op)) {
             op_iter_->Next();
             continue;
         }
diff --git a/fs_mgr/libsnapshot/snapuserd.cpp b/fs_mgr/libsnapshot/snapuserd.cpp
index d1d2521..34254a3 100644
--- a/fs_mgr/libsnapshot/snapuserd.cpp
+++ b/fs_mgr/libsnapshot/snapuserd.cpp
@@ -545,7 +545,7 @@
         struct disk_exception* de =
                 reinterpret_cast<struct disk_exception*>((char*)de_ptr.get() + offset);
 
-        if (cow_op->type == kCowFooterOp || cow_op->type == kCowLabelOp) {
+        if (IsMetadataOp(*cow_op)) {
             cowop_riter_->Next();
             continue;
         }
diff --git a/init/builtins.cpp b/init/builtins.cpp
index b235d2f..c44e03e 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -1232,7 +1232,7 @@
 }
 
 static Result<void> GenerateLinkerConfiguration() {
-    const char* linkerconfig_binary = "/system/bin/linkerconfig";
+    const char* linkerconfig_binary = "/apex/com.android.runtime/bin/linkerconfig";
     const char* linkerconfig_target = "/linkerconfig";
     const char* arguments[] = {linkerconfig_binary, "--target", linkerconfig_target};
 
diff --git a/libcutils/Android.bp b/libcutils/Android.bp
index 284c0b9..cf809f1 100644
--- a/libcutils/Android.bp
+++ b/libcutils/Android.bp
@@ -32,6 +32,7 @@
 cc_library_headers {
     name: "libcutils_headers",
     vendor_available: true,
+    product_available: true,
     recovery_available: true,
     ramdisk_available: true,
     vendor_ramdisk_available: true,
@@ -45,7 +46,10 @@
     export_include_dirs: ["include"],
     target: {
         vendor: {
-            override_export_include_dirs: ["include_vndk"],
+            override_export_include_dirs: ["include_outside_system"],
+        },
+        product: {
+            override_export_include_dirs: ["include_outside_system"],
         },
         linux_bionic: {
             enabled: true,
@@ -60,6 +64,7 @@
 cc_library {
     name: "libcutils_sockets",
     vendor_available: true,
+    product_available: true,
     recovery_available: true,
     ramdisk_available: true,
     vendor_ramdisk_available: true,
@@ -143,6 +148,7 @@
 cc_library {
     name: "libcutils",
     vendor_available: true,
+    product_available: true,
     vndk: {
         enabled: true,
         support_system_process: true,
@@ -234,14 +240,19 @@
             },
         },
 
+        // qtaguid.cpp loads libnetd_client.so with dlopen().  Since
+        // the interface of libnetd_client.so may vary between AOSP
+        // releases, exclude qtaguid.cpp from the VNDK-SP variant.
         vendor: {
             exclude_srcs: [
-                // qtaguid.cpp loads libnetd_client.so with dlopen().  Since
-                // the interface of libnetd_client.so may vary between AOSP
-                // releases, exclude qtaguid.cpp from the VNDK-SP variant.
                 "qtaguid.cpp",
             ],
-        }
+        },
+        product: {
+            exclude_srcs: [
+                "qtaguid.cpp",
+            ],
+        },
     },
 
     whole_static_libs: ["libcutils_sockets"],
diff --git a/libcutils/include_vndk/cutils/android_filesystem_config.h b/libcutils/include_outside_system/cutils/android_filesystem_config.h
similarity index 100%
rename from libcutils/include_vndk/cutils/android_filesystem_config.h
rename to libcutils/include_outside_system/cutils/android_filesystem_config.h
diff --git a/libcutils/include_vndk/cutils/android_get_control_file.h b/libcutils/include_outside_system/cutils/android_get_control_file.h
similarity index 100%
rename from libcutils/include_vndk/cutils/android_get_control_file.h
rename to libcutils/include_outside_system/cutils/android_get_control_file.h
diff --git a/libcutils/include_vndk/cutils/android_reboot.h b/libcutils/include_outside_system/cutils/android_reboot.h
similarity index 100%
rename from libcutils/include_vndk/cutils/android_reboot.h
rename to libcutils/include_outside_system/cutils/android_reboot.h
diff --git a/libcutils/include_vndk/cutils/ashmem.h b/libcutils/include_outside_system/cutils/ashmem.h
similarity index 100%
rename from libcutils/include_vndk/cutils/ashmem.h
rename to libcutils/include_outside_system/cutils/ashmem.h
diff --git a/libcutils/include_vndk/cutils/atomic.h b/libcutils/include_outside_system/cutils/atomic.h
similarity index 100%
rename from libcutils/include_vndk/cutils/atomic.h
rename to libcutils/include_outside_system/cutils/atomic.h
diff --git a/libcutils/include_vndk/cutils/bitops.h b/libcutils/include_outside_system/cutils/bitops.h
similarity index 100%
rename from libcutils/include_vndk/cutils/bitops.h
rename to libcutils/include_outside_system/cutils/bitops.h
diff --git a/libcutils/include_vndk/cutils/compiler.h b/libcutils/include_outside_system/cutils/compiler.h
similarity index 100%
rename from libcutils/include_vndk/cutils/compiler.h
rename to libcutils/include_outside_system/cutils/compiler.h
diff --git a/libcutils/include_vndk/cutils/config_utils.h b/libcutils/include_outside_system/cutils/config_utils.h
similarity index 100%
rename from libcutils/include_vndk/cutils/config_utils.h
rename to libcutils/include_outside_system/cutils/config_utils.h
diff --git a/libcutils/include_vndk/cutils/fs.h b/libcutils/include_outside_system/cutils/fs.h
similarity index 100%
rename from libcutils/include_vndk/cutils/fs.h
rename to libcutils/include_outside_system/cutils/fs.h
diff --git a/libcutils/include_vndk/cutils/hashmap.h b/libcutils/include_outside_system/cutils/hashmap.h
similarity index 100%
rename from libcutils/include_vndk/cutils/hashmap.h
rename to libcutils/include_outside_system/cutils/hashmap.h
diff --git a/libcutils/include_vndk/cutils/iosched_policy.h b/libcutils/include_outside_system/cutils/iosched_policy.h
similarity index 100%
rename from libcutils/include_vndk/cutils/iosched_policy.h
rename to libcutils/include_outside_system/cutils/iosched_policy.h
diff --git a/libcutils/include_vndk/cutils/klog.h b/libcutils/include_outside_system/cutils/klog.h
similarity index 100%
rename from libcutils/include_vndk/cutils/klog.h
rename to libcutils/include_outside_system/cutils/klog.h
diff --git a/libcutils/include_vndk/cutils/list.h b/libcutils/include_outside_system/cutils/list.h
similarity index 100%
rename from libcutils/include_vndk/cutils/list.h
rename to libcutils/include_outside_system/cutils/list.h
diff --git a/libcutils/include_vndk/cutils/log.h b/libcutils/include_outside_system/cutils/log.h
similarity index 100%
rename from libcutils/include_vndk/cutils/log.h
rename to libcutils/include_outside_system/cutils/log.h
diff --git a/libcutils/include_vndk/cutils/memory.h b/libcutils/include_outside_system/cutils/memory.h
similarity index 100%
rename from libcutils/include_vndk/cutils/memory.h
rename to libcutils/include_outside_system/cutils/memory.h
diff --git a/libcutils/include_vndk/cutils/misc.h b/libcutils/include_outside_system/cutils/misc.h
similarity index 100%
rename from libcutils/include_vndk/cutils/misc.h
rename to libcutils/include_outside_system/cutils/misc.h
diff --git a/libcutils/include_vndk/cutils/multiuser.h b/libcutils/include_outside_system/cutils/multiuser.h
similarity index 100%
rename from libcutils/include_vndk/cutils/multiuser.h
rename to libcutils/include_outside_system/cutils/multiuser.h
diff --git a/libcutils/include_vndk/cutils/native_handle.h b/libcutils/include_outside_system/cutils/native_handle.h
similarity index 100%
rename from libcutils/include_vndk/cutils/native_handle.h
rename to libcutils/include_outside_system/cutils/native_handle.h
diff --git a/libcutils/include_vndk/cutils/partition_utils.h b/libcutils/include_outside_system/cutils/partition_utils.h
similarity index 100%
rename from libcutils/include_vndk/cutils/partition_utils.h
rename to libcutils/include_outside_system/cutils/partition_utils.h
diff --git a/libcutils/include_vndk/cutils/properties.h b/libcutils/include_outside_system/cutils/properties.h
similarity index 100%
rename from libcutils/include_vndk/cutils/properties.h
rename to libcutils/include_outside_system/cutils/properties.h
diff --git a/libcutils/include_vndk/cutils/qtaguid.h b/libcutils/include_outside_system/cutils/qtaguid.h
similarity index 100%
rename from libcutils/include_vndk/cutils/qtaguid.h
rename to libcutils/include_outside_system/cutils/qtaguid.h
diff --git a/libcutils/include_vndk/cutils/record_stream.h b/libcutils/include_outside_system/cutils/record_stream.h
similarity index 100%
rename from libcutils/include_vndk/cutils/record_stream.h
rename to libcutils/include_outside_system/cutils/record_stream.h
diff --git a/libcutils/include_vndk/cutils/sched_policy.h b/libcutils/include_outside_system/cutils/sched_policy.h
similarity index 100%
rename from libcutils/include_vndk/cutils/sched_policy.h
rename to libcutils/include_outside_system/cutils/sched_policy.h
diff --git a/libcutils/include_vndk/cutils/sockets.h b/libcutils/include_outside_system/cutils/sockets.h
similarity index 100%
rename from libcutils/include_vndk/cutils/sockets.h
rename to libcutils/include_outside_system/cutils/sockets.h
diff --git a/libcutils/include_vndk/cutils/str_parms.h b/libcutils/include_outside_system/cutils/str_parms.h
similarity index 100%
rename from libcutils/include_vndk/cutils/str_parms.h
rename to libcutils/include_outside_system/cutils/str_parms.h
diff --git a/libcutils/include_vndk/cutils/threads.h b/libcutils/include_outside_system/cutils/threads.h
similarity index 100%
rename from libcutils/include_vndk/cutils/threads.h
rename to libcutils/include_outside_system/cutils/threads.h
diff --git a/libcutils/include_vndk/cutils/trace.h b/libcutils/include_outside_system/cutils/trace.h
similarity index 100%
rename from libcutils/include_vndk/cutils/trace.h
rename to libcutils/include_outside_system/cutils/trace.h
diff --git a/libcutils/include_vndk/cutils/uevent.h b/libcutils/include_outside_system/cutils/uevent.h
similarity index 100%
rename from libcutils/include_vndk/cutils/uevent.h
rename to libcutils/include_outside_system/cutils/uevent.h
diff --git a/libprocessgroup/Android.bp b/libprocessgroup/Android.bp
index 71e2b91..f104100 100644
--- a/libprocessgroup/Android.bp
+++ b/libprocessgroup/Android.bp
@@ -1,6 +1,7 @@
 cc_library_headers {
     name: "libprocessgroup_headers",
     vendor_available: true,
+    product_available: true,
     ramdisk_available: true,
     vendor_ramdisk_available: true,
     recovery_available: true,
@@ -36,6 +37,7 @@
     vendor_ramdisk_available: true,
     recovery_available: true,
     vendor_available: true,
+    product_available: true,
     vndk: {
         enabled: true,
         support_system_process: true,
diff --git a/libprocessgroup/include/processgroup/sched_policy.h b/libprocessgroup/include/processgroup/sched_policy.h
index 945d90c..a18847e 100644
--- a/libprocessgroup/include/processgroup/sched_policy.h
+++ b/libprocessgroup/include/processgroup/sched_policy.h
@@ -42,7 +42,7 @@
     SP_DEFAULT = -1,
     SP_BACKGROUND = 0,
     SP_FOREGROUND = 1,
-    SP_SYSTEM = 2,  // can't be used with set_sched_policy()
+    SP_SYSTEM = 2,
     SP_AUDIO_APP = 3,
     SP_AUDIO_SYS = 4,
     SP_TOP_APP = 5,
diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp
index 2bf48fc..d669ebe 100644
--- a/libprocessgroup/processgroup.cpp
+++ b/libprocessgroup/processgroup.cpp
@@ -131,25 +131,13 @@
     return StringPrintf("%s/uid_%d/pid_%d", cgroup, uid, pid);
 }
 
-static int RemoveProcessGroup(const char* cgroup, uid_t uid, int pid, unsigned int retries) {
-    int ret = 0;
+static int RemoveProcessGroup(const char* cgroup, uid_t uid, int pid) {
+    int ret;
+
     auto uid_pid_path = ConvertUidPidToPath(cgroup, uid, pid);
+    ret = rmdir(uid_pid_path.c_str());
+
     auto uid_path = ConvertUidToPath(cgroup, uid);
-
-    if (retries == 0) {
-        retries = 1;
-    }
-
-    while (retries--) {
-        ret = rmdir(uid_pid_path.c_str());
-        if (!ret || errno != EBUSY) break;
-        std::this_thread::sleep_for(5ms);
-    }
-
-    // With the exception of boot or shutdown, system uid_ folders are always populated. Spinning
-    // here would needlessly delay most pid removals. Additionally, once empty a uid_ cgroup won't
-    // have processes hanging on it (we've already spun for all its pid_), so there's no need to
-    // spin anyway.
     rmdir(uid_path.c_str());
 
     return ret;
@@ -188,7 +176,7 @@
     std::vector<std::string> cgroups;
     std::string path;
 
-    if (CgroupGetControllerPath(CGROUPV2_CONTROLLER_NAME, &path)) {
+    if (CgroupGetControllerPath("cpuacct", &path)) {
         cgroups.push_back(path);
     }
     if (CgroupGetControllerPath("memory", &path)) {
@@ -224,49 +212,19 @@
     }
 }
 
-/**
- * Process groups are primarily created by the Zygote, meaning that uid/pid groups are created by
- * the user root. Ownership for the newly created cgroup and all of its files must thus be
- * transferred for the user/group passed as uid/gid before system_server can properly access them.
- */
 static bool MkdirAndChown(const std::string& path, mode_t mode, uid_t uid, gid_t gid) {
     if (mkdir(path.c_str(), mode) == -1 && errno != EEXIST) {
         return false;
     }
 
-    auto dir = std::unique_ptr<DIR, decltype(&closedir)>(opendir(path.c_str()), closedir);
-
-    if (dir == NULL) {
-        PLOG(ERROR) << "opendir failed for " << path;
-        goto err;
-    }
-
-    struct dirent* dir_entry;
-    while ((dir_entry = readdir(dir.get()))) {
-        if (!strcmp("..", dir_entry->d_name)) {
-            continue;
-        }
-
-        std::string file_path = path + "/" + dir_entry->d_name;
-
-        if (lchown(file_path.c_str(), uid, gid) < 0) {
-            PLOG(ERROR) << "lchown failed for " << file_path;
-            goto err;
-        }
-
-        if (fchmodat(AT_FDCWD, file_path.c_str(), mode, AT_SYMLINK_NOFOLLOW) != 0) {
-            PLOG(ERROR) << "fchmodat failed for " << file_path;
-            goto err;
-        }
+    if (chown(path.c_str(), uid, gid) == -1) {
+        int saved_errno = errno;
+        rmdir(path.c_str());
+        errno = saved_errno;
+        return false;
     }
 
     return true;
-err:
-    int saved_errno = errno;
-    rmdir(path.c_str());
-    errno = saved_errno;
-
-    return false;
 }
 
 // Returns number of processes killed on success
@@ -344,9 +302,17 @@
 
 static int KillProcessGroup(uid_t uid, int initialPid, int signal, int retries,
                             int* max_processes) {
-    std::string hierarchy_root_path;
-    CgroupGetControllerPath(CGROUPV2_CONTROLLER_NAME, &hierarchy_root_path);
-    const char* cgroup = hierarchy_root_path.c_str();
+    std::string cpuacct_path;
+    std::string memory_path;
+
+    CgroupGetControllerPath("cpuacct", &cpuacct_path);
+    CgroupGetControllerPath("memory", &memory_path);
+    memory_path += "/apps";
+
+    const char* cgroup =
+            (!access(ConvertUidPidToPath(cpuacct_path.c_str(), uid, initialPid).c_str(), F_OK))
+                    ? cpuacct_path.c_str()
+                    : memory_path.c_str();
 
     std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();
 
@@ -389,17 +355,7 @@
             LOG(INFO) << "Successfully killed process cgroup uid " << uid << " pid " << initialPid
                       << " in " << static_cast<int>(ms) << "ms";
         }
-
-        int err = RemoveProcessGroup(cgroup, uid, initialPid, retries);
-
-        if (isMemoryCgroupSupported() && UsePerAppMemcg()) {
-            std::string memory_path;
-            CgroupGetControllerPath("memory", &memory_path);
-            memory_path += "/apps";
-            if (RemoveProcessGroup(memory_path.c_str(), uid, initialPid, retries)) return -1;
-        }
-
-        return err;
+        return RemoveProcessGroup(cgroup, uid, initialPid);
     } else {
         if (retries > 0) {
             LOG(ERROR) << "Failed to kill process cgroup uid " << uid << " pid " << initialPid
@@ -418,7 +374,15 @@
     return KillProcessGroup(uid, initialPid, signal, 0 /*retries*/, max_processes);
 }
 
-static int createProcessGroupInternal(uid_t uid, int initialPid, std::string cgroup) {
+int createProcessGroup(uid_t uid, int initialPid, bool memControl) {
+    std::string cgroup;
+    if (isMemoryCgroupSupported() && (memControl || UsePerAppMemcg())) {
+        CgroupGetControllerPath("memory", &cgroup);
+        cgroup += "/apps";
+    } else {
+        CgroupGetControllerPath("cpuacct", &cgroup);
+    }
+
     auto uid_path = ConvertUidToPath(cgroup.c_str(), uid);
 
     if (!MkdirAndChown(uid_path, 0750, AID_SYSTEM, AID_SYSTEM)) {
@@ -444,27 +408,6 @@
     return ret;
 }
 
-int createProcessGroup(uid_t uid, int initialPid, bool memControl) {
-    std::string cgroup;
-
-    if (memControl && !UsePerAppMemcg()) {
-        PLOG(ERROR) << "service memory controls are used without per-process memory cgroup support";
-        return -EINVAL;
-    }
-
-    if (isMemoryCgroupSupported() && UsePerAppMemcg()) {
-        CgroupGetControllerPath("memory", &cgroup);
-        cgroup += "/apps";
-        int ret = createProcessGroupInternal(uid, initialPid, cgroup);
-        if (ret != 0) {
-            return ret;
-        }
-    }
-
-    CgroupGetControllerPath(CGROUPV2_CONTROLLER_NAME, &cgroup);
-    return createProcessGroupInternal(uid, initialPid, cgroup);
-}
-
 static bool SetProcessGroupValue(int tid, const std::string& attr_name, int64_t value) {
     if (!isMemoryCgroupSupported()) {
         PLOG(ERROR) << "Memcg is not mounted.";
diff --git a/libprocessgroup/profiles/cgroups.json b/libprocessgroup/profiles/cgroups.json
index 7bcb94b..792af6f 100644
--- a/libprocessgroup/profiles/cgroups.json
+++ b/libprocessgroup/profiles/cgroups.json
@@ -15,6 +15,11 @@
       "GID": "system"
     },
     {
+      "Controller": "cpuacct",
+      "Path": "/acct",
+      "Mode": "0555"
+    },
+    {
       "Controller": "cpuset",
       "Path": "/dev/cpuset",
       "Mode": "0755",
@@ -37,7 +42,7 @@
     "Controllers": [
       {
         "Controller": "freezer",
-        "Path": "freezer",
+        "Path": ".",
         "Mode": "0755",
         "UID": "system",
         "GID": "system"
diff --git a/libprocessgroup/profiles/cgroups.recovery.json b/libprocessgroup/profiles/cgroups.recovery.json
index 2c63c08..f0bf5fd 100644
--- a/libprocessgroup/profiles/cgroups.recovery.json
+++ b/libprocessgroup/profiles/cgroups.recovery.json
@@ -1,2 +1,9 @@
 {
+  "Cgroups": [
+    {
+      "Controller": "cpuacct",
+      "Path": "/acct",
+      "Mode": "0555"
+    }
+  ]
 }
diff --git a/libprocessgroup/profiles/cgroups_28.json b/libprocessgroup/profiles/cgroups_28.json
index 4518487..17d4929 100644
--- a/libprocessgroup/profiles/cgroups_28.json
+++ b/libprocessgroup/profiles/cgroups_28.json
@@ -1,59 +1,11 @@
 {
   "Cgroups": [
     {
-      "Controller": "blkio",
-      "Path": "/dev/blkio",
-      "Mode": "0755",
-      "UID": "system",
-      "GID": "system"
-    },
-    {
-      "Controller": "cpu",
-      "Path": "/dev/cpuctl",
-      "Mode": "0755",
-      "UID": "system",
-      "GID": "system"
-    },
-    {
-      "Controller": "cpuacct",
-      "Path": "/acct",
-      "Mode": "0555"
-    },
-    {
-      "Controller": "cpuset",
-      "Path": "/dev/cpuset",
-      "Mode": "0755",
-      "UID": "system",
-      "GID": "system"
-    },
-    {
-      "Controller": "memory",
-      "Path": "/dev/memcg",
-      "Mode": "0700",
-      "UID": "root",
-      "GID": "system"
-    },
-    {
       "Controller": "schedtune",
       "Path": "/dev/stune",
       "Mode": "0755",
       "UID": "system",
       "GID": "system"
     }
-  ],
-  "Cgroups2": {
-    "Path": "/sys/fs/cgroup",
-    "Mode": "0755",
-    "UID": "system",
-    "GID": "system",
-    "Controllers": [
-      {
-        "Controller": "freezer",
-        "Path": "freezer",
-        "Mode": "0755",
-        "UID": "system",
-        "GID": "system"
-      }
-    ]
-  }
+  ]
 }
diff --git a/libprocessgroup/profiles/cgroups_29.json b/libprocessgroup/profiles/cgroups_29.json
index 4518487..17d4929 100644
--- a/libprocessgroup/profiles/cgroups_29.json
+++ b/libprocessgroup/profiles/cgroups_29.json
@@ -1,59 +1,11 @@
 {
   "Cgroups": [
     {
-      "Controller": "blkio",
-      "Path": "/dev/blkio",
-      "Mode": "0755",
-      "UID": "system",
-      "GID": "system"
-    },
-    {
-      "Controller": "cpu",
-      "Path": "/dev/cpuctl",
-      "Mode": "0755",
-      "UID": "system",
-      "GID": "system"
-    },
-    {
-      "Controller": "cpuacct",
-      "Path": "/acct",
-      "Mode": "0555"
-    },
-    {
-      "Controller": "cpuset",
-      "Path": "/dev/cpuset",
-      "Mode": "0755",
-      "UID": "system",
-      "GID": "system"
-    },
-    {
-      "Controller": "memory",
-      "Path": "/dev/memcg",
-      "Mode": "0700",
-      "UID": "root",
-      "GID": "system"
-    },
-    {
       "Controller": "schedtune",
       "Path": "/dev/stune",
       "Mode": "0755",
       "UID": "system",
       "GID": "system"
     }
-  ],
-  "Cgroups2": {
-    "Path": "/sys/fs/cgroup",
-    "Mode": "0755",
-    "UID": "system",
-    "GID": "system",
-    "Controllers": [
-      {
-        "Controller": "freezer",
-        "Path": "freezer",
-        "Mode": "0755",
-        "UID": "system",
-        "GID": "system"
-      }
-    ]
-  }
+  ]
 }
diff --git a/libprocessgroup/profiles/cgroups_30.json b/libprocessgroup/profiles/cgroups_30.json
index 4518487..17d4929 100644
--- a/libprocessgroup/profiles/cgroups_30.json
+++ b/libprocessgroup/profiles/cgroups_30.json
@@ -1,59 +1,11 @@
 {
   "Cgroups": [
     {
-      "Controller": "blkio",
-      "Path": "/dev/blkio",
-      "Mode": "0755",
-      "UID": "system",
-      "GID": "system"
-    },
-    {
-      "Controller": "cpu",
-      "Path": "/dev/cpuctl",
-      "Mode": "0755",
-      "UID": "system",
-      "GID": "system"
-    },
-    {
-      "Controller": "cpuacct",
-      "Path": "/acct",
-      "Mode": "0555"
-    },
-    {
-      "Controller": "cpuset",
-      "Path": "/dev/cpuset",
-      "Mode": "0755",
-      "UID": "system",
-      "GID": "system"
-    },
-    {
-      "Controller": "memory",
-      "Path": "/dev/memcg",
-      "Mode": "0700",
-      "UID": "root",
-      "GID": "system"
-    },
-    {
       "Controller": "schedtune",
       "Path": "/dev/stune",
       "Mode": "0755",
       "UID": "system",
       "GID": "system"
     }
-  ],
-  "Cgroups2": {
-    "Path": "/sys/fs/cgroup",
-    "Mode": "0755",
-    "UID": "system",
-    "GID": "system",
-    "Controllers": [
-      {
-        "Controller": "freezer",
-        "Path": "freezer",
-        "Mode": "0755",
-        "UID": "system",
-        "GID": "system"
-      }
-    ]
-  }
+  ]
 }
diff --git a/libprocessgroup/profiles/task_profiles.json b/libprocessgroup/profiles/task_profiles.json
index b528fa5..628098b 100644
--- a/libprocessgroup/profiles/task_profiles.json
+++ b/libprocessgroup/profiles/task_profiles.json
@@ -46,7 +46,7 @@
       "File": "cpu.uclamp.latency_sensitive"
     },
     {
-      "Name": "FreezerState",
+      "Name": "Freezer",
       "Controller": "freezer",
       "File": "cgroup.freeze"
     }
@@ -70,11 +70,11 @@
       "Name": "Frozen",
       "Actions": [
         {
-          "Name": "JoinCgroup",
+          "Name": "SetAttribute",
           "Params":
           {
-            "Controller": "freezer",
-            "Path": ""
+            "Name": "Freezer",
+            "Value": "1"
           }
         }
       ]
@@ -83,11 +83,11 @@
       "Name": "Unfrozen",
       "Actions": [
         {
-          "Name": "JoinCgroup",
+          "Name": "SetAttribute",
           "Params":
           {
-            "Controller": "freezer",
-            "Path": "../"
+            "Name": "Freezer",
+            "Value": "0"
           }
         }
       ]
@@ -106,6 +106,19 @@
       ]
     },
     {
+      "Name": "ServicePerformance",
+      "Actions": [
+        {
+          "Name": "JoinCgroup",
+          "Params":
+          {
+            "Controller": "cpu",
+            "Path": "system-background"
+          }
+        }
+      ]
+    },
+    {
       "Name": "HighPerformance",
       "Actions": [
         {
@@ -591,6 +604,10 @@
       "Profiles": [ "MaxPerformance", "MaxIoPriority", "TimerSlackNormal" ]
     },
     {
+      "Name": "SCHED_SP_SYSTEM",
+      "Profiles": [ "ServicePerformance", "LowIoPriority", "TimerSlackNormal" ]
+    },
+    {
       "Name": "SCHED_SP_RT_APP",
       "Profiles": [ "RealtimePerformance", "MaxIoPriority", "TimerSlackNormal" ]
     },
diff --git a/libprocessgroup/profiles/task_profiles_28.json b/libprocessgroup/profiles/task_profiles_28.json
index 142b0ba..9f83785 100644
--- a/libprocessgroup/profiles/task_profiles_28.json
+++ b/libprocessgroup/profiles/task_profiles_28.json
@@ -1,36 +1,6 @@
 {
   "Attributes": [
     {
-      "Name": "LowCapacityCPUs",
-      "Controller": "cpuset",
-      "File": "background/cpus"
-    },
-    {
-      "Name": "HighCapacityCPUs",
-      "Controller": "cpuset",
-      "File": "foreground/cpus"
-    },
-    {
-      "Name": "MaxCapacityCPUs",
-      "Controller": "cpuset",
-      "File": "top-app/cpus"
-    },
-    {
-      "Name": "MemLimit",
-      "Controller": "memory",
-      "File": "memory.limit_in_bytes"
-    },
-    {
-      "Name": "MemSoftLimit",
-      "Controller": "memory",
-      "File": "memory.soft_limit_in_bytes"
-    },
-    {
-      "Name": "MemSwappiness",
-      "Controller": "memory",
-      "File": "memory.swappiness"
-    },
-    {
       "Name": "STuneBoost",
       "Controller": "schedtune",
       "File": "schedtune.boost"
@@ -39,21 +9,6 @@
       "Name": "STunePreferIdle",
       "Controller": "schedtune",
       "File": "schedtune.prefer_idle"
-    },
-    {
-      "Name": "UClampMin",
-      "Controller": "cpu",
-      "File": "cpu.uclamp.min"
-    },
-    {
-      "Name": "UClampMax",
-      "Controller": "cpu",
-      "File": "cpu.uclamp.max"
-    },
-    {
-      "Name": "FreezerState",
-      "Controller": "freezer",
-      "File": "cgroup.freeze"
     }
   ],
 
@@ -72,32 +27,6 @@
       ]
     },
     {
-      "Name": "Frozen",
-      "Actions": [
-        {
-          "Name": "JoinCgroup",
-          "Params":
-          {
-            "Controller": "freezer",
-            "Path": ""
-          }
-        }
-      ]
-    },
-    {
-      "Name": "Unfrozen",
-      "Actions": [
-        {
-          "Name": "JoinCgroup",
-          "Params":
-          {
-            "Controller": "freezer",
-            "Path": "../"
-          }
-        }
-      ]
-    },
-    {
       "Name": "NormalPerformance",
       "Actions": [
         {
@@ -201,427 +130,6 @@
           }
         }
       ]
-    },
-
-    {
-      "Name": "VrKernelCapacity",
-      "Actions": [
-        {
-          "Name": "JoinCgroup",
-          "Params":
-          {
-            "Controller": "cpuset",
-            "Path": ""
-          }
-        }
-      ]
-    },
-    {
-      "Name": "VrServiceCapacityLow",
-      "Actions": [
-        {
-          "Name": "JoinCgroup",
-          "Params":
-          {
-            "Controller": "cpuset",
-            "Path": "system/background"
-          }
-        }
-      ]
-    },
-    {
-      "Name": "VrServiceCapacityNormal",
-      "Actions": [
-        {
-          "Name": "JoinCgroup",
-          "Params":
-          {
-            "Controller": "cpuset",
-            "Path": "system"
-          }
-        }
-      ]
-    },
-    {
-      "Name": "VrServiceCapacityHigh",
-      "Actions": [
-        {
-          "Name": "JoinCgroup",
-          "Params":
-          {
-            "Controller": "cpuset",
-            "Path": "system/performance"
-          }
-        }
-      ]
-    },
-    {
-      "Name": "VrProcessCapacityLow",
-      "Actions": [
-        {
-          "Name": "JoinCgroup",
-          "Params":
-          {
-            "Controller": "cpuset",
-            "Path": "application/background"
-          }
-        }
-      ]
-    },
-    {
-      "Name": "VrProcessCapacityNormal",
-      "Actions": [
-        {
-          "Name": "JoinCgroup",
-          "Params":
-          {
-            "Controller": "cpuset",
-            "Path": "application"
-          }
-        }
-      ]
-    },
-    {
-      "Name": "VrProcessCapacityHigh",
-      "Actions": [
-        {
-          "Name": "JoinCgroup",
-          "Params":
-          {
-            "Controller": "cpuset",
-            "Path": "application/performance"
-          }
-        }
-      ]
-    },
-
-    {
-      "Name": "ProcessCapacityLow",
-      "Actions": [
-        {
-          "Name": "JoinCgroup",
-          "Params":
-          {
-            "Controller": "cpuset",
-            "Path": "background"
-          }
-        }
-      ]
-    },
-    {
-      "Name": "ProcessCapacityNormal",
-      "Actions": [
-        {
-          "Name": "JoinCgroup",
-          "Params":
-          {
-            "Controller": "cpuset",
-            "Path": ""
-          }
-        }
-      ]
-    },
-    {
-      "Name": "ProcessCapacityHigh",
-      "Actions": [
-        {
-          "Name": "JoinCgroup",
-          "Params":
-          {
-            "Controller": "cpuset",
-            "Path": "foreground"
-          }
-        }
-      ]
-    },
-    {
-      "Name": "ProcessCapacityMax",
-      "Actions": [
-        {
-          "Name": "JoinCgroup",
-          "Params":
-          {
-            "Controller": "cpuset",
-            "Path": "top-app"
-          }
-        }
-      ]
-    },
-
-    {
-      "Name": "ServiceCapacityLow",
-      "Actions": [
-        {
-          "Name": "JoinCgroup",
-          "Params":
-          {
-            "Controller": "cpuset",
-            "Path": "system-background"
-          }
-        }
-      ]
-    },
-    {
-      "Name": "ServiceCapacityRestricted",
-      "Actions": [
-        {
-          "Name": "JoinCgroup",
-          "Params":
-          {
-            "Controller": "cpuset",
-            "Path": "restricted"
-          }
-        }
-      ]
-    },
-
-    {
-      "Name": "CameraServiceCapacity",
-      "Actions": [
-        {
-          "Name": "JoinCgroup",
-          "Params":
-          {
-            "Controller": "cpuset",
-            "Path": "camera-daemon"
-          }
-        }
-      ]
-    },
-
-    {
-      "Name": "LowIoPriority",
-      "Actions": [
-        {
-          "Name": "JoinCgroup",
-          "Params":
-          {
-            "Controller": "blkio",
-            "Path": "background"
-          }
-        }
-      ]
-    },
-    {
-      "Name": "NormalIoPriority",
-      "Actions": [
-        {
-          "Name": "JoinCgroup",
-          "Params":
-          {
-            "Controller": "blkio",
-            "Path": ""
-          }
-        }
-      ]
-    },
-    {
-      "Name": "HighIoPriority",
-      "Actions": [
-        {
-          "Name": "JoinCgroup",
-          "Params":
-          {
-            "Controller": "blkio",
-            "Path": ""
-          }
-        }
-      ]
-    },
-    {
-      "Name": "MaxIoPriority",
-      "Actions": [
-        {
-          "Name": "JoinCgroup",
-          "Params":
-          {
-            "Controller": "blkio",
-            "Path": ""
-          }
-        }
-      ]
-    },
-
-    {
-      "Name": "TimerSlackHigh",
-      "Actions": [
-        {
-          "Name": "SetTimerSlack",
-          "Params":
-          {
-            "Slack": "40000000"
-          }
-        }
-      ]
-    },
-    {
-      "Name": "TimerSlackNormal",
-      "Actions": [
-        {
-          "Name": "SetTimerSlack",
-          "Params":
-          {
-            "Slack": "50000"
-          }
-        }
-      ]
-    },
-
-    {
-      "Name": "PerfBoost",
-      "Actions": [
-        {
-          "Name": "SetClamps",
-          "Params":
-          {
-            "Boost": "50%",
-            "Clamp": "0"
-          }
-        }
-      ]
-    },
-    {
-      "Name": "PerfClamp",
-      "Actions": [
-        {
-          "Name": "SetClamps",
-          "Params":
-          {
-            "Boost": "0",
-            "Clamp": "30%"
-          }
-        }
-      ]
-    },
-
-    {
-      "Name": "LowMemoryUsage",
-      "Actions": [
-        {
-          "Name": "SetAttribute",
-          "Params":
-          {
-            "Name": "MemSoftLimit",
-            "Value": "16MB"
-          }
-        },
-        {
-          "Name": "SetAttribute",
-          "Params":
-          {
-            "Name": "MemSwappiness",
-            "Value": "150"
-
-          }
-        }
-      ]
-    },
-    {
-      "Name": "HighMemoryUsage",
-      "Actions": [
-        {
-          "Name": "SetAttribute",
-          "Params":
-          {
-            "Name": "MemSoftLimit",
-            "Value": "512MB"
-          }
-        },
-        {
-          "Name": "SetAttribute",
-          "Params":
-          {
-            "Name": "MemSwappiness",
-            "Value": "100"
-          }
-        }
-      ]
-    },
-    {
-      "Name": "SystemMemoryProcess",
-      "Actions": [
-        {
-          "Name": "JoinCgroup",
-          "Params":
-          {
-            "Controller": "memory",
-            "Path": "system"
-          }
-        }
-      ]
-    },
-    {
-      "Name": "FreezerDisabled",
-      "Actions": [
-        {
-          "Name": "SetAttribute",
-          "Params":
-          {
-            "Name": "FreezerState",
-            "Value": "0"
-          }
-        }
-      ]
-    },
-    {
-      "Name": "FreezerEnabled",
-      "Actions": [
-        {
-          "Name": "SetAttribute",
-          "Params":
-          {
-            "Name": "FreezerState",
-            "Value": "1"
-          }
-        }
-      ]
-    }
-  ],
-
-  "AggregateProfiles": [
-    {
-      "Name": "SCHED_SP_DEFAULT",
-      "Profiles": [ "TimerSlackNormal" ]
-    },
-    {
-      "Name": "SCHED_SP_BACKGROUND",
-      "Profiles": [ "HighEnergySaving", "LowIoPriority", "TimerSlackHigh" ]
-    },
-    {
-      "Name": "SCHED_SP_FOREGROUND",
-      "Profiles": [ "HighPerformance", "HighIoPriority", "TimerSlackNormal" ]
-    },
-    {
-      "Name": "SCHED_SP_TOP_APP",
-      "Profiles": [ "MaxPerformance", "MaxIoPriority", "TimerSlackNormal" ]
-    },
-    {
-      "Name": "SCHED_SP_RT_APP",
-      "Profiles": [ "RealtimePerformance", "MaxIoPriority", "TimerSlackNormal" ]
-    },
-    {
-      "Name": "CPUSET_SP_DEFAULT",
-      "Profiles": [ "TimerSlackNormal" ]
-    },
-    {
-      "Name": "CPUSET_SP_BACKGROUND",
-      "Profiles": [ "HighEnergySaving", "ProcessCapacityLow", "LowIoPriority", "TimerSlackHigh" ]
-    },
-    {
-      "Name": "CPUSET_SP_FOREGROUND",
-      "Profiles": [ "HighPerformance", "ProcessCapacityHigh", "HighIoPriority", "TimerSlackNormal" ]
-    },
-    {
-      "Name": "CPUSET_SP_TOP_APP",
-      "Profiles": [ "MaxPerformance", "ProcessCapacityMax", "MaxIoPriority", "TimerSlackNormal" ]
-    },
-    {
-      "Name": "CPUSET_SP_SYSTEM",
-      "Profiles": [ "ServiceCapacityLow", "TimerSlackNormal" ]
-    },
-    {
-      "Name": "CPUSET_SP_RESTRICTED",
-      "Profiles": [ "ServiceCapacityRestricted", "TimerSlackNormal" ]
     }
   ]
 }
diff --git a/libprocessgroup/profiles/task_profiles_29.json b/libprocessgroup/profiles/task_profiles_29.json
index 142b0ba..9f83785 100644
--- a/libprocessgroup/profiles/task_profiles_29.json
+++ b/libprocessgroup/profiles/task_profiles_29.json
@@ -1,36 +1,6 @@
 {
   "Attributes": [
     {
-      "Name": "LowCapacityCPUs",
-      "Controller": "cpuset",
-      "File": "background/cpus"
-    },
-    {
-      "Name": "HighCapacityCPUs",
-      "Controller": "cpuset",
-      "File": "foreground/cpus"
-    },
-    {
-      "Name": "MaxCapacityCPUs",
-      "Controller": "cpuset",
-      "File": "top-app/cpus"
-    },
-    {
-      "Name": "MemLimit",
-      "Controller": "memory",
-      "File": "memory.limit_in_bytes"
-    },
-    {
-      "Name": "MemSoftLimit",
-      "Controller": "memory",
-      "File": "memory.soft_limit_in_bytes"
-    },
-    {
-      "Name": "MemSwappiness",
-      "Controller": "memory",
-      "File": "memory.swappiness"
-    },
-    {
       "Name": "STuneBoost",
       "Controller": "schedtune",
       "File": "schedtune.boost"
@@ -39,21 +9,6 @@
       "Name": "STunePreferIdle",
       "Controller": "schedtune",
       "File": "schedtune.prefer_idle"
-    },
-    {
-      "Name": "UClampMin",
-      "Controller": "cpu",
-      "File": "cpu.uclamp.min"
-    },
-    {
-      "Name": "UClampMax",
-      "Controller": "cpu",
-      "File": "cpu.uclamp.max"
-    },
-    {
-      "Name": "FreezerState",
-      "Controller": "freezer",
-      "File": "cgroup.freeze"
     }
   ],
 
@@ -72,32 +27,6 @@
       ]
     },
     {
-      "Name": "Frozen",
-      "Actions": [
-        {
-          "Name": "JoinCgroup",
-          "Params":
-          {
-            "Controller": "freezer",
-            "Path": ""
-          }
-        }
-      ]
-    },
-    {
-      "Name": "Unfrozen",
-      "Actions": [
-        {
-          "Name": "JoinCgroup",
-          "Params":
-          {
-            "Controller": "freezer",
-            "Path": "../"
-          }
-        }
-      ]
-    },
-    {
       "Name": "NormalPerformance",
       "Actions": [
         {
@@ -201,427 +130,6 @@
           }
         }
       ]
-    },
-
-    {
-      "Name": "VrKernelCapacity",
-      "Actions": [
-        {
-          "Name": "JoinCgroup",
-          "Params":
-          {
-            "Controller": "cpuset",
-            "Path": ""
-          }
-        }
-      ]
-    },
-    {
-      "Name": "VrServiceCapacityLow",
-      "Actions": [
-        {
-          "Name": "JoinCgroup",
-          "Params":
-          {
-            "Controller": "cpuset",
-            "Path": "system/background"
-          }
-        }
-      ]
-    },
-    {
-      "Name": "VrServiceCapacityNormal",
-      "Actions": [
-        {
-          "Name": "JoinCgroup",
-          "Params":
-          {
-            "Controller": "cpuset",
-            "Path": "system"
-          }
-        }
-      ]
-    },
-    {
-      "Name": "VrServiceCapacityHigh",
-      "Actions": [
-        {
-          "Name": "JoinCgroup",
-          "Params":
-          {
-            "Controller": "cpuset",
-            "Path": "system/performance"
-          }
-        }
-      ]
-    },
-    {
-      "Name": "VrProcessCapacityLow",
-      "Actions": [
-        {
-          "Name": "JoinCgroup",
-          "Params":
-          {
-            "Controller": "cpuset",
-            "Path": "application/background"
-          }
-        }
-      ]
-    },
-    {
-      "Name": "VrProcessCapacityNormal",
-      "Actions": [
-        {
-          "Name": "JoinCgroup",
-          "Params":
-          {
-            "Controller": "cpuset",
-            "Path": "application"
-          }
-        }
-      ]
-    },
-    {
-      "Name": "VrProcessCapacityHigh",
-      "Actions": [
-        {
-          "Name": "JoinCgroup",
-          "Params":
-          {
-            "Controller": "cpuset",
-            "Path": "application/performance"
-          }
-        }
-      ]
-    },
-
-    {
-      "Name": "ProcessCapacityLow",
-      "Actions": [
-        {
-          "Name": "JoinCgroup",
-          "Params":
-          {
-            "Controller": "cpuset",
-            "Path": "background"
-          }
-        }
-      ]
-    },
-    {
-      "Name": "ProcessCapacityNormal",
-      "Actions": [
-        {
-          "Name": "JoinCgroup",
-          "Params":
-          {
-            "Controller": "cpuset",
-            "Path": ""
-          }
-        }
-      ]
-    },
-    {
-      "Name": "ProcessCapacityHigh",
-      "Actions": [
-        {
-          "Name": "JoinCgroup",
-          "Params":
-          {
-            "Controller": "cpuset",
-            "Path": "foreground"
-          }
-        }
-      ]
-    },
-    {
-      "Name": "ProcessCapacityMax",
-      "Actions": [
-        {
-          "Name": "JoinCgroup",
-          "Params":
-          {
-            "Controller": "cpuset",
-            "Path": "top-app"
-          }
-        }
-      ]
-    },
-
-    {
-      "Name": "ServiceCapacityLow",
-      "Actions": [
-        {
-          "Name": "JoinCgroup",
-          "Params":
-          {
-            "Controller": "cpuset",
-            "Path": "system-background"
-          }
-        }
-      ]
-    },
-    {
-      "Name": "ServiceCapacityRestricted",
-      "Actions": [
-        {
-          "Name": "JoinCgroup",
-          "Params":
-          {
-            "Controller": "cpuset",
-            "Path": "restricted"
-          }
-        }
-      ]
-    },
-
-    {
-      "Name": "CameraServiceCapacity",
-      "Actions": [
-        {
-          "Name": "JoinCgroup",
-          "Params":
-          {
-            "Controller": "cpuset",
-            "Path": "camera-daemon"
-          }
-        }
-      ]
-    },
-
-    {
-      "Name": "LowIoPriority",
-      "Actions": [
-        {
-          "Name": "JoinCgroup",
-          "Params":
-          {
-            "Controller": "blkio",
-            "Path": "background"
-          }
-        }
-      ]
-    },
-    {
-      "Name": "NormalIoPriority",
-      "Actions": [
-        {
-          "Name": "JoinCgroup",
-          "Params":
-          {
-            "Controller": "blkio",
-            "Path": ""
-          }
-        }
-      ]
-    },
-    {
-      "Name": "HighIoPriority",
-      "Actions": [
-        {
-          "Name": "JoinCgroup",
-          "Params":
-          {
-            "Controller": "blkio",
-            "Path": ""
-          }
-        }
-      ]
-    },
-    {
-      "Name": "MaxIoPriority",
-      "Actions": [
-        {
-          "Name": "JoinCgroup",
-          "Params":
-          {
-            "Controller": "blkio",
-            "Path": ""
-          }
-        }
-      ]
-    },
-
-    {
-      "Name": "TimerSlackHigh",
-      "Actions": [
-        {
-          "Name": "SetTimerSlack",
-          "Params":
-          {
-            "Slack": "40000000"
-          }
-        }
-      ]
-    },
-    {
-      "Name": "TimerSlackNormal",
-      "Actions": [
-        {
-          "Name": "SetTimerSlack",
-          "Params":
-          {
-            "Slack": "50000"
-          }
-        }
-      ]
-    },
-
-    {
-      "Name": "PerfBoost",
-      "Actions": [
-        {
-          "Name": "SetClamps",
-          "Params":
-          {
-            "Boost": "50%",
-            "Clamp": "0"
-          }
-        }
-      ]
-    },
-    {
-      "Name": "PerfClamp",
-      "Actions": [
-        {
-          "Name": "SetClamps",
-          "Params":
-          {
-            "Boost": "0",
-            "Clamp": "30%"
-          }
-        }
-      ]
-    },
-
-    {
-      "Name": "LowMemoryUsage",
-      "Actions": [
-        {
-          "Name": "SetAttribute",
-          "Params":
-          {
-            "Name": "MemSoftLimit",
-            "Value": "16MB"
-          }
-        },
-        {
-          "Name": "SetAttribute",
-          "Params":
-          {
-            "Name": "MemSwappiness",
-            "Value": "150"
-
-          }
-        }
-      ]
-    },
-    {
-      "Name": "HighMemoryUsage",
-      "Actions": [
-        {
-          "Name": "SetAttribute",
-          "Params":
-          {
-            "Name": "MemSoftLimit",
-            "Value": "512MB"
-          }
-        },
-        {
-          "Name": "SetAttribute",
-          "Params":
-          {
-            "Name": "MemSwappiness",
-            "Value": "100"
-          }
-        }
-      ]
-    },
-    {
-      "Name": "SystemMemoryProcess",
-      "Actions": [
-        {
-          "Name": "JoinCgroup",
-          "Params":
-          {
-            "Controller": "memory",
-            "Path": "system"
-          }
-        }
-      ]
-    },
-    {
-      "Name": "FreezerDisabled",
-      "Actions": [
-        {
-          "Name": "SetAttribute",
-          "Params":
-          {
-            "Name": "FreezerState",
-            "Value": "0"
-          }
-        }
-      ]
-    },
-    {
-      "Name": "FreezerEnabled",
-      "Actions": [
-        {
-          "Name": "SetAttribute",
-          "Params":
-          {
-            "Name": "FreezerState",
-            "Value": "1"
-          }
-        }
-      ]
-    }
-  ],
-
-  "AggregateProfiles": [
-    {
-      "Name": "SCHED_SP_DEFAULT",
-      "Profiles": [ "TimerSlackNormal" ]
-    },
-    {
-      "Name": "SCHED_SP_BACKGROUND",
-      "Profiles": [ "HighEnergySaving", "LowIoPriority", "TimerSlackHigh" ]
-    },
-    {
-      "Name": "SCHED_SP_FOREGROUND",
-      "Profiles": [ "HighPerformance", "HighIoPriority", "TimerSlackNormal" ]
-    },
-    {
-      "Name": "SCHED_SP_TOP_APP",
-      "Profiles": [ "MaxPerformance", "MaxIoPriority", "TimerSlackNormal" ]
-    },
-    {
-      "Name": "SCHED_SP_RT_APP",
-      "Profiles": [ "RealtimePerformance", "MaxIoPriority", "TimerSlackNormal" ]
-    },
-    {
-      "Name": "CPUSET_SP_DEFAULT",
-      "Profiles": [ "TimerSlackNormal" ]
-    },
-    {
-      "Name": "CPUSET_SP_BACKGROUND",
-      "Profiles": [ "HighEnergySaving", "ProcessCapacityLow", "LowIoPriority", "TimerSlackHigh" ]
-    },
-    {
-      "Name": "CPUSET_SP_FOREGROUND",
-      "Profiles": [ "HighPerformance", "ProcessCapacityHigh", "HighIoPriority", "TimerSlackNormal" ]
-    },
-    {
-      "Name": "CPUSET_SP_TOP_APP",
-      "Profiles": [ "MaxPerformance", "ProcessCapacityMax", "MaxIoPriority", "TimerSlackNormal" ]
-    },
-    {
-      "Name": "CPUSET_SP_SYSTEM",
-      "Profiles": [ "ServiceCapacityLow", "TimerSlackNormal" ]
-    },
-    {
-      "Name": "CPUSET_SP_RESTRICTED",
-      "Profiles": [ "ServiceCapacityRestricted", "TimerSlackNormal" ]
     }
   ]
 }
diff --git a/libprocessgroup/profiles/task_profiles_30.json b/libprocessgroup/profiles/task_profiles_30.json
index 142b0ba..9f83785 100644
--- a/libprocessgroup/profiles/task_profiles_30.json
+++ b/libprocessgroup/profiles/task_profiles_30.json
@@ -1,36 +1,6 @@
 {
   "Attributes": [
     {
-      "Name": "LowCapacityCPUs",
-      "Controller": "cpuset",
-      "File": "background/cpus"
-    },
-    {
-      "Name": "HighCapacityCPUs",
-      "Controller": "cpuset",
-      "File": "foreground/cpus"
-    },
-    {
-      "Name": "MaxCapacityCPUs",
-      "Controller": "cpuset",
-      "File": "top-app/cpus"
-    },
-    {
-      "Name": "MemLimit",
-      "Controller": "memory",
-      "File": "memory.limit_in_bytes"
-    },
-    {
-      "Name": "MemSoftLimit",
-      "Controller": "memory",
-      "File": "memory.soft_limit_in_bytes"
-    },
-    {
-      "Name": "MemSwappiness",
-      "Controller": "memory",
-      "File": "memory.swappiness"
-    },
-    {
       "Name": "STuneBoost",
       "Controller": "schedtune",
       "File": "schedtune.boost"
@@ -39,21 +9,6 @@
       "Name": "STunePreferIdle",
       "Controller": "schedtune",
       "File": "schedtune.prefer_idle"
-    },
-    {
-      "Name": "UClampMin",
-      "Controller": "cpu",
-      "File": "cpu.uclamp.min"
-    },
-    {
-      "Name": "UClampMax",
-      "Controller": "cpu",
-      "File": "cpu.uclamp.max"
-    },
-    {
-      "Name": "FreezerState",
-      "Controller": "freezer",
-      "File": "cgroup.freeze"
     }
   ],
 
@@ -72,32 +27,6 @@
       ]
     },
     {
-      "Name": "Frozen",
-      "Actions": [
-        {
-          "Name": "JoinCgroup",
-          "Params":
-          {
-            "Controller": "freezer",
-            "Path": ""
-          }
-        }
-      ]
-    },
-    {
-      "Name": "Unfrozen",
-      "Actions": [
-        {
-          "Name": "JoinCgroup",
-          "Params":
-          {
-            "Controller": "freezer",
-            "Path": "../"
-          }
-        }
-      ]
-    },
-    {
       "Name": "NormalPerformance",
       "Actions": [
         {
@@ -201,427 +130,6 @@
           }
         }
       ]
-    },
-
-    {
-      "Name": "VrKernelCapacity",
-      "Actions": [
-        {
-          "Name": "JoinCgroup",
-          "Params":
-          {
-            "Controller": "cpuset",
-            "Path": ""
-          }
-        }
-      ]
-    },
-    {
-      "Name": "VrServiceCapacityLow",
-      "Actions": [
-        {
-          "Name": "JoinCgroup",
-          "Params":
-          {
-            "Controller": "cpuset",
-            "Path": "system/background"
-          }
-        }
-      ]
-    },
-    {
-      "Name": "VrServiceCapacityNormal",
-      "Actions": [
-        {
-          "Name": "JoinCgroup",
-          "Params":
-          {
-            "Controller": "cpuset",
-            "Path": "system"
-          }
-        }
-      ]
-    },
-    {
-      "Name": "VrServiceCapacityHigh",
-      "Actions": [
-        {
-          "Name": "JoinCgroup",
-          "Params":
-          {
-            "Controller": "cpuset",
-            "Path": "system/performance"
-          }
-        }
-      ]
-    },
-    {
-      "Name": "VrProcessCapacityLow",
-      "Actions": [
-        {
-          "Name": "JoinCgroup",
-          "Params":
-          {
-            "Controller": "cpuset",
-            "Path": "application/background"
-          }
-        }
-      ]
-    },
-    {
-      "Name": "VrProcessCapacityNormal",
-      "Actions": [
-        {
-          "Name": "JoinCgroup",
-          "Params":
-          {
-            "Controller": "cpuset",
-            "Path": "application"
-          }
-        }
-      ]
-    },
-    {
-      "Name": "VrProcessCapacityHigh",
-      "Actions": [
-        {
-          "Name": "JoinCgroup",
-          "Params":
-          {
-            "Controller": "cpuset",
-            "Path": "application/performance"
-          }
-        }
-      ]
-    },
-
-    {
-      "Name": "ProcessCapacityLow",
-      "Actions": [
-        {
-          "Name": "JoinCgroup",
-          "Params":
-          {
-            "Controller": "cpuset",
-            "Path": "background"
-          }
-        }
-      ]
-    },
-    {
-      "Name": "ProcessCapacityNormal",
-      "Actions": [
-        {
-          "Name": "JoinCgroup",
-          "Params":
-          {
-            "Controller": "cpuset",
-            "Path": ""
-          }
-        }
-      ]
-    },
-    {
-      "Name": "ProcessCapacityHigh",
-      "Actions": [
-        {
-          "Name": "JoinCgroup",
-          "Params":
-          {
-            "Controller": "cpuset",
-            "Path": "foreground"
-          }
-        }
-      ]
-    },
-    {
-      "Name": "ProcessCapacityMax",
-      "Actions": [
-        {
-          "Name": "JoinCgroup",
-          "Params":
-          {
-            "Controller": "cpuset",
-            "Path": "top-app"
-          }
-        }
-      ]
-    },
-
-    {
-      "Name": "ServiceCapacityLow",
-      "Actions": [
-        {
-          "Name": "JoinCgroup",
-          "Params":
-          {
-            "Controller": "cpuset",
-            "Path": "system-background"
-          }
-        }
-      ]
-    },
-    {
-      "Name": "ServiceCapacityRestricted",
-      "Actions": [
-        {
-          "Name": "JoinCgroup",
-          "Params":
-          {
-            "Controller": "cpuset",
-            "Path": "restricted"
-          }
-        }
-      ]
-    },
-
-    {
-      "Name": "CameraServiceCapacity",
-      "Actions": [
-        {
-          "Name": "JoinCgroup",
-          "Params":
-          {
-            "Controller": "cpuset",
-            "Path": "camera-daemon"
-          }
-        }
-      ]
-    },
-
-    {
-      "Name": "LowIoPriority",
-      "Actions": [
-        {
-          "Name": "JoinCgroup",
-          "Params":
-          {
-            "Controller": "blkio",
-            "Path": "background"
-          }
-        }
-      ]
-    },
-    {
-      "Name": "NormalIoPriority",
-      "Actions": [
-        {
-          "Name": "JoinCgroup",
-          "Params":
-          {
-            "Controller": "blkio",
-            "Path": ""
-          }
-        }
-      ]
-    },
-    {
-      "Name": "HighIoPriority",
-      "Actions": [
-        {
-          "Name": "JoinCgroup",
-          "Params":
-          {
-            "Controller": "blkio",
-            "Path": ""
-          }
-        }
-      ]
-    },
-    {
-      "Name": "MaxIoPriority",
-      "Actions": [
-        {
-          "Name": "JoinCgroup",
-          "Params":
-          {
-            "Controller": "blkio",
-            "Path": ""
-          }
-        }
-      ]
-    },
-
-    {
-      "Name": "TimerSlackHigh",
-      "Actions": [
-        {
-          "Name": "SetTimerSlack",
-          "Params":
-          {
-            "Slack": "40000000"
-          }
-        }
-      ]
-    },
-    {
-      "Name": "TimerSlackNormal",
-      "Actions": [
-        {
-          "Name": "SetTimerSlack",
-          "Params":
-          {
-            "Slack": "50000"
-          }
-        }
-      ]
-    },
-
-    {
-      "Name": "PerfBoost",
-      "Actions": [
-        {
-          "Name": "SetClamps",
-          "Params":
-          {
-            "Boost": "50%",
-            "Clamp": "0"
-          }
-        }
-      ]
-    },
-    {
-      "Name": "PerfClamp",
-      "Actions": [
-        {
-          "Name": "SetClamps",
-          "Params":
-          {
-            "Boost": "0",
-            "Clamp": "30%"
-          }
-        }
-      ]
-    },
-
-    {
-      "Name": "LowMemoryUsage",
-      "Actions": [
-        {
-          "Name": "SetAttribute",
-          "Params":
-          {
-            "Name": "MemSoftLimit",
-            "Value": "16MB"
-          }
-        },
-        {
-          "Name": "SetAttribute",
-          "Params":
-          {
-            "Name": "MemSwappiness",
-            "Value": "150"
-
-          }
-        }
-      ]
-    },
-    {
-      "Name": "HighMemoryUsage",
-      "Actions": [
-        {
-          "Name": "SetAttribute",
-          "Params":
-          {
-            "Name": "MemSoftLimit",
-            "Value": "512MB"
-          }
-        },
-        {
-          "Name": "SetAttribute",
-          "Params":
-          {
-            "Name": "MemSwappiness",
-            "Value": "100"
-          }
-        }
-      ]
-    },
-    {
-      "Name": "SystemMemoryProcess",
-      "Actions": [
-        {
-          "Name": "JoinCgroup",
-          "Params":
-          {
-            "Controller": "memory",
-            "Path": "system"
-          }
-        }
-      ]
-    },
-    {
-      "Name": "FreezerDisabled",
-      "Actions": [
-        {
-          "Name": "SetAttribute",
-          "Params":
-          {
-            "Name": "FreezerState",
-            "Value": "0"
-          }
-        }
-      ]
-    },
-    {
-      "Name": "FreezerEnabled",
-      "Actions": [
-        {
-          "Name": "SetAttribute",
-          "Params":
-          {
-            "Name": "FreezerState",
-            "Value": "1"
-          }
-        }
-      ]
-    }
-  ],
-
-  "AggregateProfiles": [
-    {
-      "Name": "SCHED_SP_DEFAULT",
-      "Profiles": [ "TimerSlackNormal" ]
-    },
-    {
-      "Name": "SCHED_SP_BACKGROUND",
-      "Profiles": [ "HighEnergySaving", "LowIoPriority", "TimerSlackHigh" ]
-    },
-    {
-      "Name": "SCHED_SP_FOREGROUND",
-      "Profiles": [ "HighPerformance", "HighIoPriority", "TimerSlackNormal" ]
-    },
-    {
-      "Name": "SCHED_SP_TOP_APP",
-      "Profiles": [ "MaxPerformance", "MaxIoPriority", "TimerSlackNormal" ]
-    },
-    {
-      "Name": "SCHED_SP_RT_APP",
-      "Profiles": [ "RealtimePerformance", "MaxIoPriority", "TimerSlackNormal" ]
-    },
-    {
-      "Name": "CPUSET_SP_DEFAULT",
-      "Profiles": [ "TimerSlackNormal" ]
-    },
-    {
-      "Name": "CPUSET_SP_BACKGROUND",
-      "Profiles": [ "HighEnergySaving", "ProcessCapacityLow", "LowIoPriority", "TimerSlackHigh" ]
-    },
-    {
-      "Name": "CPUSET_SP_FOREGROUND",
-      "Profiles": [ "HighPerformance", "ProcessCapacityHigh", "HighIoPriority", "TimerSlackNormal" ]
-    },
-    {
-      "Name": "CPUSET_SP_TOP_APP",
-      "Profiles": [ "MaxPerformance", "ProcessCapacityMax", "MaxIoPriority", "TimerSlackNormal" ]
-    },
-    {
-      "Name": "CPUSET_SP_SYSTEM",
-      "Profiles": [ "ServiceCapacityLow", "TimerSlackNormal" ]
-    },
-    {
-      "Name": "CPUSET_SP_RESTRICTED",
-      "Profiles": [ "ServiceCapacityRestricted", "TimerSlackNormal" ]
     }
   ]
 }
diff --git a/libprocessgroup/sched_policy.cpp b/libprocessgroup/sched_policy.cpp
index 698e74d..c51ee61 100644
--- a/libprocessgroup/sched_policy.cpp
+++ b/libprocessgroup/sched_policy.cpp
@@ -124,6 +124,8 @@
             return SetTaskProfiles(tid, {"SCHED_SP_FOREGROUND"}, true) ? 0 : -1;
         case SP_TOP_APP:
             return SetTaskProfiles(tid, {"SCHED_SP_TOP_APP"}, true) ? 0 : -1;
+        case SP_SYSTEM:
+            return SetTaskProfiles(tid, {"SCHED_SP_SYSTEM"}, true) ? 0 : -1;
         case SP_RT_APP:
             return SetTaskProfiles(tid, {"SCHED_SP_RT_APP"}, true) ? 0 : -1;
         default:
@@ -258,7 +260,7 @@
      */
     static constexpr const char* kSchedProfiles[SP_CNT + 1] = {
             "SCHED_SP_DEFAULT", "SCHED_SP_BACKGROUND", "SCHED_SP_FOREGROUND",
-            "SCHED_SP_DEFAULT", "SCHED_SP_FOREGROUND", "SCHED_SP_FOREGROUND",
+            "SCHED_SP_SYSTEM",  "SCHED_SP_FOREGROUND", "SCHED_SP_FOREGROUND",
             "SCHED_SP_TOP_APP", "SCHED_SP_RT_APP",     "SCHED_SP_DEFAULT"};
     if (policy < SP_DEFAULT || policy >= SP_CNT) {
         return nullptr;
diff --git a/libprocessgroup/setup/cgroup_map_write.cpp b/libprocessgroup/setup/cgroup_map_write.cpp
index a53132e..753fd2d 100644
--- a/libprocessgroup/setup/cgroup_map_write.cpp
+++ b/libprocessgroup/setup/cgroup_map_write.cpp
@@ -214,23 +214,23 @@
 }
 
 static bool ReadDescriptors(std::map<std::string, CgroupDescriptor>* descriptors) {
-    unsigned int api_level = GetUintProperty<unsigned int>("ro.product.first_api_level", 0);
-    std::string sys_cgroups_path = CGROUPS_DESC_FILE;
+    // load system cgroup descriptors
+    if (!ReadDescriptorsFromFile(CGROUPS_DESC_FILE, descriptors)) {
+        return false;
+    }
 
     // load API-level specific system cgroups descriptors if available
+    unsigned int api_level = GetUintProperty<unsigned int>("ro.product.first_api_level", 0);
     if (api_level > 0) {
         std::string api_cgroups_path =
                 android::base::StringPrintf(TEMPLATE_CGROUPS_DESC_API_FILE, api_level);
         if (!access(api_cgroups_path.c_str(), F_OK) || errno != ENOENT) {
-            sys_cgroups_path = api_cgroups_path;
+            if (!ReadDescriptorsFromFile(api_cgroups_path, descriptors)) {
+                return false;
+            }
         }
     }
 
-    // load system cgroup descriptors
-    if (!ReadDescriptorsFromFile(sys_cgroups_path, 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)) {
diff --git a/libprocessgroup/task_profiles.cpp b/libprocessgroup/task_profiles.cpp
index db44228..1311306 100644
--- a/libprocessgroup/task_profiles.cpp
+++ b/libprocessgroup/task_profiles.cpp
@@ -391,23 +391,24 @@
 }
 
 TaskProfiles::TaskProfiles() {
-    unsigned int api_level = GetUintProperty<unsigned int>("ro.product.first_api_level", 0);
-    std::string sys_profiles_path = TASK_PROFILE_DB_FILE;
+    // load system task profiles
+    if (!Load(CgroupMap::GetInstance(), TASK_PROFILE_DB_FILE)) {
+        LOG(ERROR) << "Loading " << TASK_PROFILE_DB_FILE << " for [" << getpid() << "] failed";
+    }
 
     // load API-level specific system task profiles if available
+    unsigned int api_level = GetUintProperty<unsigned int>("ro.product.first_api_level", 0);
     if (api_level > 0) {
         std::string api_profiles_path =
                 android::base::StringPrintf(TEMPLATE_TASK_PROFILE_API_FILE, api_level);
         if (!access(api_profiles_path.c_str(), F_OK) || errno != ENOENT) {
-            sys_profiles_path = api_profiles_path;
+            if (!Load(CgroupMap::GetInstance(), api_profiles_path)) {
+                LOG(ERROR) << "Loading " << api_profiles_path << " for [" << getpid()
+                           << "] failed";
+            }
         }
     }
 
-    // load system task profiles
-    if (!Load(CgroupMap::GetInstance(), sys_profiles_path)) {
-        LOG(ERROR) << "Loading " << sys_profiles_path << " 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)) {
diff --git a/libstats/pull/Android.bp b/libstats/pull/Android.bp
index a8b4a4f..6d6b466 100644
--- a/libstats/pull/Android.bp
+++ b/libstats/pull/Android.bp
@@ -70,6 +70,7 @@
     ],
     visibility: [
         "//frameworks/base/apex/statsd/tests/libstatspull",
+        "//packages/modules/StatsD/apex/tests/libstatspull",
     ],
 }
 
diff --git a/libstats/socket/Android.bp b/libstats/socket/Android.bp
index a93d268..a6ea185 100644
--- a/libstats/socket/Android.bp
+++ b/libstats/socket/Android.bp
@@ -79,6 +79,7 @@
     visibility: [
         "//frameworks/base/apex/statsd/tests/libstatspull",
         "//frameworks/base/cmds/statsd",
+        "//packages/modules/StatsD/apex/tests/libstatspull",
         "//packages/modules/StatsD/bin",
     ],
 }
diff --git a/libsystem/Android.bp b/libsystem/Android.bp
index 12c946c..b37b8ec 100644
--- a/libsystem/Android.bp
+++ b/libsystem/Android.bp
@@ -1,6 +1,7 @@
 cc_library_headers {
     name: "libsystem_headers",
     vendor_available: true,
+    product_available: true,
     recovery_available: true,
     vendor_ramdisk_available: true,
     host_supported: true,
diff --git a/libutils/Android.bp b/libutils/Android.bp
index 8ee16f3..1e7cbdb 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -15,6 +15,7 @@
 cc_library_headers {
     name: "libutils_headers",
     vendor_available: true,
+    product_available: true,
     recovery_available: true,
     vendor_ramdisk_available: true,
     host_supported: true,
@@ -62,6 +63,7 @@
 cc_defaults {
     name: "libutils_defaults",
     vendor_available: true,
+    product_available: true,
     recovery_available: true,
     vndk: {
         enabled: true,
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 42a12b7..2de066d 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -56,7 +56,7 @@
     write /sys/module/dm_verity/parameters/prefetch_cluster 0
 
     # Generate ld.config.txt for early executed processes
-    exec -- /system/bin/linkerconfig --target /linkerconfig/bootstrap
+    exec -- /system/bin/bootstrap/linkerconfig --target /linkerconfig/bootstrap
     chmod 644 /linkerconfig/bootstrap/ld.config.txt
     copy /linkerconfig/bootstrap/ld.config.txt /linkerconfig/default/ld.config.txt
     chmod 644 /linkerconfig/default/ld.config.txt
@@ -154,24 +154,28 @@
     mkdir /dev/cpuctl/top-app
     mkdir /dev/cpuctl/rt
     mkdir /dev/cpuctl/system
+    mkdir /dev/cpuctl/system-background
     chown system system /dev/cpuctl
     chown system system /dev/cpuctl/foreground
     chown system system /dev/cpuctl/background
     chown system system /dev/cpuctl/top-app
     chown system system /dev/cpuctl/rt
     chown system system /dev/cpuctl/system
+    chown system system /dev/cpuctl/system-background
     chown system system /dev/cpuctl/tasks
     chown system system /dev/cpuctl/foreground/tasks
     chown system system /dev/cpuctl/background/tasks
     chown system system /dev/cpuctl/top-app/tasks
     chown system system /dev/cpuctl/rt/tasks
     chown system system /dev/cpuctl/system/tasks
+    chown system system /dev/cpuctl/system-background/tasks
     chmod 0664 /dev/cpuctl/tasks
     chmod 0664 /dev/cpuctl/foreground/tasks
     chmod 0664 /dev/cpuctl/background/tasks
     chmod 0664 /dev/cpuctl/top-app/tasks
     chmod 0664 /dev/cpuctl/rt/tasks
     chmod 0664 /dev/cpuctl/system/tasks
+    chmod 0664 /dev/cpuctl/system-background/tasks
 
     # Create a cpu group for NNAPI HAL processes
     mkdir /dev/cpuctl/nnapi-hal
@@ -196,7 +200,7 @@
     # Surfaceflinger is in FG group so giving it a bit more
     write /dev/cpuctl/foreground/cpu.rt_runtime_us 450000
     write /dev/cpuctl/foreground/cpu.rt_period_us 1000000
-    write /dev/cpuctl/background/cpu.rt_runtime_us 100000
+    write /dev/cpuctl/background/cpu.rt_runtime_us 50000
     write /dev/cpuctl/background/cpu.rt_period_us 1000000
     write /dev/cpuctl/top-app/cpu.rt_runtime_us 100000
     write /dev/cpuctl/top-app/cpu.rt_period_us 1000000
@@ -204,12 +208,22 @@
     write /dev/cpuctl/rt/cpu.rt_period_us 1000000
     write /dev/cpuctl/system/cpu.rt_runtime_us 100000
     write /dev/cpuctl/system/cpu.rt_period_us 1000000
-    write /dev/cpuctl/nnapi-hal/cpu.rt_runtime_us 100000
+    write /dev/cpuctl/system-background/cpu.rt_runtime_us 50000
+    write /dev/cpuctl/system-background/cpu.rt_period_us 1000000
+    write /dev/cpuctl/nnapi-hal/cpu.rt_runtime_us 50000
     write /dev/cpuctl/nnapi-hal/cpu.rt_period_us 1000000
+    write /dev/cpuctl/camera-daemon/cpu.rt_runtime_us 50000
+    write /dev/cpuctl/camera-daemon/cpu.rt_period_us 1000000
 
     # Migrate root group to system subgroup
     copy_per_line /dev/cpuctl/tasks /dev/cpuctl/system/tasks
 
+    # Create an stune group for camera-specific processes
+    mkdir /dev/stune/camera-daemon
+    chown system system /dev/stune/camera-daemon
+    chown system system /dev/stune/camera-daemon/tasks
+    chmod 0664 /dev/stune/camera-daemon/tasks
+
     # Create an stune group for NNAPI HAL processes
     mkdir /dev/stune/nnapi-hal
     chown system system /dev/stune/nnapi-hal
@@ -341,7 +355,6 @@
 
     # system-background is for system tasks that should only run on
     # little cores, not on bigs
-    # to be used only by init, so don't change system-bg permissions
     mkdir /dev/cpuset/system-background
     copy /dev/cpuset/cpus /dev/cpuset/system-background/cpus
     copy /dev/cpuset/mems /dev/cpuset/system-background/mems