diff options
author | Xiaochu Liu <xiaochu@chromium.org> | 2018-07-23 11:54:02 -0700 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2018-08-01 00:05:33 -0700 |
commit | d88bc3e668d298b215c48fd45cff96901cb6bd85 (patch) | |
tree | 6a63a817c581549143346d96551c45ac27f9a7bd | |
parent | a722b427ac5223635eafde4551dbb2db749ce252 (diff) | |
download | platform_external_libbrillo-d88bc3e668d298b215c48fd45cff96901cb6bd85.tar.gz platform_external_libbrillo-d88bc3e668d298b215c48fd45cff96901cb6bd85.tar.bz2 platform_external_libbrillo-d88bc3e668d298b215c48fd45cff96901cb6bd85.zip |
move manifest* from imageloader to libbrillo
We move them to libbrillo so it could be shared by
imageloader&dlcservice.
BUG=chromium:866203
TEST=unittest
Change-Id: Id6e1f898d69c5cb1d4d291147482248ee3578f03
Reviewed-on: https://chromium-review.googlesource.com/1147249
Commit-Ready: Xiaochu Liu <xiaochu@chromium.org>
Tested-by: Xiaochu Liu <xiaochu@chromium.org>
Reviewed-by: Xiaochu Liu <xiaochu@chromium.org>
-rw-r--r-- | brillo/imageloader/manifest.cc | 188 | ||||
-rw-r--r-- | brillo/imageloader/manifest.h | 52 | ||||
-rw-r--r-- | brillo/imageloader/manifest_unittest.cc | 49 | ||||
-rw-r--r-- | libbrillo.gypi | 2 |
4 files changed, 291 insertions, 0 deletions
diff --git a/brillo/imageloader/manifest.cc b/brillo/imageloader/manifest.cc new file mode 100644 index 0000000..92789df --- /dev/null +++ b/brillo/imageloader/manifest.cc @@ -0,0 +1,188 @@ +// Copyright 2018 The Chromium OS Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <brillo/imageloader/manifest.h> + +#include <memory> +#include <utility> + +#include <base/json/json_string_value_serializer.h> +#include <base/strings/string_number_conversions.h> + +namespace brillo { +namespace imageloader { + +namespace { +// The current version of the manifest file. +constexpr int kCurrentManifestVersion = 1; +// The name of the version field in the manifest. +constexpr char kManifestVersionField[] = "manifest-version"; +// The name of the component version field in the manifest. +constexpr char kVersionField[] = "version"; +// The name of the field containing the image hash. +constexpr char kImageHashField[] = "image-sha256-hash"; +// The name of the bool field indicating whether component is removable. +constexpr char kIsRemovableField[] = "is-removable"; +// The name of the metadata field. +constexpr char kMetadataField[] = "metadata"; +// The name of the field containing the table hash. +constexpr char kTableHashField[] = "table-sha256-hash"; +// The name of the optional field containing the file system type. +constexpr char kFSType[] = "fs-type"; + +bool GetSHA256FromString(const std::string& hash_str, + std::vector<uint8_t>* bytes) { + if (!base::HexStringToBytes(hash_str, bytes)) + return false; + return bytes->size() == 32; +} + +// Ensure the metadata entry is a dictionary mapping strings to strings and +// parse it into |out_metadata| and return true if so. +bool ParseMetadata(const base::Value* metadata_element, + std::map<std::string, std::string>* out_metadata) { + DCHECK(out_metadata); + + const base::DictionaryValue* metadata_dict = nullptr; + if (!metadata_element->GetAsDictionary(&metadata_dict)) + return false; + + base::DictionaryValue::Iterator it(*metadata_dict); + for (; !it.IsAtEnd(); it.Advance()) { + std::string parsed_value; + if (!it.value().GetAsString(&parsed_value)) { + LOG(ERROR) << "Key \"" << it.key() << "\" did not map to string value"; + return false; + } + + (*out_metadata)[it.key()] = std::move(parsed_value); + } + + return true; +} + +} // namespace + +Manifest::Manifest() {} + +bool Manifest::ParseManifest(const std::string& manifest_raw) { + // Now deserialize the manifest json and read out the rest of the component. + int error_code; + std::string error_message; + JSONStringValueDeserializer deserializer(manifest_raw); + std::unique_ptr<base::Value> value = + deserializer.Deserialize(&error_code, &error_message); + + if (!value) { + LOG(ERROR) << "Could not deserialize the manifest file. Error " + << error_code << ": " << error_message; + return false; + } + + base::DictionaryValue* manifest_dict = nullptr; + if (!value->GetAsDictionary(&manifest_dict)) { + LOG(ERROR) << "Could not parse manifest file as JSON."; + return false; + } + + // This will have to be changed if the manifest version is bumped. + int version; + if (!manifest_dict->GetInteger(kManifestVersionField, &version)) { + LOG(ERROR) << "Could not parse manifest version field from manifest."; + return false; + } + if (version != kCurrentManifestVersion) { + LOG(ERROR) << "Unsupported version of the manifest."; + return false; + } + manifest_version_ = version; + + std::string image_hash_str; + if (!manifest_dict->GetString(kImageHashField, &image_hash_str)) { + LOG(ERROR) << "Could not parse image hash from manifest."; + return false; + } + + if (!GetSHA256FromString(image_hash_str, &(image_sha256_))) { + LOG(ERROR) << "Could not convert image hash to bytes."; + return false; + } + + std::string table_hash_str; + if (!manifest_dict->GetString(kTableHashField, &table_hash_str)) { + LOG(ERROR) << "Could not parse table hash from manifest."; + return false; + } + + if (!GetSHA256FromString(table_hash_str, &(table_sha256_))) { + LOG(ERROR) << "Could not convert table hash to bytes."; + return false; + } + + if (!manifest_dict->GetString(kVersionField, &(version_))) { + LOG(ERROR) << "Could not parse component version from manifest."; + return false; + } + + // The fs_type field is optional, and squashfs by default. + fs_type_ = FileSystem::kSquashFS; + std::string fs_type; + if (manifest_dict->GetString(kFSType, &fs_type)) { + if (fs_type == "ext4") { + fs_type_ = FileSystem::kExt4; + } else if (fs_type == "squashfs") { + fs_type_ = FileSystem::kSquashFS; + } else { + LOG(ERROR) << "Unsupported file system type: " << fs_type; + return false; + } + } + + if (!manifest_dict->GetBoolean(kIsRemovableField, &(is_removable_))) { + // If is_removable field does not exist, by default it is false. + is_removable_ = false; + } + + // Copy out the metadata, if it's there. + const base::Value* metadata = nullptr; + if (manifest_dict->Get(kMetadataField, &metadata)) { + if (!ParseMetadata(metadata, &(metadata_))) { + LOG(ERROR) << "Manifest metadata was malformed"; + return false; + } + } + + return true; +} + +int Manifest::manifest_version() const { + return manifest_version_; +} + +const std::vector<uint8_t>& Manifest::image_sha256() const { + return image_sha256_; +} + +const std::vector<uint8_t>& Manifest::table_sha256() const { + return table_sha256_; +} + +const std::string& Manifest::version() const { + return version_; +} + +FileSystem Manifest::fs_type() const { + return fs_type_; +} + +bool Manifest::is_removable() const { + return is_removable_; +} + +const std::map<std::string, std::string> Manifest::metadata() const { + return metadata_; +} + +} // namespace imageloader +} // namespace brillo diff --git a/brillo/imageloader/manifest.h b/brillo/imageloader/manifest.h new file mode 100644 index 0000000..cfd7c3a --- /dev/null +++ b/brillo/imageloader/manifest.h @@ -0,0 +1,52 @@ +// Copyright 2018 The Chromium OS Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef LIBBRILLO_BRILLO_IMAGELOADER_MANIFEST_H_ +#define LIBBRILLO_BRILLO_IMAGELOADER_MANIFEST_H_ + +#include <map> +#include <string> +#include <vector> + +#include <base/macros.h> +#include <brillo/brillo_export.h> + +namespace brillo { +namespace imageloader { + +// The supported file systems for images. +enum class FileSystem { kExt4, kSquashFS }; + +// A class to parse and store imageloader.json manifest. +class BRILLO_EXPORT Manifest { + public: + Manifest(); + // Parse the manifest raw string. Return true if successful. + bool ParseManifest(const std::string& manifest_raw); + // Getters for manifest fields: + int manifest_version() const; + const std::vector<uint8_t>& image_sha256() const; + const std::vector<uint8_t>& table_sha256() const; + const std::string& version() const; + FileSystem fs_type() const; + bool is_removable() const; + const std::map<std::string, std::string> metadata() const; + + private: + // Manifest fields: + int manifest_version_; + std::vector<uint8_t> image_sha256_; + std::vector<uint8_t> table_sha256_; + std::string version_; + FileSystem fs_type_; + bool is_removable_; + std::map<std::string, std::string> metadata_; + + DISALLOW_COPY_AND_ASSIGN(Manifest); +}; + +} // namespace imageloader +} // namespace brillo + +#endif // LIBBRILLO_BRILLO_IMAGELOADER_MANIFEST_H_ diff --git a/brillo/imageloader/manifest_unittest.cc b/brillo/imageloader/manifest_unittest.cc new file mode 100644 index 0000000..bca7e8b --- /dev/null +++ b/brillo/imageloader/manifest_unittest.cc @@ -0,0 +1,49 @@ +// Copyright 2018 The Chromium OS Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <gtest/gtest.h> + +#include <brillo/imageloader/manifest.h> + +namespace brillo { +namespace imageloader { + +class ManifestTest : public testing::Test {}; + +TEST_F(ManifestTest, ParseManifest) { + const std::string fs_type = R"("ext4")"; + const std::string is_removable = R"(true)"; + const std::string image_sha256_hash = + R"("4CF41BD11362CCB4707FB93939DBB5AC48745EDFC9DC8D7702852FFAA81B3B3F")"; + const std::string table_sha256_hash = + R"("0E11DA3D7140C6B95496787F50D15152434EBA22B60443BFA7E054FF4C799276")"; + const std::string version = R"("9824.0.4")"; + const std::string manifest_version = R"(1)"; + const std::string manifest_raw = std::string() + R"( + { + "fs-type":)" + fs_type + R"(, + "is-removable":)" + is_removable + + R"(, + "image-sha256-hash":)" + image_sha256_hash + + R"(, + "table-sha256-hash":)" + table_sha256_hash + + R"(, + "version":)" + version + R"(, + "manifest-version":)" + manifest_version + + R"( + } + )"; + brillo::imageloader::Manifest manifest; + // Parse the manifest raw string. + ASSERT_TRUE(manifest.ParseManifest(manifest_raw)); + EXPECT_EQ(manifest.fs_type(), FileSystem::kExt4); + EXPECT_EQ(manifest.is_removable(), true); + EXPECT_NE(manifest.image_sha256().size(), 0); + EXPECT_NE(manifest.table_sha256().size(), 0); + EXPECT_NE(manifest.version().size(), 0); + EXPECT_EQ(manifest.manifest_version(), 1); +} + +} // namespace imageloader +} // namespace brillo diff --git a/libbrillo.gypi b/libbrillo.gypi index ed63e64..05d95e6 100644 --- a/libbrillo.gypi +++ b/libbrillo.gypi @@ -65,6 +65,7 @@ 'brillo/errors/error_codes.cc', 'brillo/file_utils.cc', 'brillo/flag_helper.cc', + 'brillo/imageloader/manifest.cc', 'brillo/key_value_store.cc', 'brillo/message_loops/base_message_loop.cc', 'brillo/message_loops/message_loop.cc', @@ -381,6 +382,7 @@ 'brillo/http/http_request_unittest.cc', 'brillo/http/http_transport_curl_unittest.cc', 'brillo/http/http_utils_unittest.cc', + 'brillo/imageloader/manifest_unittest.cc', 'brillo/key_value_store_unittest.cc', 'brillo/map_utils_unittest.cc', 'brillo/message_loops/base_message_loop_unittest.cc', |