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

Commit 423f0d10 authored by Tianjie Xu's avatar Tianjie Xu Committed by Gerrit Code Review
Browse files

Merge "Consolidate the vendor space misc usage for Pixels"

parents 8834b4ea 3d57c844
Loading
Loading
Loading
Loading
+3 −34
Original line number Diff line number Diff line
@@ -45,7 +45,7 @@ void SetMiscBlockDeviceForTest(std::string_view misc_device) {
  g_misc_device_for_test = misc_device;
}

static std::string get_misc_blk_device(std::string* err) {
std::string get_misc_blk_device(std::string* err) {
  if (g_misc_device_for_test.has_value() && !g_misc_device_for_test->empty()) {
    return *g_misc_device_for_test;
  }
@@ -111,7 +111,7 @@ static bool read_misc_partition(void* p, size_t size, const std::string& misc_bl
  return true;
}

static bool write_misc_partition(const void* p, size_t size, const std::string& misc_blk_device,
bool write_misc_partition(const void* p, size_t size, const std::string& misc_blk_device,
                          size_t offset, std::string* err) {
  android::base::unique_fd fd(open(misc_blk_device.c_str(), O_WRONLY));
  if (fd == -1) {
@@ -261,37 +261,6 @@ bool write_wipe_package(const std::string& package_data, std::string* err) {
                              WIPE_PACKAGE_OFFSET_IN_MISC, err);
}

static bool OffsetAndSizeInVendorSpace(size_t offset, size_t size) {
  auto total_size = WIPE_PACKAGE_OFFSET_IN_MISC - VENDOR_SPACE_OFFSET_IN_MISC;
  return size <= total_size && offset <= total_size - size;
}

bool ReadMiscPartitionVendorSpace(void* data, size_t size, size_t offset, std::string* err) {
  if (!OffsetAndSizeInVendorSpace(offset, size)) {
    *err = android::base::StringPrintf("Out of bound read (offset %zu size %zu)", offset, size);
    return false;
  }
  auto misc_blk_device = get_misc_blk_device(err);
  if (misc_blk_device.empty()) {
    return false;
  }
  return read_misc_partition(data, size, misc_blk_device, VENDOR_SPACE_OFFSET_IN_MISC + offset,
                             err);
}

bool WriteMiscPartitionVendorSpace(const void* data, size_t size, size_t offset, std::string* err) {
  if (!OffsetAndSizeInVendorSpace(offset, size)) {
    *err = android::base::StringPrintf("Out of bound write (offset %zu size %zu)", offset, size);
    return false;
  }
  auto misc_blk_device = get_misc_blk_device(err);
  if (misc_blk_device.empty()) {
    return false;
  }
  return write_misc_partition(data, size, misc_blk_device, VENDOR_SPACE_OFFSET_IN_MISC + offset,
                              err);
}

static bool ValidateSystemSpaceRegion(size_t offset, size_t size, std::string* err) {
  if (size <= SYSTEM_SPACE_SIZE_IN_MISC && offset <= (SYSTEM_SPACE_SIZE_IN_MISC - size)) {
    return true;
+7 −8
Original line number Diff line number Diff line
@@ -212,11 +212,18 @@ struct misc_system_space_layout {
#include <string>
#include <vector>

// Gets the block device name of /misc partition.
std::string get_misc_blk_device(std::string* err);
// Return the block device name for the bootloader message partition and waits
// for the device for up to 10 seconds. In case of error returns the empty
// string.
std::string get_bootloader_message_blk_device(std::string* err);

// Writes |size| bytes of data from buffer |p| to |misc_blk_device| at |offset|. If the write fails,
// sets the error message in |err|.
bool write_misc_partition(const void* p, size_t size, const std::string& misc_blk_device,
                          size_t offset, std::string* err);

// Read bootloader message into boot. Error message will be set in err.
bool read_bootloader_message(bootloader_message* boot, std::string* err);

@@ -261,14 +268,6 @@ bool read_wipe_package(std::string* package_data, size_t size, std::string* err)
// Write the wipe package into BCB (to offset WIPE_PACKAGE_OFFSET_IN_MISC).
bool write_wipe_package(const std::string& package_data, std::string* err);

// Reads data from the vendor space in /misc partition, with the given offset and size. Note that
// offset is in relative to the start of vendor space.
bool ReadMiscPartitionVendorSpace(void* data, size_t size, size_t offset, std::string* err);

// Writes the given data to the vendor space in /misc partition, at the given offset. Note that
// offset is in relative to the start of the vendor space.
bool WriteMiscPartitionVendorSpace(const void* data, size_t size, size_t offset, std::string* err);

// Read or write the Virtual A/B message from system space in /misc.
bool ReadMiscVirtualAbMessage(misc_virtual_ab_message* message, std::string* err);
bool WriteMiscVirtualAbMessage(const misc_virtual_ab_message& message, std::string* err);
+75 −5
Original line number Diff line number Diff line
@@ -14,14 +14,30 @@
// limitations under the License.
//

cc_binary {
    name: "misc_writer",
cc_defaults {
    name: "misc_writer_defaults",
    vendor: true,
    cpp_std: "experimental",

    srcs: [
        "misc_writer.cpp",
    cflags: [
        "-Wall",
        "-Werror",
    ],

    shared_libs: [
        "libbase",
    ],

    static_libs: [
        "libbootloader_message_vendor",
        "libfstab",
    ],
}

// TODO(xunchang) Remove duplicates after we convert the device specific librecovery_ui to recovery
// module. Then libmisc_writer can build as a vendor module available in recovery.
cc_library_static {
    name: "libmisc_writer",
    cpp_std: "experimental",

    cflags: [
@@ -34,7 +50,61 @@ cc_binary {
    ],

    static_libs: [
        "libbootloader_message_vendor",
        "libbootloader_message",
        "libfstab",
    ],

    srcs: [
        "misc_writer.cpp",
    ],

    export_include_dirs: [
        "include",
    ],
}

cc_library_static {
    name: "libmisc_writer_vendor",
    defaults: [
        "misc_writer_defaults",
    ],

    srcs: [
        "misc_writer.cpp",
    ],

    export_include_dirs: [
        "include",
    ],
}

cc_binary {
    name: "misc_writer",
    defaults: [
        "misc_writer_defaults",
    ],

    srcs: [
        "misc_writer_main.cpp",
    ],

    static_libs: [
        "libmisc_writer_vendor",
    ]
}

cc_test {
    name: "misc_writer_test",
    defaults: [
        "misc_writer_defaults",
    ],

    srcs: [
        "misc_writer_test.cpp",
    ],
    test_suites: ["device-tests"],

    static_libs: [
        "libmisc_writer_vendor",
    ]
}
+66 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 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 <stddef.h>
#include <stdint.h>

#include <optional>
#include <string>

namespace android {
namespace hardware {
namespace google {
namespace pixel {

enum class MiscWriterActions : int32_t {
  kSetDarkThemeFlag = 0,
  kClearDarkThemeFlag,
  kSetSotaFlag,
  kClearSotaFlag,

  kUnset = -1,
};

class MiscWriter {
 public:
  static constexpr uint32_t kThemeFlagOffsetInVendorSpace = 0;
  static constexpr char kDarkThemeFlag[] = "theme-dark";
  static constexpr uint32_t kSotaFlagOffsetInVendorSpace = 32;
  static constexpr char kSotaFlag[] = "enable-sota";

  // Returns true of |size| bytes data starting from |offset| is fully inside the vendor space.
  static bool OffsetAndSizeInVendorSpace(size_t offset, size_t size);
  // Writes the given data to the vendor space in /misc partition, at the given offset. Note that
  // offset is in relative to the start of the vendor space.
  static bool WriteMiscPartitionVendorSpace(const void* data, size_t size, size_t offset,
                                            std::string* err);

  explicit MiscWriter(const MiscWriterActions& action) : action_(action) {}

  // Performs the stored MiscWriterActions. If |override_offset| is set, writes to the input offset
  // in the vendor space of /misc instead of the default offset.
  bool PerformAction(std::optional<size_t> override_offset = std::nullopt);

 private:
  MiscWriterActions action_{ MiscWriterActions::kUnset };
};

}  // namespace pixel
}  // namespace google
}  // namespace hardware
}  // namespace android
+52 −75
Original line number Diff line number Diff line
@@ -14,93 +14,70 @@
 * limitations under the License.
 */

#include <errno.h>
#include <getopt.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include "misc_writer/misc_writer.h"

#include <iostream>
#include <string>
#include <string_view>
#include <vector>
#include <string.h>

#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/parseint.h>
#include <android-base/stringprintf.h>
#include <bootloader_message/bootloader_message.h>

using namespace std::string_literals;
namespace android {
namespace hardware {
namespace google {
namespace pixel {

static std::vector<uint8_t> ParseHexString(std::string_view hex_string) {
  auto length = hex_string.size();
  if (length % 2 != 0 || length == 0) {
    return {};
bool MiscWriter::OffsetAndSizeInVendorSpace(size_t offset, size_t size) {
  auto total_size = WIPE_PACKAGE_OFFSET_IN_MISC - VENDOR_SPACE_OFFSET_IN_MISC;
  return size <= total_size && offset <= total_size - size;
}

  std::vector<uint8_t> result(length / 2);
  for (size_t i = 0; i < length / 2; i++) {
    auto sub = "0x" + std::string(hex_string.substr(i * 2, 2));
    if (!android::base::ParseUint(sub, &result[i])) {
      return {};
bool MiscWriter::WriteMiscPartitionVendorSpace(const void* data, size_t size, size_t offset,
                                               std::string* err) {
  if (!OffsetAndSizeInVendorSpace(offset, size)) {
    *err = android::base::StringPrintf("Out of bound write (offset %zu size %zu)", offset, size);
    return false;
  }
  auto misc_blk_device = get_misc_blk_device(err);
  if (misc_blk_device.empty()) {
    return false;
  }
  return result;
  return write_misc_partition(data, size, misc_blk_device, VENDOR_SPACE_OFFSET_IN_MISC + offset,
                              err);
}

static int Usage(std::string_view name) {
  std::cerr << name << " usage:\n";
  std::cerr << name << " [--vendor-space-offset <offset>] --hex-string 0xABCDEF\n";
  std::cerr << "Writes the given hex string to the specified offset in vendor space in /misc "
               "partition. Offset defaults to 0 if unspecified.\n";
  return EXIT_FAILURE;
}

// misc_writer is a vendor tool that writes data to the vendor space in /misc.
int main(int argc, char** argv) {
  constexpr struct option OPTIONS[] = {
    { "vendor-space-offset", required_argument, nullptr, 0 },
    { "hex-string", required_argument, nullptr, 0 },
    { nullptr, 0, nullptr, 0 },
  };

  // Offset defaults to 0 if unspecified.
bool MiscWriter::PerformAction(std::optional<size_t> override_offset) {
  size_t offset = 0;
  std::string_view hex_string;

  int arg;
  int option_index;
  while ((arg = getopt_long(argc, argv, "", OPTIONS, &option_index)) != -1) {
    if (arg != 0) {
      LOG(ERROR) << "Invalid command argument";
      return Usage(argv[0]);
    }
    auto option_name = OPTIONS[option_index].name;
    if (option_name == "vendor-space-offset"s) {
      if (!android::base::ParseUint(optarg, &offset)) {
        LOG(ERROR) << "Failed to parse the offset: " << optarg;
        return Usage(argv[0]);
      }
    } else if (option_name == "hex-string"s) {
      hex_string = optarg;
    }
  std::string content;
  switch (action_) {
    case MiscWriterActions::kSetDarkThemeFlag:
    case MiscWriterActions::kClearDarkThemeFlag:
      offset = override_offset.value_or(kThemeFlagOffsetInVendorSpace);
      content = (action_ == MiscWriterActions::kSetDarkThemeFlag)
                    ? kDarkThemeFlag
                    : std::string(strlen(kDarkThemeFlag), 0);
      break;
    case MiscWriterActions::kSetSotaFlag:
    case MiscWriterActions::kClearSotaFlag:
      offset = override_offset.value_or(kSotaFlagOffsetInVendorSpace);
      content = (action_ == MiscWriterActions::kSetSotaFlag) ? kSotaFlag
                                                             : std::string(strlen(kSotaFlag), 0);
      break;
    case MiscWriterActions::kUnset:
      LOG(ERROR) << "The misc writer action must be set";
      return false;
  }

  if (hex_string.starts_with("0x") || hex_string.starts_with("0X")) {
    hex_string = hex_string.substr(2);
  if (std::string err;
      !WriteMiscPartitionVendorSpace(content.data(), content.size(), offset, &err)) {
    LOG(ERROR) << "Failed to write " << content << " at offset " << offset << " : " << err;
    return false;
  }
  if (hex_string.empty()) {
    LOG(ERROR) << "Invalid input hex string: " << hex_string;
    return Usage(argv[0]);
  return true;
}

  auto data = ParseHexString(hex_string);
  if (data.empty()) {
    LOG(ERROR) << "Failed to parse the input hex string: " << hex_string;
    return EXIT_FAILURE;
  }
  if (std::string err; !WriteMiscPartitionVendorSpace(data.data(), data.size(), offset, &err)) {
    LOG(ERROR) << "Failed to write to misc partition: " << err;
    return EXIT_FAILURE;
  }
  return EXIT_SUCCESS;
}
}  // namespace pixel
}  // namespace google
}  // namespace hardware
}  // namespace android
Loading