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

Commit 347be853 authored by Kaiwen Szu's avatar Kaiwen Szu Committed by android-build-merger
Browse files

Merge "Construct the super_vbmeta image" am: da6525c2

am: 6a7f27a4

Change-Id: If0a7fce747ff10413c3e2f99dcf52dc4fd90a39d
parents 48f88f67 6a7f27a4
Loading
Loading
Loading
Loading
+52 −0
Original line number Original line 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.
//

libvbmeta_lib_deps = [
    "libbase",
    "libcrypto",
]

cc_library {
    name: "libvbmeta",
    host_supported: true,
    srcs: [
        "builder.cpp",
        "reader.cpp",
        "utility.cpp",
        "writer.cpp",
    ],
    shared_libs: [
        "liblog",
    ] + libvbmeta_lib_deps,
    export_include_dirs: ["include"],
}

cc_test_host {
    name: "libvbmeta_test",
    static_libs: [
        "libsparse",
        "libvbmeta",
        "libz",
    ] + libvbmeta_lib_deps,
    srcs: [
        "builder_test.cpp",
        "super_vbmeta_test.cpp",
    ],
    required: [
        "avbtool",
        "vbmake",
    ],
}
 No newline at end of file
+214 −0
Original line number Original line 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.
 */

#include "builder.h"

#include <android-base/file.h>
#include <openssl/sha.h>

#include "reader.h"
#include "utility.h"
#include "writer.h"

using android::base::ErrnoError;
using android::base::Error;
using android::base::Result;
using android::base::unique_fd;

namespace android {
namespace fs_mgr {

SuperVBMetaBuilder::SuperVBMetaBuilder() {}

SuperVBMetaBuilder::SuperVBMetaBuilder(const int super_vbmeta_fd,
                                       const std::map<std::string, std::string>& images_path)
    : super_vbmeta_fd_(super_vbmeta_fd), images_path_(images_path) {}

Result<void> SuperVBMetaBuilder::Build() {
    for (const auto& [vbmeta_name, file_path] : images_path_) {
        Result<std::string> content = ReadVBMetaImageFromFile(file_path);
        if (!content) {
            return content.error();
        }

        Result<uint8_t> vbmeta_index = AddVBMetaImage(vbmeta_name);
        if (!vbmeta_index) {
            return vbmeta_index.error();
        }

        Result<void> rv_export_vbmeta_image =
                ExportVBMetaImageToFile(vbmeta_index.value(), content.value());
        if (!rv_export_vbmeta_image) {
            return rv_export_vbmeta_image;
        }
    }
    return {};
}

Result<std::string> SuperVBMetaBuilder::ReadVBMetaImageFromFile(const std::string& file) {
    unique_fd source_fd(TEMP_FAILURE_RETRY(open(file.c_str(), O_RDONLY | O_CLOEXEC)));
    if (source_fd < 0) {
        return ErrnoError() << "Couldn't open vbmeta image file " << file;
    }

    Result<uint64_t> file_size = GetFileSize(source_fd);
    if (!file_size) {
        return file_size.error();
    }

    if (file_size.value() > VBMETA_IMAGE_MAX_SIZE) {
        return Error() << "vbmeta image file size " << file_size.value() << " is too large";
    }

    std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(VBMETA_IMAGE_MAX_SIZE);
    if (!android::base::ReadFully(source_fd, buffer.get(), file_size.value())) {
        return ErrnoError() << "Couldn't read vbmeta image file " << file;
    }

    return std::string(reinterpret_cast<const char*>(buffer.get()), VBMETA_IMAGE_MAX_SIZE);
}

Result<uint8_t> SuperVBMetaBuilder::GetEmptySlot() {
    for (uint8_t i = 0; i < VBMETA_IMAGE_MAX_NUM; ++i) {
        if ((table_.header.in_use & (1 << i)) == 0) return i;
    }
    return Error() << "There isn't empty slot in super vbmeta";
}

Result<uint8_t> SuperVBMetaBuilder::AddVBMetaImage(const std::string& vbmeta_name) {
    auto desc = std::find_if(
            table_.descriptors.begin(), table_.descriptors.end(),
            [&vbmeta_name](const auto& entry) { return entry.vbmeta_name == vbmeta_name; });

    uint8_t slot_number = 0;
    if (desc != table_.descriptors.end()) {
        slot_number = desc->vbmeta_index;
    } else {
        Result<uint8_t> new_slot = GetEmptySlot();
        if (!new_slot) {
            return new_slot;
        }
        slot_number = new_slot.value();

        // insert new descriptor into table
        InternalVBMetaDescriptor new_desc;
        new_desc.vbmeta_index = slot_number;
        new_desc.vbmeta_name_length = vbmeta_name.length();
        new_desc.vbmeta_name = vbmeta_name;
        memset(new_desc.reserved, 0, sizeof(new_desc.reserved));
        table_.descriptors.emplace_back(std::move(new_desc));

        // mark slot as in use
        table_.header.in_use |= (1 << slot_number);
    }

    return slot_number;
}

void SuperVBMetaBuilder::DeleteVBMetaImage(const std::string& vbmeta_name) {
    auto desc = std::find_if(
            table_.descriptors.begin(), table_.descriptors.end(),
            [&vbmeta_name](const auto& entry) { return entry.vbmeta_name == vbmeta_name; });

    if (desc != table_.descriptors.end()) {
        // mark slot as not in use
        table_.header.in_use &= ~(1 << desc->vbmeta_index);

        // erase descriptor in table
        table_.descriptors.erase(desc);
    }
}

std::unique_ptr<VBMetaTable> SuperVBMetaBuilder::ExportVBMetaTable() {
    // calculate descriptors size
    uint32_t descriptors_size = 0;
    for (const auto& desc : table_.descriptors) {
        descriptors_size += SUPER_VBMETA_DESCRIPTOR_SIZE + desc.vbmeta_name_length * sizeof(char);
    }

    // export header
    table_.header.magic = SUPER_VBMETA_MAGIC;
    table_.header.major_version = SUPER_VBMETA_MAJOR_VERSION;
    table_.header.minor_version = SUPER_VBMETA_MINOR_VERSION;
    table_.header.header_size = SUPER_VBMETA_HEADER_SIZE;
    table_.header.total_size = SUPER_VBMETA_HEADER_SIZE + descriptors_size;
    memset(table_.header.checksum, 0, sizeof(table_.header.checksum));
    table_.header.descriptors_size = descriptors_size;
    memset(table_.header.reserved, 0, sizeof(table_.header.reserved));
    std::string serialized_table = SerializeVBMetaTable(table_);
    ::SHA256(reinterpret_cast<const uint8_t*>(serialized_table.c_str()), table_.header.total_size,
             &table_.header.checksum[0]);

    return std::make_unique<VBMetaTable>(table_);
}

Result<void> SuperVBMetaBuilder::ExportVBMetaTableToFile() {
    std::unique_ptr<VBMetaTable> table = ExportVBMetaTable();

    std::string serialized_table = SerializeVBMetaTable(*table);

    android::base::Result<void> rv_write_primary_vbmeta_table =
            WritePrimaryVBMetaTable(super_vbmeta_fd_, serialized_table);
    if (!rv_write_primary_vbmeta_table) {
        return rv_write_primary_vbmeta_table;
    }

    android::base::Result<void> rv_write_backup_vbmeta_table =
            WriteBackupVBMetaTable(super_vbmeta_fd_, serialized_table);
    return rv_write_backup_vbmeta_table;
}

Result<void> SuperVBMetaBuilder::ExportVBMetaImageToFile(const uint8_t vbmeta_index,
                                                         const std::string& vbmeta_image) {
    Result<void> rv_write_vbmeta_image =
            WriteVBMetaImage(super_vbmeta_fd_, vbmeta_index, vbmeta_image);
    if (!rv_write_vbmeta_image) {
        return rv_write_vbmeta_image;
    }

    Result<void> rv_validate_vbmeta_image =
            ValidateVBMetaImage(super_vbmeta_fd_, vbmeta_index, vbmeta_image);
    return rv_validate_vbmeta_image;
}

bool WriteToSuperVBMetaFile(const std::string& super_vbmeta_file,
                            const std::map<std::string, std::string>& images_path) {
    unique_fd super_vbmeta_fd(TEMP_FAILURE_RETRY(
            open(super_vbmeta_file.c_str(), O_CREAT | O_RDWR | O_TRUNC | O_CLOEXEC, 0644)));
    if (super_vbmeta_fd < 0) {
        PERROR << "Couldn't open super vbmeta file " << super_vbmeta_file;
        return false;
    }

    SuperVBMetaBuilder builder(super_vbmeta_fd, images_path);

    Result<void> rv_build = builder.Build();
    if (!rv_build) {
        LERROR << rv_build.error();
        return false;
    }

    Result<void> rv_export = builder.ExportVBMetaTableToFile();
    if (!rv_export) {
        LERROR << rv_export.error();
        return false;
    }

    return true;
}

}  // namespace fs_mgr
}  // namespace android
 No newline at end of file
+55 −0
Original line number Original line 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 <map>
#include <string>

#include <android-base/result.h>

#include "super_vbmeta_format.h"

namespace android {
namespace fs_mgr {

class SuperVBMetaBuilder {
  public:
    SuperVBMetaBuilder();
    SuperVBMetaBuilder(const int super_vbmeta_fd,
                       const std::map<std::string, std::string>& images_path);
    android::base::Result<void> Build();
    android::base::Result<std::string> ReadVBMetaImageFromFile(const std::string& file);
    // It adds the vbmeta image in super_vbmeta and returns the index
    // (which has the same meaning with vbmeta_index of VBMetaDescriptor).
    android::base::Result<uint8_t> AddVBMetaImage(const std::string& vbmeta_name);
    void DeleteVBMetaImage(const std::string& vbmeta_name);
    std::unique_ptr<VBMetaTable> ExportVBMetaTable();
    android::base::Result<void> ExportVBMetaTableToFile();
    android::base::Result<void> ExportVBMetaImageToFile(const uint8_t vbmeta_index,
                                                        const std::string& vbmeta_image);

  private:
    android::base::Result<uint8_t> GetEmptySlot();

    int super_vbmeta_fd_;
    VBMetaTable table_;
    // Maps vbmeta image name to vbmeta image file path.
    std::map<std::string, std::string> images_path_;
};

}  // namespace fs_mgr
}  // namespace android
 No newline at end of file
+80 −0
Original line number Original line 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.
 */

#include <gtest/gtest.h>

#include "builder.h"
#include "super_vbmeta_format.h"

using android::base::Result;
using android::fs_mgr::SuperVBMetaBuilder;

TEST(BuilderTest, VBMetaTableBasic) {
    std::unique_ptr<SuperVBMetaBuilder> builder = std::make_unique<SuperVBMetaBuilder>();
    ASSERT_NE(builder, nullptr);

    Result<uint8_t> vbmeta_index = builder->AddVBMetaImage("vbmeta" /* vbmeta_name */
    );
    EXPECT_TRUE(vbmeta_index);

    Result<uint8_t> vbmeta_system_slot = builder->AddVBMetaImage("vbmeta_system" /* vbmeta_name */
    );
    EXPECT_TRUE(vbmeta_system_slot);

    Result<uint8_t> vbmeta_vendor_slot = builder->AddVBMetaImage("vbmeta_vendor" /* vbmeta_name */
    );
    EXPECT_TRUE(vbmeta_vendor_slot);

    builder->DeleteVBMetaImage("vbmeta_system" /* vbmeta_name */
    );

    Result<uint8_t> vbmeta_product_slot = builder->AddVBMetaImage("vbmeta_product" /* vbmeta_name */
    );
    EXPECT_TRUE(vbmeta_product_slot);

    std::unique_ptr<VBMetaTable> table = builder->ExportVBMetaTable();
    ASSERT_NE(table, nullptr);

    // check for vbmeta table header
    EXPECT_EQ(table->header.magic, SUPER_VBMETA_MAGIC);
    EXPECT_EQ(table->header.major_version, SUPER_VBMETA_MAJOR_VERSION);
    EXPECT_EQ(table->header.minor_version, SUPER_VBMETA_MINOR_VERSION);
    EXPECT_EQ(table->header.header_size, SUPER_VBMETA_HEADER_SIZE);
    EXPECT_EQ(table->header.total_size,
              SUPER_VBMETA_HEADER_SIZE + SUPER_VBMETA_DESCRIPTOR_SIZE * 3 + 33);
    EXPECT_EQ(table->header.descriptors_size, SUPER_VBMETA_DESCRIPTOR_SIZE * 3 + 33);

    // Test for vbmeta table descriptors
    EXPECT_EQ(table->descriptors.size(), 3);

    EXPECT_EQ(table->descriptors[0].vbmeta_index, 0);
    EXPECT_EQ(table->descriptors[0].vbmeta_name_length, 6);
    for (int i = 0; i < sizeof(table->descriptors[0].reserved); i++)
        EXPECT_EQ(table->descriptors[0].reserved[i], 0);
    EXPECT_EQ(table->descriptors[0].vbmeta_name, "vbmeta");

    EXPECT_EQ(table->descriptors[1].vbmeta_index, 2);
    EXPECT_EQ(table->descriptors[1].vbmeta_name_length, 13);
    for (int i = 0; i < sizeof(table->descriptors[1].reserved); i++)
        EXPECT_EQ(table->descriptors[1].reserved[i], 0);
    EXPECT_EQ(table->descriptors[1].vbmeta_name, "vbmeta_vendor");

    EXPECT_EQ(table->descriptors[2].vbmeta_index, 1);
    EXPECT_EQ(table->descriptors[2].vbmeta_name_length, 14);
    for (int i = 0; i < sizeof(table->descriptors[2].reserved); i++)
        EXPECT_EQ(table->descriptors[2].reserved[i], 0);
    EXPECT_EQ(table->descriptors[2].vbmeta_name, "vbmeta_product");
}
 No newline at end of file
+29 −0
Original line number Original line 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 <map>
#include <string>

namespace android {
namespace fs_mgr {

bool WriteToSuperVBMetaFile(const std::string& super_vbmeta_file,
                            const std::map<std::string, std::string>& images_path);

}  // namespace fs_mgr
}  // namespace android
 No newline at end of file
Loading