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
This commit is contained in:
JingMatrix
2025-11-29 19:29:48 +01:00
committed by GitHub
parent ecc1dbdaeb
commit 79145e3bff
4 changed files with 76 additions and 3 deletions
+2 -2
View File
@@ -12,7 +12,7 @@ add_subdirectory(external/LSPlt/lsplt/src/main/jni)
add_compile_definitions(BINDER_DISABLE_NATIVE_HANDLE) add_compile_definitions(BINDER_DISABLE_NATIVE_HANDLE)
add_library(utils SHARED stub/stub_utils.cpp) 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) add_library(binder SHARED stub/stub_binder.cpp)
target_include_directories(binder PUBLIC external/AOSP/include) 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_include_directories(libinject.so PUBLIC include)
target_link_libraries(libinject.so PRIVATE lsplt_static) 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_include_directories(${CMAKE_PROJECT_NAME} PUBLIC external/linux-kernel/include include)
target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE binder lsplt_static utils) target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE binder lsplt_static utils)
@@ -0,0 +1,61 @@
#include "refbase_compat.h"
#include "utils/RefBase.h"
#include <atomic>
#include <cstdlib>
#include <cstring> // For memcpy
#include <dlfcn.h>
#include <mutex>
#include <sys/system_properties.h>
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<int32_t> 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
+11
View File
@@ -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
@@ -17,6 +17,7 @@
#ifndef ANDROID_STRONG_POINTER_H #ifndef ANDROID_STRONG_POINTER_H
#define ANDROID_STRONG_POINTER_H #define ANDROID_STRONG_POINTER_H
#include "refbase_compat.h"
#include <functional> #include <functional>
#include <type_traits> // for common_type. #include <type_traits> // for common_type.
@@ -212,7 +213,7 @@ sp<T> sp<T>::make(Args&&... args) {
template <typename T> template <typename T>
sp<T> sp<T>::fromExisting(T* other) { sp<T> sp<T>::fromExisting(T* other) {
if (other) { if (other) {
other->incStrongRequireStrong(other); incStrongFromExisting(other, other);
sp<T> result; sp<T> result;
result.m_ptr = other; result.m_ptr = other;
return result; return result;