Loading tools/aconfig/TEST_MAPPING +4 −0 Original line number Diff line number Diff line Loading @@ -81,6 +81,10 @@ // aconfig_storage write api rust integration tests "name": "aconfig_storage_write_api.test.rust" }, { // aconfig_storage write api cpp integration tests "name": "aconfig_storage_write_api.test.cpp" }, { // aconfig_storage read api rust integration tests "name": "aconfig_storage_read_api.test.rust" Loading tools/aconfig/aconfig_storage_write_api/Android.bp +44 −0 Original line number Diff line number Diff line Loading @@ -35,3 +35,47 @@ rust_test_host { "libaconfig_storage_read_api", ], } // cxx source codegen from rust api genrule { name: "libcxx_aconfig_storage_write_api_bridge_code", tools: ["cxxbridge"], cmd: "$(location cxxbridge) $(in) > $(out)", srcs: ["src/lib.rs"], out: ["aconfig_storage/lib.rs.cc"], } // cxx header codegen from rust api genrule { name: "libcxx_aconfig_storage_write_api_bridge_header", tools: ["cxxbridge"], cmd: "$(location cxxbridge) $(in) --header > $(out)", srcs: ["src/lib.rs"], out: ["aconfig_storage/lib.rs.h"], } // a static cc lib based on generated code rust_ffi_static { name: "libaconfig_storage_write_api_cxx_bridge", crate_name: "aconfig_storage_write_api_cxx_bridge", host_supported: true, defaults: ["aconfig_storage_write_api.defaults"], } // flag write api cc interface cc_library_static { name: "libaconfig_storage_write_api_cc", srcs: ["aconfig_storage_write_api.cpp"], generated_headers: [ "cxx-bridge-header", "libcxx_aconfig_storage_write_api_bridge_header" ], generated_sources: ["libcxx_aconfig_storage_write_api_bridge_code"], whole_static_libs: ["libaconfig_storage_write_api_cxx_bridge"], export_include_dirs: ["include"], static_libs: [ "libaconfig_storage_protos_cc", "libprotobuf-cpp-lite", "libbase", ], } tools/aconfig/aconfig_storage_write_api/Cargo.toml +1 −1 Original line number Diff line number Diff line Loading @@ -9,11 +9,11 @@ cargo = [] [dependencies] anyhow = "1.0.69" cxx = "1.0" memmap2 = "0.8.0" tempfile = "3.9.0" thiserror = "1.0.56" protobuf = "3.2.0" once_cell = "1.19.0" aconfig_storage_file = { path = "../aconfig_storage_file" } aconfig_storage_read_api = { path = "../aconfig_storage_read_api" } Loading tools/aconfig/aconfig_storage_write_api/aconfig_storage_write_api.cpp 0 → 100644 +124 −0 Original line number Diff line number Diff line #include <android-base/file.h> #include <android-base/logging.h> #include <protos/aconfig_storage_metadata.pb.h> #include <sys/mman.h> #include <sys/stat.h> #include <fcntl.h> #include "rust/cxx.h" #include "aconfig_storage/lib.rs.h" #include "aconfig_storage/aconfig_storage_write_api.hpp" 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 aconfig_storage { /// Storage location pb file static constexpr char kPersistStorageRecordsPb[] = "/metadata/aconfig/persistent_storage_file_records.pb"; /// Read aconfig storage records pb file static Result<storage_records_pb> read_storage_records_pb(std::string const& pb_file) { auto records = storage_records_pb(); auto content = std::string(); if (!ReadFileToString(pb_file, &content)) { return ErrnoError() << "ReadFileToString failed"; } if (!records.ParseFromString(content)) { return ErrnoError() << "Unable to parse persistent storage records protobuf"; } return records; } /// Get storage file path static Result<std::string> find_storage_file( std::string const& pb_file, std::string const& container) { auto records_pb = read_storage_records_pb(pb_file); if (!records_pb.ok()) { return Error() << "Unable to read storage records from " << pb_file << " : " << records_pb.error(); } for (auto& entry : records_pb->files()) { if (entry.container() == container) { return entry.flag_val(); } } return Error() << "Unable to find storage files for container " << container;; } /// Map a storage file static Result<MappedFlagValueFile> map_storage_file(std::string const& file) { struct stat file_stat; if (stat(file.c_str(), &file_stat) < 0) { return Error() << "fstat failed"; } if ((file_stat.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)) == 0) { return Error() << "cannot map nonwriteable file"; } size_t file_size = file_stat.st_size; const int fd = open(file.c_str(), O_RDWR | O_NOFOLLOW | O_CLOEXEC); if (fd == -1) { return Error() << "failed to open " << file; }; void* const map_result = mmap(nullptr, file_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (map_result == MAP_FAILED) { return Error() << "mmap failed"; } auto mapped_file = MappedFlagValueFile(); mapped_file.file_ptr = map_result; mapped_file.file_size = file_size; return mapped_file; } namespace private_internal_api { /// Get mapped file implementation. Result<MappedFlagValueFile> get_mapped_flag_value_file_impl( std::string const& pb_file, std::string const& container) { auto file_result = find_storage_file(pb_file, container); if (!file_result.ok()) { return Error() << file_result.error(); } return map_storage_file(*file_result); } } // namespace private internal api /// Get mapped writeable flag value file Result<MappedFlagValueFile> get_mapped_flag_value_file( std::string const& container) { return private_internal_api::get_mapped_flag_value_file_impl( kPersistStorageRecordsPb, container); } /// Set boolean flag value Result<void> set_boolean_flag_value( const MappedFlagValueFile& file, uint32_t offset, bool value) { auto content = rust::Slice<uint8_t>( static_cast<uint8_t*>(file.file_ptr), file.file_size); auto update_cxx = update_boolean_flag_value_cxx(content, offset, value); if (!update_cxx.update_success) { return Error() << std::string(update_cxx.error_message.c_str()); } return {}; } } // namespace aconfig_storage tools/aconfig/aconfig_storage_write_api/build.rs 0 → 100644 +4 −0 Original line number Diff line number Diff line fn main() { let _ = cxx_build::bridge("src/lib.rs"); println!("cargo:rerun-if-changed=src/lib.rs"); } Loading
tools/aconfig/TEST_MAPPING +4 −0 Original line number Diff line number Diff line Loading @@ -81,6 +81,10 @@ // aconfig_storage write api rust integration tests "name": "aconfig_storage_write_api.test.rust" }, { // aconfig_storage write api cpp integration tests "name": "aconfig_storage_write_api.test.cpp" }, { // aconfig_storage read api rust integration tests "name": "aconfig_storage_read_api.test.rust" Loading
tools/aconfig/aconfig_storage_write_api/Android.bp +44 −0 Original line number Diff line number Diff line Loading @@ -35,3 +35,47 @@ rust_test_host { "libaconfig_storage_read_api", ], } // cxx source codegen from rust api genrule { name: "libcxx_aconfig_storage_write_api_bridge_code", tools: ["cxxbridge"], cmd: "$(location cxxbridge) $(in) > $(out)", srcs: ["src/lib.rs"], out: ["aconfig_storage/lib.rs.cc"], } // cxx header codegen from rust api genrule { name: "libcxx_aconfig_storage_write_api_bridge_header", tools: ["cxxbridge"], cmd: "$(location cxxbridge) $(in) --header > $(out)", srcs: ["src/lib.rs"], out: ["aconfig_storage/lib.rs.h"], } // a static cc lib based on generated code rust_ffi_static { name: "libaconfig_storage_write_api_cxx_bridge", crate_name: "aconfig_storage_write_api_cxx_bridge", host_supported: true, defaults: ["aconfig_storage_write_api.defaults"], } // flag write api cc interface cc_library_static { name: "libaconfig_storage_write_api_cc", srcs: ["aconfig_storage_write_api.cpp"], generated_headers: [ "cxx-bridge-header", "libcxx_aconfig_storage_write_api_bridge_header" ], generated_sources: ["libcxx_aconfig_storage_write_api_bridge_code"], whole_static_libs: ["libaconfig_storage_write_api_cxx_bridge"], export_include_dirs: ["include"], static_libs: [ "libaconfig_storage_protos_cc", "libprotobuf-cpp-lite", "libbase", ], }
tools/aconfig/aconfig_storage_write_api/Cargo.toml +1 −1 Original line number Diff line number Diff line Loading @@ -9,11 +9,11 @@ cargo = [] [dependencies] anyhow = "1.0.69" cxx = "1.0" memmap2 = "0.8.0" tempfile = "3.9.0" thiserror = "1.0.56" protobuf = "3.2.0" once_cell = "1.19.0" aconfig_storage_file = { path = "../aconfig_storage_file" } aconfig_storage_read_api = { path = "../aconfig_storage_read_api" } Loading
tools/aconfig/aconfig_storage_write_api/aconfig_storage_write_api.cpp 0 → 100644 +124 −0 Original line number Diff line number Diff line #include <android-base/file.h> #include <android-base/logging.h> #include <protos/aconfig_storage_metadata.pb.h> #include <sys/mman.h> #include <sys/stat.h> #include <fcntl.h> #include "rust/cxx.h" #include "aconfig_storage/lib.rs.h" #include "aconfig_storage/aconfig_storage_write_api.hpp" 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 aconfig_storage { /// Storage location pb file static constexpr char kPersistStorageRecordsPb[] = "/metadata/aconfig/persistent_storage_file_records.pb"; /// Read aconfig storage records pb file static Result<storage_records_pb> read_storage_records_pb(std::string const& pb_file) { auto records = storage_records_pb(); auto content = std::string(); if (!ReadFileToString(pb_file, &content)) { return ErrnoError() << "ReadFileToString failed"; } if (!records.ParseFromString(content)) { return ErrnoError() << "Unable to parse persistent storage records protobuf"; } return records; } /// Get storage file path static Result<std::string> find_storage_file( std::string const& pb_file, std::string const& container) { auto records_pb = read_storage_records_pb(pb_file); if (!records_pb.ok()) { return Error() << "Unable to read storage records from " << pb_file << " : " << records_pb.error(); } for (auto& entry : records_pb->files()) { if (entry.container() == container) { return entry.flag_val(); } } return Error() << "Unable to find storage files for container " << container;; } /// Map a storage file static Result<MappedFlagValueFile> map_storage_file(std::string const& file) { struct stat file_stat; if (stat(file.c_str(), &file_stat) < 0) { return Error() << "fstat failed"; } if ((file_stat.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)) == 0) { return Error() << "cannot map nonwriteable file"; } size_t file_size = file_stat.st_size; const int fd = open(file.c_str(), O_RDWR | O_NOFOLLOW | O_CLOEXEC); if (fd == -1) { return Error() << "failed to open " << file; }; void* const map_result = mmap(nullptr, file_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (map_result == MAP_FAILED) { return Error() << "mmap failed"; } auto mapped_file = MappedFlagValueFile(); mapped_file.file_ptr = map_result; mapped_file.file_size = file_size; return mapped_file; } namespace private_internal_api { /// Get mapped file implementation. Result<MappedFlagValueFile> get_mapped_flag_value_file_impl( std::string const& pb_file, std::string const& container) { auto file_result = find_storage_file(pb_file, container); if (!file_result.ok()) { return Error() << file_result.error(); } return map_storage_file(*file_result); } } // namespace private internal api /// Get mapped writeable flag value file Result<MappedFlagValueFile> get_mapped_flag_value_file( std::string const& container) { return private_internal_api::get_mapped_flag_value_file_impl( kPersistStorageRecordsPb, container); } /// Set boolean flag value Result<void> set_boolean_flag_value( const MappedFlagValueFile& file, uint32_t offset, bool value) { auto content = rust::Slice<uint8_t>( static_cast<uint8_t*>(file.file_ptr), file.file_size); auto update_cxx = update_boolean_flag_value_cxx(content, offset, value); if (!update_cxx.update_success) { return Error() << std::string(update_cxx.error_message.c_str()); } return {}; } } // namespace aconfig_storage
tools/aconfig/aconfig_storage_write_api/build.rs 0 → 100644 +4 −0 Original line number Diff line number Diff line fn main() { let _ = cxx_build::bridge("src/lib.rs"); println!("cargo:rerun-if-changed=src/lib.rs"); }