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

Commit e71fe244 authored by Yifan Hong's avatar Yifan Hong
Browse files

fastboot driver: repack vendor boot ramdisk

When a user issues `fastboot flash vendor_boot:foo ramdisk.img`, the fastboot driver
fetches the vendor_boot image from the device,
determines if `foo` is a valid vendor ramdisk fragment,
repacks a new vendor boot image, then
flash the vendor boot image back.
This requires vendor boot header V4.

As a convinent alias, `fastboot flash vendor_boot:default ramdisk.img`
flashes the whole vendor ramdisk image. This works on vendor boot header
V3 & 4.

Fixes: 173654501
Test: pass

Change-Id: I42b2483a736ea8aa9fd9372b960502a642934cdc
parent 6d7da630
Loading
Loading
Loading
Loading
+34 −0
Original line number Diff line number Diff line
@@ -55,6 +55,7 @@ cc_library_host_static {
        "tcp.cpp",
        "udp.cpp",
        "util.cpp",
        "vendor_boot_img_utils.cpp",
        "fastboot_driver.cpp",
    ],

@@ -75,6 +76,7 @@ cc_library_host_static {
    ],

    header_libs: [
        "avb_headers",
        "bootimg_headers",
        "libstorage_literals_headers",
    ],
@@ -270,6 +272,7 @@ cc_library_host_static {
        "tcp.cpp",
        "udp.cpp",
        "util.cpp",
        "vendor_boot_img_utils.cpp",
        "fastboot_driver.cpp",
    ],

@@ -277,6 +280,7 @@ cc_library_host_static {
    use_version_lib: false,
    static_libs: ["libbuildversion"],
    header_libs: [
        "avb_headers",
        "libstorage_literals_headers",
    ],

@@ -370,3 +374,33 @@ cc_test_host {
        },
    },
}

cc_test_host {
    name: "fastboot_vendor_boot_img_utils_test",
    srcs: ["vendor_boot_img_utils_test.cpp"],
    static_libs: [
        "libbase",
        "libc++fs",
        "libfastboot",
        "libgmock",
        "liblog",
    ],
    header_libs: [
        "avb_headers",
        "bootimg_headers",
    ],
    cflags: [
        "-Wall",
        "-Werror",
    ],
    data: [
        ":fastboot_test_dtb",
        ":fastboot_test_bootconfig",
        ":fastboot_test_vendor_ramdisk_none",
        ":fastboot_test_vendor_ramdisk_platform",
        ":fastboot_test_vendor_ramdisk_replace",
        ":fastboot_test_vendor_boot_v3",
        ":fastboot_test_vendor_boot_v4_without_frag",
        ":fastboot_test_vendor_boot_v4_with_frag"
    ],
}
+37 −1
Original line number Diff line number Diff line
@@ -76,6 +76,7 @@
#include "udp.h"
#include "usb.h"
#include "util.h"
#include "vendor_boot_img_utils.h"

using android::base::borrowed_fd;
using android::base::ReadFully;
@@ -1292,6 +1293,40 @@ static void do_fetch(const std::string& partition, const std::string& slot_overr
    do_for_partitions(partition, slot_override, fetch, false /* force slot */);
}

// Return immediately if not flashing a vendor boot image. If flashing a vendor boot image,
// repack vendor_boot image with an updated ramdisk. After execution, buf is set
// to the new image to flash, and return value is the real partition name to flash.
static std::string repack_ramdisk(const char* pname, struct fastboot_buffer* buf) {
    std::string_view pname_sv{pname};

    if (!android::base::StartsWith(pname_sv, "vendor_boot:") &&
        !android::base::StartsWith(pname_sv, "vendor_boot_a:") &&
        !android::base::StartsWith(pname_sv, "vendor_boot_b:")) {
        return std::string(pname_sv);
    }
    if (buf->type != FB_BUFFER_FD) {
        die("Flashing sparse vendor ramdisk image is not supported.");
    }
    if (buf->sz <= 0) {
        die("repack_ramdisk() sees negative size: %" PRId64, buf->sz);
    }
    std::string partition(pname_sv.substr(0, pname_sv.find(':')));
    std::string ramdisk(pname_sv.substr(pname_sv.find(':') + 1));

    unique_fd vendor_boot(make_temporary_fd("vendor boot repack"));
    uint64_t vendor_boot_size = fetch_partition(partition, vendor_boot);
    auto repack_res = replace_vendor_ramdisk(vendor_boot, vendor_boot_size, ramdisk, buf->fd,
                                             static_cast<uint64_t>(buf->sz));
    if (!repack_res.ok()) {
        die("%s", repack_res.error().message().c_str());
    }

    buf->fd = std::move(vendor_boot);
    buf->sz = vendor_boot_size;
    buf->image_size = vendor_boot_size;
    return partition;
}

static void do_flash(const char* pname, const char* fname) {
    verbose("Do flash %s %s", pname, fname);
    struct fastboot_buffer buf;
@@ -1302,7 +1337,8 @@ static void do_flash(const char* pname, const char* fname) {
    if (is_logical(pname)) {
        fb->ResizePartition(pname, std::to_string(buf.image_size));
    }
    flash_buf(pname, &buf);
    std::string flash_pname = repack_ramdisk(pname, &buf);
    flash_buf(flash_pname, &buf);
}

// Sets slot_override as the active slot. If slot_override is blank,
+136 −0
Original line number Diff line number Diff line
// Copyright (C) 2021 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.

python_binary_host {
    name: "fastboot_gen_rand",
    visibility: [":__subpackages__"],
    srcs: ["fastboot_gen_rand.py"],
}

genrule_defaults {
    name: "fastboot_test_data_gen_defaults",
    visibility: ["//system/core/fastboot"],
    tools: [
        "fastboot_gen_rand",
    ],
}

// Genrules for components of test vendor boot image.

// Fake dtb image.
genrule {
    name: "fastboot_test_dtb",
    defaults: ["fastboot_test_data_gen_defaults"],
    out: ["test_dtb.img"],
    cmd: "$(location fastboot_gen_rand) --seed dtb --length 1024 > $(out)",
}

// Fake bootconfig image.
genrule {
    name: "fastboot_test_bootconfig",
    defaults: ["fastboot_test_data_gen_defaults"],
    out: ["test_bootconfig.img"],
    cmd: "$(location fastboot_gen_rand) --seed bootconfig --length 1024 > $(out)",
}

// Fake vendor ramdisk with type "none".
genrule {
    name: "fastboot_test_vendor_ramdisk_none",
    defaults: ["fastboot_test_data_gen_defaults"],
    out: ["test_vendor_ramdisk_none.img"],
    cmd: "$(location fastboot_gen_rand) --seed vendor_ramdisk_none --length 1024 > $(out)",
}

// Fake vendor ramdisk with type "platform".
genrule {
    name: "fastboot_test_vendor_ramdisk_platform",
    defaults: ["fastboot_test_data_gen_defaults"],
    out: ["test_vendor_ramdisk_platform.img"],
    cmd: "$(location fastboot_gen_rand) --seed vendor_ramdisk_platform --length 1024 > $(out)",
}

// Fake replacement ramdisk.
genrule {
    name: "fastboot_test_vendor_ramdisk_replace",
    defaults: ["fastboot_test_data_gen_defaults"],
    out: ["test_vendor_ramdisk_replace.img"],
    cmd: "$(location fastboot_gen_rand) --seed replace --length 3072 > $(out)",
}

// Genrules for test vendor boot images.

fastboot_sign_test_image = "$(location avbtool) add_hash_footer --salt 00 --image $(out) " +
    "--partition_name vendor_boot --partition_size $$(( 1 * 1024 * 1024 ))"

genrule_defaults {
    name: "fastboot_test_vendor_boot_gen_defaults",
    defaults: ["fastboot_test_data_gen_defaults"],
    tools: [
        "avbtool",
        "mkbootimg",
    ],
}

genrule {
    name: "fastboot_test_vendor_boot_v3",
    defaults: ["fastboot_test_vendor_boot_gen_defaults"],
    out: ["vendor_boot_v3.img"],
    srcs: [
        ":fastboot_test_dtb",
        ":fastboot_test_vendor_ramdisk_none",
    ],
    cmd: "$(location mkbootimg) --header_version 3 " +
        "--vendor_ramdisk $(location :fastboot_test_vendor_ramdisk_none) " +
        "--dtb $(location :fastboot_test_dtb) " +
        "--vendor_boot $(out) && " +
        fastboot_sign_test_image,
}

genrule {
    name: "fastboot_test_vendor_boot_v4_without_frag",
    defaults: ["fastboot_test_vendor_boot_gen_defaults"],
    out: ["vendor_boot_v4_without_frag.img"],
    srcs: [
        ":fastboot_test_dtb",
        ":fastboot_test_vendor_ramdisk_none",
        ":fastboot_test_bootconfig",
    ],
    cmd: "$(location mkbootimg) --header_version 4 " +
        "--vendor_ramdisk $(location :fastboot_test_vendor_ramdisk_none) " +
        "--dtb $(location :fastboot_test_dtb) " +
        "--vendor_bootconfig $(location :fastboot_test_bootconfig) " +
        "--vendor_boot $(out) && " +
        fastboot_sign_test_image,
}

genrule {
    name: "fastboot_test_vendor_boot_v4_with_frag",
    defaults: ["fastboot_test_vendor_boot_gen_defaults"],
    out: ["vendor_boot_v4_with_frag.img"],
    srcs: [
        ":fastboot_test_dtb",
        ":fastboot_test_vendor_ramdisk_none",
        ":fastboot_test_vendor_ramdisk_platform",
        ":fastboot_test_bootconfig",
    ],
    cmd: "$(location mkbootimg) --header_version 4 " +
        "--dtb $(location :fastboot_test_dtb) " +
        "--vendor_bootconfig $(location :fastboot_test_bootconfig) " +
        "--ramdisk_type none --ramdisk_name none_ramdisk " +
        "--vendor_ramdisk_fragment $(location :fastboot_test_vendor_ramdisk_none) " +
        "--ramdisk_type platform --ramdisk_name platform_ramdisk " +
        "--vendor_ramdisk_fragment $(location :fastboot_test_vendor_ramdisk_platform) " +
        "--vendor_boot $(out) && " +
        fastboot_sign_test_image,
}
+32 −0
Original line number Diff line number Diff line
#!/usr/bin/env python3

# Copyright (C) 2021 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.

"""
Write given number of random bytes, generated with optional seed.
"""

import random, argparse

if __name__ == '__main__':
  parser = argparse.ArgumentParser(description=__doc__)
  parser.add_argument('--seed', help='Seed to random generator')
  parser.add_argument('--length', type=int, required=True, help='Length of output')
  args = parser.parse_args()

  if args.seed:
    random.seed(args.seed)

  print(''.join(chr(random.randrange(0,0xff)) for _ in range(args.length)))
+422 −0

File added.

Preview size limit exceeded, changes collapsed.

Loading