Merge "aconfig: add aconfig_storage_metadata proto" into main am: dfb817c223
Original change: https://android-review.googlesource.com/c/platform/build/+/2928251 Change-Id: Id6173a23a30990e740c4a99bf12965d630dcdee4 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -9,6 +9,9 @@ rust_defaults {
|
||||
srcs: ["src/lib.rs"],
|
||||
rustlibs: [
|
||||
"libanyhow",
|
||||
"libaconfig_storage_protos",
|
||||
"libonce_cell",
|
||||
"libprotobuf",
|
||||
],
|
||||
}
|
||||
|
||||
@@ -24,3 +27,11 @@ rust_test_host {
|
||||
test_suites: ["general-tests"],
|
||||
defaults: ["aconfig_storage_file.defaults"],
|
||||
}
|
||||
|
||||
rust_protobuf {
|
||||
name: "libaconfig_storage_protos",
|
||||
protos: ["protos/aconfig_storage_metadata.proto"],
|
||||
crate_name: "aconfig_storage_protos",
|
||||
source_stem: "aconfig_storage_protos",
|
||||
host_supported: true,
|
||||
}
|
||||
|
@@ -9,3 +9,7 @@ cargo = []
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.69"
|
||||
protobuf = "3.2.0"
|
||||
|
||||
[build-dependencies]
|
||||
protobuf-codegen = "3.2.0"
|
||||
|
17
tools/aconfig/aconfig_storage_file/build.rs
Normal file
17
tools/aconfig/aconfig_storage_file/build.rs
Normal file
@@ -0,0 +1,17 @@
|
||||
use protobuf_codegen::Codegen;
|
||||
|
||||
fn main() {
|
||||
let proto_files = vec!["protos/aconfig_storage_metadata.proto"];
|
||||
|
||||
// tell cargo to only re-run the build script if any of the proto files has changed
|
||||
for path in &proto_files {
|
||||
println!("cargo:rerun-if-changed={}", path);
|
||||
}
|
||||
|
||||
Codegen::new()
|
||||
.pure()
|
||||
.include("protos")
|
||||
.inputs(proto_files)
|
||||
.cargo_out_dir("aconfig_storage_protos")
|
||||
.run_from_script();
|
||||
}
|
@@ -0,0 +1,34 @@
|
||||
// Copyright (C) 2024 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 is the schema definition for aconfig files. Modifications need to be
|
||||
// either backwards compatible, or include updates to all aconfig files in the
|
||||
// Android tree.
|
||||
|
||||
syntax = "proto2";
|
||||
|
||||
package android.aconfig_storage_metadata;
|
||||
|
||||
message storage_file_info {
|
||||
optional uint32 version = 1;
|
||||
optional string container = 2;
|
||||
optional string package_map = 3;
|
||||
optional string flag_map = 4;
|
||||
optional string flag_val = 5;
|
||||
optional int64 timestamp = 6;
|
||||
}
|
||||
|
||||
message storage_files {
|
||||
repeated storage_file_info files = 1;
|
||||
};
|
@@ -21,6 +21,10 @@ pub mod flag_table;
|
||||
pub mod flag_value;
|
||||
pub mod package_table;
|
||||
|
||||
mod protos;
|
||||
#[cfg(test)]
|
||||
mod test_utils;
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
use std::collections::hash_map::DefaultHasher;
|
||||
use std::hash::{Hash, Hasher};
|
||||
|
182
tools/aconfig/aconfig_storage_file/src/protos.rs
Normal file
182
tools/aconfig/aconfig_storage_file/src/protos.rs
Normal file
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
* Copyright (C) 2024 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.
|
||||
*/
|
||||
|
||||
// When building with the Android tool-chain
|
||||
//
|
||||
// - an external crate `aconfig_storage_metadata_protos` will be generated
|
||||
// - the feature "cargo" will be disabled
|
||||
//
|
||||
// When building with cargo
|
||||
//
|
||||
// - a local sub-module will be generated in OUT_DIR and included in this file
|
||||
// - the feature "cargo" will be enabled
|
||||
//
|
||||
// This module hides these differences from the rest of the codebase.
|
||||
|
||||
// ---- When building with the Android tool-chain ----
|
||||
#[cfg(not(feature = "cargo"))]
|
||||
mod auto_generated {
|
||||
pub use aconfig_storage_protos::aconfig_storage_metadata as ProtoStorage;
|
||||
pub use ProtoStorage::Storage_file_info as ProtoStorageFileInfo;
|
||||
pub use ProtoStorage::Storage_files as ProtoStorageFiles;
|
||||
}
|
||||
|
||||
// ---- When building with cargo ----
|
||||
#[cfg(feature = "cargo")]
|
||||
mod auto_generated {
|
||||
// include! statements should be avoided (because they import file contents verbatim), but
|
||||
// because this is only used during local development, and only if using cargo instead of the
|
||||
// Android tool-chain, we allow it
|
||||
include!(concat!(env!("OUT_DIR"), "/aconfig_storage_protos/mod.rs"));
|
||||
pub use aconfig_storage_metadata::Storage_file_info as ProtoStorageFileInfo;
|
||||
pub use aconfig_storage_metadata::Storage_files as ProtoStorageFiles;
|
||||
}
|
||||
|
||||
// ---- Common for both the Android tool-chain and cargo ----
|
||||
pub use auto_generated::*;
|
||||
|
||||
use anyhow::Result;
|
||||
|
||||
pub mod storage_files {
|
||||
use super::*;
|
||||
use anyhow::ensure;
|
||||
|
||||
pub fn try_from_binary_proto(bytes: &[u8]) -> Result<ProtoStorageFiles> {
|
||||
let message: ProtoStorageFiles = protobuf::Message::parse_from_bytes(bytes)?;
|
||||
verify_fields(&message)?;
|
||||
Ok(message)
|
||||
}
|
||||
|
||||
pub fn verify_fields(storage_files: &ProtoStorageFiles) -> Result<()> {
|
||||
for storage_file_info in storage_files.files.iter() {
|
||||
ensure!(
|
||||
!storage_file_info.package_map().is_empty(),
|
||||
"invalid storage file record: missing package map file for container {}",
|
||||
storage_file_info.container()
|
||||
);
|
||||
ensure!(
|
||||
!storage_file_info.flag_map().is_empty(),
|
||||
"invalid storage file record: missing flag map file for container {}",
|
||||
storage_file_info.container()
|
||||
);
|
||||
ensure!(
|
||||
!storage_file_info.flag_val().is_empty(),
|
||||
"invalid storage file record: missing flag val file for container {}",
|
||||
storage_file_info.container()
|
||||
);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::test_utils::get_binary_storage_proto_bytes;
|
||||
|
||||
#[test]
|
||||
fn test_parse_storage_files() {
|
||||
let text_proto = r#"
|
||||
files {
|
||||
version: 0
|
||||
container: "system"
|
||||
package_map: "/system/etc/package.map"
|
||||
flag_map: "/system/etc/flag.map"
|
||||
flag_val: "/metadata/aconfig/system.val"
|
||||
timestamp: 12345
|
||||
}
|
||||
files {
|
||||
version: 1
|
||||
container: "product"
|
||||
package_map: "/product/etc/package.map"
|
||||
flag_map: "/product/etc/flag.map"
|
||||
flag_val: "/metadata/aconfig/product.val"
|
||||
timestamp: 54321
|
||||
}
|
||||
"#;
|
||||
let binary_proto_bytes = get_binary_storage_proto_bytes(text_proto).unwrap();
|
||||
let storage_files = storage_files::try_from_binary_proto(&binary_proto_bytes).unwrap();
|
||||
assert_eq!(storage_files.files.len(), 2);
|
||||
let system_file = &storage_files.files[0];
|
||||
assert_eq!(system_file.version(), 0);
|
||||
assert_eq!(system_file.container(), "system");
|
||||
assert_eq!(system_file.package_map(), "/system/etc/package.map");
|
||||
assert_eq!(system_file.flag_map(), "/system/etc/flag.map");
|
||||
assert_eq!(system_file.flag_val(), "/metadata/aconfig/system.val");
|
||||
assert_eq!(system_file.timestamp(), 12345);
|
||||
let product_file = &storage_files.files[1];
|
||||
assert_eq!(product_file.version(), 1);
|
||||
assert_eq!(product_file.container(), "product");
|
||||
assert_eq!(product_file.package_map(), "/product/etc/package.map");
|
||||
assert_eq!(product_file.flag_map(), "/product/etc/flag.map");
|
||||
assert_eq!(product_file.flag_val(), "/metadata/aconfig/product.val");
|
||||
assert_eq!(product_file.timestamp(), 54321);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_invalid_storage_files() {
|
||||
let text_proto = r#"
|
||||
files {
|
||||
version: 0
|
||||
container: "system"
|
||||
package_map: ""
|
||||
flag_map: "/system/etc/flag.map"
|
||||
flag_val: "/metadata/aconfig/system.val"
|
||||
timestamp: 12345
|
||||
}
|
||||
"#;
|
||||
let binary_proto_bytes = get_binary_storage_proto_bytes(text_proto).unwrap();
|
||||
let err = storage_files::try_from_binary_proto(&binary_proto_bytes).unwrap_err();
|
||||
assert_eq!(
|
||||
format!("{:?}", err),
|
||||
"invalid storage file record: missing package map file for container system"
|
||||
);
|
||||
|
||||
let text_proto = r#"
|
||||
files {
|
||||
version: 0
|
||||
container: "system"
|
||||
package_map: "/system/etc/package.map"
|
||||
flag_map: ""
|
||||
flag_val: "/metadata/aconfig/system.val"
|
||||
timestamp: 12345
|
||||
}
|
||||
"#;
|
||||
let binary_proto_bytes = get_binary_storage_proto_bytes(text_proto).unwrap();
|
||||
let err = storage_files::try_from_binary_proto(&binary_proto_bytes).unwrap_err();
|
||||
assert_eq!(
|
||||
format!("{:?}", err),
|
||||
"invalid storage file record: missing flag map file for container system"
|
||||
);
|
||||
|
||||
let text_proto = r#"
|
||||
files {
|
||||
version: 0
|
||||
container: "system"
|
||||
package_map: "/system/etc/package.map"
|
||||
flag_map: "/system/etc/flag.map"
|
||||
flag_val: ""
|
||||
timestamp: 12345
|
||||
}
|
||||
"#;
|
||||
let binary_proto_bytes = get_binary_storage_proto_bytes(text_proto).unwrap();
|
||||
let err = storage_files::try_from_binary_proto(&binary_proto_bytes).unwrap_err();
|
||||
assert_eq!(
|
||||
format!("{:?}", err),
|
||||
"invalid storage file record: missing flag val file for container system"
|
||||
);
|
||||
}
|
||||
}
|
26
tools/aconfig/aconfig_storage_file/src/test_utils.rs
Normal file
26
tools/aconfig/aconfig_storage_file/src/test_utils.rs
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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.
|
||||
*/
|
||||
|
||||
use anyhow::Result;
|
||||
use protobuf::Message;
|
||||
use crate::protos::ProtoStorageFiles;
|
||||
|
||||
pub fn get_binary_storage_proto_bytes(text_proto: &str) -> Result<Vec<u8>> {
|
||||
let storage_files: ProtoStorageFiles = protobuf::text_format::parse_from_str(text_proto)?;
|
||||
let mut binary_proto = Vec::new();
|
||||
storage_files.write_to_vec(&mut binary_proto)?;
|
||||
Ok(binary_proto)
|
||||
}
|
Reference in New Issue
Block a user