From 79145e3bffbeeb7df4fae349fc0f869e5faf2bd0 Mon Sep 17 00:00:00 2001 From: JingMatrix Date: Sat, 29 Nov 2025 19:29:48 +0100 Subject: [PATCH] Add support for Android 11 RefBase ABI (#29) Implements a compatibility layer to allow the binary to run on Android 11 (API 30) and older, which lack the `incStrongRequireStrong` symbol in their `libutils.so`. This is achieved by creating a runtime wrapper that checks the device's SDK version. - On Android 12 (API 31) and newer, it dynamically loads and calls the `incStrongRequireStrong` function using `dlsym`. - On older versions, it safely falls back to the universally available `incStrong` method. This resolves the fatal `dlopen` error "cannot locate symbol" when injecting the library into processes on older Android versions. See AOSP change https://android-review.googlesource.com/c/platform/system/core/+/1660499 --- app/src/main/cpp/CMakeLists.txt | 4 +- app/src/main/cpp/compat/refbase_compat.cpp | 61 +++++++++++++++++++ app/src/main/cpp/compat/refbase_compat.h | 11 ++++ .../AOSP/include/utils/StrongPointer.h | 3 +- 4 files changed, 76 insertions(+), 3 deletions(-) create mode 100644 app/src/main/cpp/compat/refbase_compat.cpp create mode 100644 app/src/main/cpp/compat/refbase_compat.h diff --git a/app/src/main/cpp/CMakeLists.txt b/app/src/main/cpp/CMakeLists.txt index 30cd7f3..209fb1c 100644 --- a/app/src/main/cpp/CMakeLists.txt +++ b/app/src/main/cpp/CMakeLists.txt @@ -12,7 +12,7 @@ add_subdirectory(external/LSPlt/lsplt/src/main/jni) add_compile_definitions(BINDER_DISABLE_NATIVE_HANDLE) add_library(utils SHARED stub/stub_utils.cpp) -target_include_directories(utils PUBLIC external/AOSP/include) +target_include_directories(utils PUBLIC external/AOSP/include compat) add_library(binder SHARED stub/stub_binder.cpp) target_include_directories(binder PUBLIC external/AOSP/include) @@ -22,7 +22,7 @@ add_executable(libinject.so inject/main.cpp inject/utils.cpp) target_include_directories(libinject.so PUBLIC include) target_link_libraries(libinject.so PRIVATE lsplt_static) -add_library(${CMAKE_PROJECT_NAME} SHARED binder_interceptor.cpp) +add_library(${CMAKE_PROJECT_NAME} SHARED binder_interceptor.cpp compat/refbase_compat.cpp) target_include_directories(${CMAKE_PROJECT_NAME} PUBLIC external/linux-kernel/include include) target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE binder lsplt_static utils) diff --git a/app/src/main/cpp/compat/refbase_compat.cpp b/app/src/main/cpp/compat/refbase_compat.cpp new file mode 100644 index 0000000..4f7c18d --- /dev/null +++ b/app/src/main/cpp/compat/refbase_compat.cpp @@ -0,0 +1,61 @@ +#include "refbase_compat.h" +#include "utils/RefBase.h" +#include +#include +#include // For memcpy +#include +#include +#include + +namespace android { + +// Helper function to get the Android API level at runtime. +// It caches the result for performance. +int32_t get_android_api_level() { + static std::atomic api_level = -1; + if (api_level.load(std::memory_order_relaxed) == -1) { + char sdk_version_str[PROP_VALUE_MAX]; + if (__system_property_get("ro.build.version.sdk", sdk_version_str) > 0) { + api_level.store(atoi(sdk_version_str), std::memory_order_relaxed); + } + } + return api_level.load(std::memory_order_relaxed); +} + +// Define the function pointer type for the const member function +// RefBase::incStrongRequireStrong. +using incStrongRequireStrong_t = void (RefBase::*)(const void *) const; + +// This is the implementation of our compatibility wrapper. +void incStrongFromExisting(const RefBase *ref, const void *id) { + // Only attempt to use the new function on Android 12 (API 31) or higher. + if (get_android_api_level() >= 31) { + static incStrongRequireStrong_t sIncStrongRequireStrong = nullptr; + static std::once_flag sFlag; + + // Thread-safe, one-time initialization. + std::call_once(sFlag, []() { + // Find the symbol in the already loaded libraries. + // The mangled symbol is _ZNK7android7RefBase22incStrongRequireStrongEPKv + void *sym = dlsym(RTLD_DEFAULT, + "_ZNK7android7RefBase22incStrongRequireStrongEPKv"); + if (sym) { + // Safely cast the void* symbol to our member function pointer. + memcpy(&sIncStrongRequireStrong, &sym, sizeof(void *)); + } + }); + + if (sIncStrongRequireStrong) { + // If the symbol was found, call it as member function. + (ref->*sIncStrongRequireStrong)(id); + return; // Success, we are done. + } + // If dlsym failed for any reason, we fall through to the old method. + } + + // Fallback for older Android versions or if dlsym failed. + // This calls the universally available incStrong method. + ref->incStrong(id); +} + +} // namespace android diff --git a/app/src/main/cpp/compat/refbase_compat.h b/app/src/main/cpp/compat/refbase_compat.h new file mode 100644 index 0000000..20aee7e --- /dev/null +++ b/app/src/main/cpp/compat/refbase_compat.h @@ -0,0 +1,11 @@ +#pragma once + +namespace android { + +// Forward-declare the RefBase class. +class RefBase; + +// Declares our compatibility function. +void incStrongFromExisting(const RefBase *ref, const void *id); + +} // namespace android diff --git a/app/src/main/cpp/external/AOSP/include/utils/StrongPointer.h b/app/src/main/cpp/external/AOSP/include/utils/StrongPointer.h index fb9b8e8..c7a65a6 100644 --- a/app/src/main/cpp/external/AOSP/include/utils/StrongPointer.h +++ b/app/src/main/cpp/external/AOSP/include/utils/StrongPointer.h @@ -17,6 +17,7 @@ #ifndef ANDROID_STRONG_POINTER_H #define ANDROID_STRONG_POINTER_H +#include "refbase_compat.h" #include #include // for common_type. @@ -212,7 +213,7 @@ sp sp::make(Args&&... args) { template sp sp::fromExisting(T* other) { if (other) { - other->incStrongRequireStrong(other); + incStrongFromExisting(other, other); sp result; result.m_ptr = other; return result;