[core] Workaround for binder: allow blocking
This commit is contained in:
parent
0ec8959235
commit
2890aec54f
|
|
@ -39,9 +39,6 @@
|
||||||
#include "jni/native_api.h"
|
#include "jni/native_api.h"
|
||||||
#include "service.h"
|
#include "service.h"
|
||||||
|
|
||||||
#pragma clang diagnostic push
|
|
||||||
#pragma clang diagnostic ignored "-Wunused-value"
|
|
||||||
|
|
||||||
namespace lspd {
|
namespace lspd {
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
|
|
@ -132,6 +129,7 @@ namespace lspd {
|
||||||
RegisterEdxpYahfa(env);
|
RegisterEdxpYahfa(env);
|
||||||
RegisterPendingHooks(env);
|
RegisterPendingHooks(env);
|
||||||
RegisterNativeAPI(env);
|
RegisterNativeAPI(env);
|
||||||
|
// TODO: Recover this
|
||||||
|
|
||||||
// variant_ = Variant(ConfigManager::GetInstance()->GetVariant());
|
// variant_ = Variant(ConfigManager::GetInstance()->GetVariant());
|
||||||
// LOGI("LSP Variant: %d", variant_);
|
// LOGI("LSP Variant: %d", variant_);
|
||||||
|
|
@ -193,15 +191,7 @@ namespace lspd {
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Context::OnNativeForkSystemServerPre([[maybe_unused]] JNIEnv *env,
|
Context::OnNativeForkSystemServerPre(JNIEnv *env) {
|
||||||
[[maybe_unused]] jclass clazz,
|
|
||||||
[[maybe_unused]] uid_t uid,
|
|
||||||
[[maybe_unused]] gid_t gid,
|
|
||||||
[[maybe_unused]] jintArray gids,
|
|
||||||
[[maybe_unused]] jint runtime_flags,
|
|
||||||
[[maybe_unused]] jobjectArray rlimits,
|
|
||||||
[[maybe_unused]] jlong permitted_capabilities,
|
|
||||||
[[maybe_unused]] jlong effective_capabilities) {
|
|
||||||
Service::instance()->InitService(env);
|
Service::instance()->InitService(env);
|
||||||
PreLoadDex(ConfigManager::GetInjectDexPath());
|
PreLoadDex(ConfigManager::GetInjectDexPath());
|
||||||
skip_ = false;
|
skip_ = false;
|
||||||
|
|
@ -231,31 +221,24 @@ namespace lspd {
|
||||||
Service::instance()->HookBridge(*this, env);
|
Service::instance()->HookBridge(*this, env);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Context::OnNativeForkAndSpecializePre(JNIEnv *env, jclass clazz,
|
void Context::OnNativeForkAndSpecializePre(JNIEnv *env,
|
||||||
jint uid, jint gid,
|
jint uid,
|
||||||
jintArray gids,
|
|
||||||
jint runtime_flags,
|
|
||||||
jobjectArray rlimits,
|
|
||||||
jint mount_external,
|
|
||||||
jstring se_info,
|
|
||||||
jstring nice_name,
|
jstring nice_name,
|
||||||
jintArray fds_to_close,
|
|
||||||
jintArray fds_to_ignore,
|
|
||||||
jboolean is_child_zygote,
|
jboolean is_child_zygote,
|
||||||
jstring instruction_set,
|
|
||||||
jstring app_data_dir) {
|
jstring app_data_dir) {
|
||||||
PreLoadDex(ConfigManager::GetInjectDexPath());
|
PreLoadDex(ConfigManager::GetInjectDexPath());
|
||||||
Service::instance()->InitService(env);
|
Service::instance()->InitService(env);
|
||||||
this->uid = uid;
|
|
||||||
const auto app_id = uid % PER_USER_RANGE;
|
const auto app_id = uid % PER_USER_RANGE;
|
||||||
|
nice_name_ = nice_name;
|
||||||
|
JUTFString process_name(env, nice_name);
|
||||||
skip_ = false;
|
skip_ = false;
|
||||||
if (!skip_ && !app_data_dir) {
|
if (!skip_ && !app_data_dir) {
|
||||||
LOGD("skip injecting into %d because it has no data dir", uid);
|
LOGD("skip injecting into %s because it has no data dir", process_name.get());
|
||||||
skip_ = true;
|
skip_ = true;
|
||||||
}
|
}
|
||||||
if (!skip_ && is_child_zygote) {
|
if (!skip_ && is_child_zygote) {
|
||||||
skip_ = true;
|
skip_ = true;
|
||||||
LOGD("skip injecting into %d because it's a child zygote", uid);
|
LOGD("skip injecting into %s because it's a child zygote", process_name.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!skip_ && ((app_id >= FIRST_ISOLATED_UID && app_id <= LAST_ISOLATED_UID) ||
|
if (!skip_ && ((app_id >= FIRST_ISOLATED_UID && app_id <= LAST_ISOLATED_UID) ||
|
||||||
|
|
@ -263,7 +246,7 @@ namespace lspd {
|
||||||
app_id <= LAST_APP_ZYGOTE_ISOLATED_UID) ||
|
app_id <= LAST_APP_ZYGOTE_ISOLATED_UID) ||
|
||||||
app_id == SHARED_RELRO_UID)) {
|
app_id == SHARED_RELRO_UID)) {
|
||||||
skip_ = true;
|
skip_ = true;
|
||||||
LOGI("skip injecting into %d because it's isolated", uid);
|
LOGI("skip injecting into %s because it's isolated", process_name.get());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -289,5 +272,3 @@ namespace lspd {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma clang diagnostic pop
|
|
||||||
|
|
@ -56,21 +56,13 @@ namespace lspd {
|
||||||
return FindClassFromLoader(env, GetCurrentClassLoader(), className);
|
return FindClassFromLoader(env, GetCurrentClassLoader(), className);
|
||||||
};
|
};
|
||||||
|
|
||||||
void OnNativeForkAndSpecializePre(JNIEnv *env, jclass clazz, jint uid, jint gid,
|
void OnNativeForkAndSpecializePre(JNIEnv *env, jint uid, jstring nice_name, jboolean is_child_zygote, jstring app_data_dir);
|
||||||
jintArray gids, jint runtime_flags, jobjectArray rlimits,
|
|
||||||
jint mount_external,
|
|
||||||
jstring se_info, jstring se_name, jintArray fds_to_close,
|
|
||||||
jintArray fds_to_ignore, jboolean is_child_zygote,
|
|
||||||
jstring instruction_set, jstring app_data_dir);
|
|
||||||
|
|
||||||
void OnNativeForkAndSpecializePost(JNIEnv *env);
|
void OnNativeForkAndSpecializePost(JNIEnv *env);
|
||||||
|
|
||||||
void OnNativeForkSystemServerPost(JNIEnv *env, jint res);
|
void OnNativeForkSystemServerPost(JNIEnv *env, jint res);
|
||||||
|
|
||||||
void OnNativeForkSystemServerPre(JNIEnv *env, jclass clazz, uid_t uid, gid_t gid,
|
void OnNativeForkSystemServerPre(JNIEnv *env);
|
||||||
jintArray gids, jint runtime_flags, jobjectArray rlimits,
|
|
||||||
jlong permitted_capabilities,
|
|
||||||
jlong effective_capabilities);
|
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
@ -82,7 +74,6 @@ namespace lspd {
|
||||||
JavaVM *vm_ = nullptr;
|
JavaVM *vm_ = nullptr;
|
||||||
jclass class_linker_class_ = nullptr;
|
jclass class_linker_class_ = nullptr;
|
||||||
jmethodID post_fixup_static_mid_ = nullptr;
|
jmethodID post_fixup_static_mid_ = nullptr;
|
||||||
jint uid = -1;
|
|
||||||
bool skip_ = false;
|
bool skip_ = false;
|
||||||
std::vector<signed char> dex{};
|
std::vector<signed char> dex{};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,64 +37,58 @@ namespace lspd {
|
||||||
ConfigManager::Init();
|
ConfigManager::Init();
|
||||||
}
|
}
|
||||||
|
|
||||||
static int shouldSkipUid(int uid) {
|
static int shouldSkipUid(int) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nativeForkAndSpecializePre(JNIEnv *env, jclass clazz, jint *_uid, jint *gid,
|
static void nativeForkAndSpecializePre(JNIEnv *env, jclass, jint *_uid, jint *,
|
||||||
jintArray *gids, jint *runtime_flags,
|
jintArray *, jint *,
|
||||||
jobjectArray *rlimits, jint *mount_external,
|
jobjectArray *, jint *,
|
||||||
jstring *se_info, jstring *nice_name,
|
jstring *, jstring *nice_name,
|
||||||
jintArray *fds_to_close, jintArray *fds_to_ignore,
|
jintArray *, jintArray *,
|
||||||
jboolean *start_child_zygote, jstring *instruction_set,
|
jboolean *start_child_zygote, jstring *,
|
||||||
jstring *app_data_dir, jboolean *is_top_app, jobjectArray *pkg_data_info_list,
|
jstring *app_data_dir, jboolean *,
|
||||||
jobjectArray *whitelisted_data_info_list, jboolean *bind_mount_app_data_dirs,
|
jobjectArray *,
|
||||||
jboolean *bind_mount_app_storage_dirs) {
|
jobjectArray *,
|
||||||
Context::GetInstance()->OnNativeForkAndSpecializePre(env, clazz, *_uid, *gid, *gids,
|
jboolean *,
|
||||||
*runtime_flags, *rlimits,
|
jboolean *) {
|
||||||
*mount_external, *se_info, *nice_name,
|
Context::GetInstance()->OnNativeForkAndSpecializePre(env, *_uid,
|
||||||
*fds_to_close,
|
*nice_name,
|
||||||
*fds_to_ignore,
|
*start_child_zygote,
|
||||||
*start_child_zygote, *instruction_set,
|
|
||||||
*app_data_dir);
|
*app_data_dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nativeForkAndSpecializePost(JNIEnv *env, jclass clazz, jint res) {
|
static void nativeForkAndSpecializePost(JNIEnv *env, jclass, jint res) {
|
||||||
Context::GetInstance()->OnNativeForkAndSpecializePost(env);
|
if (res == 0)
|
||||||
|
Context::GetInstance()->OnNativeForkAndSpecializePost(env);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nativeForkSystemServerPre(JNIEnv *env, jclass clazz, uid_t *uid, gid_t *gid,
|
static void nativeForkSystemServerPre(JNIEnv *env, jclass, uid_t *, gid_t *,
|
||||||
jintArray *gids, jint *runtime_flags,
|
jintArray *, jint *,
|
||||||
jobjectArray *rlimits, jlong *permitted_capabilities,
|
jobjectArray *, jlong *,
|
||||||
jlong *effective_capabilities) {
|
jlong *) {
|
||||||
Context::GetInstance()->OnNativeForkSystemServerPre(env, clazz, *uid, *gid, *gids,
|
Context::GetInstance()->OnNativeForkSystemServerPre(env);
|
||||||
*runtime_flags, *rlimits,
|
|
||||||
*permitted_capabilities,
|
|
||||||
*effective_capabilities
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nativeForkSystemServerPost(JNIEnv *env, [[maybe_unused]] jclass clazz, jint res) {
|
static void nativeForkSystemServerPost(JNIEnv *env, jclass, jint res) {
|
||||||
Context::GetInstance()->OnNativeForkSystemServerPost(env, res);
|
Context::GetInstance()->OnNativeForkSystemServerPost(env, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* method added in Android Q */
|
/* method added in Android Q */
|
||||||
static void specializeAppProcessPre(JNIEnv *env, jclass clazz, jint *uid, jint *gid,
|
static void specializeAppProcessPre(JNIEnv *env, jclass, jint *uid, jint *,
|
||||||
jintArray *gids, jint *runtime_flags, jobjectArray *rlimits,
|
jintArray *, jint *, jobjectArray *,
|
||||||
jint *mount_external, jstring *se_info, jstring *nice_name,
|
jint *, jstring *, jstring *nice_name,
|
||||||
jboolean *start_child_zygote, jstring *instruction_set,
|
jboolean *start_child_zygote, jstring *,
|
||||||
jstring *app_data_dir, jboolean *is_top_app, jobjectArray *pkg_data_info_list,
|
jstring *app_data_dir, jboolean *,
|
||||||
jobjectArray *whitelisted_data_info_list, jboolean *bind_mount_app_data_dirs,
|
jobjectArray *,
|
||||||
jboolean *bind_mount_app_storage_dirs) {
|
jobjectArray *,
|
||||||
Context::GetInstance()->OnNativeForkAndSpecializePre(env, clazz, *uid, *gid, *gids,
|
jboolean *,
|
||||||
*runtime_flags, *rlimits,
|
jboolean *) {
|
||||||
*mount_external, *se_info, *nice_name,
|
Context::GetInstance()->OnNativeForkAndSpecializePre(env, *uid, *nice_name, *start_child_zygote,
|
||||||
nullptr, nullptr,
|
|
||||||
*start_child_zygote, *instruction_set,
|
|
||||||
*app_data_dir);
|
*app_data_dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void specializeAppProcessPost(JNIEnv *env, [[maybe_unused]] jclass clazz) {
|
static void specializeAppProcessPost(JNIEnv *env, jclass) {
|
||||||
Context::GetInstance()->OnNativeForkAndSpecializePost(env);
|
Context::GetInstance()->OnNativeForkAndSpecializePost(env);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -110,7 +104,9 @@ RIRU_EXPORT void *init(void *arg) {
|
||||||
switch (step) {
|
switch (step) {
|
||||||
case 1: {
|
case 1: {
|
||||||
auto core_max_api_version = *(int *) arg;
|
auto core_max_api_version = *(int *) arg;
|
||||||
riru_api_version = core_max_api_version <= RIRU_MODULE_API_VERSION ? core_max_api_version : RIRU_MODULE_API_VERSION;
|
riru_api_version =
|
||||||
|
core_max_api_version <= RIRU_MODULE_API_VERSION ? core_max_api_version
|
||||||
|
: RIRU_MODULE_API_VERSION;
|
||||||
return &riru_api_version;
|
return &riru_api_version;
|
||||||
}
|
}
|
||||||
case 2: {
|
case 2: {
|
||||||
|
|
|
||||||
|
|
@ -154,12 +154,9 @@ namespace lspd {
|
||||||
if (res) {
|
if (res) {
|
||||||
JNI_CallVoidMethod(env, reply, readExceptionMethod_);
|
JNI_CallVoidMethod(env, reply, readExceptionMethod_);
|
||||||
service = JNI_CallObjectMethod(env, reply, readStrongBinderMethod_);
|
service = JNI_CallObjectMethod(env, reply, readStrongBinderMethod_);
|
||||||
} else {
|
|
||||||
LOGD("no reply");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JNI_CallVoidMethod(env, data, recycleMethod_);
|
JNI_CallVoidMethod(env, data, recycleMethod_);
|
||||||
JNI_CallObjectMethod(env, reply, recycleMethod_);
|
JNI_CallVoidMethod(env, reply, recycleMethod_);
|
||||||
|
|
||||||
return service;
|
return service;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,9 +36,7 @@ namespace lspd {
|
||||||
inline static std::unique_ptr<Service> instance_ = std::make_unique<Service>();
|
inline static std::unique_ptr<Service> instance_ = std::make_unique<Service>();
|
||||||
bool initialized_ = false;
|
bool initialized_ = false;
|
||||||
|
|
||||||
Service() {
|
Service() = default;
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static jboolean
|
static jboolean
|
||||||
call_boolean_method_va_replace(JNIEnv *env, jobject obj, jmethodID methodId, va_list args);
|
call_boolean_method_va_replace(JNIEnv *env, jobject obj, jmethodID methodId, va_list args);
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,6 @@
|
||||||
|
|
||||||
package io.github.lsposed.lspd.core.yahfa;
|
package io.github.lsposed.lspd.core.yahfa;
|
||||||
|
|
||||||
import io.github.lsposed.lspd.nativebridge.Heap;
|
|
||||||
import io.github.lsposed.lspd.nativebridge.Yahfa;
|
import io.github.lsposed.lspd.nativebridge.Yahfa;
|
||||||
import io.github.lsposed.lspd.util.Utils;
|
import io.github.lsposed.lspd.util.Utils;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,39 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is part of LSPosed.
|
|
||||||
*
|
|
||||||
* LSPosed is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* LSPosed is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with LSPosed. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2020 EdXposed Contributors
|
|
||||||
* Copyright (C) 2021 LSPosed Contributors
|
|
||||||
*/
|
|
||||||
|
|
||||||
package io.github.lsposed.lspd.framework;
|
|
||||||
|
|
||||||
import io.github.lsposed.lspd.util.Utils;
|
|
||||||
|
|
||||||
import de.robv.android.xposed.XposedHelpers;
|
|
||||||
import de.robv.android.xposed.annotation.ApiSensitive;
|
|
||||||
import de.robv.android.xposed.annotation.Level;
|
|
||||||
|
|
||||||
@ApiSensitive(Level.LOW)
|
|
||||||
public class Zygote {
|
|
||||||
public static void allowFileAcrossFork(String path) {
|
|
||||||
try {
|
|
||||||
Class zygote = XposedHelpers.findClass("com.android.internal.os.Zygote", null);
|
|
||||||
XposedHelpers.callStaticMethod(zygote, "nativeAllowFileAcrossFork", path);
|
|
||||||
} catch (Throwable throwable) {
|
|
||||||
Utils.logE("error when allowFileAcrossFork", throwable);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is part of LSPosed.
|
|
||||||
*
|
|
||||||
* LSPosed is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* LSPosed is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with LSPosed. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2020 EdXposed Contributors
|
|
||||||
* Copyright (C) 2021 LSPosed Contributors
|
|
||||||
*/
|
|
||||||
|
|
||||||
package io.github.lsposed.lspd.nativebridge;
|
|
||||||
|
|
||||||
public class Heap {
|
|
||||||
public static native int waitForGcToComplete();
|
|
||||||
}
|
|
||||||
|
|
@ -13,6 +13,7 @@ import androidx.annotation.Nullable;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static hidden.HiddenApiBridge.Binder_allowBlocking;
|
||||||
import static io.github.lsposed.lspd.service.ServiceManager.TAG;
|
import static io.github.lsposed.lspd.service.ServiceManager.TAG;
|
||||||
|
|
||||||
public class BridgeService {
|
public class BridgeService {
|
||||||
|
|
@ -21,6 +22,7 @@ public class BridgeService {
|
||||||
private static final String SERVICE_NAME = "activity";
|
private static final String SERVICE_NAME = "activity";
|
||||||
|
|
||||||
enum ACTION {
|
enum ACTION {
|
||||||
|
ACTION_UNKNOWN,
|
||||||
ACTION_SEND_BINDER,
|
ACTION_SEND_BINDER,
|
||||||
ACTION_GET_BINDER,
|
ACTION_GET_BINDER,
|
||||||
}
|
}
|
||||||
|
|
@ -149,7 +151,7 @@ public class BridgeService {
|
||||||
serviceBinder.unlinkToDeath(LSPSERVICE_DEATH_RECIPIENT, 0);
|
serviceBinder.unlinkToDeath(LSPSERVICE_DEATH_RECIPIENT, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
serviceBinder = binder;
|
serviceBinder = Binder_allowBlocking(binder);
|
||||||
service = ILSPosedService.Stub.asInterface(serviceBinder);
|
service = ILSPosedService.Stub.asInterface(serviceBinder);
|
||||||
try {
|
try {
|
||||||
serviceBinder.linkToDeath(LSPSERVICE_DEATH_RECIPIENT, 0);
|
serviceBinder.linkToDeath(LSPSERVICE_DEATH_RECIPIENT, 0);
|
||||||
|
|
@ -171,7 +173,7 @@ public class BridgeService {
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings({"unused", "RedundantSuppression"})
|
@SuppressWarnings({"unused", "RedundantSuppression"})
|
||||||
public static boolean onTransact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags) {
|
public static boolean onTransact(@NonNull Parcel data, @Nullable Parcel reply, int flags) {
|
||||||
data.enforceInterface(DESCRIPTOR);
|
data.enforceInterface(DESCRIPTOR);
|
||||||
|
|
||||||
ACTION action = ACTION.values()[data.readInt()];
|
ACTION action = ACTION.values()[data.readInt()];
|
||||||
|
|
@ -209,13 +211,13 @@ public class BridgeService {
|
||||||
|
|
||||||
@SuppressWarnings({"unused", "RedundantSuppression"})
|
@SuppressWarnings({"unused", "RedundantSuppression"})
|
||||||
public static boolean execTransact(int code, long dataObj, long replyObj, int flags) {
|
public static boolean execTransact(int code, long dataObj, long replyObj, int flags) {
|
||||||
Log.d(TAG, String.valueOf(code));
|
|
||||||
if (code != TRANSACTION_CODE) return false;
|
if (code != TRANSACTION_CODE) return false;
|
||||||
|
|
||||||
Parcel data = ParcelUtils.fromNativePointer(dataObj);
|
Parcel data = ParcelUtils.fromNativePointer(dataObj);
|
||||||
Parcel reply = ParcelUtils.fromNativePointer(replyObj);
|
Parcel reply = ParcelUtils.fromNativePointer(replyObj);
|
||||||
|
|
||||||
if (data == null || reply == null) {
|
if (data == null || reply == null) {
|
||||||
|
Log.w(TAG, "Got transaction with null data or reply");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -224,9 +226,8 @@ public class BridgeService {
|
||||||
try {
|
try {
|
||||||
String descriptor = ParcelUtils.readInterfaceDescriptor(data);
|
String descriptor = ParcelUtils.readInterfaceDescriptor(data);
|
||||||
data.setDataPosition(0);
|
data.setDataPosition(0);
|
||||||
|
|
||||||
if (descriptor.equals(DESCRIPTOR)) {
|
if (descriptor.equals(DESCRIPTOR)) {
|
||||||
res = onTransact(code, data, reply, flags);
|
res = onTransact(data, reply, flags);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
if ((flags & IBinder.FLAG_ONEWAY) != 0) {
|
if ((flags & IBinder.FLAG_ONEWAY) != 0) {
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,17 @@
|
||||||
package io.github.lsposed.lspd.service;
|
package io.github.lsposed.lspd.service;
|
||||||
|
|
||||||
import android.content.ContentValues;
|
import android.content.ContentValues;
|
||||||
|
import android.content.pm.PackageInfo;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.database.sqlite.SQLiteQueryBuilder;
|
import android.database.sqlite.SQLiteQueryBuilder;
|
||||||
import android.database.sqlite.SQLiteStatement;
|
import android.database.sqlite.SQLiteStatement;
|
||||||
import android.database.sqlite.SQLiteDatabase;
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
import android.os.FileObserver;
|
import android.os.FileObserver;
|
||||||
import android.os.ParcelFileDescriptor;
|
import android.os.ParcelFileDescriptor;
|
||||||
|
import android.os.RemoteException;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
@ -43,6 +46,12 @@ public class ConfigManager {
|
||||||
final private File verboseLogSwitch = new File(configPath, "verbose_log");
|
final private File verboseLogSwitch = new File(configPath, "verbose_log");
|
||||||
private boolean verboseLog = false;
|
private boolean verboseLog = false;
|
||||||
|
|
||||||
|
final private String DEFAULT_MANAGER_PACKAGE_NAME = "io.github.lsposed.manager";
|
||||||
|
|
||||||
|
final private File managerPath = new File(configPath, "manager");
|
||||||
|
private String manager = null;
|
||||||
|
private int managerUid = -1;
|
||||||
|
|
||||||
final private File selinuxPath = new File("/sys/fs/selinux/enforce");
|
final private File selinuxPath = new File("/sys/fs/selinux/enforce");
|
||||||
// only check on boot
|
// only check on boot
|
||||||
final private boolean isPermissive;
|
final private boolean isPermissive;
|
||||||
|
|
@ -59,41 +68,77 @@ public class ConfigManager {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
int readInt(File file, int defaultValue) {
|
private String readText(@NonNull File file) throws IOException {
|
||||||
|
return new String(Files.readAllBytes(file.toPath()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private String readText(@NonNull File file, String defaultValue) {
|
||||||
try {
|
try {
|
||||||
return Integer.parseInt(new String(Files.readAllBytes(file.toPath())));
|
if (!file.exists()) return defaultValue;
|
||||||
|
return readText(file);
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(TAG, Log.getStackTraceString(e));
|
||||||
|
}
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeText(@NonNull File file, String value) {
|
||||||
|
try {
|
||||||
|
Files.write(file.toPath(), value.getBytes(), StandardOpenOption.CREATE_NEW);
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(TAG, Log.getStackTraceString(e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int readInt(@NonNull File file, int defaultValue) {
|
||||||
|
try {
|
||||||
|
if (!file.exists()) return defaultValue;
|
||||||
|
return Integer.parseInt(readText(file));
|
||||||
} catch (IOException | NumberFormatException e) {
|
} catch (IOException | NumberFormatException e) {
|
||||||
Log.e(TAG, Log.getStackTraceString(e));
|
Log.e(TAG, Log.getStackTraceString(e));
|
||||||
}
|
}
|
||||||
return defaultValue;
|
return defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
void writeInt(File file, int value) {
|
private void writeInt(@NonNull File file, int value) {
|
||||||
try {
|
writeText(file, String.valueOf(value));
|
||||||
Files.write(file.toPath(), String.valueOf(value).getBytes(), StandardOpenOption.CREATE_NEW);
|
|
||||||
} catch (IOException e) {
|
|
||||||
Log.e(TAG, Log.getStackTraceString(e));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateConfig() {
|
private synchronized void updateConfig() {
|
||||||
resourceHook = resourceHookSwitch.exists();
|
resourceHook = resourceHookSwitch.exists();
|
||||||
variant = readInt(variantSwitch, -1);
|
variant = readInt(variantSwitch, -1);
|
||||||
verboseLog = readInt(verboseLogSwitch, 0) == 1;
|
verboseLog = readInt(verboseLogSwitch, 0) == 1;
|
||||||
|
updateManager();
|
||||||
}
|
}
|
||||||
|
|
||||||
SQLiteStatement createEnabledModulesTable = db.compileStatement("CREATE TABLE IF NOT EXISTS enabled_modules (" +
|
public synchronized void updateManager() {
|
||||||
"mid int PRIMARY KEY AUTOINCREMENT," +
|
try {
|
||||||
|
PackageInfo info = PackageService.getPackageInfo(readText(managerPath, DEFAULT_MANAGER_PACKAGE_NAME), 0, 0);
|
||||||
|
if (info != null) {
|
||||||
|
managerUid = info.applicationInfo.uid;
|
||||||
|
manager = info.packageName;
|
||||||
|
}
|
||||||
|
} catch (RemoteException ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void updateManager(@NonNull String packageName) {
|
||||||
|
writeText(managerPath, packageName);
|
||||||
|
updateManager();
|
||||||
|
}
|
||||||
|
|
||||||
|
private final SQLiteStatement createEnabledModulesTable = db.compileStatement("CREATE TABLE IF NOT EXISTS enabled_modules (" +
|
||||||
|
"mid integer PRIMARY KEY AUTOINCREMENT," +
|
||||||
"package_name text NOT NULL UNIQUE," +
|
"package_name text NOT NULL UNIQUE," +
|
||||||
"apk_path text NOT NULL" +
|
"apk_path text NOT NULL" +
|
||||||
");");
|
");");
|
||||||
SQLiteStatement createScopeTable = db.compileStatement("CREATE TABLE IF NOT EXISTS scope (" +
|
private final SQLiteStatement createScopeTable = db.compileStatement("CREATE TABLE IF NOT EXISTS scope (" +
|
||||||
"mid int," +
|
"mid integer," +
|
||||||
"uid int," +
|
"uid integer," +
|
||||||
"PRIMARY KEY (mid, uid)" +
|
"PRIMARY KEY (mid, uid)" +
|
||||||
");");
|
");");
|
||||||
|
|
||||||
ConcurrentHashMap<Integer, ArrayList<String>> modulesForUid;
|
private final ConcurrentHashMap<Integer, ArrayList<String>> modulesForUid = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
static ConfigManager getInstance() {
|
static ConfigManager getInstance() {
|
||||||
if (instance == null)
|
if (instance == null)
|
||||||
|
|
@ -105,6 +150,7 @@ public class ConfigManager {
|
||||||
createTables();
|
createTables();
|
||||||
updateConfig();
|
updateConfig();
|
||||||
isPermissive = readInt(selinuxPath, 1) == 0;
|
isPermissive = readInt(selinuxPath, 1) == 0;
|
||||||
|
configObserver.startWatching();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createTables() {
|
private void createTables() {
|
||||||
|
|
@ -113,6 +159,7 @@ public class ConfigManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized void cacheScopes() {
|
private synchronized void cacheScopes() {
|
||||||
|
modulesForUid.clear();
|
||||||
SQLiteQueryBuilder builder = new SQLiteQueryBuilder();
|
SQLiteQueryBuilder builder = new SQLiteQueryBuilder();
|
||||||
builder.setTables("scope INNER JOIN enabled_modules ON scope.mid = enabled_modules.mid");
|
builder.setTables("scope INNER JOIN enabled_modules ON scope.mid = enabled_modules.mid");
|
||||||
Cursor cursor = builder.query(db, new String[]{"scope.uid", "enabled_modules.apk_path"},
|
Cursor cursor = builder.query(db, new String[]{"scope.uid", "enabled_modules.apk_path"},
|
||||||
|
|
@ -132,13 +179,13 @@ public class ConfigManager {
|
||||||
|
|
||||||
// This is called when a new process created, use the cached result
|
// This is called when a new process created, use the cached result
|
||||||
public List<String> getModulesPathForUid(int uid) {
|
public List<String> getModulesPathForUid(int uid) {
|
||||||
return modulesForUid.getOrDefault(uid, null);
|
return isManager(uid) ? new ArrayList<>() : modulesForUid.getOrDefault(uid, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is called when a new process created, use the cached result
|
// This is called when a new process created, use the cached result
|
||||||
// The signature matches Riru's
|
// The signature matches Riru's
|
||||||
public boolean shouldSkipUid(int uid) {
|
public boolean shouldSkipUid(int uid) {
|
||||||
return !modulesForUid.containsKey(uid);
|
return !modulesForUid.containsKey(uid) && !isManager(uid);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This should only be called by manager, so we don't need to cache it
|
// This should only be called by manager, so we don't need to cache it
|
||||||
|
|
@ -278,4 +325,12 @@ public class ConfigManager {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isManager(String package_name) {
|
||||||
|
return package_name.equals(manager);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isManager(int uid) {
|
||||||
|
return uid == managerUid;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,9 @@ public class LSPApplicationService extends ILSPApplicationService.Stub {
|
||||||
@Override
|
@Override
|
||||||
public IBinder requestManagerBinder() throws RemoteException {
|
public IBinder requestManagerBinder() throws RemoteException {
|
||||||
ensureRegistered();
|
ensureRegistered();
|
||||||
return ServiceManager.getManagerService();
|
if (ConfigManager.getInstance().isManager(Binder.getCallingUid()))
|
||||||
|
return ServiceManager.getManagerService();
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasRegister(int uid, int pid) {
|
public boolean hasRegister(int uid, int pid) {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
package io.github.lsposed.lspd.service;
|
package io.github.lsposed.lspd.service;
|
||||||
|
|
||||||
import android.os.Binder;
|
import android.os.Binder;
|
||||||
import android.os.IBinder;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import static io.github.lsposed.lspd.service.ServiceManager.TAG;
|
import static io.github.lsposed.lspd.service.ServiceManager.TAG;
|
||||||
|
|
@ -28,14 +27,18 @@ public class LSPosedService extends ILSPosedService.Stub {
|
||||||
@Override
|
@Override
|
||||||
public ILSPApplicationService requestApplicationService(int uid, int pid) {
|
public ILSPApplicationService requestApplicationService(int uid, int pid) {
|
||||||
if (Binder.getCallingUid() != 1000) {
|
if (Binder.getCallingUid() != 1000) {
|
||||||
|
Log.w(TAG, "Someone else got my binder!?");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (ConfigManager.getInstance().shouldSkipUid(uid)) {
|
if (ConfigManager.getInstance().shouldSkipUid(uid)) {
|
||||||
|
Log.d(TAG, "Skipped uid " + uid);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (ServiceManager.getApplicationService().hasRegister(uid, pid)) {
|
if (ServiceManager.getApplicationService().hasRegister(uid, pid)) {
|
||||||
|
Log.d(TAG, "Skipped duplicated request for uid " + uid + " pid " + pid);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
Log.d(TAG, "returned service");
|
||||||
return ServiceManager.getApplicationService();
|
return ServiceManager.getApplicationService();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,52 +1,15 @@
|
||||||
package hidden;
|
package hidden;
|
||||||
|
|
||||||
//import android.annotation.NonNull;
|
|
||||||
//import android.app.ActivityThread;
|
|
||||||
//import android.content.pm.ApplicationInfo;
|
|
||||||
//import android.content.pm.PackageInfo;
|
|
||||||
//import android.content.pm.PackageManager;
|
|
||||||
//import android.os.UserHandle;
|
|
||||||
import android.annotation.NonNull;
|
|
||||||
import android.content.pm.PackageInfo;
|
|
||||||
import android.content.pm.PackageManager;
|
|
||||||
import android.content.pm.UserInfo;
|
|
||||||
import android.content.res.AssetManager;
|
import android.content.res.AssetManager;
|
||||||
import android.os.UserManager;
|
import android.os.Binder;
|
||||||
|
import android.os.IBinder;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class HiddenApiBridge {
|
public class HiddenApiBridge {
|
||||||
public static int AssetManager_addAssetPath(AssetManager am, String path) {
|
public static int AssetManager_addAssetPath(AssetManager am, String path) {
|
||||||
return am.addAssetPath(path);
|
return am.addAssetPath(path);
|
||||||
}
|
}
|
||||||
public static List<UserInfo> UserManager_getUsers(UserManager um) {
|
|
||||||
return um.getUsers();
|
public static IBinder Binder_allowBlocking(IBinder binder) {
|
||||||
|
return Binder.allowBlocking(binder);
|
||||||
}
|
}
|
||||||
// public static ApplicationInfo PackageManager_getApplicationInfoAsUser(PackageManager packageManager, @NonNull String packageName, int flags, int userId) throws android.content.pm.PackageManager.NameNotFoundException {
|
|
||||||
// return packageManager.getApplicationInfoAsUser(packageName, flags, userId);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public static PackageInfo PackageManager_getPackageInfoAsUser(PackageManager packageManager, @NonNull String packageName, int flags, int userId) throws android.content.pm.PackageManager.NameNotFoundException {
|
|
||||||
// return packageManager.getPackageInfoAsUser(packageName, flags, userId);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public static List<ApplicationInfo> PackageManager_getInstalledApplicationsAsUser(PackageManager packageManager, int flags, int userId) {
|
|
||||||
// return packageManager.getInstalledApplicationsAsUser(flags, userId);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
public static List<PackageInfo> PackageManager_getInstalledPackagesAsUser(PackageManager packageManager, int flags, int userId) {
|
|
||||||
return packageManager.getInstalledPackagesAsUser(flags, userId);
|
|
||||||
}
|
|
||||||
//
|
|
||||||
// public static UserHandle createUserHandle(int userId) {
|
|
||||||
// return new UserHandle(userId);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public static ActivityThread ActivityThread_systemMain() {
|
|
||||||
// return ActivityThread.systemMain();
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public static String PackageInfo_overlayTarget(PackageInfo packageInfo) {
|
|
||||||
// return packageInfo.overlayTarget;
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -55,4 +55,8 @@ public class Binder implements IBinder {
|
||||||
int flags) throws RemoteException {
|
int flags) throws RemoteException {
|
||||||
throw new RuntimeException("STUB");
|
throw new RuntimeException("STUB");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static IBinder allowBlocking(IBinder binder){
|
||||||
|
throw new RuntimeException("STUB");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue