Merge "Update fmtlib to 10.1.1" into main
diff --git a/debuggerd/libdebuggerd/utility.cpp b/debuggerd/libdebuggerd/utility.cpp
index d71fc6c..15f09b3 100644
--- a/debuggerd/libdebuggerd/utility.cpp
+++ b/debuggerd/libdebuggerd/utility.cpp
@@ -382,8 +382,10 @@
return "SEGV_MTEAERR";
case SEGV_MTESERR:
return "SEGV_MTESERR";
+ case SEGV_CPERR:
+ return "SEGV_CPERR";
}
- static_assert(NSIGSEGV == SEGV_MTESERR, "missing SEGV_* si_code");
+ static_assert(NSIGSEGV == SEGV_CPERR, "missing SEGV_* si_code");
break;
case SIGSYS:
switch (si->si_code) {
diff --git a/fastboot/Android.bp b/fastboot/Android.bp
index 56cac88..f85d1de 100644
--- a/fastboot/Android.bp
+++ b/fastboot/Android.bp
@@ -446,3 +446,14 @@
host_supported: true,
export_include_dirs: ["."],
}
+
+python_test_host {
+ name: "fastboot_integration_test",
+ main: "test_fastboot.py",
+ srcs: ["test_fastboot.py"],
+ data: [":fastboot"],
+ test_config: "fastboot_integration_test.xml",
+ test_options: {
+ unit_test: false,
+ },
+}
diff --git a/fastboot/fastboot_integration_test.xml b/fastboot/fastboot_integration_test.xml
new file mode 100644
index 0000000..ad14cab
--- /dev/null
+++ b/fastboot/fastboot_integration_test.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 The Android Open Source Project
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Config to run fastboot integration tests">
+ <option name="test-suite-tag" value="fastboot_unittests" />
+ <test class="com.android.tradefed.testtype.python.PythonBinaryHostTest" >
+ <option name="par-file-name" value="fastboot_integration_test" />
+ <option name="test-timeout" value="1m" />
+ </test>
+</configuration>
\ No newline at end of file
diff --git a/fastboot/test_fastboot.py b/fastboot/test_fastboot.py
new file mode 100644
index 0000000..adcaec7
--- /dev/null
+++ b/fastboot/test_fastboot.py
@@ -0,0 +1,53 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2023 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+"""Tests for the fastboot command line utility.
+"""
+
+import re
+import subprocess
+import unittest
+
+
+class DevicesTest(unittest.TestCase):
+ """Tests for `fastboot devices`."""
+
+
+ def test_devices(self):
+ """Ensure that the format of `fastboot devices` does not change.
+
+ `fastboot devices` should alternate between a line containing the
+ device's serial number and fastboot state and an empty line
+ """
+ output = subprocess.check_output(["fastboot", "devices"])
+
+ previous_line_was_empty = True
+ for line in output.decode().splitlines():
+ if previous_line_was_empty:
+ if not re.match(r"[a-zA-Z\d]+\s+(bootloader|fastbootd)", line):
+ self.fail("%s does not match the expected format <serial no>\\s+(bootloader|fastbootd)" % line)
+ previous_line_was_empty = False
+ else:
+ if line:
+ self.fail("Expected an empty line. Received '%s'" % line)
+ previous_line_was_empty = True
+
+ if len(output) == 0:
+ self.fail("Output is empty. Are any devices connected?")
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/fs_mgr/fs_mgr_remount.cpp b/fs_mgr/fs_mgr_remount.cpp
index 18892f9..7ba4d2b 100644
--- a/fs_mgr/fs_mgr_remount.cpp
+++ b/fs_mgr/fs_mgr_remount.cpp
@@ -158,15 +158,25 @@
// not checkpointing.
auto vold = GetVold();
bool checkpointing = false;
- if (!vold->isCheckpointing(&checkpointing).isOk()) {
- LOG(ERROR) << "Could not determine checkpointing status.";
- return false;
- }
- if (checkpointing) {
- LOG(ERROR) << "Cannot use remount when a checkpoint is in progress.";
- LOG(ERROR) << "To force end checkpointing, call 'vdc checkpoint commitChanges'";
- LOG(ERROR) << "Warning: this can lead to data corruption if rolled back.";
- return false;
+ bool show_help = true;
+
+ while (true) {
+ if (!vold->isCheckpointing(&checkpointing).isOk()) {
+ LOG(ERROR) << "Could not determine checkpointing status.";
+ return false;
+ }
+ if (!checkpointing) {
+ break;
+ }
+ if (show_help) {
+ show_help = false;
+ std::cerr << "WARNING: Userdata checkpoint is in progress. To force end checkpointing, "
+ "call 'vdc checkpoint commitChanges'. This can lead to data corruption if "
+ "rolled back."
+ << std::endl;
+ LOG(INFO) << "Waiting for checkpoint to complete and then continue remount.";
+ }
+ std::this_thread::sleep_for(4s);
}
return true;
}
diff --git a/fs_mgr/fs_mgr_vendor_overlay.cpp b/fs_mgr/fs_mgr_vendor_overlay.cpp
index bacfa4b..6b742e5 100644
--- a/fs_mgr/fs_mgr_vendor_overlay.cpp
+++ b/fs_mgr/fs_mgr_vendor_overlay.cpp
@@ -112,6 +112,7 @@
// properties are loaded.
static const auto vndk_version = android::base::GetProperty(kVndkVersionPropertyName, "");
if (vndk_version.empty()) {
+ // Vendor overlay is disabled from VNDK deprecated devices.
LINFO << "vendor overlay: vndk version not defined";
return false;
}
diff --git a/fs_mgr/liblp/fuzzer/liblp_apis_fuzzer.cpp b/fs_mgr/liblp/fuzzer/liblp_apis_fuzzer.cpp
index b6fbc14..a15bc89 100644
--- a/fs_mgr/liblp/fuzzer/liblp_apis_fuzzer.cpp
+++ b/fs_mgr/liblp/fuzzer/liblp_apis_fuzzer.cpp
@@ -198,13 +198,13 @@
[&]() {
uint32_t groupVectorSize = metadata->groups.size();
uint32_t randomGroupIndex =
- mFdp.ConsumeIntegralInRange<uint32_t>(0, groupVectorSize);
+ mFdp.ConsumeIntegralInRange<uint32_t>(0, groupVectorSize - 1);
GetPartitionGroupName(metadata->groups[randomGroupIndex]);
},
[&]() {
uint32_t blockDeviceVectorSize = metadata->block_devices.size();
uint32_t randomBlockDeviceIndex =
- mFdp.ConsumeIntegralInRange<uint32_t>(0, blockDeviceVectorSize);
+ mFdp.ConsumeIntegralInRange<uint32_t>(0, blockDeviceVectorSize - 1);
GetBlockDevicePartitionName(
metadata->block_devices[randomBlockDeviceIndex]);
},
@@ -224,7 +224,7 @@
[&]() {
uint32_t partitionVectorSize = metadata->partitions.size();
uint32_t randomPartitionIndex =
- mFdp.ConsumeIntegralInRange<uint32_t>(0, partitionVectorSize);
+ mFdp.ConsumeIntegralInRange<uint32_t>(0, partitionVectorSize - 1);
GetPartitionName(metadata->partitions[randomPartitionIndex]);
},
[&]() { GetTotalSuperPartitionSize(metadataValue); },
diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp
index 6fad662..ac58ba0 100644
--- a/fs_mgr/libsnapshot/Android.bp
+++ b/fs_mgr/libsnapshot/Android.bp
@@ -198,6 +198,7 @@
"libsnapshot_cow/cow_format.cpp",
"libsnapshot_cow/cow_reader.cpp",
"libsnapshot_cow/parser_v2.cpp",
+ "libsnapshot_cow/parser_v3.cpp",
"libsnapshot_cow/snapshot_reader.cpp",
"libsnapshot_cow/writer_base.cpp",
"libsnapshot_cow/writer_v2.cpp",
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h
index c9777a3..91e0425 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h
@@ -99,8 +99,10 @@
uint64_t sequence_buffer_offset;
// Size, in bytes, of the CowResumePoint buffer.
uint32_t resume_buffer_size;
- // Size, in bytes, of the CowOperation buffer.
- uint32_t op_buffer_size;
+ // Number of CowOperationV3 structs in the operation buffer, currently and total
+ // region size.
+ uint32_t op_count;
+ uint32_t op_count_max;
// Compression Algorithm
uint32_t compression_algorithm;
} __attribute__((packed));
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h
index debaf36..755a3af 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h
@@ -145,6 +145,7 @@
size_t ignore_bytes = 0) override;
CowHeader& GetHeader() override { return header_; }
+ const CowHeaderV3& header_v3() const { return header_; }
bool GetRawBytes(const CowOperation* op, void* buffer, size_t len, size_t* read);
bool GetRawBytes(uint64_t offset, void* buffer, size_t len, size_t* read);
@@ -185,7 +186,6 @@
std::shared_ptr<std::unordered_map<uint64_t, uint64_t>> data_loc_;
ReaderFlags reader_flag_;
bool is_merge_{};
- uint8_t compression_type_ = kCowCompressNone;
};
// Though this function takes in a CowHeaderV3, the struct could be populated as a v1/v2 CowHeader.
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h
index 3016e93..5b1e56c 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h
@@ -54,6 +54,9 @@
// Batch write cluster ops
bool batch_write = false;
+
+ // Size of the cow operation buffer; used in v3 only.
+ uint32_t op_count_max = 0;
};
// Interface for writing to a snapuserd COW. All operations are ordered; merges
diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/cow_reader.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/cow_reader.cpp
index 3b84c95..93c31bb 100644
--- a/fs_mgr/libsnapshot/libsnapshot_cow/cow_reader.cpp
+++ b/fs_mgr/libsnapshot/libsnapshot_cow/cow_reader.cpp
@@ -28,8 +28,8 @@
#include <zlib.h>
#include "cow_decompress.h"
-#include "libsnapshot/cow_format.h"
#include "parser_v2.h"
+#include "parser_v3.h"
namespace android {
namespace snapshot {
@@ -85,7 +85,6 @@
cow->data_loc_ = data_loc_;
cow->block_pos_index_ = block_pos_index_;
cow->is_merge_ = is_merge_;
- cow->compression_type_ = compression_type_;
return cow;
}
@@ -104,11 +103,14 @@
PLOG(ERROR) << "lseek header failed";
return false;
}
- if (!android::base::ReadFully(fd_, &header_, sizeof(header_))) {
+
+ CHECK_GE(header_.prefix.header_size, sizeof(CowHeader));
+ CHECK_LE(header_.prefix.header_size, sizeof(header_));
+
+ if (!android::base::ReadFully(fd_, &header_, header_.prefix.header_size)) {
PLOG(ERROR) << "read header failed";
return false;
}
-
return true;
}
@@ -124,52 +126,36 @@
return false;
}
- CowParserV2 parser;
- if (!parser.Parse(fd, header_, label)) {
+ std::unique_ptr<CowParserBase> parser;
+ switch (header_.prefix.major_version) {
+ case 1:
+ case 2:
+ parser = std::make_unique<CowParserV2>();
+ break;
+ case 3:
+ parser = std::make_unique<CowParserV3>();
+ break;
+ default:
+ LOG(ERROR) << "Unknown version: " << header_.prefix.major_version;
+ return false;
+ }
+
+ if (!parser->Parse(fd, header_, label)) {
return false;
}
- footer_ = parser.footer();
- fd_size_ = parser.fd_size();
- last_label_ = parser.last_label();
- data_loc_ = parser.data_loc();
- ops_ = std::make_shared<std::vector<CowOperation>>(parser.ops()->size());
-
- // Translate the operation buffer from on disk to in memory
- for (size_t i = 0; i < parser.ops()->size(); i++) {
- const auto& v2_op = parser.ops()->at(i);
-
- auto& new_op = ops_->at(i);
- new_op.type = v2_op.type;
- new_op.data_length = v2_op.data_length;
-
- if (v2_op.new_block > std::numeric_limits<uint32_t>::max()) {
- LOG(ERROR) << "Out-of-range new block in COW op: " << v2_op;
- return false;
- }
- new_op.new_block = v2_op.new_block;
-
- uint64_t source_info = v2_op.source;
- if (new_op.type != kCowLabelOp) {
- source_info &= kCowOpSourceInfoDataMask;
- if (source_info != v2_op.source) {
- LOG(ERROR) << "Out-of-range source value in COW op: " << v2_op;
- return false;
- }
- }
- if (v2_op.compression != kCowCompressNone) {
- if (compression_type_ == kCowCompressNone) {
- compression_type_ = v2_op.compression;
- } else if (compression_type_ != v2_op.compression) {
- LOG(ERROR) << "COW has mixed compression types which is not supported;"
- << " previously saw " << compression_type_ << ", got "
- << v2_op.compression << ", op: " << v2_op;
- return false;
- }
- }
- new_op.source_info = source_info;
+ TranslatedCowOps ops_info;
+ if (!parser->Translate(&ops_info)) {
+ return false;
}
+ header_ = ops_info.header;
+ ops_ = std::move(ops_info.ops);
+ footer_ = parser->footer();
+ fd_size_ = parser->fd_size();
+ last_label_ = parser->last_label();
+ data_loc_ = parser->data_loc();
+
// If we're resuming a write, we're not ready to merge
if (label.has_value()) return true;
return PrepMergeOps();
@@ -615,8 +601,8 @@
bool CowReader::GetRawBytes(uint64_t offset, void* buffer, size_t len, size_t* read) {
// Validate the offset, taking care to acknowledge possible overflow of offset+len.
- if (offset < header_.prefix.header_size || offset >= fd_size_ - sizeof(CowFooter) ||
- len >= fd_size_ || offset + len > fd_size_ - sizeof(CowFooter)) {
+ if (offset < header_.prefix.header_size || offset >= fd_size_ || offset + len > fd_size_ ||
+ len >= fd_size_) {
LOG(ERROR) << "invalid data offset: " << offset << ", " << len << " bytes";
return false;
}
@@ -664,7 +650,7 @@
};
uint8_t CowReader::GetCompressionType() {
- return compression_type_;
+ return header_.compression_algorithm;
}
ssize_t CowReader::ReadData(const CowOperation* op, void* buffer, size_t buffer_size,
diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/inspect_cow.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/inspect_cow.cpp
index a291469..76509de 100644
--- a/fs_mgr/libsnapshot/libsnapshot_cow/inspect_cow.cpp
+++ b/fs_mgr/libsnapshot/libsnapshot_cow/inspect_cow.cpp
@@ -74,13 +74,13 @@
}
}
-static bool ShowRawOpStreamV2(borrowed_fd fd, const CowHeader& header) {
+static bool ShowRawOpStreamV2(borrowed_fd fd, const CowHeaderV3& header) {
CowParserV2 parser;
if (!parser.Parse(fd, header)) {
LOG(ERROR) << "v2 parser failed";
return false;
}
- for (const auto& op : *parser.ops()) {
+ for (const auto& op : *parser.get_v2ops()) {
std::cout << op << "\n";
if (auto iter = parser.data_loc()->find(op.new_block); iter != parser.data_loc()->end()) {
std::cout << " data loc: " << iter->second << "\n";
diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/parser_base.h b/fs_mgr/libsnapshot/libsnapshot_cow/parser_base.h
new file mode 100644
index 0000000..2783407
--- /dev/null
+++ b/fs_mgr/libsnapshot/libsnapshot_cow/parser_base.h
@@ -0,0 +1,53 @@
+//
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#pragma once
+
+#include <optional>
+#include <unordered_map>
+
+#include <android-base/unique_fd.h>
+#include <libsnapshot/cow_format.h>
+
+namespace android {
+namespace snapshot {
+
+struct TranslatedCowOps {
+ CowHeaderV3 header;
+ std::shared_ptr<std::vector<CowOperationV3>> ops;
+};
+
+class CowParserBase {
+ public:
+ virtual ~CowParserBase() = default;
+
+ virtual bool Parse(android::base::borrowed_fd fd, const CowHeaderV3& header,
+ std::optional<uint64_t> label = {}) = 0;
+ virtual bool Translate(TranslatedCowOps* out) = 0;
+ virtual std::optional<CowFooter> footer() const { return std::nullopt; }
+ virtual std::shared_ptr<std::unordered_map<uint64_t, uint64_t>> data_loc() const = 0;
+
+ uint64_t fd_size() const { return fd_size_; }
+ const std::optional<uint64_t>& last_label() const { return last_label_; }
+
+ protected:
+ CowHeaderV3 header_ = {};
+ uint64_t fd_size_;
+ std::optional<uint64_t> last_label_;
+};
+
+} // namespace snapshot
+} // namespace android
diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/parser_v2.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/parser_v2.cpp
index 8f20317..51489c8 100644
--- a/fs_mgr/libsnapshot/libsnapshot_cow/parser_v2.cpp
+++ b/fs_mgr/libsnapshot/libsnapshot_cow/parser_v2.cpp
@@ -18,12 +18,14 @@
#include <android-base/file.h>
#include <android-base/logging.h>
+#include <libsnapshot/cow_format.h>
+
namespace android {
namespace snapshot {
using android::base::borrowed_fd;
-bool CowParserV2::Parse(borrowed_fd fd, const CowHeader& header, std::optional<uint64_t> label) {
+bool CowParserV2::Parse(borrowed_fd fd, const CowHeaderV3& header, std::optional<uint64_t> label) {
auto pos = lseek(fd.get(), 0, SEEK_END);
if (pos < 0) {
PLOG(ERROR) << "lseek end failed";
@@ -47,8 +49,7 @@
return false;
}
- if ((header_.prefix.major_version > kCowVersionMajor) ||
- (header_.prefix.minor_version != kCowVersionMinor)) {
+ if (header_.prefix.major_version > 2 || header_.prefix.minor_version != 0) {
LOG(ERROR) << "Header version mismatch, "
<< "major version: " << header_.prefix.major_version
<< ", expected: " << kCowVersionMajor
@@ -190,11 +191,57 @@
}
}
- ops_ = ops_buffer;
- ops_->shrink_to_fit();
+ v2_ops_ = ops_buffer;
+ v2_ops_->shrink_to_fit();
data_loc_ = data_loc;
return true;
}
+bool CowParserV2::Translate(TranslatedCowOps* out) {
+ out->ops = std::make_shared<std::vector<CowOperationV3>>(v2_ops_->size());
+
+ // Translate the operation buffer from on disk to in memory
+ for (size_t i = 0; i < out->ops->size(); i++) {
+ const auto& v2_op = v2_ops_->at(i);
+
+ auto& new_op = out->ops->at(i);
+ new_op.type = v2_op.type;
+ new_op.data_length = v2_op.data_length;
+
+ if (v2_op.new_block > std::numeric_limits<uint32_t>::max()) {
+ LOG(ERROR) << "Out-of-range new block in COW op: " << v2_op;
+ return false;
+ }
+ new_op.new_block = v2_op.new_block;
+
+ uint64_t source_info = v2_op.source;
+ if (new_op.type != kCowLabelOp) {
+ source_info &= kCowOpSourceInfoDataMask;
+ if (source_info != v2_op.source) {
+ LOG(ERROR) << "Out-of-range source value in COW op: " << v2_op;
+ return false;
+ }
+ }
+ if (v2_op.compression != kCowCompressNone) {
+ if (header_.compression_algorithm == kCowCompressNone) {
+ header_.compression_algorithm = v2_op.compression;
+ } else if (header_.compression_algorithm != v2_op.compression) {
+ LOG(ERROR) << "COW has mixed compression types which is not supported;"
+ << " previously saw " << header_.compression_algorithm << ", got "
+ << v2_op.compression << ", op: " << v2_op;
+ return false;
+ }
+ }
+ new_op.source_info = source_info;
+ }
+
+ out->header = header_;
+ return true;
+}
+
+std::shared_ptr<std::unordered_map<uint64_t, uint64_t>> CowParserV2::data_loc() const {
+ return data_loc_;
+}
+
} // namespace snapshot
} // namespace android
diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/parser_v2.h b/fs_mgr/libsnapshot/libsnapshot_cow/parser_v2.h
index f51ff88..318a3ac 100644
--- a/fs_mgr/libsnapshot/libsnapshot_cow/parser_v2.h
+++ b/fs_mgr/libsnapshot/libsnapshot_cow/parser_v2.h
@@ -17,36 +17,31 @@
#include <memory>
#include <optional>
-#include <unordered_map>
#include <vector>
#include <android-base/unique_fd.h>
#include <libsnapshot/cow_format.h>
+#include <libsnapshot_cow/parser_base.h>
namespace android {
namespace snapshot {
-class CowParserV2 {
+class CowParserV2 final : public CowParserBase {
public:
- bool Parse(android::base::borrowed_fd fd, const CowHeader& header,
- std::optional<uint64_t> label = {});
+ bool Parse(android::base::borrowed_fd fd, const CowHeaderV3& header,
+ std::optional<uint64_t> label = {}) override;
+ bool Translate(TranslatedCowOps* out) override;
+ std::optional<CowFooter> footer() const override { return footer_; }
const CowHeader& header() const { return header_; }
- const std::optional<CowFooter>& footer() const { return footer_; }
- std::shared_ptr<std::vector<CowOperationV2>> ops() { return ops_; }
- std::shared_ptr<std::unordered_map<uint64_t, uint64_t>> data_loc() const { return data_loc_; }
- uint64_t fd_size() const { return fd_size_; }
- const std::optional<uint64_t>& last_label() const { return last_label_; }
+ std::shared_ptr<std::vector<CowOperationV2>> get_v2ops() { return v2_ops_; }
+ std::shared_ptr<std::unordered_map<uint64_t, uint64_t>> data_loc() const override;
private:
- bool ParseOps(android::base::borrowed_fd fd, std::optional<uint64_t> label);
-
- CowHeader header_ = {};
- std::optional<CowFooter> footer_;
- std::shared_ptr<std::vector<CowOperationV2>> ops_;
std::shared_ptr<std::unordered_map<uint64_t, uint64_t>> data_loc_;
- uint64_t fd_size_;
- std::optional<uint64_t> last_label_;
+ bool ParseOps(android::base::borrowed_fd fd, std::optional<uint64_t> label);
+ std::shared_ptr<std::vector<CowOperationV2>> v2_ops_;
+ std::optional<CowFooter> footer_;
};
} // namespace snapshot
diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/parser_v3.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/parser_v3.cpp
new file mode 100644
index 0000000..23ddaae
--- /dev/null
+++ b/fs_mgr/libsnapshot/libsnapshot_cow/parser_v3.cpp
@@ -0,0 +1,88 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#include "parser_v3.h"
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+
+#include <libsnapshot/cow_format.h>
+
+namespace android {
+namespace snapshot {
+
+using android::base::borrowed_fd;
+
+bool CowParserV3::Parse(borrowed_fd fd, const CowHeaderV3& header, std::optional<uint64_t> label) {
+ auto pos = lseek(fd.get(), 0, SEEK_END);
+ if (pos < 0) {
+ PLOG(ERROR) << "lseek end failed";
+ return false;
+ }
+ fd_size_ = pos;
+ header_ = header;
+
+ if (header_.footer_size != 0) {
+ LOG(ERROR) << "Footer size isn't 0, read " << header_.footer_size;
+ return false;
+ }
+ if (header_.op_size != sizeof(CowOperationV3)) {
+ LOG(ERROR) << "Operation size unknown, read " << header_.op_size << ", expected "
+ << sizeof(CowOperationV3);
+ return false;
+ }
+ if (header_.cluster_ops != 0) {
+ LOG(ERROR) << "Cluster ops not supported in v3";
+ return false;
+ }
+
+ if (header_.prefix.major_version != 3 || header_.prefix.minor_version != 0) {
+ LOG(ERROR) << "Header version mismatch, "
+ << "major version: " << header_.prefix.major_version
+ << ", expected: " << kCowVersionMajor
+ << ", minor version: " << header_.prefix.minor_version
+ << ", expected: " << kCowVersionMinor;
+ return false;
+ }
+
+ return ParseOps(fd, label);
+}
+
+bool CowParserV3::ParseOps(borrowed_fd fd, std::optional<uint64_t> label) {
+ ops_ = std::make_shared<std::vector<CowOperationV3>>();
+ ops_->resize(header_.op_count);
+
+ const off_t offset = header_.prefix.header_size + header_.buffer_size;
+ if (!android::base::ReadFullyAtOffset(fd, ops_->data(), ops_->size() * sizeof(CowOperationV3),
+ offset)) {
+ PLOG(ERROR) << "read ops failed";
+ return false;
+ }
+
+ // :TODO: sequence buffer & resume buffer follow
+ // Once we implement labels, we'll have to discard unused ops and adjust
+ // the header as needed.
+ CHECK(!label);
+
+ ops_->shrink_to_fit();
+ return true;
+}
+
+bool CowParserV3::Translate(TranslatedCowOps* out) {
+ out->ops = ops_;
+ out->header = header_;
+ return true;
+}
+
+} // namespace snapshot
+} // namespace android
diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/parser_v3.h b/fs_mgr/libsnapshot/libsnapshot_cow/parser_v3.h
new file mode 100644
index 0000000..5760cf2
--- /dev/null
+++ b/fs_mgr/libsnapshot/libsnapshot_cow/parser_v3.h
@@ -0,0 +1,60 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#pragma once
+
+#include <stdint.h>
+
+#include <memory>
+#include <optional>
+#include <unordered_map>
+#include <vector>
+
+#include <android-base/unique_fd.h>
+#include <libsnapshot/cow_format.h>
+#include <libsnapshot_cow/parser_base.h>
+
+namespace android {
+namespace snapshot {
+
+class CowParserV3 final : public CowParserBase {
+ public:
+ bool Parse(android::base::borrowed_fd fd, const CowHeaderV3& header,
+ std::optional<uint64_t> label = {}) override;
+ bool Translate(TranslatedCowOps* out) override;
+ std::shared_ptr<std::unordered_map<uint64_t, uint64_t>> data_loc() const override {
+ return nullptr;
+ };
+
+ private:
+ bool ParseOps(android::base::borrowed_fd fd, std::optional<uint64_t> label);
+
+ CowHeaderV3 header_ = {};
+ std::shared_ptr<std::vector<CowOperationV3>> ops_;
+};
+
+} // namespace snapshot
+} // namespace android
diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/test_v3.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/test_v3.cpp
index cc8dd83..c5d7a02 100644
--- a/fs_mgr/libsnapshot/libsnapshot_cow/test_v3.cpp
+++ b/fs_mgr/libsnapshot/libsnapshot_cow/test_v3.cpp
@@ -37,7 +37,7 @@
namespace android {
namespace snapshot {
-class CowOperationV3Test : public ::testing::Test {
+class CowTestV3 : public ::testing::Test {
protected:
virtual void SetUp() override {
cow_ = std::make_unique<TemporaryFile>();
@@ -51,7 +51,12 @@
std::unique_ptr<TemporaryFile> cow_;
};
-TEST_F(CowOperationV3Test, CowHeaderV2Test) {
+// Helper to check read sizes.
+static inline bool ReadData(CowReader& reader, const CowOperation* op, void* buffer, size_t size) {
+ return reader.ReadData(op, buffer, size) == size;
+}
+
+TEST_F(CowTestV3, CowHeaderV2Test) {
CowOptions options;
options.cluster_ops = 5;
options.num_merge_ops = 1;
@@ -67,11 +72,175 @@
const auto& header = reader.GetHeader();
ASSERT_EQ(header.prefix.magic, kCowMagicNumber);
- ASSERT_EQ(header.prefix.major_version, kCowVersionMajor);
- ASSERT_EQ(header.prefix.minor_version, kCowVersionMinor);
+ ASSERT_EQ(header.prefix.major_version, 2);
+ ASSERT_EQ(header.prefix.minor_version, 0);
ASSERT_EQ(header.block_size, options.block_size);
ASSERT_EQ(header.cluster_ops, options.cluster_ops);
}
+TEST_F(CowTestV3, Header) {
+ CowOptions options;
+ auto writer = CreateCowWriter(3, options, GetCowFd());
+ ASSERT_TRUE(writer->Finalize());
+
+ CowReader reader;
+ ASSERT_TRUE(reader.Parse(cow_->fd));
+
+ const auto& header = reader.GetHeader();
+ ASSERT_EQ(header.prefix.magic, kCowMagicNumber);
+ ASSERT_EQ(header.prefix.major_version, 3);
+ ASSERT_EQ(header.prefix.minor_version, 0);
+ ASSERT_EQ(header.block_size, options.block_size);
+ ASSERT_EQ(header.cluster_ops, 0);
+}
+
+TEST_F(CowTestV3, ZeroOp) {
+ CowOptions options;
+ options.op_count_max = 20;
+ auto writer = CreateCowWriter(3, options, GetCowFd());
+ ASSERT_TRUE(writer->AddZeroBlocks(1, 2));
+ ASSERT_TRUE(writer->Finalize());
+
+ CowReader reader;
+ ASSERT_TRUE(reader.Parse(cow_->fd));
+ ASSERT_EQ(reader.header_v3().op_count, 2);
+
+ auto iter = reader.GetOpIter();
+ ASSERT_NE(iter, nullptr);
+ ASSERT_FALSE(iter->AtEnd());
+
+ auto op = iter->Get();
+ ASSERT_EQ(op->type, kCowZeroOp);
+ ASSERT_EQ(op->data_length, 0);
+ ASSERT_EQ(op->new_block, 1);
+ ASSERT_EQ(op->source_info, 0);
+
+ iter->Next();
+ ASSERT_FALSE(iter->AtEnd());
+ op = iter->Get();
+
+ ASSERT_EQ(op->type, kCowZeroOp);
+ ASSERT_EQ(op->data_length, 0);
+ ASSERT_EQ(op->new_block, 2);
+ ASSERT_EQ(op->source_info, 0);
+}
+
+TEST_F(CowTestV3, ReplaceOp) {
+ CowOptions options;
+ options.op_count_max = 20;
+ options.scratch_space = false;
+ auto writer = CreateCowWriter(3, options, GetCowFd());
+ std::string data = "This is some data, believe it";
+ data.resize(options.block_size, '\0');
+
+ ASSERT_TRUE(writer->AddRawBlocks(5, data.data(), data.size()));
+ ASSERT_TRUE(writer->Finalize());
+
+ CowReader reader;
+ ASSERT_TRUE(reader.Parse(cow_->fd));
+
+ const auto& header = reader.header_v3();
+ ASSERT_EQ(header.prefix.magic, kCowMagicNumber);
+ ASSERT_EQ(header.prefix.major_version, 3);
+ ASSERT_EQ(header.prefix.minor_version, kCowVersionMinor);
+ ASSERT_EQ(header.block_size, options.block_size);
+ ASSERT_EQ(header.op_count, 1);
+
+ auto iter = reader.GetOpIter();
+ ASSERT_NE(iter, nullptr);
+ ASSERT_FALSE(iter->AtEnd());
+
+ auto op = iter->Get();
+ std::string sink(data.size(), '\0');
+
+ ASSERT_EQ(op->type, kCowReplaceOp);
+ ASSERT_EQ(op->data_length, 4096);
+ ASSERT_EQ(op->new_block, 5);
+ ASSERT_TRUE(ReadData(reader, op, sink.data(), sink.size()));
+ ASSERT_EQ(sink, data);
+}
+
+TEST_F(CowTestV3, ConsecutiveReplaceOp) {
+ CowOptions options;
+ options.op_count_max = 20;
+ options.scratch_space = false;
+ auto writer = CreateCowWriter(3, options, GetCowFd());
+ std::string data;
+ data.resize(options.block_size * 5);
+ for (int i = 0; i < data.size(); i++) {
+ data[i] = char(rand() % 256);
+ }
+
+ ASSERT_TRUE(writer->AddRawBlocks(5, data.data(), data.size()));
+ ASSERT_TRUE(writer->Finalize());
+
+ CowReader reader;
+ ASSERT_TRUE(reader.Parse(cow_->fd));
+
+ const auto& header = reader.header_v3();
+ ASSERT_EQ(header.prefix.magic, kCowMagicNumber);
+ ASSERT_EQ(header.prefix.major_version, 3);
+ ASSERT_EQ(header.prefix.minor_version, kCowVersionMinor);
+ ASSERT_EQ(header.block_size, options.block_size);
+ ASSERT_EQ(header.op_count, 5);
+
+ auto iter = reader.GetOpIter();
+ ASSERT_NE(iter, nullptr);
+ ASSERT_FALSE(iter->AtEnd());
+
+ size_t i = 0;
+ std::string sink(data.size(), '\0');
+
+ while (!iter->AtEnd()) {
+ auto op = iter->Get();
+ ASSERT_EQ(op->type, kCowReplaceOp);
+ ASSERT_EQ(op->data_length, options.block_size);
+ ASSERT_EQ(op->new_block, 5 + i);
+ ASSERT_TRUE(
+ ReadData(reader, op, sink.data() + (i * options.block_size), options.block_size));
+ iter->Next();
+ i++;
+ }
+ ASSERT_EQ(sink, data);
+
+ ASSERT_EQ(i, 5);
+}
+
+TEST_F(CowTestV3, CopyOp) {
+ CowOptions options;
+ options.op_count_max = 100;
+ auto writer = CreateCowWriter(3, options, GetCowFd());
+
+ ASSERT_TRUE(writer->AddCopy(10, 1000, 100));
+ ASSERT_TRUE(writer->Finalize());
+ ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
+
+ CowReader reader;
+ ASSERT_TRUE(reader.Parse(cow_->fd));
+
+ const auto& header = reader.GetHeader();
+ ASSERT_EQ(header.prefix.magic, kCowMagicNumber);
+ ASSERT_EQ(header.prefix.major_version, 3);
+ ASSERT_EQ(header.prefix.minor_version, kCowVersionMinor);
+ ASSERT_EQ(header.block_size, options.block_size);
+
+ auto iter = reader.GetOpIter();
+ ASSERT_NE(iter, nullptr);
+ ASSERT_FALSE(iter->AtEnd());
+
+ size_t i = 0;
+ while (!iter->AtEnd()) {
+ auto op = iter->Get();
+ ASSERT_EQ(op->type, kCowCopyOp);
+ ASSERT_EQ(op->data_length, 0);
+ ASSERT_EQ(op->new_block, 10 + i);
+ ASSERT_EQ(GetCowOpSourceInfoData(*op), 1000 + i);
+ iter->Next();
+ i += 1;
+ }
+
+ ASSERT_EQ(i, 100);
+}
+
} // namespace snapshot
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/writer_base.h b/fs_mgr/libsnapshot/libsnapshot_cow/writer_base.h
index 709b248..5274456 100644
--- a/fs_mgr/libsnapshot/libsnapshot_cow/writer_base.h
+++ b/fs_mgr/libsnapshot/libsnapshot_cow/writer_base.h
@@ -62,6 +62,8 @@
bool InitFd();
bool ValidateNewBlock(uint64_t new_block);
+ bool IsEstimating() const { return is_dev_null_; }
+
CowOptions options_;
android::base::unique_fd fd_;
diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp
index 83a9b1b..37324c7 100644
--- a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp
+++ b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp
@@ -273,10 +273,11 @@
if (!ReadCowHeader(fd_, &header_v3)) {
return false;
}
+
header_ = header_v3;
CowParserV2 parser;
- if (!parser.Parse(fd_, header_, {label})) {
+ if (!parser.Parse(fd_, header_v3, {label})) {
return false;
}
if (header_.prefix.major_version > 2) {
@@ -292,7 +293,7 @@
footer_.op.num_ops = 0;
InitPos();
- for (const auto& op : *parser.ops()) {
+ for (const auto& op : *parser.get_v2ops()) {
AddOperation(op);
}
diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v3.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v3.cpp
index 5ae5f19..aeb088d 100644
--- a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v3.cpp
+++ b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v3.cpp
@@ -78,7 +78,8 @@
// during COW size estimation
header_.sequence_buffer_offset = 0;
header_.resume_buffer_size = 0;
- header_.op_buffer_size = 0;
+ header_.op_count = 0;
+ header_.op_count_max = 0;
header_.compression_algorithm = kCowCompressNone;
return;
}
@@ -154,29 +155,34 @@
return false;
}
}
+ header_.op_count_max = options_.op_count_max;
if (!Sync()) {
LOG(ERROR) << "Header sync failed";
return false;
}
-
- next_op_pos_ = 0;
- next_data_pos_ = 0;
+ next_data_pos_ =
+ sizeof(CowHeaderV3) + header_.buffer_size + header_.op_count_max * sizeof(CowOperation);
return true;
}
bool CowWriterV3::EmitCopy(uint64_t new_block, uint64_t old_block, uint64_t num_blocks) {
- LOG(ERROR) << __LINE__ << " " << __FILE__ << " <- function here should never be called";
- if (new_block || old_block || num_blocks) return false;
- return false;
+ for (size_t i = 0; i < num_blocks; i++) {
+ CowOperationV3 op = {};
+ op.type = kCowCopyOp;
+ op.new_block = new_block + i;
+ op.source_info = old_block + i;
+ if (!WriteOperation(op)) {
+ return false;
+ }
+ }
+
+ return true;
}
bool CowWriterV3::EmitRawBlocks(uint64_t new_block_start, const void* data, size_t size) {
- LOG(ERROR) << __LINE__ << " " << __FILE__ << " <- function here should never be called";
-
- if (new_block_start || data || size) return false;
- return false;
+ return EmitBlocks(new_block_start, data, size, 0, 0, kCowReplaceOp);
}
bool CowWriterV3::EmitXorBlocks(uint32_t new_block_start, const void* data, size_t size,
@@ -186,10 +192,45 @@
return false;
}
+bool CowWriterV3::EmitBlocks(uint64_t new_block_start, const void* data, size_t size,
+ uint64_t old_block, uint16_t offset, uint8_t type) {
+ const uint8_t* iter = reinterpret_cast<const uint8_t*>(data);
+
+ // Placing here until we support XOR ops
+ CHECK_EQ(old_block, 0);
+ CHECK_EQ(offset, 0);
+
+ const size_t num_blocks = (size / header_.block_size);
+
+ for (size_t i = 0; i < num_blocks; i++) {
+ CowOperation op = {};
+ op.new_block = new_block_start + i;
+
+ op.type = type;
+ op.source_info = next_data_pos_;
+ op.data_length = static_cast<uint16_t>(header_.block_size);
+ if (!WriteOperation(op, iter, header_.block_size)) {
+ LOG(ERROR) << "AddRawBlocks: write failed";
+ return false;
+ }
+ iter += header_.block_size;
+ }
+
+ return true;
+}
+
bool CowWriterV3::EmitZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) {
- LOG(ERROR) << __LINE__ << " " << __FILE__ << " <- function here should never be called";
- if (new_block_start && num_blocks) return false;
- return false;
+ for (uint64_t i = 0; i < num_blocks; i++) {
+ CowOperationV3 op;
+ op.type = kCowZeroOp;
+ op.data_length = 0;
+ op.new_block = new_block_start + i;
+ op.source_info = 0;
+ if (!WriteOperation(op)) {
+ return false;
+ }
+ }
+ return true;
}
bool CowWriterV3::EmitLabel(uint64_t label) {
@@ -204,9 +245,44 @@
return false;
}
+bool CowWriterV3::WriteOperation(const CowOperationV3& op, const void* data, size_t size) {
+ if (IsEstimating()) {
+ header_.op_count++;
+ header_.op_count_max++;
+ return true;
+ }
+
+ if (header_.op_count + 1 > header_.op_count_max) {
+ LOG(ERROR) << "Maximum number of ops reached: " << header_.op_count_max;
+ return false;
+ }
+
+ const off_t offset = GetOpOffset(header_.op_count);
+ if (!android::base::WriteFullyAtOffset(fd_, &op, sizeof(op), offset)) {
+ PLOG(ERROR) << "write failed for " << op << " at " << offset;
+ return false;
+ }
+ if (data && size > 0) {
+ if (!android::base::WriteFullyAtOffset(fd_, data, size, next_data_pos_)) {
+ PLOG(ERROR) << "write failed for data of size: " << size
+ << " at offset: " << next_data_pos_;
+ return false;
+ }
+ }
+ header_.op_count++;
+ next_data_pos_ += op.data_length;
+ next_op_pos_ += sizeof(CowOperationV3);
+
+ return true;
+}
+
bool CowWriterV3::Finalize() {
- LOG(ERROR) << __LINE__ << " " << __FILE__ << " <- function here should never be called";
- return false;
+ CHECK_GE(header_.prefix.header_size, sizeof(CowHeaderV3));
+ CHECK_LE(header_.prefix.header_size, sizeof(header_));
+ if (!android::base::WriteFullyAtOffset(fd_, &header_, header_.prefix.header_size, 0)) {
+ return false;
+ }
+ return Sync();
}
uint64_t CowWriterV3::GetCowSize() {
diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v3.h b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v3.h
index 2a88a12..af71a03 100644
--- a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v3.h
+++ b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v3.h
@@ -14,7 +14,8 @@
#pragma once
-#include <future>
+#include <android-base/logging.h>
+
#include "writer_base.h"
namespace android {
@@ -42,16 +43,25 @@
void SetupHeaders();
bool ParseOptions();
bool OpenForWrite();
+ bool WriteOperation(const CowOperationV3& op, const void* data = nullptr, size_t size = 0);
+ bool EmitBlocks(uint64_t new_block_start, const void* data, size_t size, uint64_t old_block,
+ uint16_t offset, uint8_t type);
+
+ off_t GetOpOffset(uint32_t op_index) const {
+ CHECK_LT(op_index, header_.op_count_max);
+ return header_.prefix.header_size + header_.buffer_size +
+ (op_index * sizeof(CowOperationV3));
+ }
private:
CowHeaderV3 header_{};
CowCompression compression_;
- // in the case that we are using one thread for compression, we can store and re-use the same
- // compressor
uint64_t next_op_pos_ = 0;
uint64_t next_data_pos_ = 0;
+ // in the case that we are using one thread for compression, we can store and re-use the same
+ // compressor
int num_compress_threads_ = 1;
};
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index eb4beb7..c639e43 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -3513,6 +3513,11 @@
return Return::Error();
}
+ if (!android::fs_mgr::WaitForFile(cow_path, 6s)) {
+ LOG(ERROR) << "Timed out waiting for device to appear: " << cow_path;
+ return Return::Error();
+ }
+
if (it->second.using_snapuserd()) {
unique_fd fd(open(cow_path.c_str(), O_RDWR | O_CLOEXEC));
if (fd < 0) {
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp
index 8208d67..950d771 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp
@@ -112,7 +112,7 @@
return false;
}
- if (!android::base::WriteFully(cow_fd_, &header, sizeof(CowHeader))) {
+ if (!android::base::WriteFully(cow_fd_, &header, header.prefix.header_size)) {
SNAP_PLOG(ERROR) << "Write to header failed";
return false;
}
diff --git a/fs_mgr/tests/src/com/android/tests/vendoroverlay/VendorOverlayHostTest.java b/fs_mgr/tests/src/com/android/tests/vendoroverlay/VendorOverlayHostTest.java
index f08cab2..91f235c 100644
--- a/fs_mgr/tests/src/com/android/tests/vendoroverlay/VendorOverlayHostTest.java
+++ b/fs_mgr/tests/src/com/android/tests/vendoroverlay/VendorOverlayHostTest.java
@@ -21,10 +21,8 @@
import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
import com.android.tradefed.util.CommandResult;
import com.android.tradefed.util.CommandStatus;
-
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-
import org.junit.After;
import org.junit.Assert;
import org.junit.Assume;
@@ -38,9 +36,15 @@
@RunWith(DeviceJUnit4ClassRunner.class)
public class VendorOverlayHostTest extends BaseHostJUnit4Test {
boolean wasRoot = false;
+ String vndkVersion = null;
@Before
public void setup() throws DeviceNotAvailableException {
+ vndkVersion = getDevice().executeShellV2Command("getprop ro.vndk.version").getStdout();
+ Assume.assumeTrue(
+ "Vendor Overlay is disabled for VNDK deprecated devices",
+ vndkVersion != null && !vndkVersion.trim().isEmpty());
+
wasRoot = getDevice().isAdbRoot();
if (!wasRoot) {
Assume.assumeTrue("Test requires root", getDevice().enableAdbRoot());
@@ -74,8 +78,6 @@
*/
@Test
public void testVendorOverlay() throws DeviceNotAvailableException {
- String vndkVersion = getDevice().executeShellV2Command("getprop ro.vndk.version").getStdout();
-
// Create files and modify policy
CommandResult result = getDevice().executeShellV2Command(
"echo '/(product|system/product)/vendor_overlay/" + vndkVersion +
diff --git a/fs_mgr/tests/vts_fs_test.cpp b/fs_mgr/tests/vts_fs_test.cpp
index 32947b5..8f15220 100644
--- a/fs_mgr/tests/vts_fs_test.cpp
+++ b/fs_mgr/tests/vts_fs_test.cpp
@@ -32,6 +32,24 @@
return android::base::GetIntProperty("ro.vendor.api_level", -1);
}
+// Returns true iff the device has the specified feature.
+bool DeviceSupportsFeature(const char* feature) {
+ bool device_supports_feature = false;
+ FILE* p = popen("pm list features", "re");
+ if (p) {
+ char* line = NULL;
+ size_t len = 0;
+ while (getline(&line, &len, p) > 0) {
+ if (strstr(line, feature)) {
+ device_supports_feature = true;
+ break;
+ }
+ }
+ pclose(p);
+ }
+ return device_supports_feature;
+}
+
TEST(fs, ErofsSupported) {
// T-launch GKI kernels and higher must support EROFS.
if (GetVsrLevel() < __ANDROID_API_T__) {
@@ -82,7 +100,8 @@
ASSERT_TRUE(android::base::Readlink("/dev/block/by-name/userdata", &userdata_bdev));
std::vector<std::string> must_be_f2fs = {"/data"};
- if (vsr_level >= __ANDROID_API_U__) {
+ if (vsr_level >= __ANDROID_API_U__ &&
+ !DeviceSupportsFeature("android.hardware.type.automotive")) {
must_be_f2fs.emplace_back("/metadata");
}
diff --git a/init/host_init_verifier.cpp b/init/host_init_verifier.cpp
index f070776..662185c 100644
--- a/init/host_init_verifier.cpp
+++ b/init/host_init_verifier.cpp
@@ -108,9 +108,9 @@
static passwd static_passwd = {
.pw_name = static_name,
.pw_dir = static_dir,
- .pw_shell = static_shell,
.pw_uid = 0,
.pw_gid = 0,
+ .pw_shell = static_shell,
};
for (size_t n = 0; n < android_id_count; ++n) {
diff --git a/init/init.cpp b/init/init.cpp
index 40e2169..19f34da 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -751,7 +751,7 @@
static void InstallSignalFdHandler(Epoll* epoll) {
// Applying SA_NOCLDSTOP to a defaulted SIGCHLD handler prevents the signalfd from receiving
// SIGCHLD when a child process stops or continues (b/77867680#comment9).
- const struct sigaction act { .sa_handler = SIG_DFL, .sa_flags = SA_NOCLDSTOP };
+ const struct sigaction act { .sa_flags = SA_NOCLDSTOP, .sa_handler = SIG_DFL };
sigaction(SIGCHLD, &act, nullptr);
sigset_t mask;
diff --git a/init/persistent_properties.cpp b/init/persistent_properties.cpp
index e89244f..6f8a4de 100644
--- a/init/persistent_properties.cpp
+++ b/init/persistent_properties.cpp
@@ -46,6 +46,13 @@
constexpr const char kLegacyPersistentPropertyDir[] = "/data/property";
+void AddPersistentProperty(const std::string& name, const std::string& value,
+ PersistentProperties* persistent_properties) {
+ auto persistent_property_record = persistent_properties->add_properties();
+ persistent_property_record->set_name(name);
+ persistent_property_record->set_value(value);
+}
+
Result<PersistentProperties> LoadLegacyPersistentProperties() {
std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(kLegacyPersistentPropertyDir), closedir);
if (!dir) {
@@ -146,13 +153,6 @@
} // namespace
-void AddPersistentProperty(const std::string& name, const std::string& value,
- PersistentProperties* persistent_properties) {
- auto persistent_property_record = persistent_properties->add_properties();
- persistent_property_record->set_name(name);
- persistent_property_record->set_value(value);
-}
-
Result<PersistentProperties> LoadPersistentPropertyFile() {
auto file_contents = ReadPersistentPropertyFile();
if (!file_contents.ok()) return file_contents.error();
@@ -266,8 +266,57 @@
}
}
- return *persistent_properties;
+ // loop over to find all staged props
+ auto const staged_prefix = std::string_view("next_boot.");
+ auto staged_props = std::unordered_map<std::string, std::string>();
+ for (const auto& property_record : persistent_properties->properties()) {
+ auto const& prop_name = property_record.name();
+ auto const& prop_value = property_record.value();
+ if (StartsWith(prop_name, staged_prefix)) {
+ auto actual_prop_name = prop_name.substr(staged_prefix.size());
+ staged_props[actual_prop_name] = prop_value;
+ }
+ }
+
+ if (staged_props.empty()) {
+ return *persistent_properties;
+ }
+
+ // if has staging, apply staging and perserve the original prop order
+ PersistentProperties updated_persistent_properties;
+ for (const auto& property_record : persistent_properties->properties()) {
+ auto const& prop_name = property_record.name();
+ auto const& prop_value = property_record.value();
+
+ // don't include staged props anymore
+ if (StartsWith(prop_name, staged_prefix)) {
+ continue;
+ }
+
+ auto iter = staged_props.find(prop_name);
+ if (iter != staged_props.end()) {
+ AddPersistentProperty(prop_name, iter->second, &updated_persistent_properties);
+ staged_props.erase(iter);
+ } else {
+ AddPersistentProperty(prop_name, prop_value, &updated_persistent_properties);
+ }
+ }
+
+ // add any additional staged props
+ for (auto const& [prop_name, prop_value] : staged_props) {
+ AddPersistentProperty(prop_name, prop_value, &updated_persistent_properties);
+ }
+
+ // write current updated persist prop file
+ auto result = WritePersistentPropertyFile(updated_persistent_properties);
+ if (!result.ok()) {
+ LOG(ERROR) << "Could not store persistent property: " << result.error();
+ }
+
+ return updated_persistent_properties;
}
+
+
} // namespace init
} // namespace android
diff --git a/init/persistent_properties.h b/init/persistent_properties.h
index 7e9d438..11083da 100644
--- a/init/persistent_properties.h
+++ b/init/persistent_properties.h
@@ -25,8 +25,6 @@
namespace android {
namespace init {
-void AddPersistentProperty(const std::string& name, const std::string& value,
- PersistentProperties* persistent_properties);
PersistentProperties LoadPersistentProperties();
void WritePersistentProperty(const std::string& name, const std::string& value);
PersistentProperties LoadPersistentPropertiesFromMemory();
diff --git a/init/persistent_properties_test.cpp b/init/persistent_properties_test.cpp
index e5d26db..5763050 100644
--- a/init/persistent_properties_test.cpp
+++ b/init/persistent_properties_test.cpp
@@ -178,5 +178,37 @@
EXPECT_FALSE(it == read_back_properties.properties().end());
}
+TEST(persistent_properties, StagedPersistProperty) {
+ TemporaryFile tf;
+ ASSERT_TRUE(tf.fd != -1);
+ persistent_property_filename = tf.path;
+
+ std::vector<std::pair<std::string, std::string>> persistent_properties = {
+ {"persist.sys.locale", "en-US"},
+ {"next_boot.persist.test.numbers", "54321"},
+ {"persist.sys.timezone", "America/Los_Angeles"},
+ {"persist.test.numbers", "12345"},
+ {"next_boot.persist.test.extra", "abc"},
+ };
+
+ ASSERT_RESULT_OK(
+ WritePersistentPropertyFile(VectorToPersistentProperties(persistent_properties)));
+
+ std::vector<std::pair<std::string, std::string>> expected_persistent_properties = {
+ {"persist.sys.locale", "en-US"},
+ {"persist.sys.timezone", "America/Los_Angeles"},
+ {"persist.test.numbers", "54321"},
+ {"persist.test.extra", "abc"},
+ };
+
+ // lock down that staged props are applied
+ auto first_read_back_properties = LoadPersistentProperties();
+ CheckPropertiesEqual(expected_persistent_properties, first_read_back_properties);
+
+ // lock down that other props are not overwritten
+ auto second_read_back_properties = LoadPersistentProperties();
+ CheckPropertiesEqual(expected_persistent_properties, second_read_back_properties);
+}
+
} // namespace init
} // namespace android
diff --git a/init/property_service.cpp b/init/property_service.cpp
index b08a904..bd74358 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -76,6 +76,10 @@
#include "system/core/init/property_service.pb.h"
#include "util.h"
+static constexpr char APPCOMPAT_OVERRIDE_PROP_FOLDERNAME[] =
+ "/dev/__properties__/appcompat_override";
+static constexpr char APPCOMPAT_OVERRIDE_PROP_TREE_FILE[] =
+ "/dev/__properties__/appcompat_override/property_info";
using namespace std::literals;
using android::base::ErrnoError;
@@ -1279,11 +1283,17 @@
return;
}
- constexpr static const char kPropertyInfosPath[] = "/dev/__properties__/property_info";
- if (!WriteStringToFile(serialized_contexts, kPropertyInfosPath, 0444, 0, 0, false)) {
+ if (!WriteStringToFile(serialized_contexts, PROP_TREE_FILE, 0444, 0, 0, false)) {
PLOG(ERROR) << "Unable to write serialized property infos to file";
}
- selinux_android_restorecon(kPropertyInfosPath, 0);
+ selinux_android_restorecon(PROP_TREE_FILE, 0);
+
+ mkdir(APPCOMPAT_OVERRIDE_PROP_FOLDERNAME, S_IRWXU | S_IXGRP | S_IXOTH);
+ if (!WriteStringToFile(serialized_contexts, APPCOMPAT_OVERRIDE_PROP_TREE_FILE, 0444, 0, 0,
+ false)) {
+ PLOG(ERROR) << "Unable to write vendor overrides to file";
+ }
+ selinux_android_restorecon(APPCOMPAT_OVERRIDE_PROP_TREE_FILE, 0);
}
static void ExportKernelBootProps() {
@@ -1396,33 +1406,12 @@
switch (init_message.msg_case()) {
case InitMessage::kLoadPersistentProperties: {
load_override_properties();
- // Read persistent properties after all default values have been loaded.
- // Apply staged and persistent properties
- bool has_staged_prop = false;
- auto const staged_prefix = std::string_view("next_boot.");
auto persistent_properties = LoadPersistentProperties();
for (const auto& property_record : persistent_properties.properties()) {
auto const& prop_name = property_record.name();
auto const& prop_value = property_record.value();
-
- if (StartsWith(prop_name, staged_prefix)) {
- has_staged_prop = true;
- auto actual_prop_name = prop_name.substr(staged_prefix.size());
- InitPropertySet(actual_prop_name, prop_value);
- } else {
- InitPropertySet(prop_name, prop_value);
- }
- }
-
- // Update persist prop file if there are staged props
- if (has_staged_prop) {
- PersistentProperties props = LoadPersistentPropertiesFromMemory();
- // write current updated persist prop file
- auto result = WritePersistentPropertyFile(props);
- if (!result.ok()) {
- LOG(ERROR) << "Could not store persistent property: " << result.error();
- }
+ InitPropertySet(prop_name, prop_value);
}
// Apply debug ramdisk special settings after persistent properties are loaded.
diff --git a/init/sigchld_handler.cpp b/init/sigchld_handler.cpp
index f8c501f..0901a96 100644
--- a/init/sigchld_handler.cpp
+++ b/init/sigchld_handler.cpp
@@ -139,10 +139,10 @@
}
LOG(INFO) << "Waiting for " << pids.size() << " pids to be reaped took " << t << " with "
<< alive_pids.size() << " of them still running";
- for (pid_t pid : pids) {
+ for (pid_t pid : alive_pids) {
std::string status = "(no-such-pid)";
ReadFileToString(StringPrintf("/proc/%d/status", pid), &status);
- LOG(INFO) << "Still running: " << pid << ' ' << status;
+ LOG(INFO) << "Still running: " << pid << '\n' << status;
}
}
diff --git a/libutils/Android.bp b/libutils/Android.bp
index b3ddda3..4d4294b 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -68,13 +68,6 @@
"-Wno-exit-time-destructors",
"-DANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION",
],
- header_libs: [
- "libbase_headers",
- "libutils_headers",
- ],
- export_header_lib_headers: [
- "libutils_headers",
- ],
shared_libs: [
"libcutils",
@@ -134,6 +127,14 @@
whole_static_libs: ["libutils_binder"],
+ header_libs: [
+ "libbase_headers",
+ "libutils_headers",
+ ],
+ export_header_lib_headers: [
+ "libutils_headers",
+ ],
+
srcs: [
"FileMap.cpp",
"JenkinsHash.cpp",
@@ -221,6 +222,14 @@
support_system_process: true,
},
+ header_libs: [
+ "libbase_headers",
+ "libutils_headers",
+ ],
+ export_header_lib_headers: [
+ "libutils_headers",
+ ],
+
srcs: [
"CallStack.cpp",
],
diff --git a/libutils/binder/Android.bp b/libutils/binder/Android.bp
index e2eddb3..a049f3d 100644
--- a/libutils/binder/Android.bp
+++ b/libutils/binder/Android.bp
@@ -10,6 +10,7 @@
],
native_bridge_supported: true,
+ export_include_dirs: ["include"],
srcs: [
"Errors.cpp",
"RefBase.cpp",
diff --git a/libutils/binder/RefBase.cpp b/libutils/binder/RefBase.cpp
index c7055fb..2d2e40b 100644
--- a/libutils/binder/RefBase.cpp
+++ b/libutils/binder/RefBase.cpp
@@ -20,8 +20,6 @@
#include <memory>
#include <mutex>
-#include <android-base/macros.h>
-
#include <fcntl.h>
#include <log/log.h>
@@ -57,15 +55,17 @@
// log all reference counting operations
#define PRINT_REFS 0
+#if !defined(ANDROID_UTILS_CALLSTACK_ENABLED)
#if defined(__linux__)
// CallStack is only supported on linux type platforms.
-#define CALLSTACK_ENABLED 1
+#define ANDROID_UTILS_CALLSTACK_ENABLED 1
#else
-#define CALLSTACK_ENABLED 0
-#endif
+#define ANDROID_UTILS_CALLSTACK_ENABLED 0
+#endif // defined(__linux__)
+#endif // !defined(ANDROID_UTILS_CALLSTACK_ENABLED)
-#if CALLSTACK_ENABLED
-#include <utils/CallStack.h>
+#if ANDROID_UTILS_CALLSTACK_ENABLED
+#include "../../include/utils/CallStack.h"
#endif
// ---------------------------------------------------------------------------
@@ -232,7 +232,7 @@
while (refs) {
char inc = refs->ref >= 0 ? '+' : '-';
ALOGD("\t%c ID %p (ref %d):", inc, refs->id, refs->ref);
-#if DEBUG_REFS_CALLSTACK_ENABLED && CALLSTACK_ENABLED
+#if DEBUG_REFS_CALLSTACK_ENABLED && ANDROID_UTILS_CALLSTACK_ENABLED
CallStack::logStack(LOG_TAG, refs->stack.get());
#endif
refs = refs->next;
@@ -246,7 +246,7 @@
while (refs) {
char inc = refs->ref >= 0 ? '+' : '-';
ALOGD("\t%c ID %p (ref %d):", inc, refs->id, refs->ref);
-#if DEBUG_REFS_CALLSTACK_ENABLED && CALLSTACK_ENABLED
+#if DEBUG_REFS_CALLSTACK_ENABLED && ANDROID_UTILS_CALLSTACK_ENABLED
CallStack::logStack(LOG_TAG, refs->stack.get());
#endif
refs = refs->next;
@@ -254,7 +254,7 @@
}
if (dumpStack) {
ALOGE("above errors at:");
-#if CALLSTACK_ENABLED
+#if ANDROID_UTILS_CALLSTACK_ENABLED
CallStack::logStack(LOG_TAG);
#endif
}
@@ -343,7 +343,7 @@
{
ref_entry* next;
const void* id;
-#if DEBUG_REFS_CALLSTACK_ENABLED && CALLSTACK_ENABLED
+#if DEBUG_REFS_CALLSTACK_ENABLED && ANDROID_UTILS_CALLSTACK_ENABLED
CallStack::CallStackUPtr stack;
#endif
int32_t ref;
@@ -360,7 +360,7 @@
// decrement the reference count.
ref->ref = mRef;
ref->id = id;
-#if DEBUG_REFS_CALLSTACK_ENABLED && CALLSTACK_ENABLED
+#if DEBUG_REFS_CALLSTACK_ENABLED && ANDROID_UTILS_CALLSTACK_ENABLED
ref->stack = CallStack::getCurrent(2);
#endif
ref->next = *refs;
@@ -396,7 +396,7 @@
ref = ref->next;
}
-#if CALLSTACK_ENABLED
+#if ANDROID_UTILS_CALLSTACK_ENABLED
CallStack::logStack(LOG_TAG);
#endif
}
@@ -424,7 +424,7 @@
snprintf(buf, sizeof(buf), "\t%c ID %p (ref %d):\n",
inc, refs->id, refs->ref);
out->append(buf);
-#if DEBUG_REFS_CALLSTACK_ENABLED && CALLSTACK_ENABLED
+#if DEBUG_REFS_CALLSTACK_ENABLED && ANDROID_UTILS_CALLSTACK_ENABLED
out->append(CallStack::stackToString("\t\t", refs->stack.get()));
#else
out->append("\t\t(call stacks disabled)");
@@ -536,7 +536,7 @@
case INITIAL_STRONG_VALUE:
refs->mStrong.fetch_sub(INITIAL_STRONG_VALUE,
std::memory_order_relaxed);
- FALLTHROUGH_INTENDED;
+ [[fallthrough]];
case 0:
refs->mBase->onFirstRef();
}
@@ -790,7 +790,7 @@
"object.",
mRefs->mWeak.load(), this);
-#if CALLSTACK_ENABLED
+#if ANDROID_UTILS_CALLSTACK_ENABLED
CallStack::logStack(LOG_TAG);
#endif
} else if (strongs != 0) {
diff --git a/libutils/binder/String8.cpp b/libutils/binder/String8.cpp
index 6a75484..749bfcb 100644
--- a/libutils/binder/String8.cpp
+++ b/libutils/binder/String8.cpp
@@ -19,7 +19,6 @@
#include <utils/String8.h>
-#include <utils/Compat.h>
#include <log/log.h>
#include <utils/String16.h>
@@ -430,6 +429,13 @@
// ---------------------------------------------------------------------------
// Path functions
+// TODO: we should remove all the path functions from String8
+#if defined(_WIN32)
+#define OS_PATH_SEPARATOR '\\'
+#else
+#define OS_PATH_SEPARATOR '/'
+#endif
+
String8 String8::getPathDir(void) const
{
const char* cp;
diff --git a/libutils/binder/Unicode.cpp b/libutils/binder/Unicode.cpp
index 364a177..2ed2d4f 100644
--- a/libutils/binder/Unicode.cpp
+++ b/libutils/binder/Unicode.cpp
@@ -16,7 +16,6 @@
#define LOG_TAG "unicode"
-#include <android-base/macros.h>
#include <limits.h>
#include <utils/Unicode.h>
@@ -92,11 +91,11 @@
switch (bytes)
{ /* note: everything falls through. */
case 4: *--dstP = (uint8_t)((srcChar | kByteMark) & kByteMask); srcChar >>= 6;
- FALLTHROUGH_INTENDED;
+ [[fallthrough]];
case 3: *--dstP = (uint8_t)((srcChar | kByteMark) & kByteMask); srcChar >>= 6;
- FALLTHROUGH_INTENDED;
+ [[fallthrough]];
case 2: *--dstP = (uint8_t)((srcChar | kByteMark) & kByteMask); srcChar >>= 6;
- FALLTHROUGH_INTENDED;
+ [[fallthrough]];
case 1: *--dstP = (uint8_t)(srcChar | kFirstByteMark[bytes]);
}
}
@@ -304,15 +303,15 @@
while (in < end) {
char16_t w = *in++;
- if (LIKELY(w < 0x0080)) {
+ if (w < 0x0080) [[likely]] {
utf8_len += 1;
continue;
}
- if (LIKELY(w < 0x0800)) {
+ if (w < 0x0800) [[likely]] {
utf8_len += 2;
continue;
}
- if (LIKELY(!is_any_surrogate(w))) {
+ if (!is_any_surrogate(w)) [[likely]] {
utf8_len += 3;
continue;
}
@@ -345,20 +344,20 @@
while (in < in_end) {
char16_t w = *in++;
- if (LIKELY(w < 0x0080)) {
+ if (w < 0x0080) [[likely]] {
if (out + 1 > out_end)
return err_out();
*out++ = (char)(w & 0xff);
continue;
}
- if (LIKELY(w < 0x0800)) {
+ if (w < 0x0800) [[likely]] {
if (out + 2 > out_end)
return err_out();
*out++ = (char)(0xc0 | ((w >> 6) & 0x1f));
*out++ = (char)(0x80 | ((w >> 0) & 0x3f));
continue;
}
- if (LIKELY(!is_any_surrogate(w))) {
+ if (!is_any_surrogate(w)) [[likely]] {
if (out + 3 > out_end)
return err_out();
*out++ = (char)(0xe0 | ((w >> 12) & 0xf));
@@ -420,25 +419,25 @@
while (in < in_end) {
uint8_t c = *in;
utf16_len++;
- if (LIKELY((c & 0x80) == 0)) {
+ if ((c & 0x80) == 0) [[likely]] {
in++;
continue;
}
- if (UNLIKELY(c < 0xc0)) {
+ if (c < 0xc0) [[unlikely]] {
ALOGW("Invalid UTF-8 leading byte: 0x%02x", c);
in++;
continue;
}
- if (LIKELY(c < 0xe0)) {
+ if (c < 0xe0) [[likely]] {
in += 2;
continue;
}
- if (LIKELY(c < 0xf0)) {
+ if (c < 0xf0) [[likely]] {
in += 3;
continue;
} else {
uint8_t c2, c3, c4;
- if (UNLIKELY(c >= 0xf8)) {
+ if (c >= 0xf8) [[unlikely]] {
ALOGW("Invalid UTF-8 leading byte: 0x%02x", c);
}
c2 = in[1]; c3 = in[2]; c4 = in[3];
@@ -487,25 +486,25 @@
while (in < in_end && out < out_end) {
c = *in++;
- if (LIKELY((c & 0x80) == 0)) {
+ if ((c & 0x80) == 0) [[likely]] {
*out++ = (char16_t)(c);
continue;
}
- if (UNLIKELY(c < 0xc0)) {
+ if (c < 0xc0) [[unlikely]] {
ALOGW("Invalid UTF-8 leading byte: 0x%02x", c);
*out++ = (char16_t)(c);
continue;
}
- if (LIKELY(c < 0xe0)) {
- if (UNLIKELY(in + 1 > in_end)) {
+ if (c < 0xe0) [[likely]] {
+ if (in + 1 > in_end) [[unlikely]] {
return err_in();
}
c2 = *in++;
*out++ = (char16_t)(((c & 0x1f) << 6) | (c2 & 0x3f));
continue;
}
- if (LIKELY(c < 0xf0)) {
- if (UNLIKELY(in + 2 > in_end)) {
+ if (c < 0xf0) [[likely]] {
+ if (in + 2 > in_end) [[unlikely]] {
return err_in();
}
c2 = *in++; c3 = *in++;
@@ -513,19 +512,19 @@
((c2 & 0x3f) << 6) | (c3 & 0x3f));
continue;
} else {
- if (UNLIKELY(in + 3 > in_end)) {
+ if (in + 3 > in_end) [[unlikely]] {
return err_in();
}
- if (UNLIKELY(c >= 0xf8)) {
+ if (c >= 0xf8) [[unlikely]] {
ALOGW("Invalid UTF-8 leading byte: 0x%02x", c);
}
// Multiple UTF16 characters with surrogates
c2 = *in++; c3 = *in++; c4 = *in++;
w = utf8_4b_to_utf32(c, c2, c3, c4);
- if (UNLIKELY(w < 0x10000)) {
+ if (w < 0x10000) [[unlikely]] {
*out++ = (char16_t)(w);
} else {
- if (UNLIKELY(out + 2 > out_end)) {
+ if (out + 2 > out_end) [[unlikely]] {
// Ooops.... not enough room for this surrogate pair.
return out;
}
diff --git a/libutils/include/utils/LightRefBase.h b/libutils/binder/include/utils/LightRefBase.h
similarity index 100%
rename from libutils/include/utils/LightRefBase.h
rename to libutils/binder/include/utils/LightRefBase.h
diff --git a/libutils/include/utils/TypeHelpers.h b/libutils/binder/include/utils/TypeHelpers.h
similarity index 100%
rename from libutils/include/utils/TypeHelpers.h
rename to libutils/binder/include/utils/TypeHelpers.h
diff --git a/libutils/include/utils/LightRefBase.h b/libutils/include/utils/LightRefBase.h
new file mode 120000
index 0000000..9da2cf0
--- /dev/null
+++ b/libutils/include/utils/LightRefBase.h
@@ -0,0 +1 @@
+../../binder/include/utils/LightRefBase.h
\ No newline at end of file
diff --git a/libutils/include/utils/TypeHelpers.h b/libutils/include/utils/TypeHelpers.h
new file mode 120000
index 0000000..848f6d7
--- /dev/null
+++ b/libutils/include/utils/TypeHelpers.h
@@ -0,0 +1 @@
+../../binder/include/utils/TypeHelpers.h
\ No newline at end of file
diff --git a/property_service/libpropertyinfoparser/include/property_info_parser/property_info_parser.h b/property_service/libpropertyinfoparser/include/property_info_parser/property_info_parser.h
index 0548021..65705ac 100644
--- a/property_service/libpropertyinfoparser/include/property_info_parser/property_info_parser.h
+++ b/property_service/libpropertyinfoparser/include/property_info_parser/property_info_parser.h
@@ -20,6 +20,8 @@
#include <stdint.h>
#include <stdlib.h>
+static constexpr char PROP_TREE_FILE[] = "/dev/__properties__/property_info";
+
namespace android {
namespace properties {