Merge pull request #228 from ElderDrivers/resources-hook

Resources hook for ROMs with custom Resources subclass
This commit is contained in:
solohsu 2019-05-01 13:17:28 +08:00 committed by GitHub
commit 71449e2946
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
38 changed files with 283 additions and 184 deletions

View File

@ -1,8 +1,5 @@
package com.elderdrivers.riru.edxp.config;
import android.content.res.Resources;
import android.content.res.XResources;
import com.elderdrivers.riru.edxp.deopt.PrebuiltMethodsDeopter;
import com.elderdrivers.riru.edxp.hook.HookProvider;
@ -40,9 +37,4 @@ public abstract class BaseHookProvider implements HookProvider {
public boolean initXResourcesNative() {
return false;
}
@Override
public void rewriteXmlReferencesNative(long parserPtr, XResources origRes, Resources repRes) {
}
}

View File

@ -26,7 +26,22 @@ public class InlinedMethodCallers {
*/
private static final String[][] BOOT_IMAGE = {
// callers of Application#attach(Context)
{"android.app.Instrumentation", "newApplication", "(Ljava/lang/ClassLoader;Ljava/lang/String;Landroid/content/Context;)Landroid/app/Application;"}
{"android.app.Instrumentation", "newApplication", "(Ljava/lang/ClassLoader;Ljava/lang/String;Landroid/content/Context;)Landroid/app/Application;"},
// for MIUI resources hooking
{"android.content.res.MiuiResources", "init", "(Ljava/lang/String;)V"},
{"android.content.res.MiuiResources", "updateMiuiImpl", "()V"},
{"android.content.res.MiuiResources", "setImpl", "(Landroid/content/res/ResourcesImpl;)V"},
{"android.content.res.MiuiResources", "loadOverlayValue", "(Landroid/util/TypedValue;I)V"},
{"android.content.res.MiuiResources", "getThemeString", "(I)Ljava/lang/CharSequence;"},
{"android.content.res.MiuiResources", "<init>", "(Ljava/lang/ClassLoader;)V"},
{"android.content.res.MiuiResources", "<init>", "()V"},
{"android.content.res.MiuiResources", "<init>", "(Landroid/content/res/AssetManager;Landroid/util/DisplayMetrics;Landroid/content/res/Configuration;)V"},
{"android.miui.ResourcesManager", "initMiuiResource", "(Landroid/content/res/Resources;Ljava/lang/String;)V"},
{"android.app.LoadedApk", "getResources", "()Landroid/content/res/Resources;"},
{"android.content.res.Resources", "getSystem", "()Landroid/content/res/Resources;"},
{"android.app.ApplicationPackageManager", "getResourcesForApplication", "(Landroid/content/pm/ApplicationInfo;)Landroid/content/res/Resources;"},
{"android.app.ContextImpl", "setResources", "(Landroid/content/res/Resources;)V"},
};
private static final String[][] SYSTEM_SERVER = {};

View File

@ -19,8 +19,12 @@ public class PrebuiltMethodsDeopter {
}
for (String[] caller : callers) {
try {
Class clazz = XposedHelpers.findClassIfExists(caller[0], cl);
if (clazz == null) {
continue;
}
Object method = EdXpConfigGlobal.getHookProvider().findMethodNative(
XposedHelpers.findClass(caller[0], cl), caller[1], caller[2]);
clazz, caller[1], caller[2]);
if (method != null) {
EdXpConfigGlobal.getHookProvider().deoptMethodNative(method);
}

View File

@ -3,6 +3,8 @@
/libs
/obj
/release
/template_override/module.prop
/template_override/riru_module.prop
/template_override/system
/template_override/system_x86
*.iml

View File

@ -2,13 +2,17 @@ import org.gradle.internal.os.OperatingSystem
apply plugin: 'com.android.library'
version "v0.4.0.1_beta-SNAPSHOT"
version "v0.4.1.2_beta"
ext {
versionCode = "4120"
module_name = "EdXposed"
jar_dest_dir = "${projectDir}/template_override/system/framework/"
is_windows = OperatingSystem.current().isWindows()
backends = ["Yahfa", "Sandhook", "Whale"]
backends = ["YAHFA", "SandHook", "Whale"]
yahfa_authors = "solohsu, rk700 & MlgmXyysd"
sandhook_authors = "solohsu, ganyao114 & MlgmXyysd"
whale_authors = "solohsu, asLody & MlgmXyysd"
}
android {
@ -72,21 +76,34 @@ afterEvaluate {
backends.each { backend ->
def backendCapped = backend.capitalize()
def backendLowered = backend.toLowerCase()
def backendCapped = backendLowered.capitalize()
def authorList = property("${backendLowered}" + "_authors")
def zipTask = task("zip${backendCapped}${variantCapped}", type: Exec) {
dependsOn cleanTemplate, copyDalvikdxJar, copyDexmakerJar
dependsOn tasks.getByPath(":edxp-${backendLowered}:makeAndCopy${variantCapped}")
workingDir '..'
commandLine 'sh', 'build.sh', project.name,
"${backendLowered}-${project.version}-${variantLowered}", "${module_name}"
"${backend}-${project.version}-${variantLowered}", "${module_name}"
doFirst {
copy {
from "${projectDir}/edconfig.tpl"
from "${projectDir}/tpl/edconfig.tpl"
into templateFrameworkPath
rename "edconfig.tpl", "edconfig.jar"
expand(backend: "$backendCapped")
expand(version: "$version", backend: "$backend")
}
copy {
from "${projectDir}/tpl/module.prop.tpl"
into templateRootPath
rename "module.prop.tpl", "module.prop"
expand(backend: "$backendCapped", versionName: "$version" + "($backend)",
versionCode: "$versionCode", authorList: "$authorList")
}
copy {
from "${templateRootPath}/module.prop"
into templateRootPath
rename "module.prop", "riru_module.prop"
}
}
}
@ -95,7 +112,7 @@ afterEvaluate {
dependsOn zipTask
workingDir "${projectDir}/release"
def commands = ["adb", "push",
"magisk-${module_name}-${backendLowered}-${project.version}-${variantLowered}.zip",
"magisk-${module_name}-${backend}-${project.version}-${variantLowered}.zip",
"/sdcard/"]
if (is_windows) {
commandLine 'cmd', '/c', commands.join(" ")

View File

@ -1,5 +0,0 @@
version=90.0-0.4.0.1-beta-SNAPSHOT ($backend)
arch=arm64
minsdk=23
maxsdk=28
requires:fbe_aware=1

View File

@ -73,6 +73,19 @@ void setMethodNonCompilable(JNIEnv *env, jclass, jobject member) {
setNonCompilable(artMethod);
}
static constexpr uint32_t kAccFinal = 0x0010;
jboolean removeFinalFlag(JNIEnv *env, jclass, jclass clazz) {
if (clazz) {
jfieldID java_lang_Class_accessFlags = env->GetFieldID(
env->FindClass("java/lang/Class"), "accessFlags", "I");
jint access_flags = env->GetIntField(clazz, java_lang_Class_accessFlags);
env->SetIntField(clazz, java_lang_Class_accessFlags, access_flags & ~kAccFinal);
return true;
}
return false;
}
static JNINativeMethod hookMethods[] = {
{
"init",
@ -131,7 +144,7 @@ static JNINativeMethod hookMethods[] = {
"initXResourcesNative", "()Z", (void *) XposedBridge_initXResourcesNative
},
{
"rewriteXmlReferencesNative", "(JLandroid/content/res/XResources;Landroid/content/res/Resources;)V", (void *) XResources_rewriteXmlReferencesNative
"removeFinalFlagNative", "(Ljava/lang/Class;)Z", (void *) removeFinalFlag
}
};

View File

@ -59,6 +59,13 @@ static bool onIsInSamePackageCalled(void *thiz, void *that) {
|| strstr(thatDesc, "com/elderdrivers/riru/") != nullptr) {
return true;
}
// for MIUI resources hooking
if (strstr(thisDesc, "android/content/res/MiuiTypedArray") != nullptr
|| strstr(thatDesc, "android/content/res/MiuiTypedArray") != nullptr
|| strstr(thisDesc, "android/content/res/XResources$XTypedArray") != nullptr
|| strstr(thatDesc, "android/content/res/XResources$XTypedArray") != nullptr) {
return true;
}
return (*isInSamePackageBackup)(thiz, that);
}

View File

@ -6,6 +6,7 @@
#include <include/ByteOrder.h>
#include <include/logging.h>
#include <dlfcn.h>
#include <java_hook/java_hook.h>
#include "resource_hook.h"
#define CLASS_XRESOURCES "android/content/res/XResources"
@ -44,7 +45,7 @@ bool prepareSymbols() {
#if defined(__LP64__)
"_ZNK7android12ResXMLParser18getAttributeNameIDEm"
#else
"_ZNK7android12ResXMLParser18getAttributeNameIDEj"
"_ZNK7android12ResXMLParser18getAttributeNameIDEj"
#endif
));
if (!ResXMLParser_getAttributeNameID) {
@ -66,6 +67,15 @@ bool prepareSymbols() {
return true;
}
int register_natives_XResources(JNIEnv *env, jclass clazz) {
const JNINativeMethod methods[] = {
{"rewriteXmlReferencesNative",
"(JLandroid/content/res/XResources;Landroid/content/res/Resources;)V",
(void *) XResources_rewriteXmlReferencesNative},
};
return env->RegisterNatives(clazz, methods, NELEM(methods));
}
jboolean XposedBridge_initXResourcesNative(JNIEnv *env, jclass) {
classXResources = env->FindClass(CLASS_XRESOURCES);
if (classXResources == NULL) {
@ -75,6 +85,12 @@ jboolean XposedBridge_initXResourcesNative(JNIEnv *env, jclass) {
}
classXResources = reinterpret_cast<jclass>(env->NewGlobalRef(classXResources));
if (register_natives_XResources(env, classXResources) != JNI_OK) {
LOGE("Could not register natives for '%s'", CLASS_XRESOURCES);
env->ExceptionClear();
return false;
}
methodXResourcesTranslateResId = env->GetStaticMethodID(classXResources, "translateResId",
"(ILandroid/content/res/XResources;Landroid/content/res/Resources;)I");
if (methodXResourcesTranslateResId == NULL) {

View File

@ -1,6 +1,6 @@
#!/system/bin/sh
EDXP_VERSION="0.4.0.1_beta-SNAPSHOT (4010)"
EDXP_VERSION="0.4.1.2_beta (4120)"
ANDROID_SDK=`getprop ro.build.version.sdk`
BUILD_DESC=`getprop ro.build.description`
PRODUCT=`getprop ro.build.product`

View File

@ -41,7 +41,7 @@ LATESTARTSERVICE=false
print_modname() {
ui_print "************************************"
ui_print " Riru - Ed Xposed v0.4.0.1 "
ui_print " Riru - Ed Xposed "
ui_print "************************************"
}

View File

@ -1,5 +0,0 @@
name=Ed Xposed
version=v0.4.0.1_beta-SNAPSHOT
versionCode=4010
author=solohsu & MlgmXyysd
description=Magisk version of Xposed. Require Riru - Core installed.

View File

@ -0,0 +1,5 @@
version=90.0-$version ($backend)
arch=arm64
minsdk=26
maxsdk=28
requires:fbe_aware=1

View File

@ -1,7 +1,7 @@
id=riru_edxposed
name=Riru - Ed Xposed
version=v0.4.0.1_beta-SNAPSHOT
versionCode=4010
author=solohsu & MlgmXyysd
version=${versionName}
versionCode=${versionCode}
author=${authorList}
description=Magisk version of Xposed. Require Riru - Core installed.
minMagisk=17000

View File

@ -1,19 +1,17 @@
package com.elderdrivers.riru.edxp;
import android.annotation.SuppressLint;
import android.content.res.Resources;
import android.content.res.XResources;
import android.os.Build;
import android.os.Process;
import com.elderdrivers.riru.common.KeepAll;
import com.elderdrivers.riru.edxp.sandhook.BuildConfig;
import com.elderdrivers.riru.edxp.config.InstallerChooser;
import com.elderdrivers.riru.edxp.util.Utils;
import com.elderdrivers.riru.edxp.sandhook.BuildConfig;
import com.elderdrivers.riru.edxp.sandhook.core.HookMethodResolver;
import com.elderdrivers.riru.edxp.sandhook.entry.Router;
import com.elderdrivers.riru.edxp.sandhook.proxy.BlackWhiteListProxy;
import com.elderdrivers.riru.edxp.sandhook.proxy.NormalProxy;
import com.elderdrivers.riru.edxp.util.Utils;
import com.swift.sandhook.xposedcompat.XposedCompat;
import com.swift.sandhook.xposedcompat.methodgen.SandHookXposedBridge;
@ -152,5 +150,5 @@ public class Main implements KeepAll {
public static native boolean initXResourcesNative();
public static native void rewriteXmlReferencesNative(long parserPtr, XResources origRes, Resources repRes);
public static native boolean removeFinalFlagNative(Class clazz);
}

View File

@ -1,7 +1,5 @@
package com.elderdrivers.riru.edxp.sandhook.config;
import android.content.res.Resources;
import android.content.res.XResources;
import android.util.Log;
import com.elderdrivers.riru.edxp.Main;
@ -67,7 +65,7 @@ public class SandHookProvider extends BaseHookProvider {
}
@Override
public void rewriteXmlReferencesNative(long parserPtr, XResources origRes, Resources repRes) {
Main.rewriteXmlReferencesNative(parserPtr, origRes, repRes);
public boolean removeFinalFlagNative(Class clazz) {
return Main.removeFinalFlagNative(clazz);
}
}

View File

@ -14,7 +14,6 @@ import com.elderdrivers.riru.edxp.sandhook.entry.bootstrap.SysInnerHookInfo;
import com.elderdrivers.riru.edxp.sandhook.entry.bootstrap.WorkAroundHookInfo;
import com.elderdrivers.riru.edxp.sandhook.entry.hooker.SystemMainHooker;
import com.elderdrivers.riru.edxp.util.Utils;
import com.swift.sandhook.SandHookConfig;
import com.swift.sandhook.xposedcompat.XposedCompat;
import java.util.concurrent.atomic.AtomicBoolean;
@ -32,10 +31,14 @@ public class Router {
static boolean useSandHook = false;
public static void initResourcesHook() {
startWorkAroundHook(); // for OnePlus devices
XposedBridge.initXResources();
}
public static void prepare(boolean isSystem) {
// this flag is needed when loadModules
startsSystemServer = isSystem;
// InstallerChooser.setup();
}
public static void checkHookState(String appDataDir) {
@ -124,8 +127,15 @@ public class Router {
}
}
public static void onEnterChildProcess() {
public static void onForkStart() {
forkCompleted = false;
}
public static void onForkFinish() {
forkCompleted = true;
}
public static void onEnterChildProcess() {
DynamicBridge.onForkPost();
//enable compile in child process
//SandHook.enableCompiler(!XposedInit.startsSystemServer);
@ -144,5 +154,6 @@ public class Router {
public static void injectConfig() {
EdXpConfigGlobal.sConfig = new SandHookEdxpConfig();
EdXpConfigGlobal.sHookProvider = new SandHookProvider();
XposedBridge.log("using HookProvider: " + EdXpConfigGlobal.sHookProvider.getClass().getName());
}
}

View File

@ -2,17 +2,17 @@ package com.elderdrivers.riru.edxp.sandhook.proxy;
import android.text.TextUtils;
import com.elderdrivers.riru.edxp.Main;
import com.elderdrivers.riru.edxp.config.ConfigManager;
import com.elderdrivers.riru.edxp.deopt.PrebuiltMethodsDeopter;
import com.elderdrivers.riru.edxp.sandhook.entry.Router;
import com.elderdrivers.riru.edxp.util.ProcessUtils;
import com.elderdrivers.riru.edxp.util.Utils;
import com.elderdrivers.riru.edxp.Main;
import com.elderdrivers.riru.edxp.sandhook.entry.Router;
import de.robv.android.xposed.XposedBridge;
import static com.elderdrivers.riru.edxp.util.FileUtils.getDataPathPrefix;
import static com.elderdrivers.riru.edxp.Main.isAppNeedHook;
import static com.elderdrivers.riru.edxp.util.FileUtils.getDataPathPrefix;
/**
* 1. Non dynamic mode
@ -73,6 +73,8 @@ public class BlackWhiteListProxy {
* Some details are different between main zygote and secondary zygote.
*/
private static void onForkPreForNonDynamicMode(boolean isSystemServer) {
Router.onForkStart();
Router.initResourcesHook();
ConfigManager.setDynamicModulesMode(false);
// set startsSystemServer flag used when loadModules
Router.prepare(isSystemServer);
@ -92,20 +94,25 @@ public class BlackWhiteListProxy {
Main.niceName = niceName;
final boolean isDynamicModulesMode = Main.isDynamicModulesEnabled();
ConfigManager.setDynamicModulesMode(isDynamicModulesMode);
Router.onEnterChildProcess();
if (!isDynamicModulesMode) {
Main.reopenFilesAfterForkNative();
}
Router.onEnterChildProcess();
if (!checkNeedHook(appDataDir, niceName)) {
// if is blacklisted, just stop here
Router.onForkFinish();
return;
}
if (isDynamicModulesMode) {
Router.initResourcesHook();
}
Router.prepare(isSystemServer);
PrebuiltMethodsDeopter.deoptBootMethods();
Router.installBootstrapHooks(isSystemServer);
if (isDynamicModulesMode) {
Router.loadModulesSafely(false);
}
Router.onForkFinish();
}
private static boolean checkNeedHook(String appDataDir, String niceName) {

View File

@ -1,7 +1,7 @@
package com.elderdrivers.riru.edxp.sandhook.proxy;
import com.elderdrivers.riru.edxp.config.ConfigManager;
import com.elderdrivers.riru.edxp.Main;
import com.elderdrivers.riru.edxp.config.ConfigManager;
import com.elderdrivers.riru.edxp.deopt.PrebuiltMethodsDeopter;
import com.elderdrivers.riru.edxp.sandhook.entry.Router;
@ -15,6 +15,8 @@ public class NormalProxy {
boolean startChildZygote, String instructionSet,
String appDataDir) {
// mainly for secondary zygote
Router.onForkStart();
Router.initResourcesHook();
final boolean isDynamicModulesMode = Main.isDynamicModulesEnabled();
ConfigManager.setDynamicModulesMode(isDynamicModulesMode);
// call this to ensure the flag is set to false ASAP
@ -36,10 +38,13 @@ public class NormalProxy {
Router.onEnterChildProcess();
// load modules for each app process on its forked if dynamic modules mode is on
Router.loadModulesSafely(false);
Router.onForkFinish();
}
public static void forkSystemServerPre(int uid, int gid, int[] gids, int debugFlags, int[][] rlimits,
long permittedCapabilities, long effectiveCapabilities) {
Router.onForkStart();
Router.initResourcesHook();
final boolean isDynamicModulesMode = Main.isDynamicModulesEnabled();
ConfigManager.setDynamicModulesMode(isDynamicModulesMode);
// set startsSystemServer flag used when loadModules
@ -65,6 +70,7 @@ public class NormalProxy {
Router.onEnterChildProcess();
// reload module list if dynamic mode is on
Router.loadModulesSafely(false);
Router.onForkFinish();
}
}

View File

@ -1,18 +1,16 @@
package com.elderdrivers.riru.edxp;
import android.annotation.SuppressLint;
import android.content.res.Resources;
import android.content.res.XResources;
import android.os.Build;
import android.os.Process;
import com.elderdrivers.riru.common.KeepAll;
import com.elderdrivers.riru.edxp.config.InstallerChooser;
import com.elderdrivers.riru.edxp.util.Utils;
import com.elderdrivers.riru.edxp.whale.core.HookMethodResolver;
import com.elderdrivers.riru.edxp.whale.entry.Router;
import com.elderdrivers.riru.edxp.whale.proxy.BlackWhiteListProxy;
import com.elderdrivers.riru.edxp.whale.proxy.NormalProxy;
import com.elderdrivers.riru.edxp.util.Utils;
import java.lang.reflect.Method;
import java.util.Arrays;
@ -143,5 +141,5 @@ public class Main implements KeepAll {
public static native boolean initXResourcesNative();
public static native void rewriteXmlReferencesNative(long parserPtr, XResources origRes, Resources repRes);
public static native boolean removeFinalFlagNative(Class clazz);
}

View File

@ -1,8 +1,5 @@
package com.elderdrivers.riru.edxp.whale.config;
import android.content.res.Resources;
import android.content.res.XResources;
import com.elderdrivers.riru.edxp.Main;
import com.elderdrivers.riru.edxp.config.BaseHookProvider;
import com.lody.whale.WhaleRuntime;
@ -64,7 +61,7 @@ public class WhaleHookProvider extends BaseHookProvider {
}
@Override
public void rewriteXmlReferencesNative(long parserPtr, XResources origRes, Resources repRes) {
Main.rewriteXmlReferencesNative(parserPtr, origRes, repRes);
public boolean removeFinalFlagNative(Class clazz) {
return Main.removeFinalFlagNative(clazz);
}
}

View File

@ -5,8 +5,8 @@ import android.text.TextUtils;
import com.elderdrivers.riru.edxp.config.EdXpConfigGlobal;
import com.elderdrivers.riru.edxp.util.Utils;
import com.elderdrivers.riru.edxp.whale.config.WhaleHookProvider;
import com.elderdrivers.riru.edxp.whale.config.WhaleEdxpConfig;
import com.elderdrivers.riru.edxp.whale.config.WhaleHookProvider;
import com.elderdrivers.riru.edxp.whale.core.HookMain;
import com.elderdrivers.riru.edxp.whale.entry.bootstrap.AppBootstrapHookInfo;
import com.elderdrivers.riru.edxp.whale.entry.bootstrap.SysBootstrapHookInfo;
@ -25,11 +25,14 @@ public class Router {
private static volatile AtomicBoolean bootstrapHooked = new AtomicBoolean(false);
public static void initResourcesHook() {
startWorkAroundHook(); // for OnePlus devices
XposedBridge.initXResources();
}
public static void prepare(boolean isSystem) {
// this flag is needed when loadModules
XposedInit.startsSystemServer = isSystem;
// InstallerChooser.setup();
}
public static void checkHookState(String appDataDir) {
@ -101,10 +104,18 @@ public class Router {
WorkAroundHookInfo.class.getName());
}
public static void onEnterChildProcess() {
public static void onForkStart() {
forkCompleted = false;
}
public static void onForkFinish() {
forkCompleted = true;
}
public static void onEnterChildProcess() {
}
public static void logD(String prefix) {
Utils.logD(String.format("%s: pkg=%s, prc=%s", prefix, AndroidAppHelper.currentPackageName(),
AndroidAppHelper.currentProcessName()));
@ -118,5 +129,6 @@ public class Router {
public static void injectConfig() {
EdXpConfigGlobal.sConfig = new WhaleEdxpConfig();
EdXpConfigGlobal.sHookProvider = new WhaleHookProvider();
XposedBridge.log("using HookProvider: " + EdXpConfigGlobal.sHookProvider.getClass().getName());
}
}

View File

@ -73,6 +73,8 @@ public class BlackWhiteListProxy {
* Some details are different between main zygote and secondary zygote.
*/
private static void onForkPreForNonDynamicMode(boolean isSystemServer) {
Router.onForkStart();
Router.initResourcesHook();
ConfigManager.setDynamicModulesMode(false);
// set startsSystemServer flag used when loadModules
Router.prepare(isSystemServer);
@ -92,20 +94,25 @@ public class BlackWhiteListProxy {
Main.niceName = niceName;
final boolean isDynamicModulesMode = Main.isDynamicModulesEnabled();
ConfigManager.setDynamicModulesMode(isDynamicModulesMode);
Router.onEnterChildProcess();
if (!isDynamicModulesMode) {
Main.reopenFilesAfterForkNative();
}
Router.onEnterChildProcess();
if (!checkNeedHook(appDataDir, niceName)) {
// if is blacklisted, just stop here
Router.onForkFinish();
return;
}
if (isDynamicModulesMode) {
Router.initResourcesHook();
}
Router.prepare(isSystemServer);
PrebuiltMethodsDeopter.deoptBootMethods();
Router.installBootstrapHooks(isSystemServer);
if (isDynamicModulesMode) {
Router.loadModulesSafely(false);
}
Router.onForkFinish();
}
private static boolean checkNeedHook(String appDataDir, String niceName) {

View File

@ -15,6 +15,8 @@ public class NormalProxy {
boolean startChildZygote, String instructionSet,
String appDataDir) {
// mainly for secondary zygote
Router.onForkStart();
Router.initResourcesHook();
final boolean isDynamicModulesMode = Main.isDynamicModulesEnabled();
ConfigManager.setDynamicModulesMode(isDynamicModulesMode);
// call this to ensure the flag is set to false ASAP
@ -36,10 +38,13 @@ public class NormalProxy {
Router.onEnterChildProcess();
// load modules for each app process on its forked if dynamic modules mode is on
Router.loadModulesSafely(false);
Router.onForkFinish();
}
public static void forkSystemServerPre(int uid, int gid, int[] gids, int debugFlags, int[][] rlimits,
long permittedCapabilities, long effectiveCapabilities) {
Router.onForkStart();
Router.initResourcesHook();
final boolean isDynamicModulesMode = Main.isDynamicModulesEnabled();
ConfigManager.setDynamicModulesMode(isDynamicModulesMode);
// set startsSystemServer flag used when loadModules
@ -65,6 +70,7 @@ public class NormalProxy {
Router.onEnterChildProcess();
// reload module list if dynamic mode is on
Router.loadModulesSafely(false);
Router.onForkFinish();
}
}

View File

@ -143,5 +143,5 @@ public class Main implements KeepAll {
public static native boolean initXResourcesNative();
public static native void rewriteXmlReferencesNative(long parserPtr, XResources origRes, Resources repRes);
public static native boolean removeFinalFlagNative(Class clazz);
}

View File

@ -1,8 +1,5 @@
package com.elderdrivers.riru.edxp.yahfa.config;
import android.content.res.Resources;
import android.content.res.XResources;
import com.elderdrivers.riru.edxp.Main;
import com.elderdrivers.riru.edxp.config.BaseHookProvider;
import com.elderdrivers.riru.edxp.yahfa.dexmaker.DexMakerUtils;
@ -45,7 +42,7 @@ public class YahfaHookProvider extends BaseHookProvider {
}
@Override
public void rewriteXmlReferencesNative(long parserPtr, XResources origRes, Resources repRes) {
Main.rewriteXmlReferencesNative(parserPtr, origRes, repRes);
public boolean removeFinalFlagNative(Class clazz) {
return Main.removeFinalFlagNative(clazz);
}
}

View File

@ -3,7 +3,6 @@ package com.elderdrivers.riru.edxp.yahfa.entry;
import android.app.AndroidAppHelper;
import android.text.TextUtils;
import com.elderdrivers.riru.edxp.Main;
import com.elderdrivers.riru.edxp.config.EdXpConfigGlobal;
import com.elderdrivers.riru.edxp.util.Utils;
import com.elderdrivers.riru.edxp.yahfa.config.YahfaEdxpConfig;
@ -27,11 +26,14 @@ public class Router {
private static volatile AtomicBoolean bootstrapHooked = new AtomicBoolean(false);
public static void initResourcesHook() {
startWorkAroundHook(); // for OnePlus devices
XposedBridge.initXResources();
}
public static void prepare(boolean isSystem) {
// this flag is needed when loadModules
XposedInit.startsSystemServer = isSystem;
// InstallerChooser.setup();
}
public static void checkHookState(String appDataDir) {
@ -103,8 +105,15 @@ public class Router {
WorkAroundHookInfo.class.getName());
}
public static void onEnterChildProcess() {
public static void onForkStart() {
forkCompleted = false;
}
public static void onForkFinish() {
forkCompleted = true;
}
public static void onEnterChildProcess() {
DynamicBridge.onForkPost();
}
@ -121,5 +130,6 @@ public class Router {
public static void injectConfig() {
EdXpConfigGlobal.sConfig = new YahfaEdxpConfig();
EdXpConfigGlobal.sHookProvider = new YahfaHookProvider();
XposedBridge.log("using HookProvider: " + EdXpConfigGlobal.sHookProvider.getClass().getName());
}
}

View File

@ -5,9 +5,9 @@ import android.text.TextUtils;
import com.elderdrivers.riru.edxp.Main;
import com.elderdrivers.riru.edxp.config.ConfigManager;
import com.elderdrivers.riru.edxp.deopt.PrebuiltMethodsDeopter;
import com.elderdrivers.riru.edxp.yahfa.entry.Router;
import com.elderdrivers.riru.edxp.util.ProcessUtils;
import com.elderdrivers.riru.edxp.util.Utils;
import com.elderdrivers.riru.edxp.yahfa.entry.Router;
import de.robv.android.xposed.XposedBridge;
@ -73,6 +73,8 @@ public class BlackWhiteListProxy {
* Some details are different between main zygote and secondary zygote.
*/
private static void onForkPreForNonDynamicMode(boolean isSystemServer) {
Router.onForkStart();
Router.initResourcesHook();
ConfigManager.setDynamicModulesMode(false);
// set startsSystemServer flag used when loadModules
Router.prepare(isSystemServer);
@ -92,20 +94,25 @@ public class BlackWhiteListProxy {
Main.niceName = niceName;
final boolean isDynamicModulesMode = Main.isDynamicModulesEnabled();
ConfigManager.setDynamicModulesMode(isDynamicModulesMode);
Router.onEnterChildProcess();
if (!isDynamicModulesMode) {
Main.reopenFilesAfterForkNative();
}
Router.onEnterChildProcess();
if (!checkNeedHook(appDataDir, niceName)) {
// if is blacklisted, just stop here
Router.onForkFinish();
return;
}
if (isDynamicModulesMode) {
Router.initResourcesHook();
}
Router.prepare(isSystemServer);
PrebuiltMethodsDeopter.deoptBootMethods();
Router.installBootstrapHooks(isSystemServer);
if (isDynamicModulesMode) {
Router.loadModulesSafely(false);
}
Router.onForkFinish();
}
private static boolean checkNeedHook(String appDataDir, String niceName) {

View File

@ -15,6 +15,8 @@ public class NormalProxy {
boolean startChildZygote, String instructionSet,
String appDataDir) {
// mainly for secondary zygote
Router.onForkStart();
Router.initResourcesHook();
final boolean isDynamicModulesMode = Main.isDynamicModulesEnabled();
ConfigManager.setDynamicModulesMode(isDynamicModulesMode);
// call this to ensure the flag is set to false ASAP
@ -36,10 +38,13 @@ public class NormalProxy {
Router.onEnterChildProcess();
// load modules for each app process on its forked if dynamic modules mode is on
Router.loadModulesSafely(false);
Router.onForkFinish();
}
public static void forkSystemServerPre(int uid, int gid, int[] gids, int debugFlags, int[][] rlimits,
long permittedCapabilities, long effectiveCapabilities) {
Router.onForkStart();
Router.initResourcesHook();
final boolean isDynamicModulesMode = Main.isDynamicModulesEnabled();
ConfigManager.setDynamicModulesMode(isDynamicModulesMode);
// set startsSystemServer flag used when loadModules
@ -65,6 +70,7 @@ public class NormalProxy {
Router.onEnterChildProcess();
// reload module list if dynamic mode is on
Router.loadModulesSafely(false);
Router.onForkFinish();
}
}

View File

@ -16,4 +16,9 @@ public class XResourcesSuperClass extends Resources {
super(null, null, null);
throw new UnsupportedOperationException();
}
protected XResourcesSuperClass(ClassLoader classLoader) {
super(classLoader);
throw new UnsupportedOperationException();
}
}

View File

@ -13,8 +13,8 @@ import android.content.res.TypedArray;
*/
public class XTypedArraySuperClass extends TypedArray {
/** Dummy, will never be called (objects are transferred to this class only). */
protected XTypedArraySuperClass(Resources resources, int[] data, int[] indices, int len) {
super(null, null, null, 0);
protected XTypedArraySuperClass(Resources resources) {
super(resources);
throw new UnsupportedOperationException();
}
}

View File

@ -5,7 +5,7 @@ android {
buildToolsVersion '28.0.3'
defaultConfig {
minSdkVersion 23
minSdkVersion 26
}
sourceSets {

View File

@ -11,15 +11,12 @@ import android.os.Build;
import android.text.Html;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.SparseArray;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.elderdrivers.riru.edxp.config.EdXpConfigGlobal;
import org.xmlpull.v1.XmlPullParser;
import java.io.File;
@ -36,6 +33,8 @@ import de.robv.android.xposed.XposedBridge.CopyOnWriteSortedSet;
import de.robv.android.xposed.callbacks.XC_LayoutInflated;
import de.robv.android.xposed.callbacks.XC_LayoutInflated.LayoutInflatedParam;
import de.robv.android.xposed.callbacks.XCallback;
import xposed.dummy.XResourcesSuperClass;
import xposed.dummy.XTypedArraySuperClass;
import static de.robv.android.xposed.XposedHelpers.decrementMethodDepth;
import static de.robv.android.xposed.XposedHelpers.findAndHookMethod;
@ -52,7 +51,7 @@ import static de.robv.android.xposed.XposedHelpers.incrementMethodDepth;
* be set using the methods made available via the API methods in this class.
*/
@SuppressWarnings("JniMissingFunction")
public class XResources extends Resources {
public class XResources extends XResourcesSuperClass {
private static final SparseArray<HashMap<String, Object>> sReplacements = new SparseArray<>();
private static final SparseArray<HashMap<String, ResourceNames>> sResourceNames = new SparseArray<>();
@ -80,10 +79,6 @@ public class XResources extends Resources {
private String mResDir;
private String mPackageName;
public XResources(AssetManager assets, DisplayMetrics metrics, Configuration config) {
super(assets, metrics, config);
}
public XResources(ClassLoader classLoader) {
super(classLoader);
}
@ -1136,9 +1131,7 @@ public class XResources extends Resources {
return false;
}
private static void rewriteXmlReferencesNative(long parserPtr, XResources origRes, Resources repRes) {
EdXpConfigGlobal.getHookProvider().rewriteXmlReferencesNative(parserPtr, origRes, repRes);
}
private static native void rewriteXmlReferencesNative(long parserPtr, XResources origRes, Resources repRes);
/**
* Used to replace reference IDs in XMLs.
@ -1263,7 +1256,7 @@ public class XResources extends Resources {
* Mainly used when inflating layouts.
* @hide
*/
public static class XTypedArray extends TypedArray {
public static class XTypedArray extends XTypedArraySuperClass {
public XTypedArray(Resources resources) {
super(resources);

View File

@ -1,15 +1,7 @@
package com.elderdrivers.riru.edxp.config;
import android.content.res.Resources;
import android.content.res.XResources;
import com.elderdrivers.riru.edxp.hook.HookProvider;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Member;
import de.robv.android.xposed.XposedBridge;
public class EdXpConfigGlobal {
public static volatile EdXpConfig sConfig;
@ -24,7 +16,7 @@ public class EdXpConfigGlobal {
public static HookProvider getHookProvider() {
if (sHookProvider == null) {
return defaultHookProvider;
throw new IllegalArgumentException("sHookProvider should not be null.");
}
return sHookProvider;
}
@ -47,59 +39,4 @@ public class EdXpConfigGlobal {
return false;
}
};
private static final HookProvider defaultHookProvider = new HookProvider() {
@Override
public void hookMethod(Member method, XposedBridge.AdditionalHookInfo additionalInfo) {
}
@Override
public void unhookMethod(Member method) {
}
@Override
public Object invokeOriginalMethod(Member method, long methodId, Object thisObject, Object[] args)
throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
return null;
}
@Override
public Member findMethodNative(Member hookMethod) {
return hookMethod;
}
@Override
public void deoptMethods(String packageName, ClassLoader classLoader) {
}
@Override
public long getMethodId(Member member) {
return 0;
}
@Override
public Object findMethodNative(Class clazz, String methodName, String methodSig) {
return null;
}
@Override
public void deoptMethodNative(Object method) {
}
@Override
public boolean initXResourcesNative() {
return false;
}
@Override
public void rewriteXmlReferencesNative(long parserPtr, XResources origRes, Resources repRes) {
}
};
}

View File

@ -1,8 +1,5 @@
package com.elderdrivers.riru.edxp.hook;
import android.content.res.Resources;
import android.content.res.XResources;
import java.lang.reflect.Member;
import de.robv.android.xposed.XposedBridge;
@ -27,5 +24,5 @@ public interface HookProvider {
boolean initXResourcesNative();
void rewriteXmlReferencesNative(long parserPtr, XResources origRes, Resources repRes);
boolean removeFinalFlagNative(Class clazz);
}

View File

@ -1,29 +1,33 @@
package de.robv.android.xposed;
import android.annotation.SuppressLint;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.util.Log;
import com.elderdrivers.riru.edxp.config.EdXpConfigGlobal;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import dalvik.system.InMemoryDexClassLoader;
import de.robv.android.xposed.XC_MethodHook.MethodHookParam;
import de.robv.android.xposed.callbacks.XC_InitPackageResources;
import de.robv.android.xposed.callbacks.XC_LoadPackage;
import external.com.android.dx.DexMaker;
import external.com.android.dx.TypeId;
import static de.robv.android.xposed.XposedHelpers.getIntField;
import static de.robv.android.xposed.XposedHelpers.setObjectField;
/**
* This class contains most of Xposed's central logic, such as initialization and callbacks used by
@ -83,16 +87,52 @@ public final class XposedBridge {
// }
// }
private static void initXResources() throws IOException {
// ed: no support for now
}
public static volatile ClassLoader dummyClassLoader = null;
@SuppressLint("SetWorldReadable")
private static File ensureSuperDexFile(String clz, Class<?> realSuperClz, Class<?> topClz) throws IOException {
XposedBridge.removeFinalFlagNative(realSuperClz);
File dexFile = DexCreator.ensure(clz, realSuperClz, topClz);
dexFile.setReadable(true, false);
return dexFile;
public static void initXResources() {
if (disableHooks) {
return;
}
String BASE_DIR = EdXpConfigGlobal.getConfig().getInstallerBaseDir();
if (SELinuxHelper.getAppDataFileService().checkFileExists(BASE_DIR + "conf/disable_resources")) {
Log.w(TAG, "Found " + BASE_DIR + "conf/disable_resources, not hooking resources");
XposedInit.disableResources = true;
return;
}
if (dummyClassLoader != null) {
return;
}
try {
Resources res = Resources.getSystem();
Class resClass = res.getClass();
Class taClass = TypedArray.class;
try {
TypedArray ta = res.obtainTypedArray(res.getIdentifier(
"preloaded_drawables", "array", "android"));
taClass = ta.getClass();
ta.recycle();
} catch (Resources.NotFoundException nfe) {
XposedBridge.log(nfe);
}
XposedBridge.removeFinalFlagNative(resClass);
XposedBridge.removeFinalFlagNative(taClass);
DexMaker dexMaker = new DexMaker();
dexMaker.declare(TypeId.get("Lxposed/dummy/XResourcesSuperClass;"),
"XResourcesSuperClass.java",
Modifier.PUBLIC, TypeId.get(resClass));
dexMaker.declare(TypeId.get("Lxposed/dummy/XTypedArraySuperClass;"),
"XTypedArraySuperClass.java",
Modifier.PUBLIC, TypeId.get(taClass));
ClassLoader myCL = XposedBridge.class.getClassLoader();
dummyClassLoader = new InMemoryDexClassLoader(
ByteBuffer.wrap(dexMaker.generate()), myCL.getParent());
dummyClassLoader.loadClass("xposed.dummy.XResourcesSuperClass");
dummyClassLoader.loadClass("xposed.dummy.XTypedArraySuperClass");
setObjectField(myCL, "parent", dummyClassLoader);
} catch (Throwable throwable) {
XposedBridge.log(throwable);
XposedInit.disableResources = true;
}
}
// private static boolean hadInitErrors() {
@ -478,7 +518,9 @@ public final class XposedBridge {
private static native Object cloneToSubclassNative(Object obj, Class<?> targetClazz);
private static native void removeFinalFlagNative(Class<?> clazz);
private static void removeFinalFlagNative(Class clazz) {
EdXpConfigGlobal.getHookProvider().removeFinalFlagNative(clazz);
}
// /*package*/ static native void closeFilesBeforeForkNative();
// /*package*/ static native void reopenFilesAfterForkNative();

View File

@ -57,8 +57,7 @@ public final class XposedInit {
private static final String startClassName = ""; // ed: no support for tool process anymore
private static final String INSTANT_RUN_CLASS = "com.android.tools.fd.runtime.BootstrapApplication";
// TODO not supported yet
private static boolean disableResources = false;
public static boolean disableResources = false;
private static final String[] XRESOURCES_CONFLICTING_PACKAGES = {"com.sygic.aura"};
private XposedInit() {
@ -82,20 +81,15 @@ public final class XposedInit {
} catch (NoSuchFieldError ignored) {
}
}
findAndHookMethod("android.app.ApplicationPackageManager", null, "getResourcesForApplication",
ApplicationInfo.class, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
ApplicationInfo app = (ApplicationInfo) param.args[0];
XResources.setPackageNameForResDir(app.packageName,
app.uid == Process.myUid() ? app.sourceDir : app.publicSourceDir);
}
});
hookResources();
}
/*package*/
public static void hookResources() throws Throwable {
private static void hookResources() throws Throwable {
if (disableResources) {
return;
}
String BASE_DIR = EdXpConfigGlobal.getConfig().getInstallerBaseDir();
@ -111,6 +105,16 @@ public final class XposedInit {
return;
}
findAndHookMethod("android.app.ApplicationPackageManager", null, "getResourcesForApplication",
ApplicationInfo.class, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
ApplicationInfo app = (ApplicationInfo) param.args[0];
XResources.setPackageNameForResDir(app.packageName,
app.uid == Process.myUid() ? app.sourceDir : app.publicSourceDir);
}
});
/*
* getTopLevelResources(a)
* -> getTopLevelResources(b)