Snap for 11510257 from f22d89be8fb40b62762fbc1850da1488b1ec3222 to simpleperf-release
Change-Id: I9ccadbb65f9bebb4ebe23bb7df799c465052e0c8
diff --git a/aconfigd/.clang-format b/aconfigd/.clang-format
new file mode 100644
index 0000000..f6cb8ad
--- /dev/null
+++ b/aconfigd/.clang-format
@@ -0,0 +1 @@
+BasedOnStyle: Google
diff --git a/aconfigd/Android.bp b/aconfigd/Android.bp
new file mode 100644
index 0000000..d77ec33
--- /dev/null
+++ b/aconfigd/Android.bp
@@ -0,0 +1,17 @@
+cc_binary {
+ name: "aconfigd",
+ srcs: [
+ "aconfigd.cpp",
+ "aconfigd.proto",
+ "aconfigd_main.cpp",
+ "aconfigd_util.cpp",
+ ],
+ static_libs: [
+ "libaconfig_storage_protos_cc",
+ "libprotobuf-cpp-lite",
+ "libbase",
+ "libcutils",
+ "liblog",
+ ],
+ init_rc: ["aconfigd.rc"],
+}
diff --git a/aconfigd/aconfigd.cpp b/aconfigd/aconfigd.cpp
new file mode 100644
index 0000000..525c1d4
--- /dev/null
+++ b/aconfigd/aconfigd.cpp
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2024 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 <string>
+#include <unordered_map>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <cutils/sockets.h>
+#include <protos/aconfig_storage_metadata.pb.h>
+#include <aconfigd.pb.h>
+
+#include "aconfigd_util.h"
+#include "aconfigd.h"
+
+using storage_records_pb = android::aconfig_storage_metadata::storage_files;
+using storage_record_pb = android::aconfig_storage_metadata::storage_file_info;
+using namespace android::base;
+
+namespace android {
+namespace aconfigd {
+
+/// Persistent storage records pb file full path
+static constexpr char kPersistentStorageRecordsFileName[] =
+ "/metadata/aconfig/persistent_storage_file_records.pb";
+
+/// In memory data structure for storage file locations for each container
+struct StorageRecord {
+ int version;
+ std::string container;
+ std::string package_map;
+ std::string flag_map;
+ std::string flag_val;
+ int timestamp;
+
+ StorageRecord() = default;
+
+ StorageRecord(storage_record_pb const& entry)
+ : version(entry.version())
+ , container(entry.container())
+ , package_map(entry.package_map())
+ , flag_map(entry.flag_map())
+ , flag_val(entry.flag_val())
+ , timestamp(entry.timestamp())
+ {}
+};
+
+/// A map from container name to the respective storage file locations
+using StorageRecords = std::unordered_map<std::string, StorageRecord>;
+
+/// In memort storage file records. Parsed from the pb.
+static StorageRecords storage_records;
+
+namespace {
+
+/// Read persistent aconfig storage records pb file
+Result<storage_records_pb> ReadPersistentStorageRecordsPb() {
+ auto records = storage_records_pb();
+ if (FileExists(kPersistentStorageRecordsFileName)) {
+ auto content = std::string();
+ if (!ReadFileToString(kPersistentStorageRecordsFileName, &content)) {
+ return ErrnoError() << "ReadFileToString failed";
+ }
+
+ if (!records.ParseFromString(content)) {
+ return ErrnoError() << "Unable to parse persistent storage records protobuf";
+ }
+ }
+ return records;
+}
+
+/// Write in memory aconfig storage records to the persistent pb file
+Result<void> WritePersistentStorageRecordsToFile() {
+ auto records_pb = storage_records_pb();
+ for (auto const& [container, entry] : storage_records) {
+ auto* record_pb = records_pb.add_files();
+ record_pb->set_version(entry.version);
+ record_pb->set_container(entry.container);
+ record_pb->set_package_map(entry.package_map);
+ record_pb->set_flag_map(entry.flag_map);
+ record_pb->set_flag_val(entry.flag_val);
+ record_pb->set_timestamp(entry.timestamp);
+ }
+
+ auto content = std::string();
+ if (!records_pb.SerializeToString(&content)) {
+ return ErrnoError() << "Unable to serialize storage records protobuf";
+ }
+
+ if (!WriteStringToFile(content, kPersistentStorageRecordsFileName)) {
+ return ErrnoError() << "ReadStringToFile failed";
+ }
+
+ return {};
+}
+
+/// Initialize in memory aconfig storage records
+Result<void> InitializeInMemoryStorageRecords() {
+ auto records_pb = ReadPersistentStorageRecordsPb();
+ if (!records_pb.ok()) {
+ return Error() << "Unable to write to persistent storage records: "
+ << records_pb.error();
+ }
+
+ storage_records.clear();
+ for (auto& entry : records_pb->files()) {
+ storage_records.insert({entry.container(), StorageRecord(entry)});
+ }
+
+ return {};
+}
+
+} // namespace
+
+/// Initialize platform RO partition flag storage
+Result<void> InitializePlatformStorage() {
+ auto init_result = InitializeInMemoryStorageRecords();
+ if (!init_result.ok()) {
+ return Error() << "Failed to initialize persistent storage records in memory: "
+ << init_result.error();
+ }
+
+ auto value_files = std::vector<std::pair<std::string, std::string>>{
+ {"system", "/system/etc"},
+ {"system_ext", "/system_ext/etc"},
+ {"vendor", "/vendor/etc"},
+ {"product", "/product/etc"}};
+
+ bool update_persistent_storage_records = false;
+ for (auto const& [container, storage_dir] : value_files) {
+ auto package_file = std::string(storage_dir) + "/package.map";
+ auto flag_file = std::string(storage_dir) + "/flag.map";
+ auto value_file = std::string(storage_dir) + "/flag.val";
+
+ if (!FileExists(value_file)) {
+ continue;
+ }
+
+ auto timestamp = GetFileTimeStamp(value_file);
+ if (!timestamp.ok()) {
+ return Error() << "Failed to get timestamp of " << value_file
+ << ": "<< timestamp.error();
+ }
+
+ auto it = storage_records.find(container);
+ if (it == storage_records.end() || it->second.timestamp != *timestamp) {
+ update_persistent_storage_records = true;
+ auto target_value_file = std::string("/metadata/aconfig/flags/") + container + ".val";
+ auto copy_result = CopyFile(value_file, target_value_file);
+ if (!copy_result.ok()) {
+ return Error() << "CopyFile failed for " << value_file << " :"
+ << copy_result.error();
+ }
+ auto& record = storage_records[container];
+ record.container = container;
+ record.package_map = package_file;
+ record.flag_map = flag_file;
+ record.flag_val = value_file;
+ record.timestamp = *timestamp;
+ }
+ }
+
+ if (update_persistent_storage_records) {
+ auto write_result = WritePersistentStorageRecordsToFile();
+ if (!write_result.ok()) {
+ return Error() << "Failed to write to persistent storage records file"
+ << write_result.error();
+ }
+ }
+
+ return {};
+}
+
+/// Handle incoming messages to aconfigd socket
+void HandleSocketRequest(const std::string& msg) {
+ auto message = StorageMessage{};
+ if (!message.ParseFromString(msg)) {
+ LOG(ERROR) << "Could not parse message from aconfig storage init socket";
+ return;
+ }
+
+ switch (message.msg_case()) {
+ case StorageMessage::kNewStorageMessage: {
+ // TODO
+ // Initialize for new storage
+ break;
+ }
+ case StorageMessage::kFlagOverrideMessage: {
+ // TODO
+ // Update flag value based
+ break;
+ }
+ default:
+ LOG(ERROR) << "Unknown message type from aconfigd socket: " << message.msg_case();
+ }
+}
+
+} // namespace aconfigd
+} // namespace android
diff --git a/aconfigd/aconfigd.h b/aconfigd/aconfigd.h
new file mode 100644
index 0000000..7fb6941
--- /dev/null
+++ b/aconfigd/aconfigd.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2024 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 <string>
+#include <android-base/result.h>
+
+namespace android {
+ namespace aconfigd {
+
+ /// Aconfigd socket name
+ static constexpr char kAconfigdSocket[] = "aconfigd";
+
+ /// Socket message buffer size
+ static constexpr size_t kBufferSize = 4096;
+
+ /// Initialize platform RO partition flag storages
+ base::Result<void> InitializePlatformStorage();
+
+ /// Handle incoming messages to aconfigd socket
+ void HandleSocketRequest(const std::string& msg);
+
+ } // namespace aconfigd
+} // namespace android
diff --git a/aconfigd/aconfigd.proto b/aconfigd/aconfigd.proto
new file mode 100644
index 0000000..96d784c
--- /dev/null
+++ b/aconfigd/aconfigd.proto
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+syntax = "proto2";
+option optimize_for = LITE_RUNTIME;
+
+message StorageMessage {
+ message NewStorageMessage {
+ optional string container_name = 1;
+ optional string package_map_file_path = 2;
+ optional string flag_map_file_path = 3;
+ optional string flag_value_file_path = 4;
+ }
+
+ message FlagOverrideMessage {
+ optional string package_name = 1;
+ optional string flag_name = 2;
+ optional string flag_value = 3;
+ }
+
+ oneof msg {
+ NewStorageMessage new_storage_message = 1;
+ FlagOverrideMessage flag_override_message = 2;
+ };
+}
diff --git a/aconfigd/aconfigd.rc b/aconfigd/aconfigd.rc
new file mode 100644
index 0000000..b2e8bb7
--- /dev/null
+++ b/aconfigd/aconfigd.rc
@@ -0,0 +1,8 @@
+service aconfigd /system/bin/aconfigd
+ class core
+ user system
+ group system
+ oneshot
+ disabled # does not start with the core class
+ reboot_on_failure reboot
+ socket aconfigd seqpacket 660 system system
diff --git a/aconfigd/aconfigd_main.cpp b/aconfigd/aconfigd_main.cpp
new file mode 100644
index 0000000..a592c58
--- /dev/null
+++ b/aconfigd/aconfigd_main.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2024 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 <android-base/logging.h>
+#include <android-base/unique_fd.h>
+#include <cutils/sockets.h>
+#include <sys/un.h>
+
+#include "aconfigd.h"
+
+using namespace android::aconfigd;
+
+int main(int argc, char** argv) {
+ (void)argc;
+ android::base::InitLogging(argv, &android::base::KernelLogger);
+
+ auto init_result = InitializePlatformStorage();
+ if (!init_result.ok()) {
+ LOG(ERROR) << "failed to initialize storage records: " << init_result.error();
+ return 1;
+ }
+
+ pid_t pid = fork();
+ if (pid < 0) {
+ PLOG(ERROR) << "failed to fork";
+ return 1;
+ } else if (pid != 0) {
+ return 0;
+ }
+
+ auto aconfigd_fd = android_get_control_socket(kAconfigdSocket);
+ if (aconfigd_fd == -1) {
+ PLOG(ERROR) << "failed to get aconfigd socket";
+ return 1;
+ }
+
+ if (listen(aconfigd_fd, 8) < 0) {
+ PLOG(ERROR) << "failed to listen to socket";
+ return 1;
+ };
+
+ while(true) {
+ auto client_fd = accept4(aconfigd_fd, nullptr, nullptr, SOCK_CLOEXEC);
+ if (client_fd == -1) {
+ PLOG(ERROR) << "failed to establish connection";
+ break;
+ }
+
+ char buffer[kBufferSize] = {};
+ auto num_bytes = TEMP_FAILURE_RETRY(recv(client_fd, buffer, sizeof(buffer), 0));
+ if (num_bytes < 0) {
+ PLOG(ERROR) << "failed to read from aconfigd socket";
+ break;
+ } else if (num_bytes == 0) {
+ LOG(ERROR) << "failed to read from aconfigd socket, empty message";
+ break;
+ }
+ auto msg = std::string(buffer, num_bytes);
+
+ HandleSocketRequest(msg);
+ }
+
+ return 1;
+}
diff --git a/aconfigd/aconfigd_util.cpp b/aconfigd/aconfigd_util.cpp
new file mode 100644
index 0000000..29720b6
--- /dev/null
+++ b/aconfigd/aconfigd_util.cpp
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2024 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 <android-base/logging.h>
+#include <android-base/unique_fd.h>
+#include <android-base/file.h>
+
+#include "aconfigd_util.h"
+
+using ::android::base::Result;
+using ::android::base::Error;
+using ::android::base::ErrnoError;
+
+namespace android {
+namespace aconfigd {
+
+/// Copy file
+Result<void> CopyFile(const std::string& src, const std::string& dst) {
+ android::base::unique_fd src_fd(
+ TEMP_FAILURE_RETRY(open(src.c_str(), O_RDONLY | O_NOFOLLOW | O_CLOEXEC)));
+ if (src_fd == -1) {
+ return ErrnoError() << "open() failed for " << src;
+ }
+
+ android::base::unique_fd dst_fd(TEMP_FAILURE_RETRY(
+ open(dst.c_str(), O_WRONLY | O_CREAT | O_NOFOLLOW | O_TRUNC | O_CLOEXEC, 0600)));
+ if (dst_fd == -1) {
+ return ErrnoError() << "open() failed for " << dst;
+ }
+
+ struct stat st;
+ if (fstat(src_fd.get(), &st) == -1) {
+ return ErrnoError() << "fstat failed()";
+ }
+ auto len = st.st_size;
+
+ off_t ret;
+ do {
+ ret = copy_file_range(src_fd, NULL, dst_fd, NULL, len, 0);
+ if (ret == -1) {
+ return ErrnoError() << "copy_file_range failed";
+ }
+ len -= ret;
+ } while (len > 0 && ret > 0);
+
+ return {};
+}
+
+/// Get a file's timestamp
+Result<int> GetFileTimeStamp(const std::string& file) {
+ struct stat st;
+ int result = stat(file.c_str(), &st);
+ if (result == -1) {
+ return ErrnoError() << "stat() failed";
+ }
+ return static_cast<int>(st.st_mtim.tv_sec);
+}
+
+bool FileExists(const std::string& file) {
+ struct stat st;
+ return stat(file.c_str(), &st) == 0 ? true : false;
+}
+
+} // namespace aconfig
+} // namespace android
diff --git a/aconfigd/aconfigd_util.h b/aconfigd/aconfigd_util.h
new file mode 100644
index 0000000..05c53f7
--- /dev/null
+++ b/aconfigd/aconfigd_util.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2024 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 <string>
+#include <android-base/result.h>
+
+namespace android {
+ namespace aconfigd {
+
+ /// Copy file
+ base::Result<void> CopyFile(const std::string& src, const std::string& dst);
+
+ /// Get a file's timestamp
+ base::Result<int> GetFileTimeStamp(const std::string& file);
+
+ /// Check if file exists
+ bool FileExists(const std::string& file);
+
+ }// namespace aconfig
+} // namespace android