| // | |
| // Copyright (C) 2025 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 crate::library_loader::{LinkerNamespace, LoadedLibrary, NamespaceFactory}; | |
| use std::sync::OnceLock; | |
| struct PreloadedLib { | |
| namespace: LinkerNamespace, | |
| _library: LoadedLibrary, | |
| _library_name: String, | |
| library_paths: String, | |
| allowed_lib_dirs: String, | |
| } | |
| static PRELOAD_INFO: OnceLock<PreloadedLib> = OnceLock::new(); | |
| /// Preload the specified lib. | |
| /// | |
| /// # Safety | |
| /// | |
| /// The caller must ensure that initialization routine of the library is safe. | |
| #[allow(clippy::too_many_arguments)] | |
| pub unsafe fn preload_lib( | |
| library_name: &str, | |
| library_paths: &str, | |
| allowed_lib_dirs: &str, | |
| target_sdk_version: i32, | |
| is_shared: bool, | |
| zip_paths: &str, | |
| native_shared_lib_path: &str, | |
| preload_func: Option<&str>, | |
| ) { | |
| let namespace = NamespaceFactory::create_linker_namespace( | |
| target_sdk_version, | |
| is_shared, | |
| zip_paths, | |
| library_paths, | |
| allowed_lib_dirs, | |
| native_shared_lib_path, | |
| ) | |
| .expect("failed to create namespace"); | |
| let library = | |
| // SAFETY: We are assuming the caller has specified valid library name and namespace parameters. | |
| unsafe { LoadedLibrary::new(library_name, &namespace) }.expect("failed to load library"); | |
| if let Some(preload_func) = preload_func { | |
| let preload_fun_handle = | |
| library.find_symbol(preload_func).expect("failed to find preload func"); | |
| // SAFETY: The caller guarantees that the symbol pointed to by `preload_func` | |
| // has the correct signature (takes no arguments, returns nothing). | |
| // Null-check of the handle is performed in `find_symbol`. | |
| let preload_fn: extern "C" fn() = unsafe { std::mem::transmute(preload_fun_handle) }; | |
| preload_fn(); | |
| } | |
| let _ = PRELOAD_INFO.set(PreloadedLib { | |
| namespace, | |
| _library: library, | |
| _library_name: library_name.to_owned(), | |
| library_paths: library_paths.to_owned(), | |
| allowed_lib_dirs: allowed_lib_dirs.to_owned(), | |
| }); | |
| } | |
| /// Return the previously registered LinkerNamespace if it exists. | |
| pub fn reuse_namespace(library_paths: &str, allowed_lib_dirs: &str) -> Option<LinkerNamespace> { | |
| PRELOAD_INFO | |
| .get() | |
| .filter(|lib| { | |
| lib.library_paths == library_paths && lib.allowed_lib_dirs == allowed_lib_dirs | |
| }) | |
| .map(|lib| lib.namespace.clone()) | |
| } |