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

Commit 748beaf8 authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "Initial Entry for bundler"

parents 2f5f9467 71ee51f9
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -206,8 +206,8 @@ cc_binary {
        ":BluetoothFacade_security_layer",
    ],
    generated_headers: [
        "BluetoothGeneratedPackets_h",
        "BluetoothFacadeGeneratedStub_h",
        "BluetoothGeneratedPackets_h",
        // Needed here to guarantee that generated zip file is created before
        // bluetooth_cert_tests.zip is packaged
        "BluetoothFacadeAndCertGeneratedStub_py",
@@ -221,11 +221,11 @@ cc_binary {
        "breakpad_client",
    ],
    shared_libs: [
        "libbacktrace",
        "libchrome",
        "libcrypto",
        "libgrpc++_unsecure",
        "libprotobuf-cpp-full",
        "libbacktrace",
    ],
    target: {
        android: {
+77 −0
Original line number Diff line number Diff line
filegroup {
    name: "BluetoothFlatbufferBundlerSources",
    srcs: [
        "bundler.cc",
        "main.cc",
    ],
}

filegroup {
    name: "BluetoothFlatbufferBundlerTestSources",
    srcs: [
        "bundler.cc",
        "test.cc",
    ],
}

genrule {
    name: "BluetoothGeneratedBundler_h",
    tools: [
        "flatc",
    ],
    cmd: "$(location flatc) -I packages/modules/Bluetooth/system/gd -b --schema -o $(genDir) --cpp $(in) ",
    srcs: [
        "bundler.fbs",
    ],
    out: [
        "bundler_generated.h", "bundler.bfbs",
    ],
}

cc_binary {
    name: "bluetooth_flatbuffer_bundler",
    host_supported: true,
    cflags: [
        "-Wall",
        "-Werror",
        "-Wno-unused-parameter",
        "-Wno-unused-variable",
    ],
    srcs: [
        ":BluetoothFlatbufferBundlerSources",
    ],
    generated_headers: [
        "BluetoothGeneratedBundler_h",
    ],
    shared_libs: [
        "libflatbuffers-cpp",
    ],
    sanitize: {
        address: true,
    },
}

cc_test {
    name: "bluetooth_flatbuffer_bundler_test",
    host_supported: true,
    cflags: [
        "-Wall",
        "-Werror",
        "-Wno-unused-parameter",
        "-Wno-unused-variable",
        "-DUSE_TEST_GENERATED",
    ],
    srcs: [
        ":BluetoothFlatbufferBundlerTestSources",
    ],
    shared_libs: [
        "libflatbuffers-cpp",
    ],
    sanitize: {
        address: true,
    },
    data: [
        "test.bfbs",
    ],
}
+309 −0
Original line number Diff line number Diff line
/*
 * Copyright 2020 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 <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <cassert>
#include <map>
#include <vector>

#include "bundler.h"
#include "flatbuffers/idl.h"
#include "flatbuffers/util.h"

#ifdef USE_TEST_GENERATED
#include "test_generated.h"
#else
#include "bundler_generated.h"  // Production
#endif

using namespace bluetooth;
using namespace dumpsys;

struct Opts opts;

/**
 * Load a binary schema from persistent store using flatbuffer API.
 *
 * @param filename; Name of file to open and read.
 * @param binary_schema: Backing store for flatbuffer binary schema data.
 *
 * @return: True if operation successful, false otherwise.
 */
bool LoadBinarySchema(const char* filename, std::string* binary_schema) {
  assert(filename != nullptr);
  assert(binary_schema != nullptr);
  if (!flatbuffers::LoadFile(filename, helper::AsBinaryFile, binary_schema)) {
    fprintf(stderr, "Unable to open binary flatbuffer schema file:%s\n", filename);
    return false;
  };
  return true;
}

/**
 * Verify a binary schema using flatbuffer API.
 *
 * @param schema: Raw binary schema to verify
 *
 * @return: True if operation successful, false otherwise.
 */
bool VerifyBinarySchema(const std::vector<const uint8_t>& raw_schema) {
  flatbuffers::Verifier verifier(raw_schema.data(), raw_schema.size());
  if (!reflection::VerifySchemaBuffer(verifier)) {
    return false;
  }
  return true;
}

/**
 * Bundle a set of binary flatbuffer schema into the bundler database.
 *
 * @param builder; Flatbuffer builder
 * @param filenames: Set of filenames to include in bundle
 * @param vector_map: Filename to filedata mapping
 *
 * @return: True if operation successful, false otherwise.
 */
bool CreateBinarySchemaBundle(
    flatbuffers::FlatBufferBuilder* builder,
    const std::vector<std::string>& filenames,
    std::vector<flatbuffers::Offset<BundleSchemaMap>>* vector_map) {
  assert(builder != nullptr);
  assert(vector_map != nullptr);

  for (auto filename : filenames) {
    std::string string_schema;
    if (!LoadBinarySchema(filename.c_str(), &string_schema)) {
      fprintf(stderr, "Unable to load binary schema from filename:%s\n", filename.c_str());
      return false;
    }
    std::vector<const uint8_t> raw_schema(string_schema.begin(), string_schema.end());
    if (!VerifyBinarySchema(raw_schema)) {
      fprintf(stderr, "Failed verification on binary schema filename:%s\n", filename.c_str());
      return false;
    }

    const reflection::Schema* schema = reflection::GetSchema(raw_schema.data());
    if (schema->root_table() == nullptr) {
      fprintf(stderr, "Unable to find root table for binary flatbuffer schema:%s\n", filename.c_str());
      return false;
    }

    auto name = builder->CreateString(schema->root_table()->name()->str());
    auto data = builder->CreateVector<uint8_t>(raw_schema.data(), raw_schema.size());
    vector_map->push_back(CreateBundleSchemaMap(*builder, name, data));

    if (opts.verbose) {
      fprintf(stdout, "Bundled binary schema file:%s\n", schema->root_table()->name()->c_str());
    }
  }
  return true;
}

/**
 * Write generated header file containing the bundled binary schema
 * data and meta data
 *
 * @param data: Source file data.
 * @param data_len: length of data
 */
void WriteHeaderFile(FILE* fp, const uint8_t* data, size_t data_len) {
  assert(fp != nullptr);
  std::string delim(kDefaultNamespaceDelim);
  std::string ns_string(opts.ns_name);
  std::vector<std::string> namespaces;

  size_t start = 0;
  size_t end = ns_string.find(delim);
  while (end != std::string::npos) {
    namespaces.push_back(ns_string.substr(start, end - start));
    start = end + delim.size();
    end = ns_string.find(delim, start);
  }
  if (start != 0 && start != std::string::npos) {
    namespaces.push_back(ns_string.substr(start));
  }

  fprintf(
      fp,
      "// Generated file by bluetooth_flatbuffer bundler\n"
      "#pragma once\n"
      "#include <sys/types.h>\n"
      "#include <string>\n");
  for_each(
      namespaces.begin(), namespaces.end(), [fp](const std::string& s) { fprintf(fp, "namespace %s {\n", s.c_str()); });
  fprintf(
      fp,
      "extern const unsigned char* data;\n"
      "extern const size_t data_size;\n"
      "const std::string& GetBundledSchemaData();\n");
  for_each(namespaces.crbegin(), namespaces.crend(), [fp](const std::string& s) {
    fprintf(fp, "}  // namespace %s\n", s.c_str());
  });
  fprintf(
      fp,
      "namespace {\n"
      "const unsigned char data_[] = {\n");

  for (auto i = 0; i < data_len; i++) {
    fprintf(fp, " 0x%02x", data[i]);
    if (i != data_len - 1) {
      fprintf(fp, ",");
    }
    if ((i + 1) % 16 == 0) {
      fprintf(fp, "\n");
    }
  }
  fprintf(fp, " };\n");
  fprintf(
      fp,
      "const std::string string_data_(data_, data_ + sizeof(data_));\n"
      "}  // namespace\n");
  fprintf(fp, "const unsigned char* %s::data = data_;\n", opts.ns_name);
  fprintf(fp, "const size_t %s::data_size = %zd;\n", opts.ns_name, data_len);
  fprintf(fp, "const std::string& %s::GetBundledSchemaData() { return string_data_; }\n", opts.ns_name);
}

int ReadBundledSchema() {
  const char* filename = opts.filename;
  assert(filename != nullptr);

  std::string flatfile_data;
  if (!flatbuffers::LoadFile(filename, helper::AsBinaryFile, &flatfile_data)) {
    fprintf(stderr, "Unable to load schema data file:%s\n", filename);
    return -5;
  }

  auto bundle_schema = flatbuffers::GetRoot<BundleSchema>(flatfile_data.c_str());
  const flatbuffers::Vector<flatbuffers::Offset<BundleSchemaMap>>* map = bundle_schema->map();

  fprintf(stdout, "Bundle schema title:%s\n", bundle_schema->title()->c_str());
  fprintf(stdout, "Bundle schema root:%s\n", bundle_schema->root()->c_str());
  int cnt = 0;
  for (auto it = map->cbegin(); it != map->cend(); ++it, cnt++) {
    fprintf(stdout, "   %d name:%s schema:%s\n", cnt, it->name()->c_str(), "schema");
  }
  return EXIT_SUCCESS;
}

int WriteBundledSchema() {
  const char* filename = opts.filename;
  assert(filename != nullptr);

  const char* main_root = opts.main_root;
  if (main_root == nullptr) {
    fprintf(stderr, "Must specify the name of the main root for this bundle\n");
    return EXIT_FAILURE;
  }

  std::vector<std::string> bfbs_filenames;
  for (int i = 0; i < opts.arg.c; i++) {
    bfbs_filenames.push_back(std::string(opts.arg.v[i]));
  }
  if (bfbs_filenames.empty()) {
    fprintf(stderr, "No bfbs files are specified to bundle\n");
    return EXIT_FAILURE;
  }

  flatbuffers::FlatBufferBuilder builder(1024);

  std::vector<flatbuffers::Offset<BundleSchemaMap>> vector_map;
  if (!CreateBinarySchemaBundle(&builder, bfbs_filenames, &vector_map)) {
    fprintf(stderr, "Unable to bundle schema bfbs files\n");
    return EXIT_FAILURE;
  }

  auto title = "Bundled schema tables";
  auto schema_offset = CreateBundleSchemaDirect(builder, title, main_root, &vector_map);
  builder.Finish(schema_offset);

  std::string final_filename(opts.gen);
  final_filename.append("/");
  final_filename.append(filename);
  if (!flatbuffers::SaveFile(
          final_filename.c_str(), (const char*)builder.GetBufferPointer(), builder.GetSize(), helper::AsBinaryFile)) {
    fprintf(stderr, "Unable to save file:%s\n", final_filename.c_str());
    return EXIT_FAILURE;
  }
  fprintf(
      stdout, "Successfully bundled %zd bfbs files into filename:%s\n", bfbs_filenames.size(), final_filename.c_str());

  std::string header(opts.gen);
  header += ("/" + std::string(opts.filename) + ".h");
  FILE* fp = fopen(header.c_str(), "w+");
  if (fp == nullptr) {
    fprintf(stdout, "Unable to open for writing header file:%s\n", header.c_str());
    return EXIT_FAILURE;
  }
  WriteHeaderFile(fp, builder.GetBufferPointer(), builder.GetSize());
  fclose(fp);
  return EXIT_SUCCESS;
}

int Usage(int argc, char** argv) {
  fprintf(
      stderr,
      "Usage: %s [-r | -w] [-f <filename>] [-g <gen_out_path>] [-n <namespace> ] [-v] -m <main_root> <file.bfbs ...>\n",
      argv[0]);
  fprintf(stderr, " -r|-w : Read or write a dumpsys file\n");
  fprintf(stderr, " -f : Filename bundled schema to read or write (default:%s)\n", kDefaultBundleDataFile);
  fprintf(stderr, " -g : Generated file output path\n");
  fprintf(stderr, " -n : Namespace to embed binary output bundle data source\n");
  fprintf(stderr, " -m : Name of the main root of this bundle\n");
  fprintf(stderr, " -v : Verbose printing mode\n");
  return EXIT_FAILURE;
}

void ParseArgs(int argc, char** argv) {
  int opt;
  int parsed_cnt = 1;
  while ((opt = getopt(argc, argv, "f:g:m:n:rvw")) != -1) {
    parsed_cnt++;
    switch (opt) {
      case 'f':
        opts.filename = optarg;
        parsed_cnt++;
        break;
      case 'g':
        opts.gen = optarg;
        parsed_cnt++;
        break;
      case 'm':
        opts.main_root = optarg;
        parsed_cnt++;
        break;
      case 'n':
        opts.ns_name = optarg;
        parsed_cnt++;
        break;
      case 'r':
        opts.read = true;
        break;
      case 'w':
        opts.write = true;
        break;
      case 'v':
        opts.verbose = true;
        break;
      default:
        exit(Usage(argc, argv));
        break;
    }
  }
  opts.arg.c = argc - parsed_cnt;
  opts.arg.v = &argv[parsed_cnt];
}
+19 −0
Original line number Diff line number Diff line
// Bundle Schema
//
// Describes a collection of binary flatbuffer schema.
//

namespace bluetooth.dumpsys;

table BundleSchemaMap {
    name:string;
    data:[ubyte];
}

table BundleSchema {
    title:string;
    root:string;
    map:[BundleSchemaMap];
}

root_type BundleSchema;
+68 −0
Original line number Diff line number Diff line
/*
 * Copyright 2020 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

namespace {
constexpr char kDefaultBundleDataFile[] = "bundle_bfbs.bin";
constexpr char kDefaultNamespace[] = "";
constexpr char kDefaultNamespaceDelim[] = "::";
}  // namespace

struct Opts {
  bool verbose{false};
  bool read{false};
  bool write{false};
  const char* filename{kDefaultBundleDataFile};
  const char* gen{nullptr};
  const char* main_root{nullptr};
  const char* ns_name{kDefaultNamespace};
  struct {
    int c{0};
    char** v{nullptr};
  } arg;
};
extern Opts opts;

namespace {
namespace helper {  // Part of flatbuffers API
constexpr bool AsBinaryFile = true;
constexpr bool AsTextFile = false;
}  // namespace helper

}  // namespace

/**
 * Read and parse a previously generated bundle data file
 *
 **/
int ReadBundledSchema();

/**
 * Generate a bundle data file from the binary flatbuffer schema
 * files provided as input
 *
 **/
int WriteBundledSchema();

/**
 * Print tool usage options
 */
int Usage(int argc, char** argv);

/**
 * Parse tool usage options
 */
void ParseArgs(int argc, char** argv);
Loading