printflags: introduce device tool to print feature flags

Metadata about all feature flags used on device are located in
/<partition>/etc/aconfig_flags.pb. Add a new tool, printflags, to read
and pretty-print these files.

printflags is only intended for debugging purposes.

Bug: 301547297
Test: adb shell printflags
Change-Id: I0a3277fecfc8a60eea0aa6bf362a25a311360b71
diff --git a/tools/aconfig/Android.bp b/tools/aconfig/Android.bp
index 28bf8a5..02fc57c 100644
--- a/tools/aconfig/Android.bp
+++ b/tools/aconfig/Android.bp
@@ -34,12 +34,13 @@
 
 // host binary: aconfig
 
-rust_protobuf_host {
+rust_protobuf {
     name: "libaconfig_protos",
     protos: ["protos/aconfig.proto"],
     crate_name: "aconfig_protos",
     source_stem: "aconfig_protos",
     use_protobuf3: true,
+    host_supported: true,
 }
 
 rust_defaults {
@@ -192,4 +193,4 @@
     rustlibs: [
         "libaconfig_test_rust_library_with_test_mode",
     ],
-}
\ No newline at end of file
+}
diff --git a/tools/aconfig/printflags/Android.bp b/tools/aconfig/printflags/Android.bp
new file mode 100644
index 0000000..5d73d96
--- /dev/null
+++ b/tools/aconfig/printflags/Android.bp
@@ -0,0 +1,16 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+rust_binary {
+    name: "printflags",
+    edition: "2021",
+    clippy_lints: "android",
+    lints: "android",
+    srcs: ["src/main.rs"],
+    rustlibs: [
+        "libaconfig_protos",
+        "libanyhow",
+        "libprotobuf",
+    ],
+}
diff --git a/tools/aconfig/printflags/src/main.rs b/tools/aconfig/printflags/src/main.rs
new file mode 100644
index 0000000..a9f7c03
--- /dev/null
+++ b/tools/aconfig/printflags/src/main.rs
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+//! `printflags` is a device binary to print feature flags.
+
+use aconfig_protos::aconfig::Parsed_flags as ProtoParsedFlags;
+use anyhow::Result;
+use std::collections::HashMap;
+use std::fs;
+
+fn main() -> Result<()> {
+    let mut flags: HashMap<String, Vec<String>> = HashMap::new();
+    for partition in ["system", "system_ext", "product", "vendor"] {
+        let path = format!("/{}/etc/aconfig_flags.pb", partition);
+        let Ok(bytes) = fs::read(&path) else {
+            eprintln!("warning: failed to read {}", path);
+            continue;
+        };
+        let parsed_flags: ProtoParsedFlags = protobuf::Message::parse_from_bytes(&bytes)?;
+        for flag in parsed_flags.parsed_flag {
+            let key = format!("{}.{}", flag.package(), flag.name());
+            let value = format!("{:?} + {:?} ({})", flag.permission(), flag.state(), partition);
+            flags.entry(key).or_default().push(value);
+        }
+    }
+    for (key, value) in flags {
+        // TODO: if the flag is READ_WRITE (for any partition), call "device_config get" to obtain
+        // the flag's current state, and append value to the output
+        println!("{}: {}", key, value.join(", "));
+    }
+    Ok(())
+}