1 // Copyright 2021, The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 //! Provides interface for logging events to binary log buffers.
16 
17 // WARNING: this is not part of the crate's public API and is subject to change at any time
18 #[doc(hidden)]
19 pub mod __private_api {
20     use log_event_list_bindgen as log_bindgen;
21     use std::os::raw::c_char;
22 
23     pub use log_bindgen::log_id_LOG_ID_SECURITY as LogIdSecurity;
24 
25     /// Whether security logging is enabled.
26     #[cfg(not(android_vndk))]
security_log_enabled() -> bool27     fn security_log_enabled() -> bool {
28         // SAFETY: The call doesn't require any preconditions and only returns an int, so must be safe.
29         unsafe { log_bindgen::__android_log_security() != 0 }
30     }
31 
32     #[cfg(android_vndk)]
security_log_enabled() -> bool33     fn security_log_enabled() -> bool {
34         false
35     }
36 
37     /// A struct representing that liblog call returned an error. No details are provided.
38     #[derive(Clone, Copy)]
39     pub struct LogContextError;
40 
41     /// Convert liblog status code into a Result.
check_liblog_result(status: i32) -> Result<(), LogContextError>42     fn check_liblog_result(status: i32) -> Result<(), LogContextError> {
43         if status < 0 {
44             Err(LogContextError)
45         } else {
46             Ok(())
47         }
48     }
49 
50     /// Event log context.
51     pub struct LogContext {
52         ctx: log_bindgen::android_log_context,
53         log_type: log_bindgen::log_id,
54     }
55 
56     /// SAFETY: Log context is essentially a buffer with some associated state. All data that is
57     /// appended to the context is copied into the buffers, no references are ever stored.
58     unsafe impl Send for LogContext {}
59 
60     impl LogContext {
61         /// Creates a context for a given event tag.
new(log_type: log_bindgen::log_id, tag: u32) -> Option<LogContext>62         pub fn new(log_type: log_bindgen::log_id, tag: u32) -> Option<LogContext> {
63             if log_type == log_bindgen::log_id_LOG_ID_SECURITY && !security_log_enabled() {
64                 return None;
65             }
66 
67             // SAFETY: The method returns a pointer that is stored and always freed exactly once via
68             // Drop below.
69             let ctx = unsafe { log_bindgen::create_android_logger(tag) };
70             if !ctx.is_null() {
71                 Some(LogContext { ctx, log_type })
72             } else {
73                 None
74             }
75         }
76 
77         /// Appends an i32 to the context.
append_i32(self, data: i32) -> Result<Self, LogContextError>78         pub fn append_i32(self, data: i32) -> Result<Self, LogContextError> {
79             // SAFETY: This will only be called on a non-null pointer returned from
80             // create_android_logger previously, so should be safe.
81             check_liblog_result(unsafe { log_bindgen::android_log_write_int32(self.ctx, data) })?;
82             Ok(self)
83         }
84 
85         /// Appends an i64 to the context.
append_i64(self, data: i64) -> Result<Self, LogContextError>86         pub fn append_i64(self, data: i64) -> Result<Self, LogContextError> {
87             // SAFETY: This will only be called on a non-null pointer returned from
88             // create_android_logger previously, so should be safe.
89             check_liblog_result(unsafe { log_bindgen::android_log_write_int64(self.ctx, data) })?;
90             Ok(self)
91         }
92 
93         /// Appends an f32 to the context.
append_f32(self, data: f32) -> Result<Self, LogContextError>94         pub fn append_f32(self, data: f32) -> Result<Self, LogContextError> {
95             // SAFETY: This will only be called on a non-null pointer returned from
96             // create_android_logger previously, so should be safe.
97             check_liblog_result(unsafe { log_bindgen::android_log_write_float32(self.ctx, data) })?;
98             Ok(self)
99         }
100 
101         /// Append a string to the context.
append_str(self, data: &str) -> Result<Self, LogContextError>102         pub fn append_str(self, data: &str) -> Result<Self, LogContextError> {
103             // SAFETY: This will only be called on a non-null pointer returned from
104             // create_android_logger previously, and the function will only read data.len() characters
105             // from the str, the pointer itself won't be stored, so should be safe.
106             check_liblog_result(unsafe {
107                 log_bindgen::android_log_write_string8_len(
108                     self.ctx,
109                     data.as_ptr() as *const c_char,
110                     data.len(),
111                 )
112             })?;
113             Ok(self)
114         }
115 
116         /// Begin a sublist of values.
begin_list(self) -> Result<Self, LogContextError>117         pub fn begin_list(self) -> Result<Self, LogContextError> {
118             // SAFETY: This will only be called on a non-null pointer returned from
119             // create_android_logger previously, so should be safe.
120             check_liblog_result(unsafe { log_bindgen::android_log_write_list_begin(self.ctx) })?;
121             Ok(self)
122         }
123 
124         /// End a sublist of values.
end_list(self) -> Result<Self, LogContextError>125         pub fn end_list(self) -> Result<Self, LogContextError> {
126             // SAFETY: This will only be called on a non-null pointer returned from
127             // create_android_logger previously, so should be safe.
128             check_liblog_result(unsafe { log_bindgen::android_log_write_list_end(self.ctx) })?;
129             Ok(self)
130         }
131 
132         /// Writes the context to a given buffer type and consumes the context.
write(self) -> Result<(), LogContextError>133         pub fn write(self) -> Result<(), LogContextError> {
134             // SAFETY: This will only be called on a non-null pointer returned from
135             // create_android_logger previously, so should be safe.
136             check_liblog_result(unsafe {
137                 log_bindgen::android_log_write_list(self.ctx, self.log_type)
138             })
139         }
140     }
141 
142     impl Drop for LogContext {
drop(&mut self)143         fn drop(&mut self) {
144             // SAFETY: This will only be called on a non-null pointer returned from
145             // create_android_logger previously, so should be safe.
146             unsafe { log_bindgen::android_log_destroy(&mut self.ctx) };
147         }
148     }
149 }
150