aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-05-10 07:00:17 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-05-10 07:00:17 +0000
commit42c3269008bf3a0260a477bb8201d27d2ad03aaf (patch)
tree80c9cc5a3062975f6160ec7bb8506863ecd6b158
parent391daa57cf17e596315e926d98307c277288703b (diff)
parentbc62b0cc2bb1b07defd9801c5224dbd90d47f319 (diff)
downloadandroid_logger-android13-mainline-permission-release.tar.gz
Change-Id: I12002450970cc9b21effbf21ce70ac1c078bfab6
-rw-r--r--Android.bp37
-rw-r--r--TEST_MAPPING72
-rw-r--r--cargo2android.json10
-rw-r--r--patches/0001-Support-selecting-target-log-buffer.patch197
-rw-r--r--patches/0002-Use-older-API-to-avoid-requiring-API-v30.patch41
-rw-r--r--src/lib.rs65
6 files changed, 379 insertions, 43 deletions
diff --git a/Android.bp b/Android.bp
index d156d87..056c310 100644
--- a/Android.bp
+++ b/Android.bp
@@ -40,8 +40,10 @@ license {
}
rust_test {
- name: "android_logger_device_test_src_lib",
+ name: "android_logger_test_src_lib",
crate_name: "android_logger",
+ cargo_env_compat: true,
+ cargo_pkg_version: "0.10.1",
srcs: ["src/lib.rs"],
test_suites: ["general-tests"],
auto_gen_config: true,
@@ -59,8 +61,10 @@ rust_test {
}
rust_defaults {
- name: "android_logger_defaults",
+ name: "android_logger_test_defaults",
crate_name: "android_logger",
+ cargo_env_compat: true,
+ cargo_pkg_version: "0.10.1",
test_suites: ["general-tests"],
auto_gen_config: true,
edition: "2015",
@@ -78,26 +82,28 @@ rust_defaults {
}
rust_test {
- name: "android_logger_device_test_tests_config_log_level",
- defaults: ["android_logger_defaults"],
+ name: "android_logger_test_tests_config_log_level",
+ defaults: ["android_logger_test_defaults"],
srcs: ["tests/config_log_level.rs"],
}
rust_test {
- name: "android_logger_device_test_tests_default_init",
- defaults: ["android_logger_defaults"],
+ name: "android_logger_test_tests_default_init",
+ defaults: ["android_logger_test_defaults"],
srcs: ["tests/default_init.rs"],
}
rust_test {
- name: "android_logger_device_test_tests_multiple_init",
- defaults: ["android_logger_defaults"],
+ name: "android_logger_test_tests_multiple_init",
+ defaults: ["android_logger_test_defaults"],
srcs: ["tests/multiple_init.rs"],
}
rust_library {
name: "libandroid_logger",
crate_name: "android_logger",
+ cargo_env_compat: true,
+ cargo_pkg_version: "0.10.1",
srcs: ["src/lib.rs"],
edition: "2015",
features: [
@@ -112,19 +118,12 @@ rust_library {
],
apex_available: [
"//apex_available:platform",
+ "com.android.bluetooth",
+ "com.android.compos",
"com.android.resolv",
+ "com.android.uwb",
"com.android.virt",
],
+ vendor_available: true,
min_sdk_version: "29",
}
-
-// dependent_library ["feature_list"]
-// aho-corasick-0.7.15 "default,std"
-// android_log-sys-0.2.0
-// cfg-if-1.0.0
-// env_logger-0.8.3 "regex"
-// lazy_static-1.4.0
-// log-0.4.14 "std"
-// memchr-2.3.4 "default,std,use_std"
-// regex-1.4.6 "aho-corasick,memchr,perf,perf-cache,perf-dfa,perf-inline,perf-literal,std"
-// regex-syntax-0.6.23
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 813e886..526e77a 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -2,40 +2,96 @@
{
"presubmit": [
{
- "name": "android_logger_device_test_src_lib"
+ "name": "android_logger_test_src_lib"
},
{
- "name": "android_logger_device_test_tests_config_log_level"
+ "name": "android_logger_test_tests_config_log_level"
},
{
- "name": "android_logger_device_test_tests_default_init"
+ "name": "android_logger_test_tests_default_init"
},
{
- "name": "android_logger_device_test_tests_multiple_init"
+ "name": "android_logger_test_tests_multiple_init"
+ },
+ {
+ "name": "authfs_device_test_src_lib"
},
{
"name": "doh_unit_test"
},
{
+ "name": "keystore2_selinux_concurrency_test"
+ },
+ {
"name": "keystore2_selinux_test"
},
{
"name": "keystore2_test"
},
{
- "name": "logger_device_test_config_log_level"
+ "name": "logger_device_unit_tests"
+ },
+ {
+ "name": "logger_test_config_log_level"
+ },
+ {
+ "name": "logger_test_default_init"
+ },
+ {
+ "name": "logger_test_env_log_level"
+ },
+ {
+ "name": "logger_test_multiple_init"
+ },
+ {
+ "name": "virtualizationservice_device_test"
+ }
+ ],
+ "presubmit-rust": [
+ {
+ "name": "android_logger_test_src_lib"
+ },
+ {
+ "name": "android_logger_test_tests_config_log_level"
+ },
+ {
+ "name": "android_logger_test_tests_default_init"
+ },
+ {
+ "name": "android_logger_test_tests_multiple_init"
+ },
+ {
+ "name": "authfs_device_test_src_lib"
},
{
- "name": "logger_device_test_default_init"
+ "name": "doh_unit_test"
},
{
- "name": "logger_device_test_env_log_level"
+ "name": "keystore2_selinux_concurrency_test"
},
{
- "name": "logger_device_test_multiple_init"
+ "name": "keystore2_selinux_test"
+ },
+ {
+ "name": "keystore2_test"
},
{
"name": "logger_device_unit_tests"
+ },
+ {
+ "name": "logger_test_config_log_level"
+ },
+ {
+ "name": "logger_test_default_init"
+ },
+ {
+ "name": "logger_test_env_log_level"
+ },
+ {
+ "name": "logger_test_multiple_init"
+ },
+ {
+ "name": "virtualizationservice_device_test"
}
]
}
diff --git a/cargo2android.json b/cargo2android.json
index d02b87d..18ba06d 100644
--- a/cargo2android.json
+++ b/cargo2android.json
@@ -1,13 +1,17 @@
{
"apex-available": [
"//apex_available:platform",
+ "com.android.bluetooth",
+ "com.android.compos",
"com.android.resolv",
+ "com.android.uwb",
"com.android.virt"
],
- "min_sdk_version": "29",
"dependencies": true,
"device": true,
+ "min-sdk-version": "29",
"no-host": true,
"run": true,
- "tests": true
-} \ No newline at end of file
+ "tests": true,
+ "vendor-available": true
+}
diff --git a/patches/0001-Support-selecting-target-log-buffer.patch b/patches/0001-Support-selecting-target-log-buffer.patch
new file mode 100644
index 0000000..e5fc33b
--- /dev/null
+++ b/patches/0001-Support-selecting-target-log-buffer.patch
@@ -0,0 +1,197 @@
+From 2bc2650d0a7a11a74670a6583b16aa6714d7c993 Mon Sep 17 00:00:00 2001
+From: Matthew Maurer <mmaurer@google.com>
+Date: Thu, 17 Feb 2022 20:23:37 +0000
+Subject: [PATCH] Support selecting target log buffer
+
+Android has several different log buffers. Previously, this library
+would only support logging to the "Main" log. Now, it logs to the
+default log (which is Main for most processes), with the option to
+override which log buffer you send messages to in the config.
+
+Change-Id: I72779e62bd963586e3dfad431cd82c75daf04d92
+---
+ src/lib.rs | 71 ++++++++++++++++++++++++++++++++++++++++++++----------
+ 1 file changed, 58 insertions(+), 13 deletions(-)
+
+diff --git a/src/lib.rs b/src/lib.rs
+index 11a127e..d21be3f 100644
+--- a/src/lib.rs
++++ b/src/lib.rs
+@@ -87,21 +87,49 @@ pub use env_logger::fmt::Formatter;
+
+ pub(crate) type FormatFn = Box<dyn Fn(&mut dyn fmt::Write, &Record) -> fmt::Result + Sync + Send>;
+
++#[derive(Copy, Clone, Eq, PartialEq, Debug)]
++pub enum LogId {
++ Main,
++ Radio,
++ Events,
++ System,
++ Crash
++}
++
++impl LogId {
++ #[cfg(target_os = "android")]
++ fn to_native(log_id: Option<Self>) -> log_ffi::log_id_t {
++ match log_id {
++ Some(LogId::Main) => log_ffi::log_id_t::MAIN,
++ Some(LogId::Radio) => log_ffi::log_id_t::RADIO,
++ Some(LogId::Events) => log_ffi::log_id_t::EVENTS,
++ Some(LogId::System) => log_ffi::log_id_t::SYSTEM,
++ Some(LogId::Crash) => log_ffi::log_id_t::CRASH,
++ None => log_ffi::log_id_t::DEFAULT,
++ }
++ }
++}
++
+ /// Output log to android system.
+ #[cfg(target_os = "android")]
+-fn android_log(prio: log_ffi::LogPriority, tag: &CStr, msg: &CStr) {
++fn android_log(log_id: log_ffi::log_id_t, prio: log_ffi::LogPriority, tag: &CStr, msg: &CStr) {
++ let mut message = log_ffi::__android_log_message {
++ struct_size: std::mem::size_of::<log_ffi::__android_log_message>(),
++ buffer_id: log_id as i32,
++ priority: prio as i32,
++ tag: tag.as_ptr() as *const log_ffi::c_char,
++ file: ptr::null(),
++ line: 0,
++ message: msg.as_ptr() as *const log_ffi::c_char,
++ };
+ unsafe {
+- log_ffi::__android_log_write(
+- prio as log_ffi::c_int,
+- tag.as_ptr() as *const log_ffi::c_char,
+- msg.as_ptr() as *const log_ffi::c_char,
+- )
++ log_ffi::__android_log_write_log_message(&mut message as *mut _);
+ };
+ }
+
+ /// Dummy output placeholder for tests.
+ #[cfg(not(target_os = "android"))]
+-fn android_log(_priority: Level, _tag: &CStr, _msg: &CStr) {}
++fn android_log(_log_id: Option<LogId>, _priority: Level, _tag: &CStr, _msg: &CStr) {}
+
+ /// Underlying android logger backend
+ pub struct AndroidLogger {
+@@ -164,7 +192,7 @@ impl Log for AndroidLogger {
+
+ // message must not exceed LOGGING_MSG_MAX_LEN
+ // therefore split log message into multiple log calls
+- let mut writer = PlatformLogWriter::new(record.level(), tag);
++ let mut writer = PlatformLogWriter::new(config.log_id, record.level(), tag);
+
+ // If a custom tag is used, add the module path to the message.
+ // Use PlatformLogWriter to output chunks if they exceed max size.
+@@ -208,6 +236,7 @@ impl AndroidLogger {
+ /// Filter for android logger.
+ pub struct Config {
+ log_level: Option<Level>,
++ log_id: Option<LogId>,
+ filter: Option<env_logger::filter::Filter>,
+ tag: Option<CString>,
+ custom_format: Option<FormatFn>,
+@@ -217,6 +246,7 @@ impl Default for Config {
+ fn default() -> Self {
+ Config {
+ log_level: None,
++ log_id: None,
+ filter: None,
+ tag: None,
+ custom_format: None,
+@@ -234,6 +264,15 @@ impl Config {
+ self
+ }
+
++ /// Change which log buffer is used
++ ///
++ /// By default, logs are sent to the `Main` log. Other logging buffers may only be accessible
++ /// to certain processes.
++ pub fn with_log_id(mut self, log_id: LogId) -> Self {
++ self.log_id = Some(log_id);
++ self
++ }
++
+ fn filter_matches(&self, record: &Record) -> bool {
+ if let Some(ref filter) = self.filter {
+ filter.matches(&record)
+@@ -273,6 +312,8 @@ impl Config {
+ struct PlatformLogWriter<'a> {
+ #[cfg(target_os = "android")] priority: LogPriority,
+ #[cfg(not(target_os = "android"))] priority: Level,
++ #[cfg(target_os = "android")] log_id: log_ffi::log_id_t,
++ #[cfg(not(target_os = "android"))] log_id: Option<LogId>,
+ len: usize,
+ last_newline_index: usize,
+ tag: &'a CStr,
+@@ -281,7 +322,7 @@ struct PlatformLogWriter<'a> {
+
+ impl<'a> PlatformLogWriter<'a> {
+ #[cfg(target_os = "android")]
+- pub fn new(level: Level, tag: &CStr) -> PlatformLogWriter {
++ pub fn new(log_id: Option<LogId>, level: Level, tag: &CStr) -> PlatformLogWriter {
+ #[allow(deprecated)] // created an issue #35 for this
+ PlatformLogWriter {
+ priority: match level {
+@@ -291,6 +332,7 @@ impl<'a> PlatformLogWriter<'a> {
+ Level::Error => LogPriority::ERROR,
+ Level::Trace => LogPriority::VERBOSE,
+ },
++ log_id: LogId::to_native(log_id),
+ len: 0,
+ last_newline_index: 0,
+ tag,
+@@ -299,10 +341,11 @@ impl<'a> PlatformLogWriter<'a> {
+ }
+
+ #[cfg(not(target_os = "android"))]
+- pub fn new(level: Level, tag: &CStr) -> PlatformLogWriter {
++ pub fn new(log_id: Option<LogId>, level: Level, tag: &CStr) -> PlatformLogWriter {
+ #[allow(deprecated)] // created an issue #35 for this
+ PlatformLogWriter {
+ priority: level,
++ log_id,
+ len: 0,
+ last_newline_index: 0,
+ tag,
+@@ -358,7 +401,7 @@ impl<'a> PlatformLogWriter<'a> {
+ });
+
+ let msg: &CStr = unsafe { CStr::from_ptr(mem::transmute(self.buffer.as_ptr())) };
+- android_log(self.priority, self.tag, msg);
++ android_log(self.log_id, self.priority, self.tag, msg);
+
+ *unsafe { self.buffer.get_unchecked_mut(len) } = last_byte;
+ }
+@@ -458,9 +501,11 @@ mod tests {
+ // Filter is checked in config_filter_match below.
+ let config = Config::default()
+ .with_min_level(Level::Trace)
++ .with_log_id(LogId::System)
+ .with_tag("my_app");
+
+ assert_eq!(config.log_level, Some(Level::Trace));
++ assert_eq!(config.log_id, Some(LogId::System));
+ assert_eq!(config.tag, Some(CString::new("my_app").unwrap()));
+ }
+
+@@ -531,7 +576,7 @@ mod tests {
+ fn platform_log_writer_init_values() {
+ let tag = CStr::from_bytes_with_nul(b"tag\0").unwrap();
+
+- let writer = PlatformLogWriter::new(Level::Warn, &tag);
++ let writer = PlatformLogWriter::new(None, Level::Warn, &tag);
+
+ assert_eq!(writer.tag, tag);
+ // Android uses LogPriority instead, which doesn't implement equality checks
+@@ -630,6 +675,6 @@ mod tests {
+ }
+
+ fn get_tag_writer() -> PlatformLogWriter<'static> {
+- PlatformLogWriter::new(Level::Warn, &CStr::from_bytes_with_nul(b"tag\0").unwrap())
++ PlatformLogWriter::new(None, Level::Warn, &CStr::from_bytes_with_nul(b"tag\0").unwrap())
+ }
+ }
+--
+2.35.1.265.g69c8d7142f-goog
+
diff --git a/patches/0002-Use-older-API-to-avoid-requiring-API-v30.patch b/patches/0002-Use-older-API-to-avoid-requiring-API-v30.patch
new file mode 100644
index 0000000..721e9eb
--- /dev/null
+++ b/patches/0002-Use-older-API-to-avoid-requiring-API-v30.patch
@@ -0,0 +1,41 @@
+From ec84856e0f0bc5a307529122bfed3d94d2ef4011 Mon Sep 17 00:00:00 2001
+From: Matthew Maurer <mmaurer@google.com>
+Date: Thu, 24 Feb 2022 14:07:03 -0800
+Subject: [PATCH] Use older API to avoid requiring API v30
+
+Test: Check that keystore still outputs logs to system
+Bug: 221185310
+Change-Id: I25174f1617557e270db70cd432cec78c037c6b75
+---
+ src/lib.rs | 14 ++++----------
+ 1 file changed, 4 insertions(+), 10 deletions(-)
+
+diff --git a/src/lib.rs b/src/lib.rs
+index d21be3f..bc4fa61 100644
+--- a/src/lib.rs
++++ b/src/lib.rs
+@@ -113,17 +113,11 @@ impl LogId {
+ /// Output log to android system.
+ #[cfg(target_os = "android")]
+ fn android_log(log_id: log_ffi::log_id_t, prio: log_ffi::LogPriority, tag: &CStr, msg: &CStr) {
+- let mut message = log_ffi::__android_log_message {
+- struct_size: std::mem::size_of::<log_ffi::__android_log_message>(),
+- buffer_id: log_id as i32,
+- priority: prio as i32,
+- tag: tag.as_ptr() as *const log_ffi::c_char,
+- file: ptr::null(),
+- line: 0,
+- message: msg.as_ptr() as *const log_ffi::c_char,
+- };
+ unsafe {
+- log_ffi::__android_log_write_log_message(&mut message as *mut _);
++ log_ffi::__android_log_buf_write(log_id as i32,
++ prio as i32,
++ tag.as_ptr() as *const log_ffi::c_char,
++ msg.as_ptr() as *const log_ffi::c_char);
+ };
+ }
+
+--
+2.35.1.574.g5d30c73bfb-goog
+
diff --git a/src/lib.rs b/src/lib.rs
index 11a127e..bc4fa61 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -87,21 +87,43 @@ pub use env_logger::fmt::Formatter;
pub(crate) type FormatFn = Box<dyn Fn(&mut dyn fmt::Write, &Record) -> fmt::Result + Sync + Send>;
+#[derive(Copy, Clone, Eq, PartialEq, Debug)]
+pub enum LogId {
+ Main,
+ Radio,
+ Events,
+ System,
+ Crash
+}
+
+impl LogId {
+ #[cfg(target_os = "android")]
+ fn to_native(log_id: Option<Self>) -> log_ffi::log_id_t {
+ match log_id {
+ Some(LogId::Main) => log_ffi::log_id_t::MAIN,
+ Some(LogId::Radio) => log_ffi::log_id_t::RADIO,
+ Some(LogId::Events) => log_ffi::log_id_t::EVENTS,
+ Some(LogId::System) => log_ffi::log_id_t::SYSTEM,
+ Some(LogId::Crash) => log_ffi::log_id_t::CRASH,
+ None => log_ffi::log_id_t::DEFAULT,
+ }
+ }
+}
+
/// Output log to android system.
#[cfg(target_os = "android")]
-fn android_log(prio: log_ffi::LogPriority, tag: &CStr, msg: &CStr) {
+fn android_log(log_id: log_ffi::log_id_t, prio: log_ffi::LogPriority, tag: &CStr, msg: &CStr) {
unsafe {
- log_ffi::__android_log_write(
- prio as log_ffi::c_int,
- tag.as_ptr() as *const log_ffi::c_char,
- msg.as_ptr() as *const log_ffi::c_char,
- )
+ log_ffi::__android_log_buf_write(log_id as i32,
+ prio as i32,
+ tag.as_ptr() as *const log_ffi::c_char,
+ msg.as_ptr() as *const log_ffi::c_char);
};
}
/// Dummy output placeholder for tests.
#[cfg(not(target_os = "android"))]
-fn android_log(_priority: Level, _tag: &CStr, _msg: &CStr) {}
+fn android_log(_log_id: Option<LogId>, _priority: Level, _tag: &CStr, _msg: &CStr) {}
/// Underlying android logger backend
pub struct AndroidLogger {
@@ -164,7 +186,7 @@ impl Log for AndroidLogger {
// message must not exceed LOGGING_MSG_MAX_LEN
// therefore split log message into multiple log calls
- let mut writer = PlatformLogWriter::new(record.level(), tag);
+ let mut writer = PlatformLogWriter::new(config.log_id, record.level(), tag);
// If a custom tag is used, add the module path to the message.
// Use PlatformLogWriter to output chunks if they exceed max size.
@@ -208,6 +230,7 @@ impl AndroidLogger {
/// Filter for android logger.
pub struct Config {
log_level: Option<Level>,
+ log_id: Option<LogId>,
filter: Option<env_logger::filter::Filter>,
tag: Option<CString>,
custom_format: Option<FormatFn>,
@@ -217,6 +240,7 @@ impl Default for Config {
fn default() -> Self {
Config {
log_level: None,
+ log_id: None,
filter: None,
tag: None,
custom_format: None,
@@ -234,6 +258,15 @@ impl Config {
self
}
+ /// Change which log buffer is used
+ ///
+ /// By default, logs are sent to the `Main` log. Other logging buffers may only be accessible
+ /// to certain processes.
+ pub fn with_log_id(mut self, log_id: LogId) -> Self {
+ self.log_id = Some(log_id);
+ self
+ }
+
fn filter_matches(&self, record: &Record) -> bool {
if let Some(ref filter) = self.filter {
filter.matches(&record)
@@ -273,6 +306,8 @@ impl Config {
struct PlatformLogWriter<'a> {
#[cfg(target_os = "android")] priority: LogPriority,
#[cfg(not(target_os = "android"))] priority: Level,
+ #[cfg(target_os = "android")] log_id: log_ffi::log_id_t,
+ #[cfg(not(target_os = "android"))] log_id: Option<LogId>,
len: usize,
last_newline_index: usize,
tag: &'a CStr,
@@ -281,7 +316,7 @@ struct PlatformLogWriter<'a> {
impl<'a> PlatformLogWriter<'a> {
#[cfg(target_os = "android")]
- pub fn new(level: Level, tag: &CStr) -> PlatformLogWriter {
+ pub fn new(log_id: Option<LogId>, level: Level, tag: &CStr) -> PlatformLogWriter {
#[allow(deprecated)] // created an issue #35 for this
PlatformLogWriter {
priority: match level {
@@ -291,6 +326,7 @@ impl<'a> PlatformLogWriter<'a> {
Level::Error => LogPriority::ERROR,
Level::Trace => LogPriority::VERBOSE,
},
+ log_id: LogId::to_native(log_id),
len: 0,
last_newline_index: 0,
tag,
@@ -299,10 +335,11 @@ impl<'a> PlatformLogWriter<'a> {
}
#[cfg(not(target_os = "android"))]
- pub fn new(level: Level, tag: &CStr) -> PlatformLogWriter {
+ pub fn new(log_id: Option<LogId>, level: Level, tag: &CStr) -> PlatformLogWriter {
#[allow(deprecated)] // created an issue #35 for this
PlatformLogWriter {
priority: level,
+ log_id,
len: 0,
last_newline_index: 0,
tag,
@@ -358,7 +395,7 @@ impl<'a> PlatformLogWriter<'a> {
});
let msg: &CStr = unsafe { CStr::from_ptr(mem::transmute(self.buffer.as_ptr())) };
- android_log(self.priority, self.tag, msg);
+ android_log(self.log_id, self.priority, self.tag, msg);
*unsafe { self.buffer.get_unchecked_mut(len) } = last_byte;
}
@@ -458,9 +495,11 @@ mod tests {
// Filter is checked in config_filter_match below.
let config = Config::default()
.with_min_level(Level::Trace)
+ .with_log_id(LogId::System)
.with_tag("my_app");
assert_eq!(config.log_level, Some(Level::Trace));
+ assert_eq!(config.log_id, Some(LogId::System));
assert_eq!(config.tag, Some(CString::new("my_app").unwrap()));
}
@@ -531,7 +570,7 @@ mod tests {
fn platform_log_writer_init_values() {
let tag = CStr::from_bytes_with_nul(b"tag\0").unwrap();
- let writer = PlatformLogWriter::new(Level::Warn, &tag);
+ let writer = PlatformLogWriter::new(None, Level::Warn, &tag);
assert_eq!(writer.tag, tag);
// Android uses LogPriority instead, which doesn't implement equality checks
@@ -630,6 +669,6 @@ mod tests {
}
fn get_tag_writer() -> PlatformLogWriter<'static> {
- PlatformLogWriter::new(Level::Warn, &CStr::from_bytes_with_nul(b"tag\0").unwrap())
+ PlatformLogWriter::new(None, Level::Warn, &CStr::from_bytes_with_nul(b"tag\0").unwrap())
}
}