use std::{ffi::CStr, mem::MaybeUninit, os::{fd::{AsRawFd, BorrowedFd}, unix::net::UnixStream}, ptr::{null, null_mut, NonNull}};
use cstr::cstr;
use lazy_static::lazy_static;
use libc::{c_char, c_int, c_void, dlopen, dlsym, RTLD_LAZY, RTLD_LOCAL};
mod hb_raw {
#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(unused)]
include!(concat!(env!("OUT_DIR"), "/hardware_buffer.rs"));
}
pub use hb_raw::*;
#[allow(non_snake_case, dead_code)]
pub struct HBHolder {
pub api_level: c_int,
AHardwareBuffer_acquire: *const fn(buffer: NonNull<AHardwareBuffer>) -> c_void,
AHardwareBuffer_allocate: *const fn(desc: NonNull<AHardwareBufferDesc>, outBuffer: NonNull<*mut AHardwareBuffer>) -> c_int,
AHardwareBuffer_describe: *const fn(buffer: NonNull<AHardwareBuffer>, outDesc: NonNull<AHardwareBufferDesc>) -> c_void,
AHardwareBuffer_getId: *const fn(buffer: NonNull<AHardwareBuffer>, outId: NonNull<u64>) -> c_int,
AHardwareBuffer_isSupported: *const fn(desc: NonNull<AHardwareBufferDesc>) -> c_int,
AHardwareBuffer_recvHandleFromUnixSocket: *const fn(fd: c_int, outBuffer: NonNull<*mut AHardwareBuffer>) -> c_int,
AHardwareBuffer_lock: *const fn(buffer: NonNull<AHardwareBuffer>, usage: u64, fence: i32, rect: *const ARect, outAddr: NonNull<*mut c_void>) -> c_int,
AHardwareBuffer_lockAndGetInfo: *const fn(buffer: NonNull<AHardwareBuffer>, usage: u64, fence: i32, rect: *const ARect, outAddr: NonNull<*mut c_void>, bpp: NonNull<i32>, bps: NonNull<i32>) -> c_int,
AHardwareBuffer_lockPlanes: *const fn(buffer: NonNull<AHardwareBuffer>, usage: u64, fence: i32, rect: *const ARect, planes: NonNull<AHardwareBufferPlanes>) -> c_int,
AHardwareBuffer_release: *const fn(buffer: NonNull<AHardwareBuffer>) -> c_void,
AHardwareBuffer_sendHandleToUnixSocket: *const fn(buffer: NonNull<AHardwareBuffer>, fd: c_int) -> c_int,
AHardwareBuffer_unlock: *const fn(buffer: NonNull<AHardwareBuffer>, fence: *mut i32) -> c_int,
}
unsafe impl Sync for HBHolder {}
lazy_static! {
pub static ref HB: HBHolder = HBHolder::new();
}
impl HBHolder {
fn new() -> Self {
let lib = unsafe { dlopen(cstr!("libandroid.so").as_ptr(), RTLD_LAZY | RTLD_LOCAL) };
if lib == null_mut() {
return Self {
api_level: -1,
AHardwareBuffer_release: null(),
AHardwareBuffer_recvHandleFromUnixSocket: null(),
AHardwareBuffer_acquire: null(),
AHardwareBuffer_allocate: null(),
AHardwareBuffer_describe: null(),
AHardwareBuffer_getId: null(),
AHardwareBuffer_isSupported: null(),
AHardwareBuffer_lock: null(),
AHardwareBuffer_lockAndGetInfo: null(),
AHardwareBuffer_lockPlanes: null(),
AHardwareBuffer_sendHandleToUnixSocket: null(),
AHardwareBuffer_unlock: null(),
};
}
let mut api_level = -1;
{
let __system_property_get = unsafe { dlsym(lib, cstr!("__system_property_get").as_ptr()) } as *const fn(name: *const c_char, value: *mut c_char) -> c_int;
if __system_property_get != null() {
let mut buffer: [c_char; 92] = [0; 92];
if (unsafe { *__system_property_get })(cstr!("ro.build.version.sdk").as_ptr(), buffer.as_mut_ptr()) >= 1 {
if let Ok(s) = CStr::from_bytes_until_nul(bytemuck::cast_slice(&buffer[..])) {
if let Ok(l) = s.to_str() {
if let Ok(l) = l.parse() {
api_level = l;
}
}
}
}
}
}
#[allow(non_snake_case)]
{
let AHardwareBuffer_acquire = unsafe { dlsym(lib, cstr!("AHardwareBuffer_acquire").as_ptr()) } as *const fn(buffer: NonNull<AHardwareBuffer>) -> c_void;
let AHardwareBuffer_allocate = unsafe { dlsym(lib, cstr!("AHardwareBuffer_allocate").as_ptr()) } as *const fn(desc: NonNull<AHardwareBufferDesc>, outBuffer: NonNull<*mut AHardwareBuffer>) -> c_int;
let AHardwareBuffer_describe = unsafe { dlsym(lib, cstr!("AHardwareBuffer_describe").as_ptr()) } as *const fn(buffer: NonNull<AHardwareBuffer>, outDesc: NonNull<AHardwareBufferDesc>) -> c_void;
let AHardwareBuffer_getId = unsafe { dlsym(lib, cstr!("AHardwareBuffer_getId").as_ptr()) } as *const fn(buffer: NonNull<AHardwareBuffer>, outId: NonNull<u64>) -> c_int;
let AHardwareBuffer_isSupported = unsafe { dlsym(lib, cstr!("AHardwareBuffer_isSupported").as_ptr()) } as *const fn(desc: NonNull<AHardwareBufferDesc>) -> c_int;
let AHardwareBuffer_recvHandleFromUnixSocket = unsafe { dlsym(lib, cstr!("AHardwareBuffer_recvHandleFromUnixSocket").as_ptr()) } as *const fn(fd: c_int, outBuffer: NonNull<*mut AHardwareBuffer>) -> c_int;
let AHardwareBuffer_lock = unsafe { dlsym(lib, cstr!("AHardwareBuffer_lock").as_ptr()) } as *const fn(buffer: NonNull<AHardwareBuffer>, usage: u64, fence: i32, rect: *const ARect, outAddr: NonNull<*mut c_void>) -> c_int;
let AHardwareBuffer_lockAndGetInfo = unsafe { dlsym(lib, cstr!("AHardwareBuffer_lockAndGetInfo").as_ptr()) } as *const fn(buffer: NonNull<AHardwareBuffer>, usage: u64, fence: i32, rect: *const ARect, outAddr: NonNull<*mut c_void>, bpp: NonNull<i32>, bps: NonNull<i32>) -> c_int;
let AHardwareBuffer_lockPlanes = unsafe { dlsym(lib, cstr!("AHardwareBuffer_lockPlanes").as_ptr()) } as *const fn(buffer: NonNull<AHardwareBuffer>, usage: u64, fence: i32, rect: *const ARect, planes: NonNull<AHardwareBufferPlanes>) -> c_int;
let AHardwareBuffer_release = unsafe { dlsym(lib, cstr!("AHardwareBuffer_release").as_ptr()) } as *const fn(buffer: NonNull<AHardwareBuffer>) -> c_void;
let AHardwareBuffer_sendHandleToUnixSocket = unsafe { dlsym(lib, cstr!("AHardwareBuffer_sendHandleToUnixSocket").as_ptr()) } as *const fn(buffer: NonNull<AHardwareBuffer>, fd: c_int) -> c_int;
let AHardwareBuffer_unlock = unsafe { dlsym(lib, cstr!("AHardwareBuffer_unlock").as_ptr()) } as *const fn(buffer: NonNull<AHardwareBuffer>, fence: *mut i32) -> c_int;
Self {
api_level,
AHardwareBuffer_acquire,
AHardwareBuffer_release,
AHardwareBuffer_allocate,
AHardwareBuffer_describe,
AHardwareBuffer_getId,
AHardwareBuffer_isSupported,
AHardwareBuffer_recvHandleFromUnixSocket,
AHardwareBuffer_sendHandleToUnixSocket,
AHardwareBuffer_lock,
AHardwareBuffer_lockAndGetInfo,
AHardwareBuffer_lockPlanes,
AHardwareBuffer_unlock,
}
}
}
pub unsafe fn acquire(&self, buffer: NonNull<AHardwareBuffer>) {
if self.api_level < 26 {
return;
}
(*self.AHardwareBuffer_acquire)(buffer);
}
pub unsafe fn release(&self, buffer: NonNull<AHardwareBuffer>) {
if self.api_level < 26 {
return;
}
(*self.AHardwareBuffer_release)(buffer);
}
pub fn allocate(&self, desc: AHardwareBufferDesc) -> Option<HBRef> {
if self.api_level < 26 {
return None;
}
let mut desc = desc;
let mut buffer: *mut AHardwareBuffer = null_mut();
unsafe {
if (*self.AHardwareBuffer_allocate)(NonNull::new_unchecked(&mut desc), NonNull::new_unchecked(&mut buffer as *mut *mut AHardwareBuffer)) != 0 {
buffer = null_mut();
}
}
if buffer == null_mut() {
return None;
}
return Some(HBRef { data: unsafe { NonNull::new_unchecked(buffer) } });
}
pub fn describe(&self, buffer: &HBRef) -> Option<AHardwareBufferDesc> {
if self.api_level < 26 {
return None;
}
let mut desc: MaybeUninit<AHardwareBufferDesc> = MaybeUninit::uninit();
unsafe {
(*self.AHardwareBuffer_describe)(buffer.get(), NonNull::new_unchecked(desc.as_mut_ptr()));
return Some(desc.assume_init());
}
}
pub fn get_id(&self, buffer: &HBRef) -> Option<u64> {
if self.api_level < 31 {
return None;
}
let mut id: u64 = 0;
unsafe {
if (*self.AHardwareBuffer_getId)(buffer.get(), NonNull::new_unchecked(&mut id)) != 0 {
None
} else {
Some(id)
}
}
}
pub fn is_supported(&self, desc: &AHardwareBufferDesc) -> bool {
if self.api_level < 29 {
return false;
}
if (unsafe { *self.AHardwareBuffer_isSupported })(desc.into()) == 1 {
true
} else {
false
}
}
pub fn recv(&self, socket: &UnixStream) -> Option<HBRef> {
if self.api_level < 26 {
return None;
}
let mut buffer: *mut AHardwareBuffer = null_mut();
unsafe {
if (*self.AHardwareBuffer_recvHandleFromUnixSocket)(socket.as_raw_fd(), NonNull::new_unchecked(&mut buffer as *mut *mut AHardwareBuffer)) != 0 {
buffer = null_mut();
}
}
if buffer == null_mut() {
return None;
}
return Some(HBRef { data: unsafe { NonNull::new_unchecked(buffer) } });
}
pub fn send(&self, socket: &UnixStream, buffer: &HBRef) -> bool {
if self.api_level < 26 {
return false;
}
if (unsafe { *self.AHardwareBuffer_sendHandleToUnixSocket })(buffer.get(), socket.as_raw_fd()) == 0 {
true
} else {
false
}
}
pub fn lock(&self, buffer: &HBRef, usage: u64, fence: Option<BorrowedFd>, rect: Option<&ARect>) -> *mut c_void {
if self.api_level < 26 {
return null_mut();
}
let mut out: *mut c_void = null_mut();
if (unsafe { *self.AHardwareBuffer_lock })(buffer.get(), usage, fence.and_then(|f| Some(f.as_raw_fd())).unwrap_or(-1), rect.and_then(|r| Some(r as *const ARect)).unwrap_or(null()), unsafe { NonNull::new_unchecked(&mut out) }) != 0 {
out = null_mut();
}
return out;
}
pub fn lock_info(&self, buffer: &HBRef, usage: u64, fence: Option<BorrowedFd>, rect: Option<&ARect>) -> Option<LockInfo> {
if self.api_level < 29 {
return None;
}
let mut bpp: i32 = 0;
let mut bps: i32 = 0;
let mut out: *mut c_void = null_mut();
if (unsafe { *self.AHardwareBuffer_lockAndGetInfo })(buffer.get(), usage, fence.and_then(|f| Some(f.as_raw_fd())).unwrap_or(-1), rect.and_then(|r| Some(r as *const ARect)).unwrap_or(null()), unsafe { NonNull::new_unchecked(&mut out) }, (&mut bpp).into(), (&mut bps).into()) != 0 {
return None;
}
return Some(LockInfo { address: out, bytes_per_pixel: bpp, bytes_per_stride: bps });
}
pub fn lock_planes(&self, buffer: &HBRef, usage: u64, fence: Option<BorrowedFd>, rect: Option<&ARect>) -> Option<AHardwareBufferPlanes> {
if self.api_level < 29 {
return None;
}
let mut out: MaybeUninit<AHardwareBufferPlanes> = MaybeUninit::uninit();
if (unsafe { *self.AHardwareBuffer_lockPlanes })(buffer.get(), usage, fence.and_then(|f| Some(f.as_raw_fd())).unwrap_or(-1), rect.and_then(|r| Some(r as *const ARect)).unwrap_or(null()), unsafe { NonNull::new_unchecked(out.as_mut_ptr()) }) != 0 {
return None;
}
return Some(unsafe { out.assume_init() });
}
pub fn unlock(&self, buffer: &HBRef) -> bool {
if self.api_level < 26 {
return false;
}
if (unsafe { *self.AHardwareBuffer_unlock })(buffer.get(), null_mut()) == 0 {
true
} else {
false
}
}
}
pub struct LockInfo {
pub address: *mut c_void,
pub bytes_per_pixel: i32,
pub bytes_per_stride: i32,
}
#[repr(transparent)]
pub struct HBRef {
data: NonNull<AHardwareBuffer>
}
impl HBRef {
pub fn get(&self) -> NonNull<AHardwareBuffer> {
self.data
}
}
impl Clone for HBRef {
fn clone(&self) -> Self {
unsafe { (*HB.AHardwareBuffer_acquire)(self.data) };
Self { data: self.data.clone() }
}
}
impl Drop for HBRef {
fn drop(&mut self) {
unsafe { (*HB.AHardwareBuffer_release)(self.data) };
}
}