Merge "Revert "Remove cutils threads.h header completely."" into main
diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp
index 52c1c25..19ff7eb 100644
--- a/debuggerd/debuggerd_test.cpp
+++ b/debuggerd/debuggerd_test.cpp
@@ -2264,10 +2264,14 @@
ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
- // Assumes that the open files section comes after the map section.
- // If that assumption changes, the regex below needs to change.
+ // Verifies that the fault address error message is at the end of the
+ // maps section. To do this, the check below looks for the start of the
+ // open files section or the start of the log file section. It's possible
+ // for either of these sections to be present after the maps section right
+ // now.
+ // If the sections move around, this check might need to be modified.
match_str = android::base::StringPrintf(
- R"(\n--->Fault address falls at %s after any mapped regions\n\nopen files:)",
+ R"(\n--->Fault address falls at %s after any mapped regions\n(---------|\nopen files:))",
format_pointer(crash_uptr).c_str());
ASSERT_MATCH(result, match_str);
}
diff --git a/debuggerd/libdebuggerd/tombstone_proto.cpp b/debuggerd/libdebuggerd/tombstone_proto.cpp
index 7b2e068..744bfab 100644
--- a/debuggerd/libdebuggerd/tombstone_proto.cpp
+++ b/debuggerd/libdebuggerd/tombstone_proto.cpp
@@ -493,27 +493,48 @@
}
}
+// This creates a fake log message that indicates an error occurred when
+// reading the log.
+static void add_error_log_msg(Tombstone* tombstone, const std::string&& error_msg) {
+ LogBuffer buffer;
+ buffer.set_name("ERROR");
+
+ LogMessage* log_msg = buffer.add_logs();
+ log_msg->set_timestamp("00-00 00:00:00.000");
+ log_msg->set_pid(0);
+ log_msg->set_tid(0);
+ log_msg->set_priority(ANDROID_LOG_ERROR);
+ log_msg->set_tag("");
+ log_msg->set_message(error_msg);
+
+ *tombstone->add_log_buffers() = std::move(buffer);
+
+ async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG, "%s", error_msg.c_str());
+}
+
static void dump_log_file(Tombstone* tombstone, const char* logger, pid_t pid) {
logger_list* logger_list = android_logger_list_open(android_name_to_log_id(logger),
ANDROID_LOG_NONBLOCK, kMaxLogMessages, pid);
+ if (logger_list == nullptr) {
+ add_error_log_msg(tombstone, android::base::StringPrintf("Cannot open log file %s", logger));
+ return;
+ }
LogBuffer buffer;
-
while (true) {
log_msg log_entry;
ssize_t actual = android_logger_list_read(logger_list, &log_entry);
-
if (actual < 0) {
if (actual == -EINTR) {
// interrupted by signal, retry
continue;
}
- if (actual == -EAGAIN) {
- // non-blocking EOF; we're done
- break;
- } else {
- break;
+ // Don't consider EAGAIN an error since this is a non-blocking call.
+ if (actual != -EAGAIN) {
+ add_error_log_msg(tombstone, android::base::StringPrintf("reading log %s failed (%s)",
+ logger, strerror(-actual)));
}
+ break;
} else if (actual == 0) {
break;
}
diff --git a/debuggerd/libdebuggerd/tombstone_proto_to_text.cpp b/debuggerd/libdebuggerd/tombstone_proto_to_text.cpp
index 8e6abdf..eed81fc 100644
--- a/debuggerd/libdebuggerd/tombstone_proto_to_text.cpp
+++ b/debuggerd/libdebuggerd/tombstone_proto_to_text.cpp
@@ -81,6 +81,8 @@
if (!tombstone.command_line().empty()) {
process_name = tombstone.command_line()[0].c_str();
CB(should_log, "Cmdline: %s", android::base::Join(tombstone.command_line(), " ").c_str());
+ } else {
+ CB(should_log, "Cmdline: <unknown>");
}
CB(should_log, "pid: %d, tid: %d, name: %s >>> %s <<<", tombstone.pid(), thread.id(),
thread.name().c_str(), process_name);
diff --git a/fs_mgr/libfiemap/binder.cpp b/fs_mgr/libfiemap/binder.cpp
index 41e534a..439aac9 100644
--- a/fs_mgr/libfiemap/binder.cpp
+++ b/fs_mgr/libfiemap/binder.cpp
@@ -77,7 +77,7 @@
static FiemapStatus ToFiemapStatus(const char* func, const binder::Status& status) {
if (!status.isOk()) {
- LOG(ERROR) << func << " binder returned: " << status.toString8().string();
+ LOG(ERROR) << func << " binder returned: " << status.toString8().c_str();
if (status.serviceSpecificErrorCode() != 0) {
return FiemapStatus::FromErrorCode(status.serviceSpecificErrorCode());
} else {
@@ -106,7 +106,7 @@
auto status = manager_->deleteBackingImage(name);
if (!status.isOk()) {
LOG(ERROR) << __PRETTY_FUNCTION__
- << " binder returned: " << status.exceptionMessage().string();
+ << " binder returned: " << status.exceptionMessage().c_str();
return false;
}
return true;
@@ -122,7 +122,7 @@
auto status = manager_->mapImageDevice(name, timeout_ms_count, &map);
if (!status.isOk()) {
LOG(ERROR) << __PRETTY_FUNCTION__
- << " binder returned: " << status.exceptionMessage().string();
+ << " binder returned: " << status.exceptionMessage().c_str();
return false;
}
*path = map.path;
@@ -133,7 +133,7 @@
auto status = manager_->unmapImageDevice(name);
if (!status.isOk()) {
LOG(ERROR) << __PRETTY_FUNCTION__
- << " binder returned: " << status.exceptionMessage().string();
+ << " binder returned: " << status.exceptionMessage().c_str();
return false;
}
return true;
@@ -144,7 +144,7 @@
auto status = manager_->backingImageExists(name, &retval);
if (!status.isOk()) {
LOG(ERROR) << __PRETTY_FUNCTION__
- << " binder returned: " << status.exceptionMessage().string();
+ << " binder returned: " << status.exceptionMessage().c_str();
return false;
}
return retval;
@@ -155,7 +155,7 @@
auto status = manager_->isImageMapped(name, &retval);
if (!status.isOk()) {
LOG(ERROR) << __PRETTY_FUNCTION__
- << " binder returned: " << status.exceptionMessage().string();
+ << " binder returned: " << status.exceptionMessage().c_str();
return false;
}
return retval;
@@ -175,7 +175,7 @@
auto status = manager_->getAllBackingImages(&retval);
if (!status.isOk()) {
LOG(ERROR) << __PRETTY_FUNCTION__
- << " binder returned: " << status.exceptionMessage().string();
+ << " binder returned: " << status.exceptionMessage().c_str();
}
return retval;
}
@@ -189,7 +189,7 @@
auto status = manager_->removeAllImages();
if (!status.isOk()) {
LOG(ERROR) << __PRETTY_FUNCTION__
- << " binder returned: " << status.exceptionMessage().string();
+ << " binder returned: " << status.exceptionMessage().c_str();
return false;
}
return true;
@@ -199,7 +199,7 @@
auto status = manager_->disableImage(name);
if (!status.isOk()) {
LOG(ERROR) << __PRETTY_FUNCTION__
- << " binder returned: " << status.exceptionMessage().string();
+ << " binder returned: " << status.exceptionMessage().c_str();
return false;
}
return true;
@@ -209,7 +209,7 @@
auto status = manager_->removeDisabledImages();
if (!status.isOk()) {
LOG(ERROR) << __PRETTY_FUNCTION__
- << " binder returned: " << status.exceptionMessage().string();
+ << " binder returned: " << status.exceptionMessage().c_str();
return false;
}
return true;
@@ -219,7 +219,7 @@
auto status = manager_->getMappedImageDevice(name, device);
if (!status.isOk()) {
LOG(ERROR) << __PRETTY_FUNCTION__
- << " binder returned: " << status.exceptionMessage().string();
+ << " binder returned: " << status.exceptionMessage().c_str();
return false;
}
return !device->empty();
@@ -230,7 +230,7 @@
auto status = manager_->isImageDisabled(name, &retval);
if (!status.isOk()) {
LOG(ERROR) << __PRETTY_FUNCTION__
- << " binder returned: " << status.exceptionMessage().string();
+ << " binder returned: " << status.exceptionMessage().c_str();
return false;
}
return retval;
@@ -249,7 +249,7 @@
auto status = service->openImageService(dir, &manager);
if (!status.isOk() || !manager) {
- LOG(ERROR) << "Could not acquire IImageManager: " << status.exceptionMessage().string();
+ LOG(ERROR) << "Could not acquire IImageManager: " << status.exceptionMessage().c_str();
return nullptr;
}
return std::make_unique<ImageManagerBinder>(std::move(service), std::move(manager));
diff --git a/fs_mgr/libsnapshot/OWNERS b/fs_mgr/libsnapshot/OWNERS
index 9d2b877..1ee4175 100644
--- a/fs_mgr/libsnapshot/OWNERS
+++ b/fs_mgr/libsnapshot/OWNERS
@@ -3,3 +3,4 @@
dvander@google.com
elsk@google.com
akailash@google.com
+zhangkelvin@google.com
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_compress.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_compress.h
new file mode 100644
index 0000000..8add041
--- /dev/null
+++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_compress.h
@@ -0,0 +1,48 @@
+//
+// 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 <memory>
+#include <string_view>
+#include "libsnapshot/cow_format.h"
+
+namespace android {
+namespace snapshot {
+
+class ICompressor {
+ public:
+ explicit ICompressor(uint32_t compression_level) : compression_level_(compression_level) {}
+
+ virtual ~ICompressor() {}
+ // Factory methods for compression methods.
+ static std::unique_ptr<ICompressor> Gz(uint32_t compression_level);
+ static std::unique_ptr<ICompressor> Brotli(uint32_t compression_level);
+ static std::unique_ptr<ICompressor> Lz4(uint32_t compression_level);
+ static std::unique_ptr<ICompressor> Zstd(uint32_t compression_level);
+
+ static std::unique_ptr<ICompressor> Create(CowCompression compression);
+
+ uint32_t GetCompressionLevel() const { return compression_level_; }
+
+ [[nodiscard]] virtual std::basic_string<uint8_t> Compress(const void* data,
+ size_t length) const = 0;
+
+ private:
+ uint32_t compression_level_;
+};
+} // namespace snapshot
+} // namespace android
\ No newline at end of file
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h
index 74b8bb8..3016e93 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h
@@ -14,6 +14,8 @@
#pragma once
+#include <libsnapshot/cow_compress.h>
+
#include <stdint.h>
#include <condition_variable>
@@ -107,16 +109,14 @@
class CompressWorker {
public:
- CompressWorker(CowCompression compression, uint32_t block_size);
+ CompressWorker(std::unique_ptr<ICompressor>&& compressor, uint32_t block_size);
bool RunThread();
void EnqueueCompressBlocks(const void* buffer, size_t num_blocks);
bool GetCompressedBuffers(std::vector<std::basic_string<uint8_t>>* compressed_buf);
void Finalize();
static uint32_t GetDefaultCompressionLevel(CowCompressionAlgorithm compression);
- static std::basic_string<uint8_t> Compress(CowCompression compression, const void* data,
- size_t length);
- static bool CompressBlocks(CowCompression compression, size_t block_size, const void* buffer,
+ static bool CompressBlocks(ICompressor* compressor, size_t block_size, const void* buffer,
size_t num_blocks,
std::vector<std::basic_string<uint8_t>>* compressed_data);
@@ -128,7 +128,7 @@
std::vector<std::basic_string<uint8_t>> compressed_data;
};
- CowCompression compression_;
+ std::unique_ptr<ICompressor> compressor_;
uint32_t block_size_;
std::queue<CompressWork> work_queue_;
diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/cow_compress.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/cow_compress.cpp
index 96d6016..466b93c 100644
--- a/fs_mgr/libsnapshot/libsnapshot_cow/cow_compress.cpp
+++ b/fs_mgr/libsnapshot/libsnapshot_cow/cow_compress.cpp
@@ -18,12 +18,16 @@
#include <unistd.h>
#include <limits>
+#include <memory>
#include <queue>
#include <android-base/file.h>
#include <android-base/logging.h>
+#include <android-base/parseint.h>
+#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <brotli/encode.h>
+#include <libsnapshot/cow_compress.h>
#include <libsnapshot/cow_format.h>
#include <libsnapshot/cow_reader.h>
#include <libsnapshot/cow_writer.h>
@@ -51,6 +55,22 @@
}
}
+std::unique_ptr<ICompressor> ICompressor::Create(CowCompression compression) {
+ switch (compression.algorithm) {
+ case kCowCompressLz4:
+ return ICompressor::Lz4(compression.compression_level);
+ case kCowCompressBrotli:
+ return ICompressor::Brotli(compression.compression_level);
+ case kCowCompressGz:
+ return ICompressor::Gz(compression.compression_level);
+ case kCowCompressZstd:
+ return ICompressor::Zstd(compression.compression_level);
+ case kCowCompressNone:
+ return nullptr;
+ }
+ return nullptr;
+}
+
// 1. Default compression level is determined by compression algorithm
// 2. There might be compatibility issues if a value is changed here, as some older versions of
// Android will assume a different compression level, causing cow_size estimation differences that
@@ -77,101 +97,125 @@
return 0;
}
-std::basic_string<uint8_t> CompressWorker::Compress(CowCompression compression, const void* data,
- size_t length) {
- switch (compression.algorithm) {
- case kCowCompressGz: {
- const auto bound = compressBound(length);
- std::basic_string<uint8_t> buffer(bound, '\0');
+class GzCompressor final : public ICompressor {
+ public:
+ GzCompressor(uint32_t compression_level) : ICompressor(compression_level){};
- uLongf dest_len = bound;
- auto rv = compress2(buffer.data(), &dest_len, reinterpret_cast<const Bytef*>(data),
- length, compression.compression_level);
- if (rv != Z_OK) {
- LOG(ERROR) << "compress2 returned: " << rv;
- return {};
- }
- buffer.resize(dest_len);
- return buffer;
- }
- case kCowCompressBrotli: {
- const auto bound = BrotliEncoderMaxCompressedSize(length);
- if (!bound) {
- LOG(ERROR) << "BrotliEncoderMaxCompressedSize returned 0";
- return {};
- }
- std::basic_string<uint8_t> buffer(bound, '\0');
+ std::basic_string<uint8_t> Compress(const void* data, size_t length) const override {
+ const auto bound = compressBound(length);
+ std::basic_string<uint8_t> buffer(bound, '\0');
- size_t encoded_size = bound;
- auto rv = BrotliEncoderCompress(
- compression.compression_level, BROTLI_DEFAULT_WINDOW, BROTLI_DEFAULT_MODE,
- length, reinterpret_cast<const uint8_t*>(data), &encoded_size, buffer.data());
- if (!rv) {
- LOG(ERROR) << "BrotliEncoderCompress failed";
- return {};
- }
- buffer.resize(encoded_size);
- return buffer;
+ uLongf dest_len = bound;
+ auto rv = compress2(buffer.data(), &dest_len, reinterpret_cast<const Bytef*>(data), length,
+ GetCompressionLevel());
+ if (rv != Z_OK) {
+ LOG(ERROR) << "compress2 returned: " << rv;
+ return {};
}
- case kCowCompressLz4: {
- const auto bound = LZ4_compressBound(length);
- if (!bound) {
- LOG(ERROR) << "LZ4_compressBound returned 0";
- return {};
- }
- std::basic_string<uint8_t> buffer(bound, '\0');
+ buffer.resize(dest_len);
+ return buffer;
+ };
+};
- const auto compressed_size = LZ4_compress_default(
- static_cast<const char*>(data), reinterpret_cast<char*>(buffer.data()), length,
- buffer.size());
- if (compressed_size <= 0) {
- LOG(ERROR) << "LZ4_compress_default failed, input size: " << length
- << ", compression bound: " << bound << ", ret: " << compressed_size;
- return {};
- }
- // Don't run compression if the compressed output is larger
- if (compressed_size >= length) {
- buffer.resize(length);
- memcpy(buffer.data(), data, length);
- } else {
- buffer.resize(compressed_size);
- }
- return buffer;
+class Lz4Compressor final : public ICompressor {
+ public:
+ Lz4Compressor(uint32_t compression_level) : ICompressor(compression_level){};
+
+ std::basic_string<uint8_t> Compress(const void* data, size_t length) const override {
+ const auto bound = LZ4_compressBound(length);
+ if (!bound) {
+ LOG(ERROR) << "LZ4_compressBound returned 0";
+ return {};
}
- case kCowCompressZstd: {
- std::basic_string<uint8_t> buffer(ZSTD_compressBound(length), '\0');
- const auto compressed_size = ZSTD_compress(buffer.data(), buffer.size(), data, length,
- compression.compression_level);
- if (compressed_size <= 0) {
- LOG(ERROR) << "ZSTD compression failed " << compressed_size;
- return {};
- }
- // Don't run compression if the compressed output is larger
- if (compressed_size >= length) {
- buffer.resize(length);
- memcpy(buffer.data(), data, length);
- } else {
- buffer.resize(compressed_size);
- }
- return buffer;
+ std::basic_string<uint8_t> buffer(bound, '\0');
+
+ const auto compressed_size =
+ LZ4_compress_default(static_cast<const char*>(data),
+ reinterpret_cast<char*>(buffer.data()), length, buffer.size());
+ if (compressed_size <= 0) {
+ LOG(ERROR) << "LZ4_compress_default failed, input size: " << length
+ << ", compression bound: " << bound << ", ret: " << compressed_size;
+ return {};
}
- default:
- LOG(ERROR) << "unhandled compression type: " << compression.algorithm;
- break;
- }
- return {};
-}
+ // Don't run compression if the compressed output is larger
+ if (compressed_size >= length) {
+ buffer.resize(length);
+ memcpy(buffer.data(), data, length);
+ } else {
+ buffer.resize(compressed_size);
+ }
+ return buffer;
+ };
+};
+
+class BrotliCompressor final : public ICompressor {
+ public:
+ BrotliCompressor(uint32_t compression_level) : ICompressor(compression_level){};
+
+ std::basic_string<uint8_t> Compress(const void* data, size_t length) const override {
+ const auto bound = BrotliEncoderMaxCompressedSize(length);
+ if (!bound) {
+ LOG(ERROR) << "BrotliEncoderMaxCompressedSize returned 0";
+ return {};
+ }
+ std::basic_string<uint8_t> buffer(bound, '\0');
+
+ size_t encoded_size = bound;
+ auto rv = BrotliEncoderCompress(
+ GetCompressionLevel(), BROTLI_DEFAULT_WINDOW, BROTLI_DEFAULT_MODE, length,
+ reinterpret_cast<const uint8_t*>(data), &encoded_size, buffer.data());
+ if (!rv) {
+ LOG(ERROR) << "BrotliEncoderCompress failed";
+ return {};
+ }
+ buffer.resize(encoded_size);
+ return buffer;
+ };
+};
+
+class ZstdCompressor final : public ICompressor {
+ public:
+ ZstdCompressor(uint32_t compression_level)
+ : ICompressor(compression_level), zstd_context_(ZSTD_createCCtx(), ZSTD_freeCCtx) {
+ ZSTD_CCtx_setParameter(zstd_context_.get(), ZSTD_c_compressionLevel, compression_level);
+ // FIXME: hardcoding a value of 12 here for 4k blocks, should change to be either set by
+ // user, or optimized depending on block size
+ ZSTD_CCtx_setParameter(zstd_context_.get(), ZSTD_c_windowLog, 12);
+ };
+
+ std::basic_string<uint8_t> Compress(const void* data, size_t length) const override {
+ std::basic_string<uint8_t> buffer(ZSTD_compressBound(length), '\0');
+ const auto compressed_size =
+ ZSTD_compress2(zstd_context_.get(), buffer.data(), buffer.size(), data, length);
+ if (compressed_size <= 0) {
+ LOG(ERROR) << "ZSTD compression failed " << compressed_size;
+ return {};
+ }
+ // Don't run compression if the compressed output is larger
+ if (compressed_size >= length) {
+ buffer.resize(length);
+ memcpy(buffer.data(), data, length);
+ } else {
+ buffer.resize(compressed_size);
+ }
+ return buffer;
+ };
+
+ private:
+ std::unique_ptr<ZSTD_CCtx, decltype(&ZSTD_freeCCtx)> zstd_context_;
+};
+
bool CompressWorker::CompressBlocks(const void* buffer, size_t num_blocks,
std::vector<std::basic_string<uint8_t>>* compressed_data) {
- return CompressBlocks(compression_, block_size_, buffer, num_blocks, compressed_data);
+ return CompressBlocks(compressor_.get(), block_size_, buffer, num_blocks, compressed_data);
}
-bool CompressWorker::CompressBlocks(CowCompression compression, size_t block_size,
- const void* buffer, size_t num_blocks,
+bool CompressWorker::CompressBlocks(ICompressor* compressor, size_t block_size, const void* buffer,
+ size_t num_blocks,
std::vector<std::basic_string<uint8_t>>* compressed_data) {
const uint8_t* iter = reinterpret_cast<const uint8_t*>(buffer);
while (num_blocks) {
- auto data = Compress(compression, iter, block_size);
+ auto data = compressor->Compress(iter, block_size);
if (data.empty()) {
PLOG(ERROR) << "CompressBlocks: Compression failed";
return false;
@@ -270,6 +314,22 @@
return true;
}
+std::unique_ptr<ICompressor> ICompressor::Brotli(uint32_t compression_level) {
+ return std::make_unique<BrotliCompressor>(compression_level);
+}
+
+std::unique_ptr<ICompressor> ICompressor::Gz(uint32_t compression_level) {
+ return std::make_unique<GzCompressor>(compression_level);
+}
+
+std::unique_ptr<ICompressor> ICompressor::Lz4(uint32_t compression_level) {
+ return std::make_unique<Lz4Compressor>(compression_level);
+}
+
+std::unique_ptr<ICompressor> ICompressor::Zstd(uint32_t compression_level) {
+ return std::make_unique<ZstdCompressor>(compression_level);
+}
+
void CompressWorker::Finalize() {
{
std::unique_lock<std::mutex> lock(lock_);
@@ -278,8 +338,8 @@
cv_.notify_all();
}
-CompressWorker::CompressWorker(CowCompression compression, uint32_t block_size)
- : compression_(compression), block_size_(block_size) {}
+CompressWorker::CompressWorker(std::unique_ptr<ICompressor>&& compressor, uint32_t block_size)
+ : compressor_(std::move(compressor)), block_size_(block_size) {}
} // namespace snapshot
} // namespace android
diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/test_v2.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/test_v2.cpp
index 2258d9f..0ecad9d 100644
--- a/fs_mgr/libsnapshot/libsnapshot_cow/test_v2.cpp
+++ b/fs_mgr/libsnapshot/libsnapshot_cow/test_v2.cpp
@@ -480,7 +480,8 @@
std::string expected = "The quick brown fox jumps over the lazy dog.";
expected.resize(4096, '\0');
- auto result = CompressWorker::Compress(compression, expected.data(), expected.size());
+ std::unique_ptr<ICompressor> compressor = ICompressor::Create(compression);
+ auto result = compressor->Compress(expected.data(), expected.size());
ASSERT_FALSE(result.empty());
HorribleStream<uint8_t> stream(result);
diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp
index 6d04c6a..7115821 100644
--- a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp
+++ b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp
@@ -184,7 +184,8 @@
return;
}
for (int i = 0; i < num_compress_threads_; i++) {
- auto wt = std::make_unique<CompressWorker>(compression_, header_.block_size);
+ std::unique_ptr<ICompressor> compressor = ICompressor::Create(compression_);
+ auto wt = std::make_unique<CompressWorker>(std::move(compressor), header_.block_size);
threads_.emplace_back(std::async(std::launch::async, &CompressWorker::RunThread, wt.get()));
compress_threads_.push_back(std::move(wt));
}
@@ -339,10 +340,12 @@
const uint8_t* iter = reinterpret_cast<const uint8_t*>(data);
compressed_buf_.clear();
if (num_threads <= 1) {
- return CompressWorker::CompressBlocks(compression_, options_.block_size, data, num_blocks,
- &compressed_buf_);
+ if (!compressor_) {
+ compressor_ = ICompressor::Create(compression_);
+ }
+ return CompressWorker::CompressBlocks(compressor_.get(), options_.block_size, data,
+ num_blocks, &compressed_buf_);
}
-
// Submit the blocks per thread. The retrieval of
// compressed buffers has to be done in the same order.
// We should not poll for completed buffers in a different order as the
@@ -412,8 +415,11 @@
buf_iter_++;
return data;
} else {
- auto data =
- CompressWorker::Compress(compression_, iter, header_.block_size);
+ if (!compressor_) {
+ compressor_ = ICompressor::Create(compression_);
+ }
+
+ auto data = compressor_->Compress(iter, header_.block_size);
return data;
}
}();
diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.h b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.h
index 3f357e0..131a068 100644
--- a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.h
+++ b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.h
@@ -65,6 +65,9 @@
private:
CowFooter footer_{};
CowCompression compression_;
+ // in the case that we are using one thread for compression, we can store and re-use the same
+ // compressor
+ std::unique_ptr<ICompressor> compressor_;
uint64_t current_op_pos_ = 0;
uint64_t next_op_pos_ = 0;
uint64_t next_data_pos_ = 0;
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index 86ff5f7..51389a0 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -729,6 +729,14 @@
LOG(ERROR) << "Failed to remove status file " << file_path << ": " << error;
return false;
}
+
+ // This path may never exist. If it is present, then it's a stale
+ // snapshot status file. Just remove the file and log the message.
+ const std::string tmp_path = file_path + ".tmp";
+ if (!android::base::RemoveFileIfExists(tmp_path, &error)) {
+ LOG(ERROR) << "Failed to remove stale snapshot file " << tmp_path;
+ }
+
return true;
}
@@ -754,10 +762,10 @@
return false;
}
- auto other_suffix = device_->GetOtherSlotSuffix();
+ auto current_slot_suffix = device_->GetSlotSuffix();
for (const auto& snapshot : snapshots) {
- if (android::base::EndsWith(snapshot, other_suffix)) {
+ if (!android::base::EndsWith(snapshot, current_slot_suffix)) {
// Allow the merge to continue, but log this unexpected case.
LOG(ERROR) << "Unexpected snapshot found during merge: " << snapshot;
continue;
@@ -1123,7 +1131,7 @@
return MergeResult(UpdateState::MergeFailed, MergeFailureCode::ListSnapshots);
}
- auto other_suffix = device_->GetOtherSlotSuffix();
+ auto current_slot_suffix = device_->GetSlotSuffix();
bool cancelled = false;
bool merging = false;
@@ -1131,9 +1139,9 @@
bool wrong_phase = false;
MergeFailureCode failure_code = MergeFailureCode::Ok;
for (const auto& snapshot : snapshots) {
- if (android::base::EndsWith(snapshot, other_suffix)) {
+ if (!android::base::EndsWith(snapshot, current_slot_suffix)) {
// This will have triggered an error message in InitiateMerge already.
- LOG(INFO) << "Skipping merge validation of unexpected snapshot: " << snapshot;
+ LOG(ERROR) << "Skipping merge validation of unexpected snapshot: " << snapshot;
continue;
}
diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp
index 0a85489..3b6d26a 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -685,6 +685,17 @@
}
ASSERT_TRUE(sm->InitiateMerge());
+ // Create stale files in snapshot directory. Merge should skip these files
+ // as the suffix doesn't match the current slot.
+ auto tmp_path = test_device->GetMetadataDir() + "/snapshots/test_partition_b.tmp";
+ auto other_slot = test_device->GetMetadataDir() + "/snapshots/test_partition_a";
+
+ unique_fd fd(open(tmp_path.c_str(), O_RDWR | O_CLOEXEC | O_CREAT, 0644));
+ ASSERT_GE(fd, 0);
+
+ fd.reset(open(other_slot.c_str(), O_RDWR | O_CLOEXEC | O_CREAT, 0644));
+ ASSERT_GE(fd, 0);
+
// The device should have been switched to a snapshot-merge target.
DeviceMapper::TargetInfo target;
ASSERT_TRUE(sm->IsSnapshotDevice("test_partition_b", &target));
@@ -700,13 +711,23 @@
ASSERT_EQ(sm->ProcessUpdateState(), UpdateState::MergeCompleted);
ASSERT_EQ(sm->GetUpdateState(), UpdateState::None);
+ // Make sure that snapshot states are cleared and all stale files
+ // are deleted
+ {
+ ASSERT_TRUE(AcquireLock());
+ auto local_lock = std::move(lock_);
+ std::vector<std::string> snapshots;
+ ASSERT_TRUE(sm->ListSnapshots(local_lock.get(), &snapshots));
+ ASSERT_TRUE(snapshots.empty());
+ }
+
// The device should no longer be a snapshot or snapshot-merge.
ASSERT_FALSE(sm->IsSnapshotDevice("test_partition_b"));
// Test that we can read back the string we wrote to the snapshot. Note
// that the base device is gone now. |snap_device| contains the correct
// partition.
- unique_fd fd(open("/dev/block/mapper/test_partition_b", O_RDONLY | O_CLOEXEC));
+ fd.reset(open("/dev/block/mapper/test_partition_b", O_RDONLY | O_CLOEXEC));
ASSERT_GE(fd, 0);
std::string buffer(test_string.size(), '\0');
diff --git a/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp
index bd7955a..15c30be 100644
--- a/healthd/BatteryMonitor.cpp
+++ b/healthd/BatteryMonitor.cpp
@@ -444,12 +444,10 @@
for (size_t i = 0; i < mChargerNames.size(); i++) {
String8 path;
- path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH,
- mChargerNames[i].string());
+ path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH, mChargerNames[i].c_str());
if (getIntField(path)) {
path.clear();
- path.appendFormat("%s/%s/type", POWER_SUPPLY_SYSFS_PATH,
- mChargerNames[i].string());
+ path.appendFormat("%s/%s/type", POWER_SUPPLY_SYSFS_PATH, mChargerNames[i].c_str());
switch(readPowerSupplyType(path)) {
case ANDROID_POWER_SUPPLY_TYPE_AC:
mHealthInfo->chargerAcOnline = true;
@@ -466,26 +464,24 @@
default:
path.clear();
path.appendFormat("%s/%s/is_dock", POWER_SUPPLY_SYSFS_PATH,
- mChargerNames[i].string());
- if (access(path.string(), R_OK) == 0)
+ mChargerNames[i].c_str());
+ if (access(path.c_str(), R_OK) == 0)
mHealthInfo->chargerDockOnline = true;
else
KLOG_WARNING(LOG_TAG, "%s: Unknown power supply type\n",
- mChargerNames[i].string());
+ mChargerNames[i].c_str());
}
path.clear();
path.appendFormat("%s/%s/current_max", POWER_SUPPLY_SYSFS_PATH,
- mChargerNames[i].string());
- int ChargingCurrent =
- (access(path.string(), R_OK) == 0) ? getIntField(path) : 0;
+ mChargerNames[i].c_str());
+ int ChargingCurrent = (access(path.c_str(), R_OK) == 0) ? getIntField(path) : 0;
path.clear();
path.appendFormat("%s/%s/voltage_max", POWER_SUPPLY_SYSFS_PATH,
- mChargerNames[i].string());
+ mChargerNames[i].c_str());
int ChargingVoltage =
- (access(path.string(), R_OK) == 0) ? getIntField(path) :
- DEFAULT_VBUS_VOLTAGE;
+ (access(path.c_str(), R_OK) == 0) ? getIntField(path) : DEFAULT_VBUS_VOLTAGE;
double power = ((double)ChargingCurrent / MILLION) *
((double)ChargingVoltage / MILLION);
@@ -775,8 +771,7 @@
case ANDROID_POWER_SUPPLY_TYPE_DOCK:
path.clear();
path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH, name);
- if (access(path.string(), R_OK) == 0)
- mChargerNames.add(String8(name));
+ if (access(path.c_str(), R_OK) == 0) mChargerNames.add(String8(name));
break;
case ANDROID_POWER_SUPPLY_TYPE_BATTERY:
@@ -958,12 +953,10 @@
// Look for "is_dock" file
path.clear();
path.appendFormat("%s/%s/is_dock", POWER_SUPPLY_SYSFS_PATH, name);
- if (access(path.string(), R_OK) == 0) {
+ if (access(path.c_str(), R_OK) == 0) {
path.clear();
path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH, name);
- if (access(path.string(), R_OK) == 0)
- mChargerNames.add(String8(name));
-
+ if (access(path.c_str(), R_OK) == 0) mChargerNames.add(String8(name));
}
}
}
diff --git a/healthd/BatteryMonitor_v1.cpp b/healthd/BatteryMonitor_v1.cpp
index b87c493..b2d6518 100644
--- a/healthd/BatteryMonitor_v1.cpp
+++ b/healthd/BatteryMonitor_v1.cpp
@@ -358,12 +358,10 @@
for (size_t i = 0; i < mChargerNames.size(); i++) {
String8 path;
- path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH,
- mChargerNames[i].string());
+ path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH, mChargerNames[i].c_str());
if (getIntField(path)) {
path.clear();
- path.appendFormat("%s/%s/type", POWER_SUPPLY_SYSFS_PATH,
- mChargerNames[i].string());
+ path.appendFormat("%s/%s/type", POWER_SUPPLY_SYSFS_PATH, mChargerNames[i].c_str());
switch(readPowerSupplyType(path)) {
case ANDROID_POWER_SUPPLY_TYPE_AC:
mHealthInfo->chargerAcOnline = true;
@@ -380,26 +378,24 @@
default:
path.clear();
path.appendFormat("%s/%s/is_dock", POWER_SUPPLY_SYSFS_PATH,
- mChargerNames[i].string());
- if (access(path.string(), R_OK) == 0)
+ mChargerNames[i].c_str());
+ if (access(path.c_str(), R_OK) == 0)
mHealthInfo->chargerDockOnline = true;
else
KLOG_WARNING(LOG_TAG, "%s: Unknown power supply type\n",
- mChargerNames[i].string());
+ mChargerNames[i].c_str());
}
path.clear();
path.appendFormat("%s/%s/current_max", POWER_SUPPLY_SYSFS_PATH,
- mChargerNames[i].string());
- int ChargingCurrent =
- (access(path.string(), R_OK) == 0) ? getIntField(path) : 0;
+ mChargerNames[i].c_str());
+ int ChargingCurrent = (access(path.c_str(), R_OK) == 0) ? getIntField(path) : 0;
path.clear();
path.appendFormat("%s/%s/voltage_max", POWER_SUPPLY_SYSFS_PATH,
- mChargerNames[i].string());
+ mChargerNames[i].c_str());
int ChargingVoltage =
- (access(path.string(), R_OK) == 0) ? getIntField(path) :
- DEFAULT_VBUS_VOLTAGE;
+ (access(path.c_str(), R_OK) == 0) ? getIntField(path) : DEFAULT_VBUS_VOLTAGE;
double power = ((double)ChargingCurrent / MILLION) *
((double)ChargingVoltage / MILLION);
@@ -628,8 +624,7 @@
case ANDROID_POWER_SUPPLY_TYPE_DOCK:
path.clear();
path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH, name);
- if (access(path.string(), R_OK) == 0)
- mChargerNames.add(String8(name));
+ if (access(path.c_str(), R_OK) == 0) mChargerNames.add(String8(name));
break;
case ANDROID_POWER_SUPPLY_TYPE_BATTERY:
@@ -767,12 +762,10 @@
// Look for "is_dock" file
path.clear();
path.appendFormat("%s/%s/is_dock", POWER_SUPPLY_SYSFS_PATH, name);
- if (access(path.string(), R_OK) == 0) {
+ if (access(path.c_str(), R_OK) == 0) {
path.clear();
path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH, name);
- if (access(path.string(), R_OK) == 0)
- mChargerNames.add(String8(name));
-
+ if (access(path.c_str(), R_OK) == 0) mChargerNames.add(String8(name));
}
}
}
diff --git a/init/README.md b/init/README.md
index 5fced19..11c4e1c 100644
--- a/init/README.md
+++ b/init/README.md
@@ -674,11 +674,12 @@
_options_ include "barrier=1", "noauto\_da\_alloc", "discard", ... as
a comma separated string, e.g. barrier=1,noauto\_da\_alloc
-`perform_apex_config`
+`perform_apex_config [--bootstrap]`
> Performs tasks after APEXes are mounted. For example, creates data directories
for the mounted APEXes, parses config file(s) from them, and updates linker
configurations. Intended to be used only once when apexd notifies the mount
event by setting `apexd.status` to ready.
+ Use --bootstrap when invoking in the bootstrap mount namespace.
`restart [--only-if-running] <service>`
> Stops and restarts a running service, does nothing if the service is currently
diff --git a/init/apex_init_util.cpp b/init/apex_init_util.cpp
index c818f8f..6d17f36 100644
--- a/init/apex_init_util.cpp
+++ b/init/apex_init_util.cpp
@@ -16,13 +16,15 @@
#include "apex_init_util.h"
+#include <dirent.h>
#include <glob.h>
+#include <set>
#include <vector>
#include <android-base/logging.h>
-#include <android-base/result.h>
#include <android-base/properties.h>
+#include <android-base/result.h>
#include <android-base/strings.h>
#include "action_manager.h"
@@ -34,10 +36,13 @@
namespace android {
namespace init {
-static Result<std::vector<std::string>> CollectApexConfigs(const std::string& apex_name) {
+static Result<std::vector<std::string>> CollectRcScriptsFromApex(
+ const std::string& apex_name, const std::set<std::string>& skip_apexes) {
glob_t glob_result;
- std::string glob_pattern = apex_name.empty() ?
- "/apex/*/etc/*rc" : "/apex/" + apex_name + "/etc/*rc";
+ // Pattern uses "*rc" instead of ".rc" because APEXes can have versioned RC files
+ // like foo.34rc.
+ std::string glob_pattern =
+ apex_name.empty() ? "/apex/*/etc/*rc" : "/apex/" + apex_name + "/etc/*rc";
const int ret = glob(glob_pattern.c_str(), GLOB_MARK, nullptr, &glob_result);
if (ret != 0 && ret != GLOB_NOMATCH) {
@@ -47,15 +52,28 @@
std::vector<std::string> configs;
for (size_t i = 0; i < glob_result.gl_pathc; i++) {
std::string path = glob_result.gl_pathv[i];
- // Filter-out /apex/<name>@<ver> paths. The paths are bind-mounted to
- // /apex/<name> paths, so unless we filter them out, we will parse the
- // same file twice.
- std::vector<std::string> paths = android::base::Split(path, "/");
- if (paths.size() >= 3 && paths[2].find('@') != std::string::npos) {
+
+ // Filter out directories
+ if (path.back() == '/') {
continue;
}
- // Filter directories
- if (path.back() == '/') {
+
+ // Get apex name from path.
+ std::vector<std::string> paths = android::base::Split(path, "/");
+ if (paths.size() < 3) {
+ continue;
+ }
+ const std::string& apex_name = paths[2];
+
+ // Filter out /apex/<name>@<ver> paths. The paths are bind-mounted to
+ // /apex/<name> paths, so unless we filter them out, we will parse the
+ // same file twice.
+ if (apex_name.find('@') != std::string::npos) {
+ continue;
+ }
+
+ // Filter out skip_set apexes
+ if (skip_apexes.count(apex_name) > 0) {
continue;
}
configs.push_back(path);
@@ -64,11 +82,41 @@
return configs;
}
-static Result<void> ParseConfigs(const std::vector<std::string>& configs) {
+std::set<std::string> GetApexListFrom(const std::string& apex_dir) {
+ std::set<std::string> apex_list;
+ auto dirp = std::unique_ptr<DIR, int (*)(DIR*)>(opendir(apex_dir.c_str()), closedir);
+ if (!dirp) {
+ return apex_list;
+ }
+ struct dirent* entry;
+ while ((entry = readdir(dirp.get())) != nullptr) {
+ if (entry->d_type != DT_DIR) continue;
+
+ const char* name = entry->d_name;
+ if (name[0] == '.') continue;
+ if (strchr(name, '@') != nullptr) continue;
+ if (strcmp(name, "sharedlibs") == 0) continue;
+ apex_list.insert(name);
+ }
+ return apex_list;
+}
+
+static Result<void> ParseRcScripts(const std::vector<std::string>& files) {
+ if (files.empty()) {
+ return {};
+ }
+ // APEXes can have versioned RC files. These should be filtered based on
+ // SDK version.
+ auto filtered = FilterVersionedConfigs(
+ files, android::base::GetIntProperty("ro.build.version.sdk", INT_MAX));
+ if (filtered.empty()) {
+ return {};
+ }
+
Parser parser =
CreateApexConfigParser(ActionManager::GetInstance(), ServiceList::GetInstance());
std::vector<std::string> errors;
- for (const auto& c : configs) {
+ for (const auto& c : filtered) {
auto result = parser.ParseConfigFile(c);
// We should handle other config files even when there's an error.
if (!result.ok()) {
@@ -81,16 +129,21 @@
return {};
}
-Result<void> ParseApexConfigs(const std::string& apex_name) {
- auto configs = OR_RETURN(CollectApexConfigs(apex_name));
+Result<void> ParseRcScriptsFromApex(const std::string& apex_name) {
+ auto configs = OR_RETURN(CollectRcScriptsFromApex(apex_name, /*skip_apexes=*/{}));
+ return ParseRcScripts(configs);
+}
- if (configs.empty()) {
- return {};
+Result<void> ParseRcScriptsFromAllApexes(bool bootstrap) {
+ std::set<std::string> skip_apexes;
+ if (!bootstrap) {
+ // In case we already loaded config files from bootstrap APEXes, we need to avoid loading
+ // them again. We can get the list of bootstrap APEXes by scanning /bootstrap-apex and
+ // skip them in CollectRcScriptsFromApex.
+ skip_apexes = GetApexListFrom("/bootstrap-apex");
}
-
- auto filtered_configs = FilterVersionedConfigs(configs,
- android::base::GetIntProperty("ro.build.version.sdk", INT_MAX));
- return ParseConfigs(filtered_configs);
+ auto configs = OR_RETURN(CollectRcScriptsFromApex(/*apex_name=*/"", skip_apexes));
+ return ParseRcScripts(configs);
}
} // namespace init
diff --git a/init/apex_init_util.h b/init/apex_init_util.h
index 43f8ad5..75dfee1 100644
--- a/init/apex_init_util.h
+++ b/init/apex_init_util.h
@@ -16,6 +16,7 @@
#pragma once
+#include <set>
#include <string>
#include <vector>
@@ -24,9 +25,14 @@
namespace android {
namespace init {
-// Parse all config files for a given apex.
-// If apex name is empty(""), config files for all apexes will be parsed.
-Result<void> ParseApexConfigs(const std::string& apex_name);
+// Scans apex_dir (/apex) to get the list of active APEXes.
+std::set<std::string> GetApexListFrom(const std::string& apex_dir);
+
+// Parse all RC scripts for a given apex.
+Result<void> ParseRcScriptsFromApex(const std::string& apex_name);
+
+// Parse all RC scripts for all apexes under /apex.
+Result<void> ParseRcScriptsFromAllApexes(bool bootstrap);
} // namespace init
} // namespace android
diff --git a/init/builtins.cpp b/init/builtins.cpp
index fa5e36d..a5b762c 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -1269,36 +1269,33 @@
/*
* Creates a directory under /data/misc/apexdata/ for each APEX.
*/
-static Result<void> create_apex_data_dirs() {
- auto dirp = std::unique_ptr<DIR, int (*)(DIR*)>(opendir("/apex"), closedir);
- if (!dirp) {
- return ErrnoError() << "Unable to open apex directory";
- }
- struct dirent* entry;
- while ((entry = readdir(dirp.get())) != nullptr) {
- if (entry->d_type != DT_DIR) continue;
-
- const char* name = entry->d_name;
- // skip any starting with "."
- if (name[0] == '.') continue;
-
- if (strchr(name, '@') != nullptr) continue;
-
- auto path = "/data/misc/apexdata/" + std::string(name);
+static void create_apex_data_dirs() {
+ for (const auto& name : GetApexListFrom("/apex")) {
+ auto path = "/data/misc/apexdata/" + name;
auto options = MkdirOptions{path, 0771, AID_ROOT, AID_SYSTEM, FscryptAction::kNone, "ref"};
- make_dir_with_options(options);
+ auto result = make_dir_with_options(options);
+ if (!result.ok()) {
+ LOG(ERROR) << result.error();
+ }
}
- return {};
}
static Result<void> do_perform_apex_config(const BuiltinArguments& args) {
- auto create_dirs = create_apex_data_dirs();
- if (!create_dirs.ok()) {
- return create_dirs.error();
+ bool bootstrap = false;
+ if (args.size() == 2) {
+ if (args[1] != "--bootstrap") {
+ return Error() << "Unexpected argument: " << args[1];
+ }
+ bootstrap = true;
}
- auto parse_configs = ParseApexConfigs(/*apex_name=*/"");
- if (!parse_configs.ok()) {
- return parse_configs.error();
+
+ if (!bootstrap) {
+ create_apex_data_dirs();
+ }
+
+ auto parse_result = ParseRcScriptsFromAllApexes(bootstrap);
+ if (!parse_result.ok()) {
+ return parse_result.error();
}
auto update_linker_config = do_update_linker_config(args);
@@ -1306,8 +1303,10 @@
return update_linker_config.error();
}
- // Now start delayed services
- ServiceList::GetInstance().MarkServicesUpdate();
+ if (!bootstrap) {
+ // Now start delayed services
+ ServiceList::GetInstance().MarkServicesUpdate();
+ }
return {};
}
@@ -1362,7 +1361,7 @@
// mount and umount are run in the same context as mount_all for symmetry.
{"mount_all", {0, kMax, {false, do_mount_all}}},
{"mount", {3, kMax, {false, do_mount}}},
- {"perform_apex_config", {0, 0, {false, do_perform_apex_config}}},
+ {"perform_apex_config", {0, 1, {false, do_perform_apex_config}}},
{"umount", {1, 1, {false, do_umount}}},
{"umount_all", {0, 1, {false, do_umount_all}}},
{"update_linker_config", {0, 0, {false, do_update_linker_config}}},
diff --git a/init/init.cpp b/init/init.cpp
index 4bb8eec..40e2169 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -487,7 +487,7 @@
}
static Result<void> DoLoadApex(const std::string& apex_name) {
- if (auto result = ParseApexConfigs(apex_name); !result.ok()) {
+ if (auto result = ParseRcScriptsFromApex(apex_name); !result.ok()) {
return result.error();
}
diff --git a/init/selinux.cpp b/init/selinux.cpp
index ebdcaa6..ac102eb 100644
--- a/init/selinux.cpp
+++ b/init/selinux.cpp
@@ -735,6 +735,14 @@
TEMP_FAILURE_RETRY(send(fd.get(), &request, sizeof(request), 0));
}
+int RestoreconIfExists(const char* path, unsigned int flags) {
+ if (access(path, F_OK) != 0 && errno == ENOENT) {
+ // Avoid error message for path that is expected to not always exist.
+ return 0;
+ }
+ return selinux_android_restorecon(path, flags);
+}
+
} // namespace
void SelinuxRestoreContext() {
@@ -762,9 +770,9 @@
// adb remount, snapshot-based updates, and DSUs all create files during
// first-stage init.
- selinux_android_restorecon(SnapshotManager::GetGlobalRollbackIndicatorPath().c_str(), 0);
- selinux_android_restorecon("/metadata/gsi", SELINUX_ANDROID_RESTORECON_RECURSE |
- SELINUX_ANDROID_RESTORECON_SKIP_SEHASH);
+ RestoreconIfExists(SnapshotManager::GetGlobalRollbackIndicatorPath().c_str(), 0);
+ RestoreconIfExists("/metadata/gsi",
+ SELINUX_ANDROID_RESTORECON_RECURSE | SELINUX_ANDROID_RESTORECON_SKIP_SEHASH);
}
int SelinuxKlogCallback(int type, const char* fmt, ...) {
diff --git a/libutils/ProcessCallStack.cpp b/libutils/ProcessCallStack.cpp
index f054de9..4b27bdd 100644
--- a/libutils/ProcessCallStack.cpp
+++ b/libutils/ProcessCallStack.cpp
@@ -205,8 +205,7 @@
}
void ProcessCallStack::printInternal(Printer& printer, Printer& csPrinter) const {
- dumpProcessHeader(printer, getpid(),
- getTimeString(mTimeUpdated).string());
+ dumpProcessHeader(printer, getpid(), getTimeString(mTimeUpdated).c_str());
for (size_t i = 0; i < mThreadMap.size(); ++i) {
pid_t tid = mThreadMap.keyAt(i);
@@ -214,7 +213,7 @@
const String8& threadName = threadInfo.threadName;
printer.printLine("");
- printer.printFormatLine("\"%s\" sysTid=%d", threadName.string(), tid);
+ printer.printFormatLine("\"%s\" sysTid=%d", threadName.c_str(), tid);
threadInfo.callStack.print(csPrinter);
}
diff --git a/libutils/RefBase.cpp b/libutils/RefBase.cpp
index ab122c7..e0a2846 100644
--- a/libutils/RefBase.cpp
+++ b/libutils/RefBase.cpp
@@ -330,7 +330,7 @@
this);
int rc = open(name, O_RDWR | O_CREAT | O_APPEND, 0644);
if (rc >= 0) {
- (void)write(rc, text.string(), text.length());
+ (void)write(rc, text.c_str(), text.length());
close(rc);
ALOGI("STACK TRACE for %p saved in %s", this, name);
}
diff --git a/libutils/String16.cpp b/libutils/String16.cpp
index 68642d8..38d483e 100644
--- a/libutils/String16.cpp
+++ b/libutils/String16.cpp
@@ -26,7 +26,7 @@
static const StaticString16 emptyString(u"");
static inline char16_t* getEmptyString() {
- return const_cast<char16_t*>(emptyString.string());
+ return const_cast<char16_t*>(emptyString.c_str());
}
// ---------------------------------------------------------------------------
@@ -112,10 +112,7 @@
String16::String16(const char16_t* o, size_t len) : mString(allocFromUTF16(o, len)) {}
-String16::String16(const String8& o)
- : mString(allocFromUTF8(o.string(), o.size()))
-{
-}
+String16::String16(const String8& o) : mString(allocFromUTF8(o.c_str(), o.size())) {}
String16::String16(const char* o)
: mString(allocFromUTF8(o, strlen(o)))
@@ -173,7 +170,7 @@
LOG_ALWAYS_FATAL("Not implemented");
}
- return setTo(other.string()+begin, len);
+ return setTo(other.c_str() + begin, len);
}
status_t String16::setTo(const char16_t* other)
@@ -200,7 +197,7 @@
}
status_t String16::append(const String16& other) {
- return append(other.string(), other.size());
+ return append(other.c_str(), other.size());
}
status_t String16::append(const char16_t* chrs, size_t otherLen) {
@@ -286,7 +283,7 @@
{
const size_t ps = prefix.size();
if (ps > size()) return false;
- return strzcmp16(mString, ps, prefix.string(), ps) == 0;
+ return strzcmp16(mString, ps, prefix.c_str(), ps) == 0;
}
bool String16::startsWith(const char16_t* prefix) const
diff --git a/libutils/String16_fuzz.cpp b/libutils/String16_fuzz.cpp
index d7e5ec7..a271aee 100644
--- a/libutils/String16_fuzz.cpp
+++ b/libutils/String16_fuzz.cpp
@@ -25,7 +25,7 @@
// Bytes and size
([](FuzzedDataProvider&, android::String16 str1, android::String16) -> void {
- str1.string();
+ str1.c_str();
}),
([](FuzzedDataProvider&, android::String16 str1, android::String16) -> void {
str1.isStaticString();
@@ -39,7 +39,7 @@
str1.startsWith(str2);
}),
([](FuzzedDataProvider&, android::String16 str1, android::String16 str2) -> void {
- str1.contains(str2.string());
+ str1.contains(str2.c_str());
}),
([](FuzzedDataProvider&, android::String16 str1, android::String16 str2) -> void {
str1.compare(str2);
@@ -52,7 +52,7 @@
([](FuzzedDataProvider& dataProvider, android::String16 str1,
android::String16 str2) -> void {
int pos = dataProvider.ConsumeIntegralInRange<int>(0, str1.size());
- str1.insert(pos, str2.string());
+ str1.insert(pos, str2.c_str());
}),
// Find and replace operations
diff --git a/libutils/String8.cpp b/libutils/String8.cpp
index 8d312b5..79b7edf 100644
--- a/libutils/String8.cpp
+++ b/libutils/String8.cpp
@@ -150,10 +150,7 @@
}
}
-String8::String8(const String16& o)
- : mString(allocFromUTF16(o.string(), o.size()))
-{
-}
+String8::String8(const String16& o) : mString(allocFromUTF16(o.c_str(), o.size())) {}
String8::String8(const char16_t* o)
: mString(allocFromUTF16(o, strlen16(o)))
@@ -267,7 +264,7 @@
return OK;
}
- return real_append(other.string(), otherLen);
+ return real_append(other.c_str(), otherLen);
}
status_t String8::append(const char* other)
diff --git a/libutils/String8_test.cpp b/libutils/String8_test.cpp
index 35fd512..9c12cb1 100644
--- a/libutils/String8_test.cpp
+++ b/libutils/String8_test.cpp
@@ -36,7 +36,7 @@
TEST_F(String8Test, Cstr) {
String8 tmp("Hello, world!");
- EXPECT_STREQ(tmp.string(), "Hello, world!");
+ EXPECT_STREQ(tmp.c_str(), "Hello, world!");
}
TEST_F(String8Test, OperatorPlus) {
@@ -45,16 +45,16 @@
// Test adding String8 + const char*
const char* ccsrc2 = "world!";
String8 dst1 = src1 + ccsrc2;
- EXPECT_STREQ(dst1.string(), "Hello, world!");
- EXPECT_STREQ(src1.string(), "Hello, ");
+ EXPECT_STREQ(dst1.c_str(), "Hello, world!");
+ EXPECT_STREQ(src1.c_str(), "Hello, ");
EXPECT_STREQ(ccsrc2, "world!");
// Test adding String8 + String8
String8 ssrc2("world!");
String8 dst2 = src1 + ssrc2;
- EXPECT_STREQ(dst2.string(), "Hello, world!");
- EXPECT_STREQ(src1.string(), "Hello, ");
- EXPECT_STREQ(ssrc2.string(), "world!");
+ EXPECT_STREQ(dst2.c_str(), "Hello, world!");
+ EXPECT_STREQ(src1.c_str(), "Hello, ");
+ EXPECT_STREQ(ssrc2.c_str(), "world!");
}
TEST_F(String8Test, OperatorPlusEquals) {
@@ -63,14 +63,14 @@
// Testing String8 += String8
String8 src2(" is my passport.");
src1 += src2;
- EXPECT_STREQ(src1.string(), "My voice is my passport.");
- EXPECT_STREQ(src2.string(), " is my passport.");
+ EXPECT_STREQ(src1.c_str(), "My voice is my passport.");
+ EXPECT_STREQ(src2.c_str(), " is my passport.");
// Adding const char* to the previous string.
const char* src3 = " Verify me.";
src1 += src3;
- EXPECT_STREQ(src1.string(), "My voice is my passport. Verify me.");
- EXPECT_STREQ(src2.string(), " is my passport.");
+ EXPECT_STREQ(src1.c_str(), "My voice is my passport. Verify me.");
+ EXPECT_STREQ(src2.c_str(), " is my passport.");
EXPECT_STREQ(src3, " Verify me.");
}
diff --git a/libutils/Tokenizer.cpp b/libutils/Tokenizer.cpp
index c3ec165..9fc955c 100644
--- a/libutils/Tokenizer.cpp
+++ b/libutils/Tokenizer.cpp
@@ -50,15 +50,15 @@
*outTokenizer = nullptr;
int result = OK;
- int fd = ::open(filename.string(), O_RDONLY);
+ int fd = ::open(filename.c_str(), O_RDONLY);
if (fd < 0) {
result = -errno;
- ALOGE("Error opening file '%s': %s", filename.string(), strerror(errno));
+ ALOGE("Error opening file '%s': %s", filename.c_str(), strerror(errno));
} else {
struct stat stat;
if (fstat(fd, &stat)) {
result = -errno;
- ALOGE("Error getting size of file '%s': %s", filename.string(), strerror(errno));
+ ALOGE("Error getting size of file '%s': %s", filename.c_str(), strerror(errno));
} else {
size_t length = size_t(stat.st_size);
@@ -80,7 +80,7 @@
ssize_t nrd = read(fd, buffer, length);
if (nrd < 0) {
result = -errno;
- ALOGE("Error reading file '%s': %s", filename.string(), strerror(errno));
+ ALOGE("Error reading file '%s': %s", filename.c_str(), strerror(errno));
delete[] buffer;
buffer = nullptr;
} else {
@@ -106,7 +106,7 @@
String8 Tokenizer::getLocation() const {
String8 result;
- result.appendFormat("%s:%d", mFilename.string(), mLineNumber);
+ result.appendFormat("%s:%d", mFilename.c_str(), mLineNumber);
return result;
}
diff --git a/libutils/include/utils/String16.h b/libutils/include/utils/String16.h
index 3ef56a3..d719aea 100644
--- a/libutils/include/utils/String16.h
+++ b/libutils/include/utils/String16.h
@@ -53,6 +53,7 @@
~String16();
+ inline const char16_t* c_str() const;
inline const char16_t* string() const;
private:
@@ -234,6 +235,11 @@
return compare_type(lhs, rhs) < 0;
}
+inline const char16_t* String16::c_str() const
+{
+ return mString;
+}
+
inline const char16_t* String16::string() const
{
return mString;
@@ -241,7 +247,7 @@
inline std::string String16::std_string(const String16& str)
{
- return std::string(String8(str).string());
+ return std::string(String8(str).c_str());
}
inline String16& String16::operator=(const String16& other)
diff --git a/libutils/include/utils/String8.h b/libutils/include/utils/String8.h
index 8b2dcf9..e58f1a5 100644
--- a/libutils/include/utils/String8.h
+++ b/libutils/include/utils/String8.h
@@ -193,14 +193,14 @@
* replaces whatever was there before.
*/
String8& appendPath(const char* leaf);
- String8& appendPath(const String8& leaf) { return appendPath(leaf.string()); }
+ String8& appendPath(const String8& leaf) { return appendPath(leaf.c_str()); }
/*
* Like appendPath(), but does not affect this string. Returns a new one instead.
*/
String8 appendPathCopy(const char* leaf) const
{ String8 p(*this); p.appendPath(leaf); return p; }
- String8 appendPathCopy(const String8& leaf) const { return appendPathCopy(leaf.string()); }
+ String8 appendPathCopy(const String8& leaf) const { return appendPathCopy(leaf.c_str()); }
/*
* Converts all separators in this string to /, the default path separator.
@@ -255,7 +255,7 @@
inline std::string String8::std_string(const String8& str)
{
- return std::string(str.string());
+ return std::string(str.c_str());
}
inline size_t String8::size() const
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index 5218753..cc6b64a 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -98,20 +98,31 @@
ln -sf /data/user_de/0/com.android.shell/files/bugreports $(TARGET_ROOT_OUT)/bugreports; \
ln -sfn /sys/kernel/debug $(TARGET_ROOT_OUT)/d; \
ln -sf /storage/self/primary $(TARGET_ROOT_OUT)/sdcard
+
+ALL_ROOTDIR_SYMLINKS := \
+ $(TARGET_ROOT_OUT)/bin \
+ $(TARGET_ROOT_OUT)/etc \
+ $(TARGET_ROOT_OUT)/bugreports \
+ $(TARGET_ROOT_OUT)/d \
+ $(TARGET_ROOT_OUT)/sdcard
+
ifdef BOARD_USES_VENDORIMAGE
LOCAL_POST_INSTALL_CMD += ; mkdir -p $(TARGET_ROOT_OUT)/vendor
else
LOCAL_POST_INSTALL_CMD += ; ln -sf /system/vendor $(TARGET_ROOT_OUT)/vendor
+ ALL_ROOTDIR_SYMLINKS += $(TARGET_ROOT_OUT)/vendor
endif
ifdef BOARD_USES_PRODUCTIMAGE
LOCAL_POST_INSTALL_CMD += ; mkdir -p $(TARGET_ROOT_OUT)/product
else
LOCAL_POST_INSTALL_CMD += ; ln -sf /system/product $(TARGET_ROOT_OUT)/product
+ ALL_ROOTDIR_SYMLINKS += $(TARGET_ROOT_OUT)/product
endif
ifdef BOARD_USES_SYSTEM_EXTIMAGE
LOCAL_POST_INSTALL_CMD += ; mkdir -p $(TARGET_ROOT_OUT)/system_ext
else
LOCAL_POST_INSTALL_CMD += ; ln -sf /system/system_ext $(TARGET_ROOT_OUT)/system_ext
+ ALL_ROOTDIR_SYMLINKS += $(TARGET_ROOT_OUT)/system_ext
endif
ifdef BOARD_USES_METADATA_PARTITION
LOCAL_POST_INSTALL_CMD += ; mkdir -p $(TARGET_ROOT_OUT)/metadata
@@ -134,6 +145,18 @@
LOCAL_POST_INSTALL_CMD += ; ln -sf /vendor/odm/priv-app $(TARGET_ROOT_OUT)/odm/priv-app
LOCAL_POST_INSTALL_CMD += ; ln -sf /vendor/odm/usr $(TARGET_ROOT_OUT)/odm/usr
+ALL_ROOTDIR_SYMLINKS += \
+ $(TARGET_ROOT_OUT)/odm/app \
+ $(TARGET_ROOT_OUT)/odm/bin \
+ $(TARGET_ROOT_OUT)/odm/etc \
+ $(TARGET_ROOT_OUT)/odm/firmware \
+ $(TARGET_ROOT_OUT)/odm/framework \
+ $(TARGET_ROOT_OUT)/odm/lib \
+ $(TARGET_ROOT_OUT)/odm/lib64 \
+ $(TARGET_ROOT_OUT)/odm/overlay \
+ $(TARGET_ROOT_OUT)/odm/priv-app \
+ $(TARGET_ROOT_OUT)/odm/usr
+
# For /vendor_dlkm partition.
LOCAL_POST_INSTALL_CMD += ; mkdir -p $(TARGET_ROOT_OUT)/vendor_dlkm
@@ -144,6 +167,7 @@
# Note that /vendor_dlkm/lib is omitted because vendor DLKMs should be accessed
# via /vendor/lib/modules directly.
LOCAL_POST_INSTALL_CMD += ; ln -sf /vendor/vendor_dlkm/etc $(TARGET_ROOT_OUT)/vendor_dlkm/etc
+ALL_ROOTDIR_SYMLINKS += $(TARGET_ROOT_OUT)/vendor_dlkm/etc
# For /odm_dlkm partition.
LOCAL_POST_INSTALL_CMD += ; mkdir -p $(TARGET_ROOT_OUT)/odm_dlkm
@@ -154,6 +178,7 @@
# Note that /odm_dlkm/lib is omitted because odm DLKMs should be accessed
# via /odm/lib/modules directly.
LOCAL_POST_INSTALL_CMD += ; ln -sf /odm/odm_dlkm/etc $(TARGET_ROOT_OUT)/odm_dlkm/etc
+ALL_ROOTDIR_SYMLINKS += $(TARGET_ROOT_OUT)/odm_dlkm/etc
# For /system_dlkm partition
LOCAL_POST_INSTALL_CMD += ; mkdir -p $(TARGET_ROOT_OUT)/system_dlkm
@@ -162,6 +187,7 @@
LOCAL_POST_INSTALL_CMD += ; mkdir -p $(TARGET_ROOT_OUT)/cache
else
LOCAL_POST_INSTALL_CMD += ; ln -sf /data/cache $(TARGET_ROOT_OUT)/cache
+ ALL_ROOTDIR_SYMLINKS += $(TARGET_ROOT_OUT)/cache
endif
ifdef BOARD_ROOT_EXTRA_SYMLINKS
# BOARD_ROOT_EXTRA_SYMLINKS is a list of <target>:<link_name>.
@@ -169,14 +195,19 @@
$(eval p := $(subst :,$(space),$(s)))\
; mkdir -p $(dir $(TARGET_ROOT_OUT)/$(word 2,$(p))) \
; ln -sf $(word 1,$(p)) $(TARGET_ROOT_OUT)/$(word 2,$(p)))
+ ALL_ROOTDIR_SYMLINKS += $(foreach s,$(BOARD_ROOT_EXTRA_SYMLINKS),$(TARGET_ROOT_OUT)/$(call word-colon,2,$s))
endif
# The init symlink must be a post install command of a file that is to TARGET_ROOT_OUT.
# Since init.environ.rc is required for init and satisfies that requirement, we hijack it to create the symlink.
LOCAL_POST_INSTALL_CMD += ; ln -sf /system/bin/init $(TARGET_ROOT_OUT)/init
+ALL_ROOTDIR_SYMLINKS += $(TARGET_ROOT_OUT)/init
+
+ALL_DEFAULT_INSTALLED_MODULES += $(ALL_ROOTDIR_SYMLINKS)
include $(BUILD_SYSTEM)/base_rules.mk
+$(ALL_ROOTDIR_SYMLINKS): $(LOCAL_BUILT_MODULE)
$(LOCAL_BUILT_MODULE): $(LOCAL_PATH)/init.environ.rc.in
@echo "Generate: $< -> $@"
@mkdir -p $(dir $@)
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 8f01d93..0d31cdc 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -74,9 +74,7 @@
# become available. Note that this is executed as exec_start to ensure that
# the libraries are available to the processes started after this statement.
exec_start apexd-bootstrap
-
- # Generate linker config based on apex mounted in bootstrap namespace
- update_linker_config
+ perform_apex_config --bootstrap
# These must already exist by the time boringssl_self_test32 / boringssl_self_test64 run.
mkdir /dev/boringssl 0755 root root
diff --git a/trusty/OWNERS b/trusty/OWNERS
index 61b97c6..bf16912 100644
--- a/trusty/OWNERS
+++ b/trusty/OWNERS
@@ -3,6 +3,7 @@
danielangell@google.com
gmar@google.com
marcone@google.com
+mikemcternan@google.com
mmaurer@google.com
ncbray@google.com
swillden@google.com
diff --git a/trusty/keymaster/TrustyKeymaster.cpp b/trusty/keymaster/TrustyKeymaster.cpp
index ac98695..b118a20 100644
--- a/trusty/keymaster/TrustyKeymaster.cpp
+++ b/trusty/keymaster/TrustyKeymaster.cpp
@@ -218,6 +218,11 @@
ForwardCommand(KM_DELETE_ALL_KEYS, request, response);
}
+void TrustyKeymaster::DestroyAttestationIds(const DestroyAttestationIdsRequest& request,
+ DestroyAttestationIdsResponse* response) {
+ ForwardCommand(KM_DESTROY_ATTESTATION_IDS, request, response);
+}
+
void TrustyKeymaster::BeginOperation(const BeginOperationRequest& request,
BeginOperationResponse* response) {
ForwardCommand(KM_BEGIN_OPERATION, request, response);
diff --git a/trusty/keymaster/include/trusty_keymaster/TrustyKeymaster.h b/trusty/keymaster/include/trusty_keymaster/TrustyKeymaster.h
index 60d3f87..c50178b 100644
--- a/trusty/keymaster/include/trusty_keymaster/TrustyKeymaster.h
+++ b/trusty/keymaster/include/trusty_keymaster/TrustyKeymaster.h
@@ -55,6 +55,8 @@
void UpgradeKey(const UpgradeKeyRequest& request, UpgradeKeyResponse* response);
void DeleteKey(const DeleteKeyRequest& request, DeleteKeyResponse* response);
void DeleteAllKeys(const DeleteAllKeysRequest& request, DeleteAllKeysResponse* response);
+ void DestroyAttestationIds(const DestroyAttestationIdsRequest& request,
+ DestroyAttestationIdsResponse* response);
void BeginOperation(const BeginOperationRequest& request, BeginOperationResponse* response);
void UpdateOperation(const UpdateOperationRequest& request, UpdateOperationResponse* response);
void FinishOperation(const FinishOperationRequest& request, FinishOperationResponse* response);
diff --git a/trusty/keymaster/keymint/TrustyKeyMintDevice.cpp b/trusty/keymaster/keymint/TrustyKeyMintDevice.cpp
index b696ff9..fec4c60 100644
--- a/trusty/keymaster/keymint/TrustyKeyMintDevice.cpp
+++ b/trusty/keymaster/keymint/TrustyKeyMintDevice.cpp
@@ -258,7 +258,11 @@
}
ScopedAStatus TrustyKeyMintDevice::destroyAttestationIds() {
- return kmError2ScopedAStatus(KM_ERROR_UNIMPLEMENTED);
+ keymaster::DestroyAttestationIdsRequest request(impl_->message_version());
+ keymaster::DestroyAttestationIdsResponse response(impl_->message_version());
+ impl_->DestroyAttestationIds(request, &response);
+
+ return kmError2ScopedAStatus(response.error);
}
ScopedAStatus TrustyKeyMintDevice::begin(KeyPurpose purpose, const vector<uint8_t>& keyBlob,
diff --git a/trusty/utils/coverage-controller/Android.bp b/trusty/utils/coverage-controller/Android.bp
index 1aa88cc..e6d30d9 100644
--- a/trusty/utils/coverage-controller/Android.bp
+++ b/trusty/utils/coverage-controller/Android.bp
@@ -17,7 +17,7 @@
}
cc_binary {
- name: "coverage-controller",
+ name: "trusty-coverage-controller",
vendor: true,
srcs: ["controller.cpp"],