Create Android trace events (if available) from tracing spans

This commit is contained in:
Jack Grigg 2022-11-22 17:29:24 +13:00 committed by str4d
parent 4c2bf6da69
commit f4755cfbd7
6 changed files with 119 additions and 1 deletions

25
sdk-lib/Cargo.lock generated
View File

@ -520,6 +520,29 @@ version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0"
[[package]]
name = "dlopen2"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b121caccfc363e4d9a4589528f3bef7c71b83c6ed01c8dc68cbeeb7fd29ec698"
dependencies = [
"dlopen2_derive",
"libc",
"once_cell",
"winapi",
]
[[package]]
name = "dlopen2_derive"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a09ac8bb8c16a282264c379dffba707b9c998afc7506009137f3c6136888078"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "either"
version = "1.8.0"
@ -2167,11 +2190,13 @@ dependencies = [
name = "zcash-android-wallet-sdk"
version = "0.0.4"
dependencies = [
"dlopen2",
"failure",
"hdwallet",
"hdwallet-bitcoin",
"hex",
"jni",
"libc",
"log-panics",
"paranoid-android",
"schemer",

View File

@ -31,6 +31,10 @@ paranoid-android = "0.2"
tracing = "0.1"
tracing-subscriber = "0.3"
# Conditional access to newer NDK features
dlopen2 = "0.4"
libc = "0.2"
## Uncomment this to test librustzcash changes locally
#[patch.crates-io]
#zcash_address = { path = '../../clones/librustzcash/components/zcash_address' }

View File

@ -15,6 +15,7 @@ use schemer::MigratorError;
use secrecy::{ExposeSecret, SecretVec};
use tracing::{debug, error};
use tracing_subscriber::prelude::*;
use tracing_subscriber::reload;
use zcash_address::{ToAddress, ZcashAddress};
use zcash_client_backend::keys::{DecodingError, UnifiedSpendingKey};
use zcash_client_backend::{
@ -104,15 +105,27 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_initLogs(
.with_ansi(false)
.with_filter(tracing_subscriber::filter::LevelFilter::DEBUG);
// Generate Android trace events from `tracing` spans.
let (trace_event_layer, reload_handle) = reload::Layer::new(utils::trace::Layer::new(None));
// Install the `tracing` subscriber.
let registry = tracing_subscriber::registry();
#[cfg(target_os = "android")]
let registry = registry.with(android_layer);
registry.init();
registry.with(trace_event_layer).init();
// Log panics instead of writing them to stderr.
log_panics::init();
// Load optional NDK APIs. We do this via a reload so that we can capture any errors
// that occur while trying to dynamically load the NDK.
if let Err(e) = reload_handle.modify(|layer| match utils::target_ndk::load() {
Ok(api) => *layer = utils::trace::Layer::new(Some(api)),
Err(e) => error!("Could not open NDK library or load symbols: {}", e),
}) {
error!("Failed to reload tracing subscriber with NDK APIs: {}", e);
}
debug!("logs have been initialized successfully");
print_debug_state();
}

View File

@ -9,6 +9,8 @@ use jni::{
use std::ops::Deref;
pub(crate) mod exception;
pub(crate) mod target_ndk;
pub(crate) mod trace;
pub(crate) fn java_string_to_rust(env: &JNIEnv<'_>, jstring: JString<'_>) -> String {
env.get_string(jstring)

View File

@ -0,0 +1,28 @@
//! Utilities for accessing target NDK APIs.
use dlopen2::{
wrapper::{Container, WrapperApi, WrapperMultiApi},
Error,
};
use libc::c_char;
/// NDK APIs introduced in API level 23.
#[derive(WrapperApi)]
#[allow(non_snake_case)]
pub struct Api23 {
#[allow(non_snake_case)]
ATrace_beginSection: unsafe extern "C" fn(sectionName: *const c_char),
#[allow(non_snake_case)]
ATrace_endSection: unsafe extern "C" fn(),
}
#[derive(WrapperMultiApi)]
pub struct Api {
pub v23: Option<Api23>,
}
pub type NdkApi = Container<Api>;
pub fn load() -> Result<NdkApi, Error> {
unsafe { Container::load("libandroid.so") }
}

View File

@ -0,0 +1,46 @@
use std::ffi::CString;
use tracing::{error, span, Subscriber};
use tracing_subscriber::{layer::Context, registry::LookupSpan};
use super::target_ndk::{Api23, NdkApi};
pub struct Layer {
ndk_api: Option<NdkApi>,
}
impl Layer {
pub fn new(ndk_api: Option<NdkApi>) -> Self {
Layer { ndk_api }
}
fn with_api(&self, f: impl FnOnce(&Api23)) {
if let Some(v23) = self.ndk_api.as_ref().and_then(|api| api.v23.as_ref()) {
f(v23)
}
}
}
impl<S: Subscriber> tracing_subscriber::Layer<S> for Layer
where
for<'lookup> S: LookupSpan<'lookup>,
{
fn on_enter(&self, id: &span::Id, ctx: Context<'_, S>) {
self.with_api(|api| match ctx.metadata(id) {
Some(metadata) => match CString::new(metadata.name()) {
Ok(section_name) => unsafe { api.ATrace_beginSection(section_name.as_ptr()) },
Err(_) => error!(
"Span name contains internal NUL byte: '{}'",
metadata.name()
),
},
None => error!("Span {:?} has no metadata", id),
});
}
fn on_exit(&self, _id: &span::Id, _ctx: Context<'_, S>) {
self.with_api(|api| {
unsafe { api.ATrace_endSection() };
});
}
}