Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1fdb6cc4 authored by Dennis Shen's avatar Dennis Shen
Browse files

aconfig_storage: create aconfig storage c++ flag value write api

Bug: b/312444587
Test: atest aconfig_storage_write_api.test.cpp
Change-Id: Ib08575b7e6ca23141ebbf739bf604a66da472dc2
parent 7c30411d
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -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"
+44 −0
Original line number Diff line number Diff line
@@ -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",
    ],
}
+1 −1
Original line number Diff line number Diff line
@@ -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" }

+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
+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