Construct the super_vbmeta image
This commit constructs the super_vbmeta image to eliminate the need of adding /vbmeta_system and/or /vbmeta_vendor when AVB chain partition is used with Android Dynamic Partition. See BOARD_AVB_VBMETA_SYSTEM under the link: https://android.googlesource.com/platform/external/avb/#build-system-integration The structure of super_vbmeta : | VBMeta Table | (fixed-length 2KiB) | Backup VBMeta Table | (fixed-length 2KiB) | VBMeta Images | (fixed-length 64KiB each) The structure of VBMeta Table : | Super VBMeta Header | (fixed-length 128B) | VBMeta Descriptors | (variable-length) The VBMeta Table records the slot number of each vbmeta image within the /super_vbmeta partition. Bug: 137054296 Test: m libvbmeta_test Test: ./out/host/linux-x86/nativetest/libvbmeta_test/libvbmeta_test Change-Id: I01aeadd850750ae87d9125484c1b1f570bb84756
This commit is contained in:
parent
17438477cb
commit
6dd098cb1e
14 changed files with 1130 additions and 0 deletions
52
fs_mgr/libvbmeta/Android.bp
Normal file
52
fs_mgr/libvbmeta/Android.bp
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
//
|
||||
// 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",
|
||||
],
|
||||
}
|
||||
214
fs_mgr/libvbmeta/builder.cpp
Normal file
214
fs_mgr/libvbmeta/builder.cpp
Normal file
|
|
@ -0,0 +1,214 @@
|
|||
/*
|
||||
* 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
|
||||
55
fs_mgr/libvbmeta/builder.h
Normal file
55
fs_mgr/libvbmeta/builder.h
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* 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
|
||||
80
fs_mgr/libvbmeta/builder_test.cpp
Normal file
80
fs_mgr/libvbmeta/builder_test.cpp
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* 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");
|
||||
}
|
||||
29
fs_mgr/libvbmeta/include/libvbmeta/libvbmeta.h
Normal file
29
fs_mgr/libvbmeta/include/libvbmeta/libvbmeta.h
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* 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
|
||||
118
fs_mgr/libvbmeta/reader.cpp
Normal file
118
fs_mgr/libvbmeta/reader.cpp
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
* 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 "reader.h"
|
||||
|
||||
#include <android-base/file.h>
|
||||
|
||||
using android::base::ErrnoError;
|
||||
using android::base::Error;
|
||||
using android::base::Result;
|
||||
|
||||
namespace android {
|
||||
namespace fs_mgr {
|
||||
|
||||
Result<void> LoadAndVerifySuperVBMetaHeader(const void* buffer, SuperVBMetaHeader* header) {
|
||||
memcpy(header, buffer, sizeof(*header));
|
||||
|
||||
// Do basic validation of super vbmeta.
|
||||
if (header->magic != SUPER_VBMETA_MAGIC) {
|
||||
return Error() << "Super VBMeta has invalid magic value";
|
||||
}
|
||||
|
||||
// Check that the version is compatible.
|
||||
if (header->major_version != SUPER_VBMETA_MAJOR_VERSION ||
|
||||
header->minor_version > SUPER_VBMETA_MINOR_VERSION) {
|
||||
return Error() << "Super VBMeta has incompatible version";
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
void LoadVBMetaDescriptors(const void* buffer, uint32_t size,
|
||||
std::vector<InternalVBMetaDescriptor>* descriptors) {
|
||||
for (int p = 0; p < size;) {
|
||||
InternalVBMetaDescriptor descriptor;
|
||||
memcpy(&descriptor, (char*)buffer + p, SUPER_VBMETA_DESCRIPTOR_SIZE);
|
||||
p += SUPER_VBMETA_DESCRIPTOR_SIZE;
|
||||
|
||||
descriptor.vbmeta_name = std::string((char*)buffer + p, descriptor.vbmeta_name_length);
|
||||
p += descriptor.vbmeta_name_length;
|
||||
|
||||
descriptors->emplace_back(std::move(descriptor));
|
||||
}
|
||||
}
|
||||
|
||||
Result<void> ReadVBMetaTable(int fd, uint64_t offset, VBMetaTable* table) {
|
||||
std::unique_ptr<uint8_t[]> header_buffer =
|
||||
std::make_unique<uint8_t[]>(SUPER_VBMETA_HEADER_SIZE);
|
||||
if (!android::base::ReadFullyAtOffset(fd, header_buffer.get(), SUPER_VBMETA_HEADER_SIZE,
|
||||
offset)) {
|
||||
return ErrnoError() << "Couldn't read super vbmeta header at offset " << offset;
|
||||
}
|
||||
|
||||
Result<void> rv_header = LoadAndVerifySuperVBMetaHeader(header_buffer.get(), &table->header);
|
||||
if (!rv_header) {
|
||||
return rv_header;
|
||||
}
|
||||
|
||||
const uint64_t descriptors_offset = offset + table->header.header_size;
|
||||
std::unique_ptr<uint8_t[]> descriptors_buffer =
|
||||
std::make_unique<uint8_t[]>(table->header.descriptors_size);
|
||||
if (!android::base::ReadFullyAtOffset(fd, descriptors_buffer.get(),
|
||||
table->header.descriptors_size, descriptors_offset)) {
|
||||
return ErrnoError() << "Couldn't read super vbmeta descriptors at offset "
|
||||
<< descriptors_offset;
|
||||
}
|
||||
|
||||
LoadVBMetaDescriptors(descriptors_buffer.get(), table->header.descriptors_size,
|
||||
&table->descriptors);
|
||||
return {};
|
||||
}
|
||||
|
||||
Result<void> ReadPrimaryVBMetaTable(int fd, VBMetaTable* table) {
|
||||
uint64_t offset = PRIMARY_SUPER_VBMETA_TABLE_OFFSET;
|
||||
return ReadVBMetaTable(fd, offset, table);
|
||||
}
|
||||
|
||||
Result<void> ReadBackupVBMetaTable(int fd, VBMetaTable* table) {
|
||||
uint64_t offset = BACKUP_SUPER_VBMETA_TABLE_OFFSET;
|
||||
return ReadVBMetaTable(fd, offset, table);
|
||||
}
|
||||
|
||||
Result<std::string> ReadVBMetaImage(int fd, int slot) {
|
||||
const uint64_t offset = 2 * SUPER_VBMETA_TABLE_MAX_SIZE + slot * VBMETA_IMAGE_MAX_SIZE;
|
||||
std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(VBMETA_IMAGE_MAX_SIZE);
|
||||
if (!android::base::ReadFullyAtOffset(fd, buffer.get(), VBMETA_IMAGE_MAX_SIZE, offset)) {
|
||||
return ErrnoError() << "Couldn't read vbmeta image at offset " << offset;
|
||||
}
|
||||
return std::string(reinterpret_cast<char*>(buffer.get()), VBMETA_IMAGE_MAX_SIZE);
|
||||
}
|
||||
|
||||
Result<void> ValidateVBMetaImage(int super_vbmeta_fd, int vbmeta_index,
|
||||
const std::string& vbmeta_image) {
|
||||
Result<std::string> content = ReadVBMetaImage(super_vbmeta_fd, vbmeta_index);
|
||||
if (!content) {
|
||||
return content.error();
|
||||
}
|
||||
|
||||
if (vbmeta_image != content.value()) {
|
||||
return Error() << "VBMeta Image in Super VBMeta differ from the original one.";
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
} // namespace fs_mgr
|
||||
} // namespace android
|
||||
34
fs_mgr/libvbmeta/reader.h
Normal file
34
fs_mgr/libvbmeta/reader.h
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* 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 <android-base/result.h>
|
||||
|
||||
#include "super_vbmeta_format.h"
|
||||
|
||||
namespace android {
|
||||
namespace fs_mgr {
|
||||
|
||||
android::base::Result<void> ReadPrimaryVBMetaTable(int fd, VBMetaTable* table);
|
||||
android::base::Result<void> ReadBackupVBMetaTable(int fd, VBMetaTable* table);
|
||||
android::base::Result<std::string> ReadVBMetaImage(int fd, int slot);
|
||||
|
||||
android::base::Result<void> ValidateVBMetaImage(int super_vbmeta_fd, int vbmeta_index,
|
||||
const std::string& vbmeta_image);
|
||||
|
||||
} // namespace fs_mgr
|
||||
} // namespace android
|
||||
34
fs_mgr/libvbmeta/super_vbmeta_format.h
Normal file
34
fs_mgr/libvbmeta/super_vbmeta_format.h
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* This .h file is intended for CPP clients (usually fastbootd, recovery and update_engine) */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "super_vbmeta_format_c.h"
|
||||
|
||||
struct InternalVBMetaDescriptor : VBMetaDescriptor {
|
||||
/* 64: The vbmeta image's name */
|
||||
std::string vbmeta_name;
|
||||
};
|
||||
|
||||
struct VBMetaTable {
|
||||
SuperVBMetaHeader header;
|
||||
std::vector<InternalVBMetaDescriptor> descriptors;
|
||||
};
|
||||
122
fs_mgr/libvbmeta/super_vbmeta_format_c.h
Normal file
122
fs_mgr/libvbmeta/super_vbmeta_format_c.h
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* This .h file is intended for C clients (usually bootloader). */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* Magic signature for super vbmeta. */
|
||||
#define SUPER_VBMETA_MAGIC 0x5356424d
|
||||
|
||||
/* Current super vbmeta version. */
|
||||
#define SUPER_VBMETA_MAJOR_VERSION 1
|
||||
#define SUPER_VBMETA_MINOR_VERSION 0
|
||||
|
||||
/* super vbmeta size. */
|
||||
#define SUPER_VBMETA_HEADER_SIZE sizeof(SuperVBMetaHeader)
|
||||
#define SUPER_VBMETA_DESCRIPTOR_SIZE sizeof(VBMetaDescriptor)
|
||||
#define SUPER_VBMETA_TABLE_MAX_SIZE 2048
|
||||
|
||||
/* super vbmeta offset. */
|
||||
#define PRIMARY_SUPER_VBMETA_TABLE_OFFSET 0
|
||||
#define BACKUP_SUPER_VBMETA_TABLE_OFFSET SUPER_VBMETA_TABLE_MAX_SIZE
|
||||
|
||||
/* restriction of vbmeta image */
|
||||
#define VBMETA_IMAGE_MAX_NUM 32
|
||||
#define VBMETA_IMAGE_MAX_SIZE 64 * 1024
|
||||
|
||||
/* Binary format of the super vbmeta image.
|
||||
*
|
||||
* The super vbmeta image consists of two blocks:
|
||||
*
|
||||
* +------------------------------------------+
|
||||
* | Super VBMeta Table - fixed size |
|
||||
* +------------------------------------------+
|
||||
* | Backup Super VBMeta Table - fixed size |
|
||||
* +------------------------------------------+
|
||||
* | VBMeta Images - fixed size |
|
||||
* +------------------------------------------+
|
||||
*
|
||||
* The "Super VBMeta Table" records the offset
|
||||
* and the size of each vbmeta_partition within
|
||||
* /super_vbmeta.
|
||||
*
|
||||
* The "VBMeta Image" is copied from each vbmeta_partition
|
||||
* and filled with 0 until 64K bytes.
|
||||
*
|
||||
* The super vbmeta table consists of two blocks:
|
||||
*
|
||||
* +-----------------------------------------+
|
||||
* | Header data - fixed size |
|
||||
* +-----------------------------------------+
|
||||
* | VBMeta descriptors - variable size |
|
||||
* +-----------------------------------------+
|
||||
*
|
||||
* The "Header data" block is described by the following struct and
|
||||
* is always 128 bytes long.
|
||||
*
|
||||
* The "VBMeta descriptor" is |descriptors_size| + |vbmeta_name_length|
|
||||
* bytes long. It contains the offset and size for each vbmeta image
|
||||
* and is followed by |vbmeta_name_length| bytes of the partition name
|
||||
* (UTF-8 encoded).
|
||||
*/
|
||||
|
||||
typedef struct SuperVBMetaHeader {
|
||||
/* 0: Magic signature (SUPER_VBMETA_MAGIC). */
|
||||
uint32_t magic;
|
||||
|
||||
/* 4: Major version. Version number required to read this super vbmeta. If the version is not
|
||||
* equal to the library version, the super vbmeta should be considered incompatible.
|
||||
*/
|
||||
uint16_t major_version;
|
||||
|
||||
/* 6: Minor version. A library supporting newer features should be able to
|
||||
* read super vbmeta with an older minor version. However, an older library
|
||||
* should not support reading super vbmeta if its minor version is higher.
|
||||
*/
|
||||
uint16_t minor_version;
|
||||
|
||||
/* 8: The size of this header struct. */
|
||||
uint32_t header_size;
|
||||
|
||||
/* 12: The size of this super vbmeta table. */
|
||||
uint32_t total_size;
|
||||
|
||||
/* 16: SHA256 checksum of this super vbmeta table, with this field set to 0. */
|
||||
uint8_t checksum[32];
|
||||
|
||||
/* 48: The size of the vbmeta table descriptors. */
|
||||
uint32_t descriptors_size;
|
||||
|
||||
/* 52: mark which slot is in use. */
|
||||
uint32_t in_use = 0;
|
||||
|
||||
/* 56: reserved for other usage, filled with 0. */
|
||||
uint8_t reserved[72];
|
||||
} __attribute__((packed)) SuperVBMetaHeader;
|
||||
|
||||
typedef struct VBMetaDescriptor {
|
||||
/* 0: The slot number of the vbmeta image. */
|
||||
uint8_t vbmeta_index;
|
||||
|
||||
/* 12: The length of the vbmeta image name. */
|
||||
uint32_t vbmeta_name_length;
|
||||
|
||||
/* 16: Space reserved for other usage, filled with 0. */
|
||||
uint8_t reserved[48];
|
||||
} __attribute__((packed)) VBMetaDescriptor;
|
||||
191
fs_mgr/libvbmeta/super_vbmeta_test.cpp
Normal file
191
fs_mgr/libvbmeta/super_vbmeta_test.cpp
Normal file
|
|
@ -0,0 +1,191 @@
|
|||
/*
|
||||
* 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 <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <android-base/file.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <openssl/sha.h>
|
||||
#include <sparse/sparse.h>
|
||||
|
||||
#include "reader.h"
|
||||
#include "super_vbmeta_format.h"
|
||||
#include "utility.h"
|
||||
#include "writer.h"
|
||||
|
||||
#define FAKE_DATA_SIZE 40960
|
||||
#define FAKE_PARTITION_SIZE FAKE_DATA_SIZE * 25
|
||||
|
||||
using android::base::Result;
|
||||
using android::fs_mgr::GetFileSize;
|
||||
using android::fs_mgr::ReadVBMetaImage;
|
||||
using SparsePtr = std::unique_ptr<sparse_file, decltype(&sparse_file_destroy)>;
|
||||
|
||||
void GeneratePartitionImage(int fd, const std::string& file_name,
|
||||
const std::string& partition_name) {
|
||||
std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(FAKE_DATA_SIZE);
|
||||
for (size_t c = 0; c < FAKE_DATA_SIZE; c++) {
|
||||
buffer[c] = uint8_t(c);
|
||||
}
|
||||
|
||||
SparsePtr file(sparse_file_new(512 /* block size */, FAKE_DATA_SIZE), sparse_file_destroy);
|
||||
EXPECT_TRUE(file);
|
||||
EXPECT_EQ(0, sparse_file_add_data(file.get(), buffer.get(), FAKE_DATA_SIZE,
|
||||
0 /* offset in blocks */));
|
||||
EXPECT_EQ(0, sparse_file_write(file.get(), fd, false /* gz */, true /* sparse */,
|
||||
false /* crc */));
|
||||
|
||||
std::stringstream cmd;
|
||||
cmd << "avbtool add_hashtree_footer"
|
||||
<< " --image " << file_name << " --partition_name " << partition_name
|
||||
<< " --partition_size " << FAKE_PARTITION_SIZE << " --algorithm SHA256_RSA2048"
|
||||
<< " --key external/avb/test/data/testkey_rsa2048.pem";
|
||||
|
||||
int rc = system(cmd.str().c_str());
|
||||
EXPECT_TRUE(WIFEXITED(rc));
|
||||
EXPECT_EQ(WEXITSTATUS(rc), 0);
|
||||
}
|
||||
|
||||
void GenerateVBMetaImage(const std::string& vbmeta_file_name,
|
||||
const std::string& include_file_name) {
|
||||
std::stringstream cmd;
|
||||
cmd << "avbtool make_vbmeta_image"
|
||||
<< " --output " << vbmeta_file_name << " --include_descriptors_from_image "
|
||||
<< include_file_name;
|
||||
|
||||
int rc = system(cmd.str().c_str());
|
||||
EXPECT_TRUE(WIFEXITED(rc));
|
||||
EXPECT_EQ(WEXITSTATUS(rc), 0);
|
||||
}
|
||||
|
||||
std::string ReadVBMetaImageFromFile(const std::string& file) {
|
||||
android::base::unique_fd fd(open(file.c_str(), O_RDONLY | O_CLOEXEC));
|
||||
EXPECT_GT(fd, 0);
|
||||
Result<uint64_t> file_size = GetFileSize(fd);
|
||||
EXPECT_TRUE(file_size);
|
||||
std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(VBMETA_IMAGE_MAX_SIZE);
|
||||
EXPECT_TRUE(android::base::ReadFully(fd, buffer.get(), file_size.value()));
|
||||
return std::string(reinterpret_cast<char*>(buffer.get()), VBMETA_IMAGE_MAX_SIZE);
|
||||
}
|
||||
|
||||
TEST(VBMetaTableTest, VBMetaTableBasic) {
|
||||
TemporaryDir td;
|
||||
|
||||
// Generate Partition Image
|
||||
TemporaryFile system_tf(std::string(td.path));
|
||||
std::string system_path(system_tf.path);
|
||||
GeneratePartitionImage(system_tf.fd, system_path, "system");
|
||||
system_tf.release();
|
||||
|
||||
TemporaryFile vendor_tf(std::string(td.path));
|
||||
std::string vendor_path(vendor_tf.path);
|
||||
GeneratePartitionImage(vendor_tf.fd, vendor_path, "vendor");
|
||||
vendor_tf.release();
|
||||
|
||||
TemporaryFile product_tf(std::string(td.path));
|
||||
std::string product_path(product_tf.path);
|
||||
GeneratePartitionImage(product_tf.fd, product_path, "product");
|
||||
product_tf.release();
|
||||
|
||||
// Generate VBMeta Image
|
||||
std::string vbmeta_system_path(td.path);
|
||||
vbmeta_system_path.append("/vbmeta_system.img");
|
||||
GenerateVBMetaImage(vbmeta_system_path, system_path);
|
||||
|
||||
std::string vbmeta_vendor_path(td.path);
|
||||
vbmeta_vendor_path.append("/vbmeta_vendor.img");
|
||||
GenerateVBMetaImage(vbmeta_vendor_path, vendor_path);
|
||||
|
||||
std::string vbmeta_product_path(td.path);
|
||||
vbmeta_product_path.append("/vbmeta_product.img");
|
||||
GenerateVBMetaImage(vbmeta_product_path, product_path);
|
||||
|
||||
// Generate Super VBMeta Image
|
||||
std::string super_vbmeta_path(td.path);
|
||||
super_vbmeta_path.append("/super_vbmeta.img");
|
||||
|
||||
std::stringstream cmd;
|
||||
cmd << "vbmake"
|
||||
<< " --image "
|
||||
<< "vbmeta_system"
|
||||
<< "=" << vbmeta_system_path << " --image "
|
||||
<< "vbmeta_vendor"
|
||||
<< "=" << vbmeta_vendor_path << " --image "
|
||||
<< "vbmeta_product"
|
||||
<< "=" << vbmeta_product_path << " --output=" << super_vbmeta_path;
|
||||
|
||||
int rc = system(cmd.str().c_str());
|
||||
ASSERT_TRUE(WIFEXITED(rc));
|
||||
ASSERT_EQ(WEXITSTATUS(rc), 0);
|
||||
|
||||
android::base::unique_fd fd(open(super_vbmeta_path.c_str(), O_RDONLY | O_CLOEXEC));
|
||||
EXPECT_GT(fd, 0);
|
||||
|
||||
// Check the size of vbmeta table
|
||||
Result<uint64_t> super_vbmeta_size = GetFileSize(fd);
|
||||
EXPECT_TRUE(super_vbmeta_size);
|
||||
EXPECT_EQ(super_vbmeta_size.value(),
|
||||
SUPER_VBMETA_TABLE_MAX_SIZE * 2 + VBMETA_IMAGE_MAX_SIZE * 3);
|
||||
|
||||
// Check Primary vbmeta table is equal to Backup one
|
||||
VBMetaTable table;
|
||||
EXPECT_TRUE(android::fs_mgr::ReadPrimaryVBMetaTable(fd, &table));
|
||||
VBMetaTable table_backup;
|
||||
EXPECT_TRUE(android::fs_mgr::ReadBackupVBMetaTable(fd, &table_backup));
|
||||
EXPECT_EQ(android::fs_mgr::SerializeVBMetaTable(table),
|
||||
android::fs_mgr::SerializeVBMetaTable(table_backup));
|
||||
|
||||
// Check vbmeta table Header Checksum
|
||||
std::string serial_table = android::fs_mgr::SerializeVBMetaTable(table);
|
||||
std::string serial_removed_checksum(serial_table);
|
||||
// Replace checksum 32 bytes (starts at 16th byte) with 0
|
||||
serial_removed_checksum.replace(16, 32, 32, 0);
|
||||
uint8_t test_checksum[32];
|
||||
::SHA256(reinterpret_cast<const uint8_t*>(serial_removed_checksum.c_str()),
|
||||
table.header.total_size, &test_checksum[0]);
|
||||
EXPECT_EQ(memcmp(table.header.checksum, test_checksum, 32), 0);
|
||||
|
||||
// Check vbmeta table descriptors and vbmeta images
|
||||
EXPECT_EQ(table.descriptors.size(), 3);
|
||||
|
||||
EXPECT_EQ(table.descriptors[0].vbmeta_index, 0);
|
||||
EXPECT_EQ(table.descriptors[0].vbmeta_name_length, 14);
|
||||
EXPECT_EQ(table.descriptors[0].vbmeta_name, "vbmeta_product");
|
||||
Result<std::string> vbmeta_product_content = ReadVBMetaImage(fd, 0);
|
||||
EXPECT_TRUE(vbmeta_product_content);
|
||||
EXPECT_EQ(ReadVBMetaImageFromFile(vbmeta_product_path), vbmeta_product_content.value());
|
||||
|
||||
EXPECT_EQ(table.descriptors[1].vbmeta_index, 1);
|
||||
EXPECT_EQ(table.descriptors[1].vbmeta_name_length, 13);
|
||||
EXPECT_EQ(table.descriptors[1].vbmeta_name, "vbmeta_system");
|
||||
Result<std::string> vbmeta_system_content = ReadVBMetaImage(fd, 1);
|
||||
EXPECT_TRUE(vbmeta_system_content);
|
||||
EXPECT_EQ(ReadVBMetaImageFromFile(vbmeta_system_path), vbmeta_system_content.value());
|
||||
|
||||
EXPECT_EQ(table.descriptors[2].vbmeta_index, 2);
|
||||
EXPECT_EQ(table.descriptors[2].vbmeta_name_length, 13);
|
||||
EXPECT_EQ(table.descriptors[2].vbmeta_name, "vbmeta_vendor");
|
||||
Result<std::string> vbmeta_vendor_content = ReadVBMetaImage(fd, 2);
|
||||
EXPECT_TRUE(vbmeta_vendor_content);
|
||||
EXPECT_EQ(ReadVBMetaImageFromFile(vbmeta_vendor_path), vbmeta_vendor_content.value());
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
47
fs_mgr/libvbmeta/utility.cpp
Normal file
47
fs_mgr/libvbmeta/utility.cpp
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* 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 "utility.h"
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "super_vbmeta_format.h"
|
||||
|
||||
using android::base::ErrnoError;
|
||||
using android::base::Error;
|
||||
using android::base::Result;
|
||||
|
||||
namespace android {
|
||||
namespace fs_mgr {
|
||||
|
||||
Result<uint64_t> GetFileSize(int fd) {
|
||||
struct stat sb;
|
||||
if (fstat(fd, &sb) == -1) {
|
||||
return ErrnoError() << "Couldn't get the file size";
|
||||
}
|
||||
return sb.st_size;
|
||||
}
|
||||
|
||||
uint64_t IndexOffset(const uint8_t vbmeta_index) {
|
||||
/* There are primary and backup vbmeta table in super_vbmeta,
|
||||
so SUPER_VBMETA_TABLE_MAX_SIZE is counted twice. */
|
||||
return 2 * SUPER_VBMETA_TABLE_MAX_SIZE + vbmeta_index * VBMETA_IMAGE_MAX_SIZE;
|
||||
}
|
||||
|
||||
} // namespace fs_mgr
|
||||
} // namespace android
|
||||
37
fs_mgr/libvbmeta/utility.h
Normal file
37
fs_mgr/libvbmeta/utility.h
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* 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 <android-base/logging.h>
|
||||
#include <android-base/result.h>
|
||||
|
||||
#define VBMETA_TAG "[libvbmeta]"
|
||||
#define LWARN LOG(WARNING) << VBMETA_TAG
|
||||
#define LINFO LOG(INFO) << VBMETA_TAG
|
||||
#define LERROR LOG(ERROR) << VBMETA_TAG
|
||||
#define PWARNING PLOG(WARNING) << VBMETA_TAG
|
||||
#define PERROR PLOG(ERROR) << VBMETA_TAG
|
||||
|
||||
namespace android {
|
||||
namespace fs_mgr {
|
||||
|
||||
android::base::Result<uint64_t> GetFileSize(int fd);
|
||||
|
||||
uint64_t IndexOffset(const uint8_t vbmeta_index);
|
||||
|
||||
} // namespace fs_mgr
|
||||
} // namespace android
|
||||
81
fs_mgr/libvbmeta/writer.cpp
Normal file
81
fs_mgr/libvbmeta/writer.cpp
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* 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 "writer.h"
|
||||
|
||||
#include <android-base/file.h>
|
||||
|
||||
#include "utility.h"
|
||||
|
||||
using android::base::ErrnoError;
|
||||
using android::base::Result;
|
||||
|
||||
namespace android {
|
||||
namespace fs_mgr {
|
||||
|
||||
std::string SerializeVBMetaTable(const VBMetaTable& input) {
|
||||
std::string table;
|
||||
table.append(reinterpret_cast<const char*>(&input.header), SUPER_VBMETA_HEADER_SIZE);
|
||||
|
||||
for (const auto& desc : input.descriptors) {
|
||||
table.append(reinterpret_cast<const char*>(&desc), SUPER_VBMETA_DESCRIPTOR_SIZE);
|
||||
table.append(desc.vbmeta_name);
|
||||
}
|
||||
|
||||
// Ensure the size of vbmeta table is SUPER_VBMETA_TABLE_MAX_SIZE
|
||||
table.resize(SUPER_VBMETA_TABLE_MAX_SIZE, '\0');
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
Result<void> WritePrimaryVBMetaTable(int fd, const std::string& table) {
|
||||
const uint64_t offset = PRIMARY_SUPER_VBMETA_TABLE_OFFSET;
|
||||
if (lseek(fd, offset, SEEK_SET) < 0) {
|
||||
return ErrnoError() << __PRETTY_FUNCTION__ << " lseek failed";
|
||||
}
|
||||
|
||||
if (!android::base::WriteFully(fd, table.data(), table.size())) {
|
||||
return ErrnoError() << "Failed to write primary vbmeta table at offset " << offset;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
Result<void> WriteBackupVBMetaTable(int fd, const std::string& table) {
|
||||
const uint64_t offset = BACKUP_SUPER_VBMETA_TABLE_OFFSET;
|
||||
if (lseek(fd, offset, SEEK_SET) < 0) {
|
||||
return ErrnoError() << __PRETTY_FUNCTION__ << " lseek failed";
|
||||
}
|
||||
|
||||
if (!android::base::WriteFully(fd, table.data(), table.size())) {
|
||||
return ErrnoError() << "Failed to write backup vbmeta table at offset " << offset;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
Result<void> WriteVBMetaImage(int fd, const uint8_t slot_number, const std::string& vbmeta_image) {
|
||||
const uint64_t offset = IndexOffset(slot_number);
|
||||
if (lseek(fd, offset, SEEK_SET) < 0) {
|
||||
return ErrnoError() << __PRETTY_FUNCTION__ << " lseek failed";
|
||||
}
|
||||
|
||||
if (!android::base::WriteFully(fd, vbmeta_image.data(), vbmeta_image.size())) {
|
||||
return ErrnoError() << "Failed to write vbmeta image at offset " << offset;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
} // namespace fs_mgr
|
||||
} // namespace android
|
||||
36
fs_mgr/libvbmeta/writer.h
Normal file
36
fs_mgr/libvbmeta/writer.h
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* 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 <string>
|
||||
|
||||
#include <android-base/result.h>
|
||||
|
||||
#include "super_vbmeta_format.h"
|
||||
|
||||
namespace android {
|
||||
namespace fs_mgr {
|
||||
|
||||
std::string SerializeVBMetaTable(const VBMetaTable& input);
|
||||
|
||||
android::base::Result<void> WritePrimaryVBMetaTable(int fd, const std::string& table);
|
||||
android::base::Result<void> WriteBackupVBMetaTable(int fd, const std::string& table);
|
||||
android::base::Result<void> WriteVBMetaImage(int fd, const uint8_t slot_number,
|
||||
const std::string& vbmeta_image);
|
||||
|
||||
} // namespace fs_mgr
|
||||
} // namespace android
|
||||
Loading…
Add table
Reference in a new issue