Commit 3615f339 authored by swift_gan's avatar swift_gan

done compat for xposed

parent 8e0774b6
...@@ -27,4 +27,5 @@ dependencies { ...@@ -27,4 +27,5 @@ dependencies {
androidTestImplementation 'com.android.support.test:runner:1.0.2' androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
implementation project(':hooklib') implementation project(':hooklib')
implementation project(':xposedcompat')
} }
package com.swift.sandhook; package com.swift.sandhook;
import android.app.Activity;
import android.app.Application; import android.app.Application;
import android.util.Log;
import com.swift.sandhook.testHookers.ActivityHooker; import com.swift.sandhook.testHookers.ActivityHooker;
import com.swift.sandhook.testHookers.CtrHook; import com.swift.sandhook.testHookers.CtrHook;
...@@ -9,13 +11,17 @@ import com.swift.sandhook.testHookers.JniHooker; ...@@ -9,13 +11,17 @@ import com.swift.sandhook.testHookers.JniHooker;
import com.swift.sandhook.testHookers.LogHooker; import com.swift.sandhook.testHookers.LogHooker;
import com.swift.sandhook.testHookers.ObjectHooker; import com.swift.sandhook.testHookers.ObjectHooker;
import com.swift.sandhook.wrapper.HookErrorException; import com.swift.sandhook.wrapper.HookErrorException;
import com.swift.sandhook.xposedcompat.XposedCompat;
import dalvik.system.DexClassLoader; import dalvik.system.DexClassLoader;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedHelpers;
public class MyApp extends Application { public class MyApp extends Application {
@Override @Override
public void onCreate() { public void onCreate() {
super.onCreate(); super.onCreate();
try { try {
SandHook.addHookClass(JniHooker.class, SandHook.addHookClass(JniHooker.class,
CtrHook.class, CtrHook.class,
...@@ -27,6 +33,26 @@ public class MyApp extends Application { ...@@ -27,6 +33,26 @@ public class MyApp extends Application {
e.printStackTrace(); e.printStackTrace();
} }
//setup for xposed
XposedCompat.cacheDir = getCacheDir();
XposedCompat.context = this;
XposedCompat.classLoader = getClassLoader();
XposedCompat.isFirstApplication= true;
XposedHelpers.findAndHookMethod(Activity.class, "onResume", new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
super.beforeHookedMethod(param);
Log.e("XposedCompat", "beforeHookedMethod: " + param.method.getName());
}
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
Log.e("XposedCompat", "afterHookedMethod: " + param.method.getName());
}
});
try { try {
ClassLoader classLoader = getClassLoader(); ClassLoader classLoader = getClassLoader();
DexClassLoader dexClassLoader = new DexClassLoader("/sdcard/hookers-debug.apk", DexClassLoader dexClassLoader = new DexClassLoader("/sdcard/hookers-debug.apk",
......
...@@ -10,9 +10,13 @@ import java.lang.reflect.Field; ...@@ -10,9 +10,13 @@ import java.lang.reflect.Field;
import java.lang.reflect.Member; import java.lang.reflect.Member;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class SandHook { public class SandHook {
static Map<Member,HookWrapper.HookEntity> globalHookEntityMap = new ConcurrentHashMap<>();
public static Class artMethodClass; public static Class artMethodClass;
public static Field nativePeerField; public static Field nativePeerField;
...@@ -55,6 +59,15 @@ public class SandHook { ...@@ -55,6 +59,15 @@ public class SandHook {
HookWrapper.addHookClass(classLoader, hookWrapperClass); HookWrapper.addHookClass(classLoader, hookWrapperClass);
} }
public static void hook(HookWrapper.HookEntity entity) throws HookErrorException {
if (entity.target != null && entity.hook != null) {
if (!SandHook.hook(entity.target, entity.hook, entity.backup)) {
throw new HookErrorException("hook method <" + entity.target.getName() + "> error in native!");
}
globalHookEntityMap.put(entity.target, entity);
}
}
public static boolean hook(Member target, Method hook, Method backup) { public static boolean hook(Member target, Method hook, Method backup) {
if (target == null || hook == null) if (target == null || hook == null)
return false; return false;
......
...@@ -21,8 +21,6 @@ import java.util.concurrent.ConcurrentHashMap; ...@@ -21,8 +21,6 @@ import java.util.concurrent.ConcurrentHashMap;
public class HookWrapper { public class HookWrapper {
static Map<Member,HookEntity> globalHookEntityMap = new ConcurrentHashMap<>();
public static void addHookClass(Class<?>... classes) throws HookErrorException { public static void addHookClass(Class<?>... classes) throws HookErrorException {
addHookClass(null, classes); addHookClass(null, classes);
} }
...@@ -40,12 +38,7 @@ public class HookWrapper { ...@@ -40,12 +38,7 @@ public class HookWrapper {
Map<Member,HookEntity> hookEntityMap = getHookMethods(classLoader, targetHookClass, clazz); Map<Member,HookEntity> hookEntityMap = getHookMethods(classLoader, targetHookClass, clazz);
fillBackupMethod(classLoader, clazz, hookEntityMap); fillBackupMethod(classLoader, clazz, hookEntityMap);
for (HookEntity entity:hookEntityMap.values()) { for (HookEntity entity:hookEntityMap.values()) {
if (entity.target != null && entity.hook != null) { SandHook.hook(entity);
if (!SandHook.hook(entity.target, entity.hook, entity.backup)) {
throw new HookErrorException("hook method <" + entity.target.getName() + "> error in native!");
}
globalHookEntityMap.put(entity.target, entity);
}
} }
} }
...@@ -285,6 +278,11 @@ public class HookWrapper { ...@@ -285,6 +278,11 @@ public class HookWrapper {
this.target = target; this.target = target;
} }
public HookEntity(Member target, Method hook, Method backup) {
this.target = target;
this.hook = hook;
this.backup = backup;
}
public boolean isCtor() { public boolean isCtor() {
return target instanceof Constructor; return target instanceof Constructor;
......
...@@ -25,6 +25,7 @@ android { ...@@ -25,6 +25,7 @@ android {
} }
dependencies { dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar']) implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'com.linkedin.dexmaker:dexmaker:2.21.0' implementation 'com.linkedin.dexmaker:dexmaker:2.21.0'
compileOnly project(':hooklib')
} }
package com.swift.sandhook.xposedcompat;
import android.app.ActivityManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.text.TextUtils;
import java.util.ArrayList;
import java.util.List;
/**
* Created by swift_gan on 2017/11/23.
*/
public class ProcessUtils {
private static volatile String processName = null;
public static String getProcessName(Context context) {
if (!TextUtils.isEmpty(processName))
return processName;
processName = doGetProcessName(context);
return processName;
}
private static String doGetProcessName(Context context) {
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningAppProcessInfo> runningApps = am.getRunningAppProcesses();
if (runningApps == null) {
return null;
}
for (ActivityManager.RunningAppProcessInfo proInfo : runningApps) {
if (proInfo.pid == android.os.Process.myPid()) {
if (proInfo.processName != null) {
return proInfo.processName;
}
}
}
return context.getPackageName();
}
public static boolean isMainProcess(Context context) {
String processName = getProcessName(context);
String pkgName = context.getPackageName();
if (!TextUtils.isEmpty(processName) && !TextUtils.equals(processName, pkgName)) {
return false;
} else {
return true;
}
}
public static List<ResolveInfo> findActivitiesForPackage(Context context, String packageName) {
final PackageManager packageManager = context.getPackageManager();
final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
mainIntent.setPackage(packageName);
final List<ResolveInfo> apps = packageManager.queryIntentActivities(mainIntent, 0);
return apps != null ? apps : new ArrayList<ResolveInfo>();
}
}
package com.swift.sandhook.xposedcompat; package com.swift.sandhook.xposedcompat;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import java.io.File;
public class XposedCompat { public class XposedCompat {
public static File cacheDir;
public static Context context;
public static ClassLoader classLoader;
public static boolean isFirstApplication;
} }
package com.swift.sandhook.xposedcompat.methodgen;
import android.util.Log;
import com.swift.sandhook.xposedcompat.BuildConfig;
public class DexLog {
public static final String TAG = "SandXposed-dexmaker";
public static int v(String s) {
return Log.v(TAG, s);
}
public static int i(String s) {
return Log.i(TAG, s);
}
public static int d(String s) {
if (BuildConfig.DEBUG) {
return Log.d(TAG, s);
}
return 0;
}
public static int w(String s) {
return Log.w(TAG, s);
}
public static int e(String s) {
return Log.e(TAG, s);
}
public static int e(String s, Throwable t) {
return Log.e(TAG, s, t);
}
}
...@@ -225,6 +225,7 @@ public class DexMakerUtils { ...@@ -225,6 +225,7 @@ public class DexMakerUtils {
if (addInstMethod == null) { if (addInstMethod == null) {
try { try {
addInstMethod = Code.class.getDeclaredMethod("addInstruction", Insn.class); addInstMethod = Code.class.getDeclaredMethod("addInstruction", Insn.class);
addInstMethod.setAccessible(true);
} catch (NoSuchMethodException e) { } catch (NoSuchMethodException e) {
e.printStackTrace(); e.printStackTrace();
} }
...@@ -240,6 +241,7 @@ public class DexMakerUtils { ...@@ -240,6 +241,7 @@ public class DexMakerUtils {
if (specMethod == null) { if (specMethod == null) {
try { try {
specMethod = Local.class.getDeclaredMethod("spec"); specMethod = Local.class.getDeclaredMethod("spec");
specMethod.setAccessible(true);
} catch (NoSuchMethodException e) { } catch (NoSuchMethodException e) {
e.printStackTrace(); e.printStackTrace();
} }
......
package com.swift.sandhook.xposedcompat.methodgen;
import com.swift.sandhook.xposedcompat.XposedCompat;
import java.io.File;
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.util.HashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import de.robv.android.xposed.XposedBridge;
public final class DynamicBridge {
private static final HashMap<Member, Method> hookedInfo = new HashMap<>();
private static final HookerDexMaker dexMaker = new HookerDexMaker();
private static final AtomicBoolean dexPathInited = new AtomicBoolean(false);
private static File dexDir;
private static File dexOptDir;
public static void onForkPost() {
dexPathInited.set(false);
}
public static synchronized void hookMethod(Member hookMethod, XposedBridge.AdditionalHookInfo additionalHookInfo) {
if (!checkMember(hookMethod)) {
return;
}
if (hookedInfo.containsKey(hookMethod)) {
DexLog.w("already hook method:" + hookMethod.toString());
return;
}
DexLog.d("start to generate class for: " + hookMethod);
try {
// using file based DexClassLoader
if (dexPathInited.compareAndSet(false, true)) {
// delete previous compiled dex to prevent potential crashing
// TODO find a way to reuse them in consideration of performance
try {
// we always choose to use device encrypted storage data on android N and later
// in case some app is installing hooks before phone is unlocked
String fixedAppDataDir = XposedCompat.cacheDir.getAbsolutePath();
dexDir = new File(fixedAppDataDir, "/sandxposed/");
dexOptDir = new File(dexDir, "oat");
dexDir.mkdirs();
try {
FileUtils.delete(dexOptDir);
} catch (Throwable throwable) {
}
} catch (Throwable throwable) {
DexLog.e("error when init dex path", throwable);
}
}
dexMaker.start(hookMethod, additionalHookInfo,
hookMethod.getDeclaringClass().getClassLoader(), dexDir == null ? null : dexDir.getAbsolutePath());
hookedInfo.put(hookMethod, dexMaker.getCallBackupMethod());
} catch (Exception e) {
DexLog.e("error occur when generating dex. dexDir=" + dexDir, e);
}
}
private static boolean checkMember(Member member) {
if (member instanceof Method) {
return true;
} else if (member instanceof Constructor<?>) {
return true;
} else if (member.getDeclaringClass().isInterface()) {
DexLog.e("Cannot hook interfaces: " + member.toString());
return false;
} else if (Modifier.isAbstract(member.getModifiers())) {
DexLog.e("Cannot hook abstract methods: " + member.toString());
return false;
} else {
DexLog.e("Only methods and constructors can be hooked: " + member.toString());
return false;
}
}
public static Object invokeOriginalMethod(Member method, Object thisObject, Object[] args)
throws InvocationTargetException, IllegalAccessException {
Method callBackup = hookedInfo.get(method);
if (callBackup == null) {
throw new IllegalStateException("method not hooked, cannot call original method.");
}
if (!Modifier.isStatic(callBackup.getModifiers())) {
throw new IllegalStateException("original method is not static, something must be wrong!");
}
callBackup.setAccessible(true);
if (args == null) {
args = new Object[0];
}
final int argsSize = args.length;
if (Modifier.isStatic(method.getModifiers())) {
return callBackup.invoke(null, args);
} else {
Object[] newArgs = new Object[argsSize + 1];
newArgs[0] = thisObject;
for (int i = 1; i < newArgs.length; i++) {
newArgs[i] = args[i - 1];
}
return callBackup.invoke(null, newArgs);
}
}
}
package com.swift.sandhook.xposedcompat.methodgen;
import android.os.Build;
import android.text.TextUtils;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class FileUtils {
public static final boolean IS_USING_PROTECTED_STORAGE = Build.VERSION.SDK_INT >= Build.VERSION_CODES.N;
/**
* Delete a file or a directory and its children.
*
* @param file The directory to delete.
* @throws IOException Exception when problem occurs during deleting the directory.
*/
public static void delete(File file) throws IOException {
for (File childFile : file.listFiles()) {
if (childFile.isDirectory()) {
delete(childFile);
} else {
if (!childFile.delete()) {
throw new IOException();
}
}
}
if (!file.delete()) {
throw new IOException();
}
}
public static String readLine(File file) {
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
return reader.readLine();
} catch (Throwable throwable) {
return "";
}
}
public static void writeLine(File file, String line) {
try {
file.createNewFile();
} catch (IOException ex) {
}
try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) {
writer.write(line);
writer.flush();
} catch (Throwable throwable) {
DexLog.e("error writing line to file " + file + ": " + throwable.getMessage());
}
}
public static String getPackageName(String dataDir) {
if (TextUtils.isEmpty(dataDir)) {
DexLog.e("getPackageName using empty dataDir");
return "";
}
int lastIndex = dataDir.lastIndexOf("/");
if (lastIndex < 0) {
return dataDir;
}
return dataDir.substring(lastIndex + 1);
}
public static String getDataPathPrefix() {
return IS_USING_PROTECTED_STORAGE ? "/data/user_de/0/" : "/data/data/";
}
}
...@@ -11,6 +11,8 @@ import com.android.dx.Label; ...@@ -11,6 +11,8 @@ import com.android.dx.Label;
import com.android.dx.Local; import com.android.dx.Local;
import com.android.dx.MethodId; import com.android.dx.MethodId;
import com.android.dx.TypeId; import com.android.dx.TypeId;
import com.swift.sandhook.SandHook;
import com.swift.sandhook.wrapper.HookWrapper;
import java.io.File; import java.io.File;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
...@@ -37,7 +39,7 @@ public class HookerDexMaker { ...@@ -37,7 +39,7 @@ public class HookerDexMaker {
public static final String METHOD_NAME_SETUP = "setup"; public static final String METHOD_NAME_SETUP = "setup";
public static final TypeId<Object[]> objArrayTypeId = TypeId.get(Object[].class); public static final TypeId<Object[]> objArrayTypeId = TypeId.get(Object[].class);
private static final String CLASS_DESC_PREFIX = "L"; private static final String CLASS_DESC_PREFIX = "L";
private static final String CLASS_NAME_PREFIX = "EdHooker"; private static final String CLASS_NAME_PREFIX = "SandHooker";
private static final String FIELD_NAME_HOOK_INFO = "additionalHookInfo"; private static final String FIELD_NAME_HOOK_INFO = "additionalHookInfo";
private static final String FIELD_NAME_METHOD = "method"; private static final String FIELD_NAME_METHOD = "method";
private static final String PARAMS_FIELD_NAME_METHOD = "method"; private static final String PARAMS_FIELD_NAME_METHOD = "method";
...@@ -203,7 +205,7 @@ public class HookerDexMaker { ...@@ -203,7 +205,7 @@ public class HookerDexMaker {
mHookMethod = mHookClass.getMethod(METHOD_NAME_HOOK, mActualParameterTypes); mHookMethod = mHookClass.getMethod(METHOD_NAME_HOOK, mActualParameterTypes);
mBackupMethod = mHookClass.getMethod(METHOD_NAME_BACKUP, mActualParameterTypes); mBackupMethod = mHookClass.getMethod(METHOD_NAME_BACKUP, mActualParameterTypes);
mCallBackupMethod = mHookClass.getMethod(METHOD_NAME_CALL_BACKUP, mActualParameterTypes); mCallBackupMethod = mHookClass.getMethod(METHOD_NAME_CALL_BACKUP, mActualParameterTypes);
//HookMain.backupAndHook(mMember, mHookMethod, mBackupMethod); SandHook.hook(new HookWrapper.HookEntity(mMember, mHookMethod, mBackupMethod));
} }
public Method getHookMethod() { public Method getHookMethod() {
......
package com.swift.sandhook.xposedcompat.methodgen;
import android.os.Process;
import android.text.TextUtils;
//import com.elderdrivers.riru.xposed.Main;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
public class ProcessUtils {
public static String getCurrentProcessName() {
String prettyName = null;//Main.sAppProcessName;
if (!TextUtils.isEmpty(prettyName)) {
return prettyName;
}
return getProcessName(Process.myPid());
}
/**
* a common solution from https://stackoverflow.com/a/21389402
* <p>
* use {@link com.elderdrivers.riru.xposed.Main#sAppProcessName} to get current process name
*/
public static String getProcessName(int pid) {
BufferedReader cmdlineReader = null;
try {
cmdlineReader = new BufferedReader(new InputStreamReader(
new FileInputStream(
"/proc/" + pid + "/cmdline"),
"iso-8859-1"));
int c;
StringBuilder processName = new StringBuilder();
while ((c = cmdlineReader.read()) > 0) {
processName.append((char) c);
}
return processName.toString();
} catch (Throwable throwable) {
DexLog.w("getProcessName: " + throwable.getMessage());
} finally {
try {
if (cmdlineReader != null) {
cmdlineReader.close();
}
} catch (Throwable throwable) {
DexLog.e("getProcessName: " + throwable.getMessage());
}
}
return "";
}
public static boolean isLastPidAlive(File lastPidFile) {
String lastPidInfo = FileUtils.readLine(lastPidFile);
try {
String[] split = lastPidInfo.split(":", 2);
return checkProcessAlive(Integer.parseInt(split[0]), split[1]);
} catch (Throwable throwable) {
DexLog.w("error when check last pid " + lastPidFile + ": " + throwable.getMessage());
return false;
}
}
public static void saveLastPidInfo(File lastPidFile, int pid, String processName) {
try {
if (!lastPidFile.exists()) {
lastPidFile.getParentFile().mkdirs();
lastPidFile.createNewFile();
}
} catch (Throwable throwable) {
}
FileUtils.writeLine(lastPidFile, pid + ":" + processName);
}
public static boolean checkProcessAlive(int pid, String processName) {
String existsPrcName = getProcessName(pid);
DexLog.w("checking pid alive: " + pid + ", " + processName + ", processName=" + existsPrcName);
return existsPrcName.equals(processName);
}
}
package de.robv.android.xposed; package de.robv.android.xposed;
import android.content.res.XResources; //import android.content.res.XResources;
import de.robv.android.xposed.callbacks.XC_InitPackageResources; import de.robv.android.xposed.callbacks.XC_InitPackageResources;
import de.robv.android.xposed.callbacks.XC_InitPackageResources.InitPackageResourcesParam; import de.robv.android.xposed.callbacks.XC_InitPackageResources.InitPackageResourcesParam;
......
package de.robv.android.xposed; package de.robv.android.xposed;
import android.os.SELinux; //import android.os.SELinux;
import de.robv.android.xposed.services.BaseService; import de.robv.android.xposed.services.BaseService;
import de.robv.android.xposed.services.DirectAccessService; import de.robv.android.xposed.services.DirectAccessService;
...@@ -25,18 +25,18 @@ public final class SELinuxHelper { ...@@ -25,18 +25,18 @@ public final class SELinuxHelper {
* *
* @return A boolean indicating whether SELinux is enforcing. * @return A boolean indicating whether SELinux is enforcing.
*/ */
public static boolean isSELinuxEnforced() { // public static boolean isSELinuxEnforced() {
return sIsSELinuxEnabled && SELinux.isSELinuxEnforced(); // return sIsSELinuxEnabled && SELinux.isSELinuxEnforced();
} // }
/** /**
* Gets the security context of the current process. * Gets the security context of the current process.
* *
* @return A String representing the security context of the current process. * @return A String representing the security context of the current process.
*/ */
public static String getContext() { // public static String getContext() {
return sIsSELinuxEnabled ? SELinux.getContext() : null; // return sIsSELinuxEnabled ? SELinux.getContext() : null;
} // }
/** /**
* Retrieve the service to be used when accessing files in {@code /data/data/*}. * Retrieve the service to be used when accessing files in {@code /data/data/*}.
......
...@@ -7,7 +7,6 @@ import android.os.Environment; ...@@ -7,7 +7,6 @@ import android.os.Environment;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.util.Log; import android.util.Log;
import com.android.internal.util.XmlUtils;
import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlPullParserException;
...@@ -121,14 +120,12 @@ public final class XSharedPreferences implements SharedPreferences { ...@@ -121,14 +120,12 @@ public final class XSharedPreferences implements SharedPreferences {
try { try {
result = SELinuxHelper.getAppDataFileService().getFileInputStream(mFilename, mFileSize, mLastModified); result = SELinuxHelper.getAppDataFileService().getFileInputStream(mFilename, mFileSize, mLastModified);
if (result.stream != null) { if (result.stream != null) {
map = XmlUtils.readMapXml(result.stream); //map = XmlUtils.readMapXml(result.stream);
result.stream.close(); result.stream.close();
} else { } else {
// The file is unchanged, keep the current values // The file is unchanged, keep the current values
map = mMap; map = mMap;
} }
} catch (XmlPullParserException e) {
Log.w(TAG, "getSharedPreferences", e);
} catch (FileNotFoundException ignored) { } catch (FileNotFoundException ignored) {
// SharedPreferencesImpl has a canRead() check, so it doesn't log anything in case the file doesn't exist // SharedPreferencesImpl has a canRead() check, so it doesn't log anything in case the file doesn't exist
} catch (IOException e) { } catch (IOException e) {
......
...@@ -4,6 +4,8 @@ import android.annotation.SuppressLint; ...@@ -4,6 +4,8 @@ import android.annotation.SuppressLint;
import android.util.Log; import android.util.Log;
import com.swift.sandhook.xposedcompat.methodgen.DynamicBridge;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.AccessibleObject; import java.lang.reflect.AccessibleObject;
...@@ -151,7 +153,6 @@ public final class XposedBridge { ...@@ -151,7 +153,6 @@ public final class XposedBridge {
* @see #hookAllConstructors * @see #hookAllConstructors
*/ */
public static XC_MethodHook.Unhook hookMethod(Member hookMethod, XC_MethodHook callback) { public static XC_MethodHook.Unhook hookMethod(Member hookMethod, XC_MethodHook callback) {
hookMethod = MethodHookUtils.preCheck(hookMethod);
if (!(hookMethod instanceof Method) && !(hookMethod instanceof Constructor<?>)) { if (!(hookMethod instanceof Method) && !(hookMethod instanceof Constructor<?>)) {
throw new IllegalArgumentException("Only methods and constructors can be hooked: " + hookMethod.toString()); throw new IllegalArgumentException("Only methods and constructors can be hooked: " + hookMethod.toString());
} else if (hookMethod.getDeclaringClass().isInterface()) { } else if (hookMethod.getDeclaringClass().isInterface()) {
...@@ -196,16 +197,7 @@ public final class XposedBridge { ...@@ -196,16 +197,7 @@ public final class XposedBridge {
} }
AdditionalHookInfo additionalInfo = new AdditionalHookInfo(callbacks, parameterTypes, returnType); AdditionalHookInfo additionalInfo = new AdditionalHookInfo(callbacks, parameterTypes, returnType);
MethodInfo methodInfo = new MethodInfo(hookMethod); hookMethodNative(hookMethod, declaringClass, slot, additionalInfo);
declaringClass = methodInfo.getClassForSure();
Member reflectMethod = (Member) HookMain.findMethod(
declaringClass, methodInfo.methodName, methodInfo.methodSig);
if (reflectMethod == null) {
Log.e(TAG, "method not found: name="
+ methodInfo.methodName + ", sig=" + methodInfo.methodSig);
reflectMethod = hookMethod;
}
hookMethodNative(reflectMethod, declaringClass, slot, additionalInfo);
} }
return callback.new Unhook(hookMethod); return callback.new Unhook(hookMethod);
......
package de.robv.android.xposed; package de.robv.android.xposed;
import android.annotation.SuppressLint; //import android.annotation.SuppressLint;
import android.app.AndroidAppHelper; //import android.app.AndroidAppHelper;
import android.os.Build; //import android.os.Build;
import android.text.TextUtils; //import android.text.TextUtils;
import android.util.Log; //import android.util.Log;
//
import com.android.internal.os.ZygoteInit; //import com.android.internal.os.ZygoteInit;
import com.elderdrivers.riru.xposed.BuildConfig; //import com.elderdrivers.riru.xposed.BuildConfig;
import com.elderdrivers.riru.xposed.entry.Router; //import com.elderdrivers.riru.xposed.entry.Router;
import com.elderdrivers.riru.xposed.util.Utils; //import com.elderdrivers.riru.xposed.util.Utils;
//
import java.io.BufferedReader; //import java.io.BufferedReader;
import java.io.File; //import java.io.File;
import java.io.IOException; //import java.io.IOException;
import java.io.InputStream; //import java.io.InputStream;
import java.io.InputStreamReader; //import java.io.InputStreamReader;
import java.util.HashSet; //import java.util.HashSet;
import java.util.concurrent.atomic.AtomicBoolean; //import java.util.concurrent.atomic.AtomicBoolean;
import java.util.zip.ZipEntry; //import java.util.zip.ZipEntry;
import java.util.zip.ZipFile; //import java.util.zip.ZipFile;
//
import dalvik.system.DexFile; //import dalvik.system.DexFile;
import dalvik.system.PathClassLoader; //import dalvik.system.PathClassLoader;
import de.robv.android.xposed.services.BaseService; //import de.robv.android.xposed.services.BaseService;
//
import static com.elderdrivers.riru.xposed.entry.hooker.XposedBlackListHooker.BLACK_LIST_PACKAGE_NAME; //import static com.elderdrivers.riru.xposed.entry.hooker.XposedBlackListHooker.BLACK_LIST_PACKAGE_NAME;
import static de.robv.android.xposed.XposedHelpers.closeSilently; //import static de.robv.android.xposed.XposedHelpers.closeSilently;
import static de.robv.android.xposed.XposedHelpers.findClass; //import static de.robv.android.xposed.XposedHelpers.findClass;
import static de.robv.android.xposed.XposedHelpers.findFieldIfExists; //import static de.robv.android.xposed.XposedHelpers.findFieldIfExists;
import static de.robv.android.xposed.XposedHelpers.setStaticBooleanField; //import static de.robv.android.xposed.XposedHelpers.setStaticBooleanField;
import static de.robv.android.xposed.XposedHelpers.setStaticLongField; //import static de.robv.android.xposed.XposedHelpers.setStaticLongField;
public final class XposedInit { public final class XposedInit {
private static final String TAG = XposedBridge.TAG; // private static final String TAG = XposedBridge.TAG;
private static boolean startsSystemServer = false; // private static boolean startsSystemServer = false;
private static final String startClassName = ""; // ed: no support for tool process anymore // private static final String startClassName = ""; // ed: no support for tool process anymore
//
public static final String INSTALLER_PACKAGE_NAME = "com.solohsu.android.edxp.manager"; // public static final String INSTALLER_PACKAGE_NAME = "com.solohsu.android.edxp.manager";
public static final String INSTALLER_LEGACY_PACKAGE_NAME = "de.robv.android.xposed.installer"; // public static final String INSTALLER_LEGACY_PACKAGE_NAME = "de.robv.android.xposed.installer";
@SuppressLint("SdCardPath") // @SuppressLint("SdCardPath")
public static final String INSTALLER_DATA_BASE_DIR = Build.VERSION.SDK_INT >= 24 // public static final String INSTALLER_DATA_BASE_DIR = Build.VERSION.SDK_INT >= 24
? "/data/user_de/0/" + INSTALLER_PACKAGE_NAME + "/" // ? "/data/user_de/0/" + INSTALLER_PACKAGE_NAME + "/"
: "/data/data/" + INSTALLER_PACKAGE_NAME + "/"; // : "/data/data/" + INSTALLER_PACKAGE_NAME + "/";
private static final String INSTANT_RUN_CLASS = "com.android.tools.fd.runtime.BootstrapApplication"; // private static final String INSTANT_RUN_CLASS = "com.android.tools.fd.runtime.BootstrapApplication";
// TODO not supported yet // // TODO not supported yet
private static boolean disableResources = true; // private static boolean disableResources = true;
private static final String[] XRESOURCES_CONFLICTING_PACKAGES = {"com.sygic.aura"}; // private static final String[] XRESOURCES_CONFLICTING_PACKAGES = {"com.sygic.aura"};
//
private XposedInit() { // private XposedInit() {
} // }
//
private static volatile AtomicBoolean bootstrapHooked = new AtomicBoolean(false); // private static volatile AtomicBoolean bootstrapHooked = new AtomicBoolean(false);
//
/** // /**
* Hook some methods which we want to create an easier interface for developers. // * Hook some methods which we want to create an easier interface for developers.
*/ // */
/*package*/ // /*package*/
public static void initForZygote(boolean isSystem) throws Throwable { // public static void initForZygote(boolean isSystem) throws Throwable {
if (!bootstrapHooked.compareAndSet(false, true)) { // if (!bootstrapHooked.compareAndSet(false, true)) {
return; // return;
} // }
startsSystemServer = isSystem; // startsSystemServer = isSystem;
Router.startBootstrapHook(isSystem); // Router.startBootstrapHook(isSystem);
// MIUI // // MIUI
if (findFieldIfExists(ZygoteInit.class, "BOOT_START_TIME") != null) { // if (findFieldIfExists(ZygoteInit.class, "BOOT_START_TIME") != null) {
setStaticLongField(ZygoteInit.class, "BOOT_START_TIME", XposedBridge.BOOT_START_TIME); // setStaticLongField(ZygoteInit.class, "BOOT_START_TIME", XposedBridge.BOOT_START_TIME);
} // }
//
// Samsung // // Samsung
if (Build.VERSION.SDK_INT >= 24) { // if (Build.VERSION.SDK_INT >= 24) {
Class<?> zygote = findClass("com.android.internal.os.Zygote", null); // Class<?> zygote = findClass("com.android.internal.os.Zygote", null);
try { // try {
setStaticBooleanField(zygote, "isEnhancedZygoteASLREnabled", false); // setStaticBooleanField(zygote, "isEnhancedZygoteASLREnabled", false);
} catch (NoSuchFieldError ignored) { // } catch (NoSuchFieldError ignored) {
} // }
} // }
} // }
//
/*package*/ // /*package*/
static void hookResources() throws Throwable { // static void hookResources() throws Throwable {
// ed: not for now // // ed: not for now
} // }
//
private static boolean needsToCloseFilesForFork() { // private static boolean needsToCloseFilesForFork() {
// ed: we always start to do our work after forking finishes // // ed: we always start to do our work after forking finishes
return false; // return false;
} // }
//
/** // /**
* Try to load all modules defined in <code>INSTALLER_DATA_BASE_DIR/conf/modules.list</code> // * Try to load all modules defined in <code>INSTALLER_DATA_BASE_DIR/conf/modules.list</code>
*/ // */
private static volatile AtomicBoolean modulesLoaded = new AtomicBoolean(false); // private static volatile AtomicBoolean modulesLoaded = new AtomicBoolean(false);
//
public static void loadModules() throws IOException { // public static void loadModules() throws IOException {
if (!modulesLoaded.compareAndSet(false, true)) { // if (!modulesLoaded.compareAndSet(false, true)) {
return; // return;
} // }
final String filename = INSTALLER_DATA_BASE_DIR + "conf/modules.list"; // final String filename = INSTALLER_DATA_BASE_DIR + "conf/modules.list";
BaseService service = SELinuxHelper.getAppDataFileService(); // BaseService service = SELinuxHelper.getAppDataFileService();
if (!service.checkFileExists(filename)) { // if (!service.checkFileExists(filename)) {
Log.e(TAG, "Cannot load any modules because " + filename + " was not found"); // Log.e(TAG, "Cannot load any modules because " + filename + " was not found");
return; // return;
} // }
//
ClassLoader topClassLoader = XposedBridge.BOOTCLASSLOADER; // ClassLoader topClassLoader = XposedBridge.BOOTCLASSLOADER;
ClassLoader parent; // ClassLoader parent;
while ((parent = topClassLoader.getParent()) != null) { // while ((parent = topClassLoader.getParent()) != null) {
topClassLoader = parent; // topClassLoader = parent;
} // }
//
InputStream stream = service.getFileInputStream(filename); // InputStream stream = service.getFileInputStream(filename);
BufferedReader apks = new BufferedReader(new InputStreamReader(stream)); // BufferedReader apks = new BufferedReader(new InputStreamReader(stream));
String apk; // String apk;
while ((apk = apks.readLine()) != null) { // while ((apk = apks.readLine()) != null) {
loadModule(apk, topClassLoader); // loadModule(apk, topClassLoader);
} // }
apks.close(); // apks.close();
} // }
//
//
/** // /**
* Load a module from an APK by calling the init(String) method for all classes defined // * Load a module from an APK by calling the init(String) method for all classes defined
* in <code>assets/xposed_init</code>. // * in <code>assets/xposed_init</code>.
*/ // */
private static void loadModule(String apk, ClassLoader topClassLoader) { // private static void loadModule(String apk, ClassLoader topClassLoader) {
if (BuildConfig.DEBUG) // if (BuildConfig.DEBUG)
Log.i(TAG, "Loading modules from " + apk); // Log.i(TAG, "Loading modules from " + apk);
//
if (!TextUtils.isEmpty(apk) && apk.contains(BLACK_LIST_PACKAGE_NAME)) { // if (!TextUtils.isEmpty(apk) && apk.contains(BLACK_LIST_PACKAGE_NAME)) {
if (BuildConfig.DEBUG) // if (BuildConfig.DEBUG)
Log.i(TAG, "We are going to take over black list's job..."); // Log.i(TAG, "We are going to take over black list's job...");
return; // return;
} // }
//
if (!new File(apk).exists()) { // if (!new File(apk).exists()) {
Log.e(TAG, " File does not exist"); // Log.e(TAG, " File does not exist");
return; // return;
} // }
//
DexFile dexFile; // DexFile dexFile;
try { // try {
dexFile = new DexFile(apk); // dexFile = new DexFile(apk);
} catch (IOException e) { // } catch (IOException e) {
Log.e(TAG, " Cannot load module", e); // Log.e(TAG, " Cannot load module", e);
return; // return;
} // }
//
if (dexFile.loadClass(INSTANT_RUN_CLASS, topClassLoader) != null) { // if (dexFile.loadClass(INSTANT_RUN_CLASS, topClassLoader) != null) {
Log.e(TAG, " Cannot load module, please disable \"Instant Run\" in Android Studio."); // Log.e(TAG, " Cannot load module, please disable \"Instant Run\" in Android Studio.");
closeSilently(dexFile); // closeSilently(dexFile);
return; // return;
} // }
//
if (dexFile.loadClass(XposedBridge.class.getName(), topClassLoader) != null) { // if (dexFile.loadClass(XposedBridge.class.getName(), topClassLoader) != null) {
Log.e(TAG, " Cannot load module:"); // Log.e(TAG, " Cannot load module:");
Log.e(TAG, " The Xposed API classes are compiled into the module's APK."); // Log.e(TAG, " The Xposed API classes are compiled into the module's APK.");
Log.e(TAG, " This may cause strange issues and must be fixed by the module developer."); // Log.e(TAG, " This may cause strange issues and must be fixed by the module developer.");
Log.e(TAG, " For details, see: http://api.xposed.info/using.html"); // Log.e(TAG, " For details, see: http://api.xposed.info/using.html");
closeSilently(dexFile); // closeSilently(dexFile);
return; // return;
} // }
//
closeSilently(dexFile); // closeSilently(dexFile);
//
ZipFile zipFile = null; // ZipFile zipFile = null;
InputStream is; // InputStream is;
try { // try {
zipFile = new ZipFile(apk); // zipFile = new ZipFile(apk);
ZipEntry zipEntry = zipFile.getEntry("assets/xposed_init"); // ZipEntry zipEntry = zipFile.getEntry("assets/xposed_init");
if (zipEntry == null) { // if (zipEntry == null) {
Log.e(TAG, " assets/xposed_init not found in the APK"); // Log.e(TAG, " assets/xposed_init not found in the APK");
closeSilently(zipFile); // closeSilently(zipFile);
return; // return;
} // }
is = zipFile.getInputStream(zipEntry); // is = zipFile.getInputStream(zipEntry);
} catch (IOException e) { // } catch (IOException e) {
Log.e(TAG, " Cannot read assets/xposed_init in the APK", e); // Log.e(TAG, " Cannot read assets/xposed_init in the APK", e);
closeSilently(zipFile); // closeSilently(zipFile);
return; // return;
} // }
//
ClassLoader mcl = new PathClassLoader(apk, XposedInit.class.getClassLoader()); // ClassLoader mcl = new PathClassLoader(apk, XposedInit.class.getClassLoader());
BufferedReader moduleClassesReader = new BufferedReader(new InputStreamReader(is)); // BufferedReader moduleClassesReader = new BufferedReader(new InputStreamReader(is));
try { // try {
String moduleClassName; // String moduleClassName;
while ((moduleClassName = moduleClassesReader.readLine()) != null) { // while ((moduleClassName = moduleClassesReader.readLine()) != null) {
moduleClassName = moduleClassName.trim(); // moduleClassName = moduleClassName.trim();
if (moduleClassName.isEmpty() || moduleClassName.startsWith("#")) // if (moduleClassName.isEmpty() || moduleClassName.startsWith("#"))
continue; // continue;
//
try { // try {
if (BuildConfig.DEBUG) // if (BuildConfig.DEBUG)
Log.i(TAG, " Loading class " + moduleClassName); // Log.i(TAG, " Loading class " + moduleClassName);
Class<?> moduleClass = mcl.loadClass(moduleClassName); // Class<?> moduleClass = mcl.loadClass(moduleClassName);
//
if (!IXposedMod.class.isAssignableFrom(moduleClass)) { // if (!IXposedMod.class.isAssignableFrom(moduleClass)) {
Log.e(TAG, " This class doesn't implement any sub-interface of IXposedMod, skipping it"); // Log.e(TAG, " This class doesn't implement any sub-interface of IXposedMod, skipping it");
continue; // continue;
} else if (disableResources && IXposedHookInitPackageResources.class.isAssignableFrom(moduleClass)) { // } else if (disableResources && IXposedHookInitPackageResources.class.isAssignableFrom(moduleClass)) {
Log.e(TAG, " This class requires resource-related hooks (which are disabled), skipping it."); // Log.e(TAG, " This class requires resource-related hooks (which are disabled), skipping it.");
continue; // continue;
} // }
//
final Object moduleInstance = moduleClass.newInstance(); // final Object moduleInstance = moduleClass.newInstance();
if (XposedBridge.isZygote) { // if (XposedBridge.isZygote) {
if (moduleInstance instanceof IXposedHookZygoteInit) { // if (moduleInstance instanceof IXposedHookZygoteInit) {
IXposedHookZygoteInit.StartupParam param = new IXposedHookZygoteInit.StartupParam(); // IXposedHookZygoteInit.StartupParam param = new IXposedHookZygoteInit.StartupParam();
param.modulePath = apk; // param.modulePath = apk;
param.startsSystemServer = startsSystemServer; // param.startsSystemServer = startsSystemServer;
((IXposedHookZygoteInit) moduleInstance).initZygote(param); // ((IXposedHookZygoteInit) moduleInstance).initZygote(param);
} // }
//
if (moduleInstance instanceof IXposedHookLoadPackage) // if (moduleInstance instanceof IXposedHookLoadPackage)
XposedBridge.hookLoadPackage(new IXposedHookLoadPackage.Wrapper((IXposedHookLoadPackage) moduleInstance)); // XposedBridge.hookLoadPackage(new IXposedHookLoadPackage.Wrapper((IXposedHookLoadPackage) moduleInstance));
//
if (moduleInstance instanceof IXposedHookInitPackageResources) // if (moduleInstance instanceof IXposedHookInitPackageResources)
XposedBridge.hookInitPackageResources(new IXposedHookInitPackageResources.Wrapper((IXposedHookInitPackageResources) moduleInstance)); // XposedBridge.hookInitPackageResources(new IXposedHookInitPackageResources.Wrapper((IXposedHookInitPackageResources) moduleInstance));
} else { // } else {
if (moduleInstance instanceof IXposedHookCmdInit) { // if (moduleInstance instanceof IXposedHookCmdInit) {
IXposedHookCmdInit.StartupParam param = new IXposedHookCmdInit.StartupParam(); // IXposedHookCmdInit.StartupParam param = new IXposedHookCmdInit.StartupParam();
param.modulePath = apk; // param.modulePath = apk;
param.startClassName = startClassName; // param.startClassName = startClassName;
((IXposedHookCmdInit) moduleInstance).initCmdApp(param); // ((IXposedHookCmdInit) moduleInstance).initCmdApp(param);
} // }
} // }
} catch (Throwable t) { // } catch (Throwable t) {
Log.e(TAG, " Failed to load class " + moduleClassName, t); // Log.e(TAG, " Failed to load class " + moduleClassName, t);
} // }
} // }
} catch (IOException e) { // } catch (IOException e) {
Log.e(TAG, " Failed to load module from " + apk, e); // Log.e(TAG, " Failed to load module from " + apk, e);
} finally { // } finally {
closeSilently(is); // closeSilently(is);
closeSilently(zipFile); // closeSilently(zipFile);
} // }
} // }
//
public final static HashSet<String> loadedPackagesInProcess = new HashSet<>(1); // public final static HashSet<String> loadedPackagesInProcess = new HashSet<>(1);
//
public static void logD(String prefix) { // public static void logD(String prefix) {
Utils.logD(String.format("%s: pkg=%s, prc=%s", prefix, AndroidAppHelper.currentPackageName(), // Utils.logD(String.format("%s: pkg=%s, prc=%s", prefix, AndroidAppHelper.currentPackageName(),
AndroidAppHelper.currentProcessName())); // AndroidAppHelper.currentProcessName()));
} // }
//
public static void logE(String prefix, Throwable throwable) { // public static void logE(String prefix, Throwable throwable) {
Utils.logE(String.format("%s: pkg=%s, prc=%s", prefix, AndroidAppHelper.currentPackageName(), // Utils.logE(String.format("%s: pkg=%s, prc=%s", prefix, AndroidAppHelper.currentPackageName(),
AndroidAppHelper.currentProcessName()), throwable); // AndroidAppHelper.currentProcessName()), throwable);
} // }
} }
package de.robv.android.xposed.callbacks; package de.robv.android.xposed.callbacks;
import android.content.res.XResources; //import android.content.res.XResources;
import de.robv.android.xposed.IXposedHookInitPackageResources; import de.robv.android.xposed.IXposedHookInitPackageResources;
import de.robv.android.xposed.XposedBridge.CopyOnWriteSortedSet; import de.robv.android.xposed.XposedBridge.CopyOnWriteSortedSet;
...@@ -45,7 +45,7 @@ public abstract class XC_InitPackageResources extends XCallback implements IXpos ...@@ -45,7 +45,7 @@ public abstract class XC_InitPackageResources extends XCallback implements IXpos
* Reference to the resources that can be used for calls to * Reference to the resources that can be used for calls to
* {@link XResources#setReplacement(String, String, String, Object)}. * {@link XResources#setReplacement(String, String, String, Object)}.
*/ */
public XResources res; //public XResources res;
} }
/** @hide */ /** @hide */
......
package de.robv.android.xposed.callbacks; package de.robv.android.xposed.callbacks;
import android.content.res.XResources; //import android.content.res.XResources;
import android.content.res.XResources.ResourceNames; //import android.content.res.XResources.ResourceNames;
import android.view.View; import android.view.View;
import de.robv.android.xposed.XposedBridge.CopyOnWriteSortedSet; import de.robv.android.xposed.XposedBridge.CopyOnWriteSortedSet;
...@@ -41,13 +41,13 @@ public abstract class XC_LayoutInflated extends XCallback { ...@@ -41,13 +41,13 @@ public abstract class XC_LayoutInflated extends XCallback {
public View view; public View view;
/** Container with the ID and name of the underlying resource. */ /** Container with the ID and name of the underlying resource. */
public ResourceNames resNames; // public ResourceNames resNames;
/** Directory from which the layout was actually loaded (e.g. "layout-sw600dp"). */ /** Directory from which the layout was actually loaded (e.g. "layout-sw600dp"). */
public String variant; // public String variant;
/** Resources containing the layout. */ /** Resources containing the layout. */
public XResources res; // public XResources res;
} }
/** @hide */ /** @hide */
...@@ -92,7 +92,7 @@ public abstract class XC_LayoutInflated extends XCallback { ...@@ -92,7 +92,7 @@ public abstract class XC_LayoutInflated extends XCallback {
@Override @Override
public void unhook() { public void unhook() {
XResources.unhookLayout(resDir, id, XC_LayoutInflated.this); // XResources.unhookLayout(resDir, id, XC_LayoutInflated.this);
} }
} }
......
...@@ -2,6 +2,9 @@ package de.robv.android.xposed.callbacks; ...@@ -2,6 +2,9 @@ package de.robv.android.xposed.callbacks;
import android.content.pm.ApplicationInfo; import android.content.pm.ApplicationInfo;
import com.swift.sandhook.xposedcompat.ProcessUtils;
import com.swift.sandhook.xposedcompat.XposedCompat;
import de.robv.android.xposed.IXposedHookLoadPackage; import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.XposedBridge.CopyOnWriteSortedSet; import de.robv.android.xposed.XposedBridge.CopyOnWriteSortedSet;
...@@ -39,19 +42,19 @@ public abstract class XC_LoadPackage extends XCallback implements IXposedHookLoa ...@@ -39,19 +42,19 @@ public abstract class XC_LoadPackage extends XCallback implements IXposedHookLoa
} }
/** The name of the package being loaded. */ /** The name of the package being loaded. */
public String packageName; public String packageName = XposedCompat.context.getPackageName();
/** The process in which the package is executed. */ /** The process in which the package is executed. */
public String processName; public String processName = ProcessUtils.getProcessName(XposedCompat.context);
/** The ClassLoader used for this package. */ /** The ClassLoader used for this package. */
public ClassLoader classLoader; public ClassLoader classLoader = XposedCompat.classLoader;
/** More information about the application being loaded. */ /** More information about the application being loaded. */
public ApplicationInfo appInfo; public ApplicationInfo appInfo = XposedCompat.context.getApplicationInfo();
/** Set to {@code true} if this is the first (and main) application for this process. */ /** Set to {@code true} if this is the first (and main) application for this process. */
public boolean isFirstApplication; public boolean isFirstApplication = XposedCompat.isFirstApplication;
} }
/** @hide */ /** @hide */
......
...@@ -3,7 +3,7 @@ package de.robv.android.xposed.services; ...@@ -3,7 +3,7 @@ package de.robv.android.xposed.services;
import android.os.IBinder; import android.os.IBinder;
import android.os.Parcel; import android.os.Parcel;
import android.os.RemoteException; import android.os.RemoteException;
import android.os.ServiceManager; //import android.os.ServiceManager;
import java.io.IOException; import java.io.IOException;
...@@ -158,7 +158,7 @@ public final class BinderService extends BaseService { ...@@ -158,7 +158,7 @@ public final class BinderService extends BaseService {
private final IBinder mRemote; private final IBinder mRemote;
private BinderService(int target) { private BinderService(int target) {
IBinder binder = ServiceManager.getService(SERVICE_NAMES[target]); IBinder binder = null; //ServiceManager.getService(SERVICE_NAMES[target]);
if (binder == null) if (binder == null)
throw new IllegalStateException("Service " + SERVICE_NAMES[target] + " does not exist"); throw new IllegalStateException("Service " + SERVICE_NAMES[target] + " does not exist");
this.mRemote = binder; this.mRemote = binder;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment