mirror of
https://github.com/rhunk/SnapEnhance.git
synced 2025-04-30 06:34:29 +02:00
feat: experimental native hooks
This commit is contained in:
parent
b004f92b9c
commit
c0225919e9
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
[submodule "dobby"]
|
||||||
|
path = native/jni/external/dobby
|
||||||
|
url = https://github.com/jmpews/Dobby
|
@ -42,4 +42,5 @@ dependencies {
|
|||||||
implementation(libs.androidx.documentfile)
|
implementation(libs.androidx.documentfile)
|
||||||
|
|
||||||
implementation(project(":mapper"))
|
implementation(project(":mapper"))
|
||||||
|
implementation(project(":native"))
|
||||||
}
|
}
|
@ -249,6 +249,10 @@
|
|||||||
"name": "Disable Metrics",
|
"name": "Disable Metrics",
|
||||||
"description": "Disables some analytics data sent to Snapchat"
|
"description": "Disables some analytics data sent to Snapchat"
|
||||||
},
|
},
|
||||||
|
"disable_bitmoji": {
|
||||||
|
"name": "Disable Bitmoji",
|
||||||
|
"description": "Disables friends profile bitmoji for the whole app"
|
||||||
|
},
|
||||||
"block_ads": {
|
"block_ads": {
|
||||||
"name": "Block Ads",
|
"name": "Block Ads",
|
||||||
"description": "Prevent ads from being displayed"
|
"description": "Prevent ads from being displayed"
|
||||||
|
@ -21,6 +21,8 @@ import me.rhunk.snapenhance.database.DatabaseAccess
|
|||||||
import me.rhunk.snapenhance.features.Feature
|
import me.rhunk.snapenhance.features.Feature
|
||||||
import me.rhunk.snapenhance.manager.impl.ActionManager
|
import me.rhunk.snapenhance.manager.impl.ActionManager
|
||||||
import me.rhunk.snapenhance.manager.impl.FeatureManager
|
import me.rhunk.snapenhance.manager.impl.FeatureManager
|
||||||
|
import me.rhunk.snapenhance.nativelib.NativeConfig
|
||||||
|
import me.rhunk.snapenhance.nativelib.NativeLib
|
||||||
import me.rhunk.snapenhance.util.download.HttpServer
|
import me.rhunk.snapenhance.util.download.HttpServer
|
||||||
import java.util.concurrent.ExecutorService
|
import java.util.concurrent.ExecutorService
|
||||||
import java.util.concurrent.Executors
|
import java.util.concurrent.Executors
|
||||||
@ -44,6 +46,7 @@ class ModContext {
|
|||||||
val config by modConfig
|
val config by modConfig
|
||||||
val event = EventBus(this)
|
val event = EventBus(this)
|
||||||
val eventDispatcher = EventDispatcher(this)
|
val eventDispatcher = EventDispatcher(this)
|
||||||
|
val native = NativeLib()
|
||||||
|
|
||||||
val translation = LocaleWrapper()
|
val translation = LocaleWrapper()
|
||||||
val features = FeatureManager(this)
|
val features = FeatureManager(this)
|
||||||
@ -121,6 +124,16 @@ class ModContext {
|
|||||||
|
|
||||||
fun reloadConfig() {
|
fun reloadConfig() {
|
||||||
modConfig.loadFromBridge(bridgeClient)
|
modConfig.loadFromBridge(bridgeClient)
|
||||||
|
runCatching {
|
||||||
|
native.loadConfig(
|
||||||
|
NativeConfig(
|
||||||
|
disableBitmoji = config.global.disableBitmoji.get(),
|
||||||
|
disableMetrics = config.global.disableMetrics.get()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}.onFailure {
|
||||||
|
Logger.xposedLog("Failed to load native config", it)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getConfigLocale(): String {
|
fun getConfigLocale(): String {
|
||||||
|
@ -97,6 +97,12 @@ class SnapEnhance {
|
|||||||
private suspend fun init() {
|
private suspend fun init() {
|
||||||
measureTime {
|
measureTime {
|
||||||
with(appContext) {
|
with(appContext) {
|
||||||
|
runCatching {
|
||||||
|
native.init()
|
||||||
|
}.onFailure {
|
||||||
|
Logger.xposedLog("Failed to init native", it)
|
||||||
|
return
|
||||||
|
}
|
||||||
reloadConfig()
|
reloadConfig()
|
||||||
withContext(appContext.coroutineDispatcher) {
|
withContext(appContext.coroutineDispatcher) {
|
||||||
translation.userLocale = getConfigLocale()
|
translation.userLocale = getConfigLocale()
|
||||||
|
@ -8,6 +8,7 @@ class Global : ConfigContainer() {
|
|||||||
val snapchatPlus = boolean("snapchat_plus") { addNotices(FeatureNotice.MAY_BAN) }
|
val snapchatPlus = boolean("snapchat_plus") { addNotices(FeatureNotice.MAY_BAN) }
|
||||||
val autoUpdater = unique("auto_updater", "EVERY_LAUNCH", "DAILY", "WEEKLY").apply { set("DAILY") }
|
val autoUpdater = unique("auto_updater", "EVERY_LAUNCH", "DAILY", "WEEKLY").apply { set("DAILY") }
|
||||||
val disableMetrics = boolean("disable_metrics")
|
val disableMetrics = boolean("disable_metrics")
|
||||||
|
val disableBitmoji = boolean("disable_bitmoji") { addNotices(FeatureNotice.UNSTABLE) }
|
||||||
val blockAds = boolean("block_ads")
|
val blockAds = boolean("block_ads")
|
||||||
val disableVideoLengthRestrictions = boolean("disable_video_length_restrictions") { addNotices(FeatureNotice.MAY_BAN) }
|
val disableVideoLengthRestrictions = boolean("disable_video_length_restrictions") { addNotices(FeatureNotice.MAY_BAN) }
|
||||||
val disableGooglePlayDialogs = boolean("disable_google_play_dialogs")
|
val disableGooglePlayDialogs = boolean("disable_google_play_dialogs")
|
||||||
|
@ -56,7 +56,7 @@ class EventBus(
|
|||||||
|
|
||||||
event.context = context
|
event.context = context
|
||||||
|
|
||||||
subscribers[event::class]?.forEach { listener ->
|
subscribers[event::class]?.toTypedArray()?.forEach { listener ->
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
runCatching {
|
runCatching {
|
||||||
(listener as IListener<T>).handle(event)
|
(listener as IListener<T>).handle(event)
|
||||||
|
1
native/.gitignore
vendored
Normal file
1
native/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/build
|
28
native/build.gradle.kts
Normal file
28
native/build.gradle.kts
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
@Suppress("DSL_SCOPE_VIOLATION") // TODO: Remove once KTIJ-19369 is fixed
|
||||||
|
plugins {
|
||||||
|
alias(libs.plugins.androidLibrary)
|
||||||
|
alias(libs.plugins.kotlinAndroid)
|
||||||
|
}
|
||||||
|
|
||||||
|
android {
|
||||||
|
namespace = "me.rhunk.snapenhance.nativelib"
|
||||||
|
compileSdk = 34
|
||||||
|
|
||||||
|
defaultConfig {
|
||||||
|
externalNativeBuild {
|
||||||
|
cmake {
|
||||||
|
cppFlags("")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
externalNativeBuild {
|
||||||
|
cmake {
|
||||||
|
path("jni/CMakeLists.txt")
|
||||||
|
version = "3.22.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
kotlinOptions {
|
||||||
|
jvmTarget = "1.8"
|
||||||
|
}
|
||||||
|
}
|
16
native/jni/CMakeLists.txt
Normal file
16
native/jni/CMakeLists.txt
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.22.1)
|
||||||
|
|
||||||
|
project("nativelib")
|
||||||
|
|
||||||
|
set(DOBBY_GENERATE_SHARED OFF)
|
||||||
|
add_subdirectory(external/dobby)
|
||||||
|
|
||||||
|
add_library(${CMAKE_PROJECT_NAME} SHARED
|
||||||
|
src/library.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(${CMAKE_PROJECT_NAME}
|
||||||
|
android
|
||||||
|
log
|
||||||
|
dobby_static
|
||||||
|
)
|
1
native/jni/external/dobby
vendored
Submodule
1
native/jni/external/dobby
vendored
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit b0176de574104726bb68dff3b77ee666300fc338
|
6
native/jni/src/config.h
Normal file
6
native/jni/src/config.h
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
bool disable_bitmoji;
|
||||||
|
bool disable_metrics;
|
||||||
|
} native_config_t;
|
76
native/jni/src/library.cpp
Normal file
76
native/jni/src/library.cpp
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
#include <jni.h>
|
||||||
|
#include <string>
|
||||||
|
#include <dobby.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fstream>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "logger.h"
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
static native_config_t *native_config;
|
||||||
|
|
||||||
|
static auto fstat_original = fstat;
|
||||||
|
static int fstat_hook(int fd, struct stat *buf) {
|
||||||
|
char name[256];
|
||||||
|
memset(name, 0, 256);
|
||||||
|
snprintf(name, sizeof(name), "/proc/self/fd/%d", fd);
|
||||||
|
readlink(name, name, sizeof(name));
|
||||||
|
|
||||||
|
auto fileName = std::string(name);
|
||||||
|
|
||||||
|
//prevent blizzardv2 metrics
|
||||||
|
if (native_config->disable_metrics && fileName.find("files/blizzardv2/queues") != std::string::npos) {
|
||||||
|
unlink(name);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//prevent bitmoji to load
|
||||||
|
if (native_config->disable_bitmoji && fileName.find("com.snap.file_manager_4_SCContent") != std::string::npos) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fstat_original(fd, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define GET_BOOL_FIELD(env, clazz, field) env->GetBooleanField(clazz, env->GetFieldID(clazz, field, "Z"))
|
||||||
|
|
||||||
|
extern "C" JNIEXPORT void JNICALL
|
||||||
|
loadConfig(JNIEnv *env, jobject clazz, jobject config_object) {
|
||||||
|
auto native_config_class = env->GetObjectClass(config_object);
|
||||||
|
|
||||||
|
native_config->disable_bitmoji = GET_BOOL_FIELD(env, native_config_class, "disableBitmoji");
|
||||||
|
native_config->disable_metrics = GET_BOOL_FIELD(env, native_config_class, "disableMetrics");
|
||||||
|
|
||||||
|
LOGD("config loaded");
|
||||||
|
}
|
||||||
|
|
||||||
|
//jni onload
|
||||||
|
extern "C" JNIEXPORT jint JNICALL
|
||||||
|
JNI_OnLoad(JavaVM *vm, void *reserved) {
|
||||||
|
LOGD("initializing native");
|
||||||
|
// config
|
||||||
|
native_config = new native_config_t;
|
||||||
|
|
||||||
|
// hooks
|
||||||
|
DobbyHook((void *) fstat_original,(void *) fstat_hook,(void **) &fstat_original);
|
||||||
|
|
||||||
|
// register native methods
|
||||||
|
JNIEnv *env = nullptr;
|
||||||
|
vm->GetEnv((void **) &env, JNI_VERSION_1_6);
|
||||||
|
|
||||||
|
auto methods = std::vector<JNINativeMethod>();
|
||||||
|
methods.push_back({"loadConfig", "(Lme/rhunk/snapenhance/nativelib/NativeConfig;)V", (void *) loadConfig});
|
||||||
|
|
||||||
|
env->RegisterNatives(
|
||||||
|
env->FindClass("me/rhunk/snapenhance/nativelib/NativeLib"),
|
||||||
|
methods.data(),
|
||||||
|
methods.size()
|
||||||
|
);
|
||||||
|
|
||||||
|
LOGD("native initialized");
|
||||||
|
|
||||||
|
return JNI_VERSION_1_6;
|
||||||
|
}
|
10
native/jni/src/logger.h
Normal file
10
native/jni/src/logger.h
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <android/log.h>
|
||||||
|
|
||||||
|
#define LOG_TAG "SnapEnhanceNative"
|
||||||
|
|
||||||
|
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
|
||||||
|
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
|
||||||
|
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)
|
||||||
|
|
@ -0,0 +1,6 @@
|
|||||||
|
package me.rhunk.snapenhance.nativelib
|
||||||
|
|
||||||
|
data class NativeConfig(
|
||||||
|
val disableBitmoji: Boolean = false,
|
||||||
|
val disableMetrics: Boolean = false
|
||||||
|
)
|
@ -0,0 +1,10 @@
|
|||||||
|
package me.rhunk.snapenhance.nativelib
|
||||||
|
|
||||||
|
class NativeLib {
|
||||||
|
fun init() {
|
||||||
|
System.loadLibrary("nativelib")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
external fun loadConfig(config: NativeConfig)
|
||||||
|
}
|
@ -19,4 +19,5 @@ dependencyResolutionManagement {
|
|||||||
rootProject.name = "SnapEnhance"
|
rootProject.name = "SnapEnhance"
|
||||||
include(":core")
|
include(":core")
|
||||||
include(":app")
|
include(":app")
|
||||||
include(":mapper")
|
include(":mapper")
|
||||||
|
include(":native")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user