[core] Native request binder

This commit is contained in:
LoveSy 2021-02-16 03:18:15 +08:00 committed by tehcneko
parent c65af4c4b5
commit 0ec8959235
12 changed files with 322 additions and 300 deletions

View File

@ -3,7 +3,9 @@ package io.github.lsposed.lspd.service;
interface ILSPApplicationService {
void registerHeartBeat(IBinder handle) = 1;
IBinder requestModuleBinder() = 2;
int getVariant() = 2;
IBinder requestManagerBinder() = 3;
IBinder requestModuleBinder() = 3;
IBinder requestManagerBinder() = 4;
}

View File

@ -87,6 +87,10 @@ ALWAYS_INLINE static int ClearException(JNIEnv *env) {
env->CallVoidMethod(obj, __VA_ARGS__); \
if (ClearException(env)) LOGE("CallVoidMethod " #obj " " #__VA_ARGS__)
#define JNI_CallBooleanMethod(env, obj, ...) \
env->CallBooleanMethod(obj, __VA_ARGS__); \
if (ClearException(env)) LOGE("CallVoidMethod " #obj " " #__VA_ARGS__)
#define JNI_GetStaticFieldID(env, class, name, sig) \
env->GetStaticFieldID(class, name, sig); \
if (ClearException(env)) LOGE("GetStaticFieldID " #name " " #sig)

View File

@ -20,7 +20,7 @@
#include <jni.h>
#include <android-base/macros.h>
#include <JNIHelper.h>
#include "JNIHelper.h"
#include "jni/config_manager.h"
#include "jni/art_class_linker.h"
#include "jni/yahfa.h"
@ -133,23 +133,23 @@ namespace lspd {
RegisterPendingHooks(env);
RegisterNativeAPI(env);
variant_ = Variant(ConfigManager::GetInstance()->GetVariant());
LOGI("LSP Variant: %d", variant_);
if (variant_ == SANDHOOK) {
//for SandHook variant
ScopedLocalRef sandhook_class(env, FindClassFromCurrentLoader(env, kSandHookClassName));
ScopedLocalRef nevercall_class(env,
FindClassFromCurrentLoader(env,
kSandHookNeverCallClassName));
if (sandhook_class == nullptr || nevercall_class == nullptr) { // fail-fast
return;
}
if (!JNI_Load_Ex(env, sandhook_class.get(), nevercall_class.get())) {
LOGE("SandHook: HookEntry class error. %d", getpid());
}
}
// variant_ = Variant(ConfigManager::GetInstance()->GetVariant());
// LOGI("LSP Variant: %d", variant_);
//
// if (variant_ == SANDHOOK) {
// //for SandHook variant
// ScopedLocalRef sandhook_class(env, FindClassFromCurrentLoader(env, kSandHookClassName));
// ScopedLocalRef nevercall_class(env,
// FindClassFromCurrentLoader(env,
// kSandHookNeverCallClassName));
// if (sandhook_class == nullptr || nevercall_class == nullptr) { // fail-fast
// return;
// }
// if (!JNI_Load_Ex(env, sandhook_class.get(), nevercall_class.get())) {
// LOGE("SandHook: HookEntry class error. %d", getpid());
// }
//
// }
}
jclass
@ -202,108 +202,33 @@ namespace lspd {
[[maybe_unused]] jobjectArray rlimits,
[[maybe_unused]] jlong permitted_capabilities,
[[maybe_unused]] jlong effective_capabilities) {
ConfigManager::SetCurrentUser(0u);
app_modules_list_ = ConfigManager::GetInstance()->GetAppModuleList(
"android"); // I don't think we need this, but anyway
skip_ = false;
if (!ConfigManager::GetInstance()->IsInitialized()) {
LOGE("skip injecting into android because configurations are not loaded properly");
}
if (!skip_ && app_modules_list_.empty()) {
skip_ = true;
LOGD("skip injecting into android because no module hooks it");
}
Service::instance()->InitService(env);
PreLoadDex(ConfigManager::GetInjectDexPath());
ConfigManager::GetInstance()->EnsurePermission("android", 1000);
skip_ = false;
}
int
Context::OnNativeForkSystemServerPost(JNIEnv *env, [[maybe_unused]] jclass clazz, jint res) {
if (res == 0) {
if (!skip_) {
if (void *buf = mmap(nullptr, 1, PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_ANONYMOUS | MAP_PRIVATE, -1,
0);
buf == MAP_FAILED) {
skip_ = true;
LOGE("skip injecting into android because sepolicy was not loaded properly");
} else {
munmap(buf, 1);
}
void
Context::OnNativeForkSystemServerPost(JNIEnv *env, jint res) {
if (res != 0) return;
auto binder = Service::instance()->RequestBinder(env);
if (binder) {
if (void *buf = mmap(nullptr, 1, PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_ANONYMOUS | MAP_PRIVATE, -1,
0);
buf == MAP_FAILED) {
skip_ = true;
LOGE("skip injecting into android because sepolicy was not loaded properly");
} else {
munmap(buf, 1);
}
LoadDex(env);
if (!skip_) {
InstallInlineHooks();
Init(env);
// only do work in child since FindAndCall would print log
FindAndCall(env, "forkSystemServerPost", "(II)V", res,
variant_);
}
InitService(*this, env);
} else {
// in zygote process, res is child zygote pid
// don't print log here, see https://github.com/RikkaApps/Riru/blob/77adfd6a4a6a81bfd20569c910bc4854f2f84f5e/riru-core/jni/main/jni_native_method.cpp#L55-L66
}
return 0;
}
std::tuple<bool, uid_t, std::string>
Context::GetAppInfoFromDir(JNIEnv *env, jstring dir, jstring nice_name) {
uid_t uid = 0;
JUTFString app_data_dir(env, dir);
JUTFString name(env, nice_name);
if (!app_data_dir) return {false, 0, name.get()};
fs::path path(app_data_dir.get());
std::vector<std::string> splits(path.begin(), path.end());
if (splits.size() < 5u) {
LOGE("can't parse %s", path.c_str());
return {false, 0, name.get()};
LoadDex(env);
if (!skip_ && binder) {
InstallInlineHooks();
Init(env);
FindAndCall(env, "forkSystemServerPost", "(Landroid/os/IBinder;)V", binder);
}
const auto &uid_str = splits[3];
const auto &package_name = splits[4];
try {
uid = stol(uid_str);
} catch (const std::invalid_argument &ignored) {
LOGE("can't parse %s", app_data_dir.get());
return {false, uid, {}};
}
return {true, uid, package_name};
}
bool Context::ShouldSkipInject(const std::string &package_name, uid_t user, uid_t uid,
bool info_res,
const std::function<bool()> &empty_list,
bool is_child_zygote) {
const auto app_id = uid % PER_USER_RANGE;
bool skip = false;
if (!ConfigManager::GetInstance()->IsInitialized()) {
LOGE("skip injecting into %s because configurations are not loaded properly",
package_name.c_str());
skip = true;
}
if (!skip && !info_res) {
LOGD("skip injecting into %s because it has no data dir", package_name.c_str());
skip = true;
}
if (!skip && is_child_zygote) {
skip = true;
LOGD("skip injecting into %s because it's a child zygote", package_name.c_str());
}
if (!skip && ((app_id >= FIRST_ISOLATED_UID && app_id <= LAST_ISOLATED_UID) ||
(app_id >= FIRST_APP_ZYGOTE_ISOLATED_UID &&
app_id <= LAST_APP_ZYGOTE_ISOLATED_UID) ||
app_id == SHARED_RELRO_UID)) {
skip = true;
LOGI("skip injecting into %s because it's isolated", package_name.c_str());
}
if (!skip && empty_list() && !ConfigManager::GetInstance()->IsInstaller(package_name)) {
skip = true;
LOGD("skip injecting xposed into %s because no module hooks it",
package_name.c_str());
}
return skip;
Service::instance()->HookBridge(*this, env);
}
void Context::OnNativeForkAndSpecializePre(JNIEnv *env, jclass clazz,
@ -319,50 +244,50 @@ namespace lspd {
jboolean is_child_zygote,
jstring instruction_set,
jstring app_data_dir) {
const auto&[res, user, package_name] = GetAppInfoFromDir(env, app_data_dir, nice_name);
app_data_dir_ = app_data_dir;
nice_name_ = nice_name;
ConfigManager::SetCurrentUser(user);
skip_ = ShouldSkipInject(package_name, user, uid, res,
// Only obtains when needed
[this, &package_name = package_name]() {
app_modules_list_ = ConfigManager::GetInstance()->GetAppModuleList(
package_name);
return app_modules_list_.empty();
}, is_child_zygote);
if (!skip_) {
ConfigManager::GetInstance()->EnsurePermission(package_name, uid);
PreLoadDex(ConfigManager::GetInjectDexPath());
PreLoadDex(ConfigManager::GetInjectDexPath());
Service::instance()->InitService(env);
this->uid = uid;
const auto app_id = uid % PER_USER_RANGE;
skip_ = false;
if (!skip_ && !app_data_dir) {
LOGD("skip injecting into %d because it has no data dir", uid);
skip_ = true;
}
if (!skip_ && is_child_zygote) {
skip_ = true;
LOGD("skip injecting into %d because it's a child zygote", uid);
}
if (!skip_ && ((app_id >= FIRST_ISOLATED_UID && app_id <= LAST_ISOLATED_UID) ||
(app_id >= FIRST_APP_ZYGOTE_ISOLATED_UID &&
app_id <= LAST_APP_ZYGOTE_ISOLATED_UID) ||
app_id == SHARED_RELRO_UID)) {
skip_ = true;
LOGI("skip injecting into %d because it's isolated", uid);
}
}
int
Context::OnNativeForkAndSpecializePost(JNIEnv *env, [[maybe_unused]]jclass clazz, jint res) {
if (res == 0) {
const JUTFString process_name(env, nice_name_);
if (!skip_) {
LoadDex(env);
InstallInlineHooks();
Init(env);
LOGD("Done prepare");
FindAndCall(env, "forkAndSpecializePost",
"(ILjava/lang/String;Ljava/lang/String;I)V",
res, app_data_dir_, nice_name_,
variant_);
LOGD("injected xposed into %s", process_name.get());
} else {
[[maybe_unused]] auto config_manager = ConfigManager::ReleaseInstances();
auto context = Context::ReleaseInstance();
LOGD("skipped %s", process_name.get());
}
void
Context::OnNativeForkAndSpecializePost(JNIEnv *env) {
const JUTFString process_name(env, nice_name_);
auto binder = skip_? nullptr : Service::instance()->RequestBinder(env);
if (binder) {
LoadDex(env);
InstallInlineHooks();
Init(env);
LOGD("Done prepare");
// TODO: cache this method
FindAndCall(env, "forkAndSpecializePost",
"(Ljava/lang/String;Ljava/lang/String;Landroid/os/IBinder;)V",
app_data_dir_, nice_name_,
binder);
LOGD("injected xposed into %s", process_name.get());
} else {
// in zygote process, res is child zygote pid
// don't print log here, see https://github.com/RikkaApps/Riru/blob/77adfd6a4a6a81bfd20569c910bc4854f2f84f5e/riru-core/jni/main/jni_native_method.cpp#L55-L66
auto context = Context::ReleaseInstance();
auto service = Service::ReleaseInstance();
LOGD("skipped %s", process_name.get());
}
return 0;
}
}
#pragma clang diagnostic pop

View File

@ -39,9 +39,6 @@ namespace lspd {
public:
inline static Context *GetInstance() {
if (!instance_) {
instance_ = std::make_unique<Context>();
}
return instance_.get();
}
@ -55,18 +52,6 @@ namespace lspd {
void FindAndCall(JNIEnv *env, const char *method_name, const char *method_sig, ...) const;
inline auto *GetJavaVM() const { return vm_; }
inline void SetAppDataDir(jstring app_data_dir) { app_data_dir_ = app_data_dir; }
inline void SetNiceName(jstring nice_name) { nice_name_ = nice_name; }
inline auto GetAppDataDir() const { return app_data_dir_; }
inline auto GetNiceName() const { return nice_name_; }
inline auto GetAppModulesList() const { return app_modules_list_; }
inline jclass FindClassFromCurrentLoader(JNIEnv *env, std::string_view className) const {
return FindClassFromLoader(env, GetCurrentClassLoader(), className);
};
@ -78,20 +63,18 @@ namespace lspd {
jintArray fds_to_ignore, jboolean is_child_zygote,
jstring instruction_set, jstring app_data_dir);
int OnNativeForkAndSpecializePost(JNIEnv *env, jclass clazz, jint res);
void OnNativeForkAndSpecializePost(JNIEnv *env);
int OnNativeForkSystemServerPost(JNIEnv *env, jclass clazz, jint res);
void OnNativeForkSystemServerPost(JNIEnv *env, jint res);
void OnNativeForkSystemServerPre(JNIEnv *env, jclass clazz, uid_t uid, gid_t gid,
jintArray gids, jint runtime_flags, jobjectArray rlimits,
jlong permitted_capabilities,
jlong effective_capabilities);
inline auto GetVariant() const { return variant_; };
private:
inline static std::unique_ptr<Context> instance_;
Variant variant_ = NONE;
inline static std::unique_ptr<Context> instance_ = std::make_unique<Context>();
jobject inject_class_loader_ = nullptr;
jclass entry_class_ = nullptr;
jstring app_data_dir_ = nullptr;
@ -99,9 +82,9 @@ namespace lspd {
JavaVM *vm_ = nullptr;
jclass class_linker_class_ = nullptr;
jmethodID post_fixup_static_mid_ = nullptr;
jint uid = -1;
bool skip_ = false;
std::vector<signed char> dex{};
std::vector<std::string> app_modules_list_{};
Context() {}
@ -114,14 +97,6 @@ namespace lspd {
static jclass FindClassFromLoader(JNIEnv *env, jobject class_loader,
std::string_view class_name);
static bool
ShouldSkipInject(const std::string &package_name, uid_t user, uid_t uid, bool res,
const std::function<bool()> &empty_list,
bool is_child_zygote);
static std::tuple<bool, uid_t, std::string>
GetAppInfoFromDir(JNIEnv *env, jstring dir, jstring nice_name);
friend std::unique_ptr<Context> std::make_unique<Context>();
};

View File

@ -74,13 +74,7 @@ namespace lspd {
}
LSP_DEF_NATIVE_METHOD(jstring, ConfigManager, getModulesList) {
auto module_list = Context::GetInstance()->GetAppModulesList();
std::ostringstream join;
std::copy(module_list.begin(), module_list.end(),
std::ostream_iterator<std::string>(join, "\n"));
const auto &list = join.str();
LOGD("module list: %s", list.c_str());
return env->NewStringUTF(list.c_str());
return nullptr;
}
LSP_DEF_NATIVE_METHOD(jboolean, ConfigManager, isPermissive) {

View File

@ -29,9 +29,6 @@
#include "config_manager.h"
#include "symbol_cache.h"
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-value"
namespace lspd {
static void onModuleLoaded() {
LOGI("onModuleLoaded: welcome to LSPosed!");
@ -63,7 +60,7 @@ namespace lspd {
}
static void nativeForkAndSpecializePost(JNIEnv *env, jclass clazz, jint res) {
Context::GetInstance()->OnNativeForkAndSpecializePost(env, clazz, res);
Context::GetInstance()->OnNativeForkAndSpecializePost(env);
}
static void nativeForkSystemServerPre(JNIEnv *env, jclass clazz, uid_t *uid, gid_t *gid,
@ -77,8 +74,8 @@ namespace lspd {
);
}
static void nativeForkSystemServerPost(JNIEnv *env, jclass clazz, jint res) {
Context::GetInstance()->OnNativeForkSystemServerPost(env, clazz, res);
static void nativeForkSystemServerPost(JNIEnv *env, [[maybe_unused]] jclass clazz, jint res) {
Context::GetInstance()->OnNativeForkSystemServerPost(env, res);
}
/* method added in Android Q */
@ -97,13 +94,12 @@ namespace lspd {
*app_data_dir);
}
static void specializeAppProcessPost(JNIEnv *env, jclass clazz) {
Context::GetInstance()->OnNativeForkAndSpecializePost(env, clazz, 0);
static void specializeAppProcessPost(JNIEnv *env, [[maybe_unused]] jclass clazz) {
Context::GetInstance()->OnNativeForkAndSpecializePost(env);
}
}
int riru_api_version;
RiruApiV10 *riru_api_v10;
RIRU_EXPORT void *init(void *arg) {
static int step = 0;
@ -122,8 +118,6 @@ RIRU_EXPORT void *init(void *arg) {
case 10:
[[fallthrough]];
case 9: {
riru_api_v10 = (RiruApiV10 *) arg;
auto module = (RiruModuleInfoV10 *) malloc(sizeof(RiruModuleInfoV10));
memset(module, 0, sizeof(RiruModuleInfoV10));
_module = module;
@ -156,5 +150,3 @@ RIRU_EXPORT void *init(void *arg) {
}
}
}
#pragma clang diagnostic pop

View File

@ -3,27 +3,14 @@
//
#include <nativehelper/scoped_local_ref.h>
#include <base/object.h>
#include <dobby.h>
#include "base/object.h"
#include "service.h"
#include "context.h"
#include "JNIHelper.h"
namespace lspd {
namespace {
constexpr uint32_t BRIDGE_TRANSACTION_CODE = 1598837584;
JNINativeInterface native_interface_replace{};
jmethodID exec_transact_backup_methodID = nullptr;
jboolean (*call_boolean_method_va_backup)(JNIEnv *env, jobject obj, jmethodID methodId,
va_list args) = nullptr;
jclass bridge_service_class = nullptr;
jmethodID exec_transact_replace_methodID = nullptr;
}
static bool exec_transact_replace(jboolean *res, JNIEnv *env, jobject obj, va_list args) {
jboolean Service::exec_transact_replace(jboolean *res, JNIEnv *env, [[maybe_unused]] jobject obj, va_list args) {
jint code;
va_list copy;
@ -32,8 +19,8 @@ namespace lspd {
va_end(copy);
if (UNLIKELY(code == BRIDGE_TRANSACTION_CODE)) {
*res = env->CallStaticBooleanMethodV(bridge_service_class,
exec_transact_replace_methodID,
*res = env->CallStaticBooleanMethodV(instance()->bridge_service_class_,
instance()->exec_transact_replace_methodID_,
args);
return true;
}
@ -41,50 +28,139 @@ namespace lspd {
return false;
}
static jboolean
call_boolean_method_va_replace(JNIEnv *env, jobject obj, jmethodID methodId, va_list args) {
if (UNLIKELY(methodId == exec_transact_backup_methodID)) {
jboolean
Service::call_boolean_method_va_replace(JNIEnv *env, jobject obj, jmethodID methodId,
va_list args) {
if (UNLIKELY(methodId == instance()->exec_transact_backup_methodID_)) {
jboolean res = false;
if (LIKELY(exec_transact_replace(&res, env, obj, args))) return res;
// else fallback to backup
}
return call_boolean_method_va_backup(env, obj, methodId, args);
return instance()->call_boolean_method_va_backup_(env, obj, methodId, args);
}
void InitService(const Context &context, JNIEnv *env) {
bridge_service_class = context.FindClassFromCurrentLoader(env, kBridgeServiceClassName);
if (!bridge_service_class) {
void Service::InitService(JNIEnv *env) {
if (LIKELY(initialized_)) return;
initialized_ = true;
// ServiceManager
serviceManagerClass_ = env->FindClass("android/os/ServiceManager");
if (serviceManagerClass_) {
serviceManagerClass_ = (jclass) env->NewGlobalRef(serviceManagerClass_);
} else {
env->ExceptionClear();
return;
}
getServiceMethod_ = env->GetStaticMethodID(serviceManagerClass_, "getService",
"(Ljava/lang/String;)Landroid/os/IBinder;");
if (!getServiceMethod_) {
env->ExceptionClear();
return;
}
// IBinder
jclass iBinderClass = env->FindClass("android/os/IBinder");
transactMethod_ = env->GetMethodID(iBinderClass, "transact",
"(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z");
// Parcel
parcelClass_ = env->FindClass("android/os/Parcel");
if (parcelClass_) parcelClass_ = (jclass) env->NewGlobalRef(parcelClass_);
obtainMethod_ = env->GetStaticMethodID(parcelClass_, "obtain", "()Landroid/os/Parcel;");
recycleMethod_ = env->GetMethodID(parcelClass_, "recycle", "()V");
writeInterfaceTokenMethod_ = env->GetMethodID(parcelClass_, "writeInterfaceToken",
"(Ljava/lang/String;)V");
writeIntMethod_ = env->GetMethodID(parcelClass_, "writeInt", "(I)V");
writeStringMethod_ = env->GetMethodID(parcelClass_, "writeString", "(Ljava/lang/String;)V");
readExceptionMethod_ = env->GetMethodID(parcelClass_, "readException", "()V");
readStrongBinderMethod_ = env->GetMethodID(parcelClass_, "readStrongBinder",
"()Landroid/os/IBinder;");
createStringArray_ = env->GetMethodID(parcelClass_, "createStringArray",
"()[Ljava/lang/String;");
deadObjectExceptionClass_ = env->FindClass("android/os/DeadObjectException");
if (deadObjectExceptionClass_)
deadObjectExceptionClass_ = (jclass) env->NewGlobalRef(deadObjectExceptionClass_);
}
void Service::HookBridge(const Context &context, JNIEnv *env) {
static bool hooked = false;
// This should only be ran once, so unlikely
if (UNLIKELY(hooked)) return;
hooked = true;
bridge_service_class_ = context.FindClassFromCurrentLoader(env, kBridgeServiceClassName);
if (!bridge_service_class_) {
LOGE("server class not found");
return;
}
bridge_service_class = (jclass) env->NewGlobalRef(bridge_service_class);
exec_transact_replace_methodID = env->GetStaticMethodID(bridge_service_class,
"execTransact",
"(IJJI)Z");
if (!exec_transact_replace_methodID) {
bridge_service_class_ = (jclass) env->NewGlobalRef(bridge_service_class_);
exec_transact_replace_methodID_ = env->GetStaticMethodID(bridge_service_class_,
"execTransact",
"(IJJI)Z");
if (!exec_transact_replace_methodID_) {
LOGE("execTransact class not found");
return;
}
ScopedLocalRef<jclass> binderClass(env, env->FindClass("android/os/Binder"));
exec_transact_backup_methodID = env->GetMethodID(binderClass.get(), "execTransact",
"(IJJI)Z");
exec_transact_backup_methodID_ = env->GetMethodID(binderClass.get(), "execTransact",
"(IJJI)Z");
auto set_table_override = reinterpret_cast<void (*)(
JNINativeInterface *)>(DobbySymbolResolver(nullptr,
"_ZN3art9JNIEnvExt16SetTableOverrideEPK18JNINativeInterface"));
if (!set_table_override) {
LOGE("set table override not found");
}
memcpy(&native_interface_replace, env->functions, sizeof(JNINativeInterface));
memcpy(&native_interface_replace_, env->functions, sizeof(JNINativeInterface));
call_boolean_method_va_backup = env->functions->CallBooleanMethodV;
native_interface_replace.CallBooleanMethodV = &call_boolean_method_va_replace;
call_boolean_method_va_backup_ = env->functions->CallBooleanMethodV;
native_interface_replace_.CallBooleanMethodV = &call_boolean_method_va_replace;
if (set_table_override != nullptr) {
set_table_override(&native_interface_replace);
set_table_override(&native_interface_replace_);
}
LOGD("Done InitService");
}
jobject Service::RequestBinder(JNIEnv *env) {
if (UNLIKELY(!initialized_)) {
LOGE("Service not initialized");
return nullptr;
}
auto bridgeServiceName = env->NewStringUTF(BRIDGE_SERVICE_NAME.data());
auto bridgeService = JNI_CallStaticObjectMethod(env, serviceManagerClass_,
getServiceMethod_, bridgeServiceName);
if (!bridgeService) {
LOGD("can't get %s", BRIDGE_SERVICE_NAME.data());
return nullptr;
}
auto data = JNI_CallStaticObjectMethod(env, parcelClass_, obtainMethod_);
auto reply = JNI_CallStaticObjectMethod(env, parcelClass_, obtainMethod_);
auto descriptor = env->NewStringUTF(BRIDGE_SERVICE_DESCRIPTOR.data());
JNI_CallVoidMethod(env, data, writeInterfaceTokenMethod_, descriptor);
JNI_CallVoidMethod(env, data, writeIntMethod_, BRIDGE_ACTION_GET_BINDER);
auto res = JNI_CallBooleanMethod(env, bridgeService, transactMethod_,
BRIDGE_TRANSACTION_CODE,
data,
reply, 0);
jobject service = nullptr;
if (res) {
JNI_CallVoidMethod(env, reply, readExceptionMethod_);
service = JNI_CallObjectMethod(env, reply, readStrongBinderMethod_);
} else {
LOGD("no reply");
}
JNI_CallVoidMethod(env, data, recycleMethod_);
JNI_CallObjectMethod(env, reply, recycleMethod_);
return service;
}
}

View File

@ -8,8 +8,72 @@
#include <jni.h>
#include "context.h"
using namespace std::literals::string_view_literals;
namespace lspd {
void InitService(const Context & context, JNIEnv *env);
class Service {
constexpr static jint BRIDGE_TRANSACTION_CODE = 1598837584;
constexpr static auto BRIDGE_SERVICE_DESCRIPTOR = "android.app.IActivityManager"sv;
constexpr static auto BRIDGE_SERVICE_NAME = "activity"sv;
constexpr static jint BRIDGE_ACTION_GET_BINDER = 2;
public:
inline static Service* instance() {
return instance_.get();
}
inline static std::unique_ptr<Service> ReleaseInstance() {
return std::move(instance_);
}
void InitService(JNIEnv *env);
void HookBridge(const Context& context, JNIEnv *env);
jobject RequestBinder(JNIEnv *env);
private:
inline static std::unique_ptr<Service> instance_ = std::make_unique<Service>();
bool initialized_ = false;
Service() {
}
static jboolean
call_boolean_method_va_replace(JNIEnv *env, jobject obj, jmethodID methodId, va_list args);
static jboolean exec_transact_replace(jboolean *res, JNIEnv *env, jobject obj, va_list args);
JNINativeInterface native_interface_replace_{};
jmethodID exec_transact_backup_methodID_ = nullptr;
jboolean (*call_boolean_method_va_backup_)(JNIEnv *env, jobject obj, jmethodID methodId,
va_list args) = nullptr;
jclass bridge_service_class_ = nullptr;
jmethodID exec_transact_replace_methodID_ = nullptr;
jclass serviceManagerClass_ = nullptr;
jmethodID getServiceMethod_ = nullptr;
jmethodID transactMethod_ = nullptr;
jclass parcelClass_ = nullptr;
jmethodID obtainMethod_ = nullptr;
jmethodID recycleMethod_ = nullptr;
jmethodID writeInterfaceTokenMethod_ = nullptr;
jmethodID writeIntMethod_ = nullptr;
jmethodID writeStringMethod_ = nullptr;
jmethodID readExceptionMethod_ = nullptr;
jmethodID readStrongBinderMethod_ = nullptr;
jmethodID createStringArray_ = nullptr;
jclass deadObjectExceptionClass_ = nullptr;
friend std::unique_ptr<Service> std::make_unique<Service>();
};
}

View File

@ -22,10 +22,14 @@ package io.github.lsposed.lspd.core;
import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.ddm.DdmHandleAppName;
import io.github.lsposed.common.KeepAll;
import io.github.lsposed.lspd.service.ILSPApplicationService;
import io.github.lsposed.lspd.service.ServiceManager;
import io.github.lsposed.lspd.util.Utils;
@ -36,43 +40,41 @@ import static io.github.lsposed.lspd.service.ServiceManager.TAG;
@SuppressLint("DefaultLocale")
public class Main implements KeepAll {
private static final AtomicReference<EdxpImpl> lspdImplRef = new AtomicReference<>(null);
private static final Binder heartBeatBinder = new Binder();
///////////////////////////////////////////////////////////////////////////////////////////////
// entry points
///////////////////////////////////////////////////////////////////////////////////////////////
public static void forkAndSpecializePre(int uid, int gid, int[] gids, int debugFlags,
int[][] rlimits, int mountExternal, String seInfo,
String niceName, int[] fdsToClose, int[] fdsToIgnore,
boolean startChildZygote, String instructionSet,
String appDataDir) {
// won't be loaded
}
public static void forkAndSpecializePost(int pid, String appDataDir, String niceName, int variant) {
public static void forkAndSpecializePost(String appDataDir, String niceName, IBinder binder) {
ILSPApplicationService service = ILSPApplicationService.Stub.asInterface(binder);
final int variant;
try {
service.registerHeartBeat(heartBeatBinder);
variant = service.getVariant();
} catch (RemoteException e) {
Utils.logW("Register fail", e);
return;
}
EdxpImpl lspd = getEdxpImpl(variant);
if (lspd == null || !lspd.isInitialized()) {
Utils.logE("Not started up");
return;
}
if (pid == 0) {
lspd.getNormalProxy().forkAndSpecializePost(pid, appDataDir, niceName);
lspd.getNormalProxy().forkAndSpecializePost(appDataDir, niceName);
}
public static void forkSystemServerPost(IBinder binder) {
ILSPApplicationService service = ILSPApplicationService.Stub.asInterface(binder);
final int variant;
try {
service.registerHeartBeat(heartBeatBinder);
variant = service.getVariant();
} catch (RemoteException e) {
Utils.logW("Register fail", e);
return;
}
}
public static void forkSystemServerPre(int uid, int gid, int[] gids, int debugFlags, int[][] rlimits,
long permittedCapabilities, long effectiveCapabilities) {
// Won't load
}
public static void forkSystemServerPost(int pid, int variant) {
EdxpImpl lspd = getEdxpImpl(variant);
if (lspd == null || !lspd.isInitialized()) {
return;
}
if (pid == 0) {
lspd.getNormalProxy().forkSystemServerPost(pid);
}
lspd.getNormalProxy().forkSystemServerPost();
}
public static synchronized boolean setEdxpImpl(EdxpImpl lspd) {

View File

@ -26,16 +26,6 @@ public interface Proxy extends KeepAll {
boolean init();
void forkAndSpecializePre(int uid, int gid, int[] gids, int debugFlags,
int[][] rlimits, int mountExternal, String seInfo,
String niceName, int[] fdsToClose, int[] fdsToIgnore,
boolean startChildZygote, String instructionSet,
String appDataDir);
void forkAndSpecializePost(int pid, String appDataDir, String niceName);
void forkSystemServerPre(int uid, int gid, int[] gids, int debugFlags, int[][] rlimits,
long permittedCapabilities, long effectiveCapabilities);
void forkSystemServerPost(int pid);
void forkAndSpecializePost(String appDataDir, String niceName);
void forkSystemServerPost();
}

View File

@ -35,28 +35,17 @@ public class NormalProxy extends BaseProxy {
super(router);
}
public void forkAndSpecializePre(int uid, int gid, int[] gids, int debugFlags,
int[][] rlimits, int mountExternal, String seInfo,
String niceName, int[] fdsToClose, int[] fdsToIgnore,
boolean startChildZygote, String instructionSet,
String appDataDir) {
public void forkAndSpecializePost(String appDataDir, String niceName) {
forkPostCommon(false, appDataDir, niceName);
}
public void forkAndSpecializePost(int pid, String appDataDir, String niceName) {
forkPostCommon(pid, false, appDataDir, niceName);
}
public void forkSystemServerPre(int uid, int gid, int[] gids, int debugFlags, int[][] rlimits,
long permittedCapabilities, long effectiveCapabilities) {
}
public void forkSystemServerPost(int pid) {
forkPostCommon(pid, true,
public void forkSystemServerPost() {
forkPostCommon(true,
getDataPathPrefix() + "android", "system_server");
}
private void forkPostCommon(int pid, boolean isSystem, String appDataDir, String niceName) {
private void forkPostCommon(boolean isSystem, String appDataDir, String niceName) {
SELinuxHelper.initOnce();
mRouter.initResourcesHook();
mRouter.prepare(isSystem);

View File

@ -29,23 +29,32 @@ public class LSPApplicationService extends ILSPApplicationService.Stub {
}, 0);
}
@Override
public int getVariant() throws RemoteException {
ensureRegistered();
return ConfigManager.getInstance().variant();
}
// TODO: check if module
@Override
public IBinder requestModuleBinder() {
if (!hasRegister(Binder.getCallingUid(), Binder.getCallingPid()))
return null;
public IBinder requestModuleBinder() throws RemoteException {
ensureRegistered();
return ServiceManager.getModuleService();
}
// TODO: check if manager
@Override
public IBinder requestManagerBinder() {
if (!hasRegister(Binder.getCallingUid(), Binder.getCallingPid()))
return null;
public IBinder requestManagerBinder() throws RemoteException {
ensureRegistered();
return ServiceManager.getManagerService();
}
public boolean hasRegister(int uid, int pid) {
return cache.contains(new Pair<>(uid, pid));
}
private void ensureRegistered() throws RemoteException {
if (!hasRegister(Binder.getCallingUid(), Binder.getCallingPid()))
throw new RemoteException("Not registered");
}
}