[core] Remove useless codes (#505)
* [core] Replace tabs with spaces * [core] Remove useless codes
This commit is contained in:
parent
86304f11ce
commit
d7897b67d9
|
|
@ -28,21 +28,29 @@ package de.robv.android.xposed;
|
|||
* implemented anymore.
|
||||
*/
|
||||
public interface IXposedHookCmdInit extends IXposedMod {
|
||||
/**
|
||||
* Called very early during startup of a command-line tool.
|
||||
* @param startupParam Details about the module itself and the started process.
|
||||
* @throws Throwable Everything is caught, but it will prevent further initialization of the module.
|
||||
*/
|
||||
void initCmdApp(StartupParam startupParam) throws Throwable;
|
||||
/**
|
||||
* Called very early during startup of a command-line tool.
|
||||
*
|
||||
* @param startupParam Details about the module itself and the started process.
|
||||
* @throws Throwable Everything is caught, but it will prevent further initialization of the module.
|
||||
*/
|
||||
void initCmdApp(StartupParam startupParam) throws Throwable;
|
||||
|
||||
/** Data holder for {@link #initCmdApp}. */
|
||||
final class StartupParam {
|
||||
/*package*/ StartupParam() {}
|
||||
/**
|
||||
* Data holder for {@link #initCmdApp}.
|
||||
*/
|
||||
final class StartupParam {
|
||||
/*package*/ StartupParam() {
|
||||
}
|
||||
|
||||
/** The path to the module's APK. */
|
||||
public String modulePath;
|
||||
/**
|
||||
* The path to the module's APK.
|
||||
*/
|
||||
public String modulePath;
|
||||
|
||||
/** The class name of the tools that the hook was invoked for. */
|
||||
public String startClassName;
|
||||
}
|
||||
/**
|
||||
* The class name of the tools that the hook was invoked for.
|
||||
*/
|
||||
public String startClassName;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,33 +33,35 @@ import de.robv.android.xposed.callbacks.XC_InitPackageResources.InitPackageResou
|
|||
* registering it as a callback automatically.
|
||||
*/
|
||||
public interface IXposedHookInitPackageResources extends IXposedMod {
|
||||
/**
|
||||
* This method is called when resources for an app are being initialized.
|
||||
* Modules can call special methods of the {@link XResources} class in order to replace resources.
|
||||
*
|
||||
* @param resparam Information about the resources.
|
||||
* @throws Throwable Everything the callback throws is caught and logged.
|
||||
*/
|
||||
void handleInitPackageResources(InitPackageResourcesParam resparam) throws Throwable;
|
||||
/**
|
||||
* This method is called when resources for an app are being initialized.
|
||||
* Modules can call special methods of the {@link XResources} class in order to replace resources.
|
||||
*
|
||||
* @param resparam Information about the resources.
|
||||
* @throws Throwable Everything the callback throws is caught and logged.
|
||||
*/
|
||||
void handleInitPackageResources(InitPackageResourcesParam resparam) throws Throwable;
|
||||
|
||||
/** @hide */
|
||||
final class Wrapper extends XC_InitPackageResources {
|
||||
private final IXposedHookInitPackageResources instance;
|
||||
private final String apkPath;
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
final class Wrapper extends XC_InitPackageResources {
|
||||
private final IXposedHookInitPackageResources instance;
|
||||
private final String apkPath;
|
||||
|
||||
public Wrapper(IXposedHookInitPackageResources instance, String apkPath) {
|
||||
this.instance = instance;
|
||||
this.apkPath = apkPath;
|
||||
}
|
||||
public Wrapper(IXposedHookInitPackageResources instance, String apkPath) {
|
||||
this.instance = instance;
|
||||
this.apkPath = apkPath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleInitPackageResources(InitPackageResourcesParam resparam) throws Throwable {
|
||||
instance.handleInitPackageResources(resparam);
|
||||
}
|
||||
@Override
|
||||
public void handleInitPackageResources(InitPackageResourcesParam resparam) throws Throwable {
|
||||
instance.handleInitPackageResources(resparam);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getApkPath() {
|
||||
return apkPath;
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public String getApkPath() {
|
||||
return apkPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,33 +33,36 @@ import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam;
|
|||
* registering it as a callback automatically.
|
||||
*/
|
||||
public interface IXposedHookLoadPackage extends IXposedMod {
|
||||
/**
|
||||
* This method is called when an app is loaded. It's called very early, even before
|
||||
* {@link Application#onCreate} is called.
|
||||
* Modules can set up their app-specific hooks here.
|
||||
*
|
||||
* @param lpparam Information about the app.
|
||||
* @throws Throwable Everything the callback throws is caught and logged.
|
||||
*/
|
||||
void handleLoadPackage(LoadPackageParam lpparam) throws Throwable;
|
||||
/**
|
||||
* This method is called when an app is loaded. It's called very early, even before
|
||||
* {@link Application#onCreate} is called.
|
||||
* Modules can set up their app-specific hooks here.
|
||||
*
|
||||
* @param lpparam Information about the app.
|
||||
* @throws Throwable Everything the callback throws is caught and logged.
|
||||
*/
|
||||
void handleLoadPackage(LoadPackageParam lpparam) throws Throwable;
|
||||
|
||||
/** @hide */
|
||||
final class Wrapper extends XC_LoadPackage {
|
||||
private final IXposedHookLoadPackage instance;
|
||||
private final String apkPath;
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
final class Wrapper extends XC_LoadPackage {
|
||||
private final IXposedHookLoadPackage instance;
|
||||
private final String apkPath;
|
||||
|
||||
public Wrapper(IXposedHookLoadPackage instance, String apkPath) {
|
||||
this.instance = instance;
|
||||
this.apkPath = apkPath;
|
||||
}
|
||||
@Override
|
||||
public void handleLoadPackage(LoadPackageParam lpparam) throws Throwable {
|
||||
instance.handleLoadPackage(lpparam);
|
||||
}
|
||||
public Wrapper(IXposedHookLoadPackage instance, String apkPath) {
|
||||
this.instance = instance;
|
||||
this.apkPath = apkPath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getApkPath() {
|
||||
return apkPath;
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void handleLoadPackage(LoadPackageParam lpparam) throws Throwable {
|
||||
instance.handleLoadPackage(lpparam);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getApkPath() {
|
||||
return apkPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,16 +35,20 @@ import de.robv.android.xposed.callbacks.XCallback;
|
|||
* <p>If you want to hook one/multiple specific apps, use {@link IXposedHookLoadPackage} instead.
|
||||
*/
|
||||
public interface IXposedHookZygoteInit extends IXposedMod {
|
||||
/**
|
||||
* Called very early during startup of Zygote.
|
||||
* @param startupParam Details about the module itself and the started process.
|
||||
* @throws Throwable everything is caught, but will prevent further initialization of the module.
|
||||
*/
|
||||
void initZygote(StartupParam startupParam) throws Throwable;
|
||||
/**
|
||||
* Called very early during startup of Zygote.
|
||||
*
|
||||
* @param startupParam Details about the module itself and the started process.
|
||||
* @throws Throwable everything is caught, but will prevent further initialization of the module.
|
||||
*/
|
||||
void initZygote(StartupParam startupParam) throws Throwable;
|
||||
|
||||
/** Data holder for {@link #initZygote}. */
|
||||
final class StartupParam extends XCallback.Param {
|
||||
/*package*/ StartupParam() {}
|
||||
/**
|
||||
* Data holder for {@link #initZygote}.
|
||||
*/
|
||||
final class StartupParam extends XCallback.Param {
|
||||
/*package*/ StartupParam() {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param callbacks
|
||||
|
|
@ -54,15 +58,17 @@ public interface IXposedHookZygoteInit extends IXposedMod {
|
|||
super(callbacks);
|
||||
}
|
||||
|
||||
/** The path to the module's APK. */
|
||||
public String modulePath;
|
||||
/**
|
||||
* The path to the module's APK.
|
||||
*/
|
||||
public String modulePath;
|
||||
|
||||
/**
|
||||
* Always {@code true} on 32-bit ROMs. On 64-bit, it's only {@code true} for the primary
|
||||
* process that starts the system_server.
|
||||
*/
|
||||
public boolean startsSystemServer;
|
||||
}
|
||||
/**
|
||||
* Always {@code true} on 32-bit ROMs. On 64-bit, it's only {@code true} for the primary
|
||||
* process that starts the system_server.
|
||||
*/
|
||||
public boolean startsSystemServer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
|
|
@ -83,9 +89,9 @@ public interface IXposedHookZygoteInit extends IXposedMod {
|
|||
instance.initZygote(this.startupParam);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getApkPath() {
|
||||
return startupParam.modulePath;
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public String getApkPath() {
|
||||
return startupParam.modulePath;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,5 +20,8 @@
|
|||
|
||||
package de.robv.android.xposed;
|
||||
|
||||
/** Marker interface for Xposed modules. Cannot be implemented directly. */
|
||||
/* package */ interface IXposedMod {}
|
||||
/**
|
||||
* Marker interface for Xposed modules. Cannot be implemented directly.
|
||||
*/
|
||||
/* package */ interface IXposedMod {
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,49 +27,50 @@ import de.robv.android.xposed.services.DirectAccessService;
|
|||
* A helper to work with (or without) SELinux, abstracting much of its big complexity.
|
||||
*/
|
||||
public final class SELinuxHelper {
|
||||
private SELinuxHelper() {}
|
||||
private SELinuxHelper() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether SELinux is disabled or enabled.
|
||||
*
|
||||
* @return A boolean indicating whether SELinux is enabled.
|
||||
*/
|
||||
public static boolean isSELinuxEnabled() {
|
||||
// lsp: always enabled
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Determines whether SELinux is disabled or enabled.
|
||||
*
|
||||
* @return A boolean indicating whether SELinux is enabled.
|
||||
*/
|
||||
public static boolean isSELinuxEnabled() {
|
||||
// lsp: always enabled
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether SELinux is permissive or enforcing.
|
||||
*
|
||||
* @return A boolean indicating whether SELinux is enforcing.
|
||||
*/
|
||||
public static boolean isSELinuxEnforced() {
|
||||
// lsp: always enforcing
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Determines whether SELinux is permissive or enforcing.
|
||||
*
|
||||
* @return A boolean indicating whether SELinux is enforcing.
|
||||
*/
|
||||
public static boolean isSELinuxEnforced() {
|
||||
// lsp: always enforcing
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the security context of the current process.
|
||||
*
|
||||
* @return A String representing the security context of the current process.
|
||||
*/
|
||||
public static String getContext() {
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* Gets the security context of the current process.
|
||||
*
|
||||
* @return A String representing the security context of the current process.
|
||||
*/
|
||||
public static String getContext() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the service to be used when accessing files in {@code /data/data/*}.
|
||||
*
|
||||
* <p class="caution"><strong>IMPORTANT:</strong> If you call this from the Zygote process,
|
||||
* don't re-use the result in different process!
|
||||
*
|
||||
* @return An instance of the service.
|
||||
*/
|
||||
public static BaseService getAppDataFileService() {
|
||||
/**
|
||||
* Retrieve the service to be used when accessing files in {@code /data/data/*}.
|
||||
*
|
||||
* <p class="caution"><strong>IMPORTANT:</strong> If you call this from the Zygote process,
|
||||
* don't re-use the result in different process!
|
||||
*
|
||||
* @return An instance of the service.
|
||||
*/
|
||||
public static BaseService getAppDataFileService() {
|
||||
return sServiceAppDataFile;
|
||||
}
|
||||
|
||||
private static final BaseService sServiceAppDataFile = new DirectAccessService(); // ed: initialized directly
|
||||
private static final BaseService sServiceAppDataFile = new DirectAccessService(); // ed: initialized directly
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,157 +32,175 @@ import de.robv.android.xposed.callbacks.XCallback;
|
|||
* {@link #beforeHookedMethod} and/or {@link #afterHookedMethod}.
|
||||
*/
|
||||
public abstract class XC_MethodHook extends XCallback {
|
||||
/**
|
||||
* Creates a new callback with default priority.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public XC_MethodHook() {
|
||||
super();
|
||||
}
|
||||
/**
|
||||
* Creates a new callback with default priority.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public XC_MethodHook() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new callback with a specific priority.
|
||||
*
|
||||
* <p class="note">Note that {@link #afterHookedMethod} will be called in reversed order, i.e.
|
||||
* the callback with the highest priority will be called last. This way, the callback has the
|
||||
* final control over the return value. {@link #beforeHookedMethod} is called as usual, i.e.
|
||||
* highest priority first.
|
||||
*
|
||||
* @param priority See {@link XCallback#priority}.
|
||||
*/
|
||||
public XC_MethodHook(int priority) {
|
||||
super(priority);
|
||||
}
|
||||
/**
|
||||
* Creates a new callback with a specific priority.
|
||||
*
|
||||
* <p class="note">Note that {@link #afterHookedMethod} will be called in reversed order, i.e.
|
||||
* the callback with the highest priority will be called last. This way, the callback has the
|
||||
* final control over the return value. {@link #beforeHookedMethod} is called as usual, i.e.
|
||||
* highest priority first.
|
||||
*
|
||||
* @param priority See {@link XCallback#priority}.
|
||||
*/
|
||||
public XC_MethodHook(int priority) {
|
||||
super(priority);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called before the invocation of the method.
|
||||
*
|
||||
* <p>You can use {@link MethodHookParam#setResult} and {@link MethodHookParam#setThrowable}
|
||||
* to prevent the original method from being called.
|
||||
*
|
||||
* <p>Note that implementations shouldn't call {@code super(param)}, it's not necessary.
|
||||
*
|
||||
* @param param Information about the method call.
|
||||
* @throws Throwable Everything the callback throws is caught and logged.
|
||||
*/
|
||||
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {}
|
||||
/**
|
||||
* Called before the invocation of the method.
|
||||
*
|
||||
* <p>You can use {@link MethodHookParam#setResult} and {@link MethodHookParam#setThrowable}
|
||||
* to prevent the original method from being called.
|
||||
*
|
||||
* <p>Note that implementations shouldn't call {@code super(param)}, it's not necessary.
|
||||
*
|
||||
* @param param Information about the method call.
|
||||
* @throws Throwable Everything the callback throws is caught and logged.
|
||||
*/
|
||||
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
|
||||
}
|
||||
|
||||
public void callBeforeHookedMethod(MethodHookParam param) throws Throwable {
|
||||
beforeHookedMethod(param);
|
||||
}
|
||||
public void callBeforeHookedMethod(MethodHookParam param) throws Throwable {
|
||||
beforeHookedMethod(param);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called after the invocation of the method.
|
||||
*
|
||||
* <p>You can use {@link MethodHookParam#setResult} and {@link MethodHookParam#setThrowable}
|
||||
* to modify the return value of the original method.
|
||||
*
|
||||
* <p>Note that implementations shouldn't call {@code super(param)}, it's not necessary.
|
||||
*
|
||||
* @param param Information about the method call.
|
||||
* @throws Throwable Everything the callback throws is caught and logged.
|
||||
*/
|
||||
protected void afterHookedMethod(MethodHookParam param) throws Throwable {}
|
||||
/**
|
||||
* Called after the invocation of the method.
|
||||
*
|
||||
* <p>You can use {@link MethodHookParam#setResult} and {@link MethodHookParam#setThrowable}
|
||||
* to modify the return value of the original method.
|
||||
*
|
||||
* <p>Note that implementations shouldn't call {@code super(param)}, it's not necessary.
|
||||
*
|
||||
* @param param Information about the method call.
|
||||
* @throws Throwable Everything the callback throws is caught and logged.
|
||||
*/
|
||||
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
|
||||
}
|
||||
|
||||
public void callAfterHookedMethod(MethodHookParam param) throws Throwable {
|
||||
afterHookedMethod(param);
|
||||
}
|
||||
public void callAfterHookedMethod(MethodHookParam param) throws Throwable {
|
||||
afterHookedMethod(param);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps information about the method call and allows to influence it.
|
||||
*/
|
||||
public static final class MethodHookParam extends XCallback.Param {
|
||||
/** @hide */
|
||||
@SuppressWarnings("deprecation")
|
||||
public MethodHookParam() {
|
||||
super();
|
||||
}
|
||||
/**
|
||||
* Wraps information about the method call and allows to influence it.
|
||||
*/
|
||||
public static final class MethodHookParam extends XCallback.Param {
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public MethodHookParam() {
|
||||
super();
|
||||
}
|
||||
|
||||
/** The hooked method/constructor. */
|
||||
public Member method;
|
||||
/**
|
||||
* The hooked method/constructor.
|
||||
*/
|
||||
public Member method;
|
||||
|
||||
/** The {@code this} reference for an instance method, or {@code null} for static methods. */
|
||||
public Object thisObject;
|
||||
/**
|
||||
* The {@code this} reference for an instance method, or {@code null} for static methods.
|
||||
*/
|
||||
public Object thisObject;
|
||||
|
||||
/** Arguments to the method call. */
|
||||
public Object[] args;
|
||||
/**
|
||||
* Arguments to the method call.
|
||||
*/
|
||||
public Object[] args;
|
||||
|
||||
private Object result = null;
|
||||
private Throwable throwable = null;
|
||||
public boolean returnEarly = false;
|
||||
private Object result = null;
|
||||
private Throwable throwable = null;
|
||||
public boolean returnEarly = false;
|
||||
|
||||
/** Returns the result of the method call. */
|
||||
public Object getResult() {
|
||||
return result;
|
||||
}
|
||||
/**
|
||||
* Returns the result of the method call.
|
||||
*/
|
||||
public Object getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Modify the result of the method call.
|
||||
*
|
||||
* <p>If called from {@link #beforeHookedMethod}, it prevents the call to the original method.
|
||||
*/
|
||||
public void setResult(Object result) {
|
||||
this.result = result;
|
||||
this.throwable = null;
|
||||
this.returnEarly = true;
|
||||
}
|
||||
/**
|
||||
* Modify the result of the method call.
|
||||
*
|
||||
* <p>If called from {@link #beforeHookedMethod}, it prevents the call to the original method.
|
||||
*/
|
||||
public void setResult(Object result) {
|
||||
this.result = result;
|
||||
this.throwable = null;
|
||||
this.returnEarly = true;
|
||||
}
|
||||
|
||||
/** Returns the {@link Throwable} thrown by the method, or {@code null}. */
|
||||
public Throwable getThrowable() {
|
||||
return throwable;
|
||||
}
|
||||
/**
|
||||
* Returns the {@link Throwable} thrown by the method, or {@code null}.
|
||||
*/
|
||||
public Throwable getThrowable() {
|
||||
return throwable;
|
||||
}
|
||||
|
||||
/** Returns true if an exception was thrown by the method. */
|
||||
public boolean hasThrowable() {
|
||||
return throwable != null;
|
||||
}
|
||||
/**
|
||||
* Returns true if an exception was thrown by the method.
|
||||
*/
|
||||
public boolean hasThrowable() {
|
||||
return throwable != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Modify the exception thrown of the method call.
|
||||
*
|
||||
* <p>If called from {@link #beforeHookedMethod}, it prevents the call to the original method.
|
||||
*/
|
||||
public void setThrowable(Throwable throwable) {
|
||||
this.throwable = throwable;
|
||||
this.result = null;
|
||||
this.returnEarly = true;
|
||||
}
|
||||
/**
|
||||
* Modify the exception thrown of the method call.
|
||||
*
|
||||
* <p>If called from {@link #beforeHookedMethod}, it prevents the call to the original method.
|
||||
*/
|
||||
public void setThrowable(Throwable throwable) {
|
||||
this.throwable = throwable;
|
||||
this.result = null;
|
||||
this.returnEarly = true;
|
||||
}
|
||||
|
||||
/** Returns the result of the method call, or throws the Throwable caused by it. */
|
||||
public Object getResultOrThrowable() throws Throwable {
|
||||
if (throwable != null)
|
||||
throw throwable;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Returns the result of the method call, or throws the Throwable caused by it.
|
||||
*/
|
||||
public Object getResultOrThrowable() throws Throwable {
|
||||
if (throwable != null)
|
||||
throw throwable;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An object with which the method/constructor can be unhooked.
|
||||
*/
|
||||
public class Unhook implements IXUnhook<XC_MethodHook> {
|
||||
private final Member hookMethod;
|
||||
/**
|
||||
* An object with which the method/constructor can be unhooked.
|
||||
*/
|
||||
public class Unhook implements IXUnhook<XC_MethodHook> {
|
||||
private final Member hookMethod;
|
||||
|
||||
/*package*/ Unhook(Member hookMethod) {
|
||||
this.hookMethod = hookMethod;
|
||||
}
|
||||
/*package*/ Unhook(Member hookMethod) {
|
||||
this.hookMethod = hookMethod;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the method/constructor that has been hooked.
|
||||
*/
|
||||
public Member getHookedMethod() {
|
||||
return hookMethod;
|
||||
}
|
||||
/**
|
||||
* Returns the method/constructor that has been hooked.
|
||||
*/
|
||||
public Member getHookedMethod() {
|
||||
return hookMethod;
|
||||
}
|
||||
|
||||
@Override
|
||||
public XC_MethodHook getCallback() {
|
||||
return XC_MethodHook.this;
|
||||
}
|
||||
@Override
|
||||
public XC_MethodHook getCallback() {
|
||||
return XC_MethodHook.this;
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public void unhook() {
|
||||
XposedBridge.unhookMethod(hookMethod, XC_MethodHook.this);
|
||||
}
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public void unhook() {
|
||||
XposedBridge.unhookMethod(hookMethod, XC_MethodHook.this);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,83 +26,88 @@ import de.robv.android.xposed.callbacks.XCallback;
|
|||
* A special case of {@link XC_MethodHook} which completely replaces the original method.
|
||||
*/
|
||||
public abstract class XC_MethodReplacement extends XC_MethodHook {
|
||||
/**
|
||||
* Creates a new callback with default priority.
|
||||
*/
|
||||
public XC_MethodReplacement() {
|
||||
super();
|
||||
}
|
||||
/**
|
||||
* Creates a new callback with default priority.
|
||||
*/
|
||||
public XC_MethodReplacement() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new callback with a specific priority.
|
||||
*
|
||||
* @param priority See {@link XCallback#priority}.
|
||||
*/
|
||||
public XC_MethodReplacement(int priority) {
|
||||
super(priority);
|
||||
}
|
||||
/**
|
||||
* Creates a new callback with a specific priority.
|
||||
*
|
||||
* @param priority See {@link XCallback#priority}.
|
||||
*/
|
||||
public XC_MethodReplacement(int priority) {
|
||||
super(priority);
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@Override
|
||||
protected final void beforeHookedMethod(MethodHookParam param) throws Throwable {
|
||||
try {
|
||||
Object result = replaceHookedMethod(param);
|
||||
param.setResult(result);
|
||||
} catch (Throwable t) {
|
||||
XposedBridge.log(t);
|
||||
param.setThrowable(t);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@Override
|
||||
protected final void beforeHookedMethod(MethodHookParam param) throws Throwable {
|
||||
try {
|
||||
Object result = replaceHookedMethod(param);
|
||||
param.setResult(result);
|
||||
} catch (Throwable t) {
|
||||
XposedBridge.log(t);
|
||||
param.setThrowable(t);
|
||||
}
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@Override
|
||||
@SuppressWarnings("EmptyMethod")
|
||||
protected final void afterHookedMethod(MethodHookParam param) throws Throwable {}
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("EmptyMethod")
|
||||
protected final void afterHookedMethod(MethodHookParam param) throws Throwable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Shortcut for replacing a method completely. Whatever is returned/thrown here is taken
|
||||
* instead of the result of the original method (which will not be called).
|
||||
*
|
||||
* <p>Note that implementations shouldn't call {@code super(param)}, it's not necessary.
|
||||
*
|
||||
* @param param Information about the method call.
|
||||
* @throws Throwable Anything that is thrown by the callback will be passed on to the original caller.
|
||||
*/
|
||||
@SuppressWarnings("UnusedParameters")
|
||||
protected abstract Object replaceHookedMethod(MethodHookParam param) throws Throwable;
|
||||
/**
|
||||
* Shortcut for replacing a method completely. Whatever is returned/thrown here is taken
|
||||
* instead of the result of the original method (which will not be called).
|
||||
*
|
||||
* <p>Note that implementations shouldn't call {@code super(param)}, it's not necessary.
|
||||
*
|
||||
* @param param Information about the method call.
|
||||
* @throws Throwable Anything that is thrown by the callback will be passed on to the original caller.
|
||||
*/
|
||||
@SuppressWarnings("UnusedParameters")
|
||||
protected abstract Object replaceHookedMethod(MethodHookParam param) throws Throwable;
|
||||
|
||||
/**
|
||||
* Predefined callback that skips the method without replacements.
|
||||
*/
|
||||
public static final XC_MethodReplacement DO_NOTHING = new XC_MethodReplacement(PRIORITY_HIGHEST*2) {
|
||||
@Override
|
||||
protected Object replaceHookedMethod(MethodHookParam param) throws Throwable {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Predefined callback that skips the method without replacements.
|
||||
*/
|
||||
public static final XC_MethodReplacement DO_NOTHING = new XC_MethodReplacement(PRIORITY_HIGHEST * 2) {
|
||||
@Override
|
||||
protected Object replaceHookedMethod(MethodHookParam param) throws Throwable {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a callback which always returns a specific value.
|
||||
*
|
||||
* @param result The value that should be returned to callers of the hooked method.
|
||||
*/
|
||||
public static XC_MethodReplacement returnConstant(final Object result) {
|
||||
return returnConstant(PRIORITY_DEFAULT, result);
|
||||
}
|
||||
/**
|
||||
* Creates a callback which always returns a specific value.
|
||||
*
|
||||
* @param result The value that should be returned to callers of the hooked method.
|
||||
*/
|
||||
public static XC_MethodReplacement returnConstant(final Object result) {
|
||||
return returnConstant(PRIORITY_DEFAULT, result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Like {@link #returnConstant(Object)}, but allows to specify a priority for the callback.
|
||||
*
|
||||
* @param priority See {@link XCallback#priority}.
|
||||
* @param result The value that should be returned to callers of the hooked method.
|
||||
*/
|
||||
public static XC_MethodReplacement returnConstant(int priority, final Object result) {
|
||||
return new XC_MethodReplacement(priority) {
|
||||
@Override
|
||||
protected Object replaceHookedMethod(MethodHookParam param) throws Throwable {
|
||||
return result;
|
||||
}
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Like {@link #returnConstant(Object)}, but allows to specify a priority for the callback.
|
||||
*
|
||||
* @param priority See {@link XCallback#priority}.
|
||||
* @param result The value that should be returned to callers of the hooked method.
|
||||
*/
|
||||
public static XC_MethodReplacement returnConstant(int priority, final Object result) {
|
||||
return new XC_MethodReplacement(priority) {
|
||||
@Override
|
||||
protected Object replaceHookedMethod(MethodHookParam param) throws Throwable {
|
||||
return result;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ import android.preference.PreferenceManager;
|
|||
import android.util.Log;
|
||||
|
||||
import com.android.internal.util.XmlUtils;
|
||||
|
||||
import org.lsposed.lspd.BuildConfig;
|
||||
import org.lsposed.lspd.util.MetaDataReader;
|
||||
|
||||
|
|
@ -99,7 +100,8 @@ public final class XSharedPreferences implements SharedPreferences {
|
|||
Path dir = (Path) key.watchable();
|
||||
Path path = dir.resolve((Path) event.context());
|
||||
String pathStr = path.toString();
|
||||
if (BuildConfig.DEBUG) Log.v(TAG, "File " + path.toString() + " event: " + kind.name());
|
||||
if (BuildConfig.DEBUG)
|
||||
Log.v(TAG, "File " + path.toString() + " event: " + kind.name());
|
||||
// We react to both real and backup files due to rare race conditions
|
||||
if (pathStr.endsWith(".bak")) {
|
||||
if (kind != StandardWatchEventKinds.ENTRY_DELETE) {
|
||||
|
|
@ -114,7 +116,8 @@ public final class XSharedPreferences implements SharedPreferences {
|
|||
try {
|
||||
l.onSharedPreferenceChanged(data.mPrefs, null);
|
||||
} catch (Throwable t) {
|
||||
if (BuildConfig.DEBUG) Log.e(TAG, "Fail in preference change listener", t);
|
||||
if (BuildConfig.DEBUG)
|
||||
Log.e(TAG, "Fail in preference change listener", t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -183,7 +186,7 @@ public final class XSharedPreferences implements SharedPreferences {
|
|||
}
|
||||
}
|
||||
if (newModule) {
|
||||
mFile = new File(serviceClient.getPrefsPath( packageName ), prefFileName + ".xml");
|
||||
mFile = new File(serviceClient.getPrefsPath(packageName), prefFileName + ".xml");
|
||||
} else {
|
||||
mFile = new File(Environment.getDataDirectory(), "data/" + packageName + "/shared_prefs/" + prefFileName + ".xml");
|
||||
}
|
||||
|
|
@ -209,7 +212,8 @@ public final class XSharedPreferences implements SharedPreferences {
|
|||
if (sWatcherDaemon == null || !sWatcherDaemon.isAlive()) {
|
||||
initWatcherDaemon();
|
||||
}
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, "tryRegisterWatcher: registered file watcher for " + path);
|
||||
if (BuildConfig.DEBUG)
|
||||
Log.d(TAG, "tryRegisterWatcher: registered file watcher for " + path);
|
||||
} catch (AccessDeniedException accDeniedEx) {
|
||||
if (BuildConfig.DEBUG) Log.e(TAG, "tryRegisterWatcher: access denied to " + path);
|
||||
} catch (Exception e) {
|
||||
|
|
@ -232,7 +236,8 @@ public final class XSharedPreferences implements SharedPreferences {
|
|||
if (!atLeastOneValid) {
|
||||
try {
|
||||
sWatcher.close();
|
||||
} catch (Exception ignore) { }
|
||||
} catch (Exception ignore) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -522,7 +527,7 @@ public final class XSharedPreferences implements SharedPreferences {
|
|||
if (listener == null)
|
||||
throw new IllegalArgumentException("listener cannot be null");
|
||||
|
||||
synchronized(this) {
|
||||
synchronized (this) {
|
||||
if (mListeners.put(listener, sContent) == null) {
|
||||
tryRegisterWatcher();
|
||||
}
|
||||
|
|
@ -537,7 +542,7 @@ public final class XSharedPreferences implements SharedPreferences {
|
|||
*/
|
||||
@Override
|
||||
public void unregisterOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener) {
|
||||
synchronized(this) {
|
||||
synchronized (this) {
|
||||
if (mListeners.remove(listener) != null && mListeners.isEmpty()) {
|
||||
tryUnregisterWatcher();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,11 +20,16 @@
|
|||
|
||||
package de.robv.android.xposed;
|
||||
|
||||
import static de.robv.android.xposed.XposedHelpers.setObjectField;
|
||||
|
||||
import android.content.res.Resources;
|
||||
import android.content.res.TypedArray;
|
||||
import android.util.Log;
|
||||
|
||||
import org.lsposed.lspd.BuildConfig;
|
||||
import org.lsposed.lspd.nativebridge.ModuleLogger;
|
||||
import org.lsposed.lspd.nativebridge.ResourcesHook;
|
||||
import org.lsposed.lspd.yahfa.hooker.YahfaHooker;
|
||||
|
||||
import java.lang.reflect.AccessibleObject;
|
||||
import java.lang.reflect.Executable;
|
||||
|
|
@ -43,12 +48,6 @@ import java.util.Set;
|
|||
import de.robv.android.xposed.callbacks.XC_InitPackageResources;
|
||||
import de.robv.android.xposed.callbacks.XC_InitZygote;
|
||||
import de.robv.android.xposed.callbacks.XC_LoadPackage;
|
||||
import org.lsposed.lspd.nativebridge.ModuleLogger;
|
||||
import org.lsposed.lspd.nativebridge.ResourcesHook;
|
||||
import org.lsposed.lspd.yahfa.dexmaker.DynamicBridge;
|
||||
import org.lsposed.lspd.yahfa.hooker.YahfaHooker;
|
||||
|
||||
import static de.robv.android.xposed.XposedHelpers.setObjectField;
|
||||
|
||||
/**
|
||||
* This class contains most of Xposed's central logic, such as initialization and callbacks used by
|
||||
|
|
@ -56,377 +55,373 @@ import static de.robv.android.xposed.XposedHelpers.setObjectField;
|
|||
*/
|
||||
@SuppressWarnings("JniMissingFunction")
|
||||
public final class XposedBridge {
|
||||
/**
|
||||
* The system class loader which can be used to locate Android framework classes.
|
||||
* Application classes cannot be retrieved from it.
|
||||
*
|
||||
* @see ClassLoader#getSystemClassLoader
|
||||
*/
|
||||
public static final ClassLoader BOOTCLASSLOADER = XposedBridge.class.getClassLoader();
|
||||
/**
|
||||
* The system class loader which can be used to locate Android framework classes.
|
||||
* Application classes cannot be retrieved from it.
|
||||
*
|
||||
* @see ClassLoader#getSystemClassLoader
|
||||
*/
|
||||
public static final ClassLoader BOOTCLASSLOADER = XposedBridge.class.getClassLoader();
|
||||
|
||||
/** @hide */
|
||||
public static final String TAG = "LSPosed-Bridge";
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public static final String TAG = "LSPosed-Bridge";
|
||||
|
||||
/** @deprecated Use {@link #getXposedVersion()} instead. */
|
||||
@Deprecated
|
||||
public static int XPOSED_BRIDGE_VERSION;
|
||||
/**
|
||||
* @deprecated Use {@link #getXposedVersion()} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public static int XPOSED_BRIDGE_VERSION;
|
||||
|
||||
/*package*/ static boolean isZygote = true; // ed: RuntimeInit.main() tool process not supported yet
|
||||
private static final Object[] EMPTY_ARRAY = new Object[0];
|
||||
|
||||
// This field is set "magically" on MIUI.
|
||||
/*package*/ static long BOOT_START_TIME;
|
||||
// built-in handlers
|
||||
private static final Map<Member, CopyOnWriteSortedSet<XC_MethodHook>> sHookedMethodCallbacks = new NoValuesHashMap<>();
|
||||
public static final CopyOnWriteSortedSet<XC_LoadPackage> sLoadedPackageCallbacks = new CopyOnWriteSortedSet<>();
|
||||
/*package*/ static final CopyOnWriteSortedSet<XC_InitPackageResources> sInitPackageResourcesCallbacks = new CopyOnWriteSortedSet<>();
|
||||
/*package*/ static final CopyOnWriteSortedSet<XC_InitZygote> sInitZygoteCallbacks = new CopyOnWriteSortedSet<>();
|
||||
|
||||
private static final Object[] EMPTY_ARRAY = new Object[0];
|
||||
private XposedBridge() {
|
||||
}
|
||||
|
||||
// built-in handlers
|
||||
private static final Map<Member, CopyOnWriteSortedSet<XC_MethodHook>> sHookedMethodCallbacks = new NoValuesHashMap<>();
|
||||
public static final CopyOnWriteSortedSet<XC_LoadPackage> sLoadedPackageCallbacks = new CopyOnWriteSortedSet<>();
|
||||
/*package*/ static final CopyOnWriteSortedSet<XC_InitPackageResources> sInitPackageResourcesCallbacks = new CopyOnWriteSortedSet<>();
|
||||
/*package*/ static final CopyOnWriteSortedSet<XC_InitZygote> sInitZygoteCallbacks = new CopyOnWriteSortedSet<>();
|
||||
public static volatile ClassLoader dummyClassLoader = null;
|
||||
|
||||
private XposedBridge() {}
|
||||
|
||||
public static volatile ClassLoader dummyClassLoader = null;
|
||||
|
||||
public static void initXResources() {
|
||||
public static void initXResources() {
|
||||
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);
|
||||
}
|
||||
ResourcesHook.removeFinalFlagNative(resClass);
|
||||
ResourcesHook.removeFinalFlagNative(taClass);
|
||||
ClassLoader myCL = XposedBridge.class.getClassLoader();
|
||||
dummyClassLoader = ResourcesHook.buildDummyClassLoader(myCL.getParent(), resClass, taClass);
|
||||
dummyClassLoader.loadClass("xposed.dummy.XResourcesSuperClass");
|
||||
dummyClassLoader.loadClass("xposed.dummy.XTypedArraySuperClass");
|
||||
setObjectField(myCL, "parent", dummyClassLoader);
|
||||
} catch (Throwable throwable) {
|
||||
XposedBridge.log(throwable);
|
||||
XposedInit.disableResources = true;
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
ResourcesHook.removeFinalFlagNative(resClass);
|
||||
ResourcesHook.removeFinalFlagNative(taClass);
|
||||
ClassLoader myCL = XposedBridge.class.getClassLoader();
|
||||
dummyClassLoader = ResourcesHook.buildDummyClassLoader(myCL.getParent(), resClass, taClass);
|
||||
dummyClassLoader.loadClass("xposed.dummy.XResourcesSuperClass");
|
||||
dummyClassLoader.loadClass("xposed.dummy.XTypedArraySuperClass");
|
||||
setObjectField(myCL, "parent", dummyClassLoader);
|
||||
} catch (Throwable throwable) {
|
||||
XposedBridge.log(throwable);
|
||||
XposedInit.disableResources = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the currently installed version of the Xposed framework.
|
||||
*/
|
||||
public static int getXposedVersion() {
|
||||
return BuildConfig.API_CODE;
|
||||
}
|
||||
/**
|
||||
* Returns the currently installed version of the Xposed framework.
|
||||
*/
|
||||
public static int getXposedVersion() {
|
||||
return BuildConfig.API_CODE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a message to the Xposed modules log.
|
||||
*
|
||||
* <p class="warning"><b>DON'T FLOOD THE LOG!!!</b> This is only meant for error logging.
|
||||
* If you want to write information/debug messages, use logcat.
|
||||
*
|
||||
* @param text The log message.
|
||||
*/
|
||||
public synchronized static void log(String text) {
|
||||
Log.i(TAG, text);
|
||||
ModuleLogger.log(text, false);
|
||||
}
|
||||
/**
|
||||
* Writes a message to the Xposed modules log.
|
||||
*
|
||||
* <p class="warning"><b>DON'T FLOOD THE LOG!!!</b> This is only meant for error logging.
|
||||
* If you want to write information/debug messages, use logcat.
|
||||
*
|
||||
* @param text The log message.
|
||||
*/
|
||||
public synchronized static void log(String text) {
|
||||
Log.i(TAG, text);
|
||||
ModuleLogger.log(text, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs a stack trace to the Xposed modules log.
|
||||
*
|
||||
* <p class="warning"><b>DON'T FLOOD THE LOG!!!</b> This is only meant for error logging.
|
||||
* If you want to write information/debug messages, use logcat.
|
||||
*
|
||||
* @param t The Throwable object for the stack trace.
|
||||
*/
|
||||
public synchronized static void log(Throwable t) {
|
||||
String logStr = Log.getStackTraceString(t);
|
||||
Log.e(TAG, logStr);
|
||||
ModuleLogger.log(logStr, true);
|
||||
}
|
||||
/**
|
||||
* Logs a stack trace to the Xposed modules log.
|
||||
*
|
||||
* <p class="warning"><b>DON'T FLOOD THE LOG!!!</b> This is only meant for error logging.
|
||||
* If you want to write information/debug messages, use logcat.
|
||||
*
|
||||
* @param t The Throwable object for the stack trace.
|
||||
*/
|
||||
public synchronized static void log(Throwable t) {
|
||||
String logStr = Log.getStackTraceString(t);
|
||||
Log.e(TAG, logStr);
|
||||
ModuleLogger.log(logStr, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook any method (or constructor) with the specified callback. See below for some wrappers
|
||||
* that make it easier to find a method/constructor in one step.
|
||||
*
|
||||
* @param hookMethod The method to be hooked.
|
||||
* @param callback The callback to be executed when the hooked method is called.
|
||||
* @return An object that can be used to remove the hook.
|
||||
*
|
||||
* @see XposedHelpers#findAndHookMethod(String, ClassLoader, String, Object...)
|
||||
* @see XposedHelpers#findAndHookMethod(Class, String, Object...)
|
||||
* @see #hookAllMethods
|
||||
* @see XposedHelpers#findAndHookConstructor(String, ClassLoader, Object...)
|
||||
* @see XposedHelpers#findAndHookConstructor(Class, Object...)
|
||||
* @see #hookAllConstructors
|
||||
*/
|
||||
public static XC_MethodHook.Unhook hookMethod(Member hookMethod, XC_MethodHook callback) {
|
||||
if (!(hookMethod instanceof Executable)) {
|
||||
throw new IllegalArgumentException("Only methods and constructors can be hooked: " + hookMethod.toString());
|
||||
}
|
||||
// No check interface because there may be default methods
|
||||
/**
|
||||
* Hook any method (or constructor) with the specified callback. See below for some wrappers
|
||||
* that make it easier to find a method/constructor in one step.
|
||||
*
|
||||
* @param hookMethod The method to be hooked.
|
||||
* @param callback The callback to be executed when the hooked method is called.
|
||||
* @return An object that can be used to remove the hook.
|
||||
* @see XposedHelpers#findAndHookMethod(String, ClassLoader, String, Object...)
|
||||
* @see XposedHelpers#findAndHookMethod(Class, String, Object...)
|
||||
* @see #hookAllMethods
|
||||
* @see XposedHelpers#findAndHookConstructor(String, ClassLoader, Object...)
|
||||
* @see XposedHelpers#findAndHookConstructor(Class, Object...)
|
||||
* @see #hookAllConstructors
|
||||
*/
|
||||
public static XC_MethodHook.Unhook hookMethod(Member hookMethod, XC_MethodHook callback) {
|
||||
if (!(hookMethod instanceof Executable)) {
|
||||
throw new IllegalArgumentException("Only methods and constructors can be hooked: " + hookMethod.toString());
|
||||
}
|
||||
// No check interface because there may be default methods
|
||||
/*else if (hookMethod.getDeclaringClass().isInterface()) {
|
||||
throw new IllegalArgumentException("Cannot hook interfaces: " + hookMethod.toString());
|
||||
}*/
|
||||
else if (Modifier.isAbstract(hookMethod.getModifiers())) {
|
||||
throw new IllegalArgumentException("Cannot hook abstract methods: " + hookMethod.toString());
|
||||
}
|
||||
else if (Modifier.isAbstract(hookMethod.getModifiers())) {
|
||||
throw new IllegalArgumentException("Cannot hook abstract methods: " + hookMethod.toString());
|
||||
}
|
||||
|
||||
Executable targetMethod = (Executable) hookMethod;
|
||||
Executable targetMethod = (Executable) hookMethod;
|
||||
|
||||
if (callback == null) {
|
||||
throw new IllegalArgumentException("callback should not be null!");
|
||||
}
|
||||
if (callback == null) {
|
||||
throw new IllegalArgumentException("callback should not be null!");
|
||||
}
|
||||
|
||||
boolean newMethod = false;
|
||||
CopyOnWriteSortedSet<XC_MethodHook> callbacks;
|
||||
synchronized (sHookedMethodCallbacks) {
|
||||
callbacks = sHookedMethodCallbacks.get(targetMethod);
|
||||
if (callbacks == null) {
|
||||
callbacks = new CopyOnWriteSortedSet<>();
|
||||
sHookedMethodCallbacks.put(targetMethod, callbacks);
|
||||
newMethod = true;
|
||||
}
|
||||
}
|
||||
callbacks.add(callback);
|
||||
boolean newMethod = false;
|
||||
CopyOnWriteSortedSet<XC_MethodHook> callbacks;
|
||||
synchronized (sHookedMethodCallbacks) {
|
||||
callbacks = sHookedMethodCallbacks.get(targetMethod);
|
||||
if (callbacks == null) {
|
||||
callbacks = new CopyOnWriteSortedSet<>();
|
||||
sHookedMethodCallbacks.put(targetMethod, callbacks);
|
||||
newMethod = true;
|
||||
}
|
||||
}
|
||||
callbacks.add(callback);
|
||||
|
||||
if (newMethod) {
|
||||
AdditionalHookInfo additionalInfo = new AdditionalHookInfo(callbacks);
|
||||
if (newMethod) {
|
||||
AdditionalHookInfo additionalInfo = new AdditionalHookInfo(callbacks);
|
||||
if (!YahfaHooker.shouldDelayHook(targetMethod)) {
|
||||
YahfaHooker.hookMethod(targetMethod, additionalInfo);
|
||||
} else {
|
||||
PendingHooks.recordPendingMethod((Method)hookMethod, additionalInfo);
|
||||
}
|
||||
YahfaHooker.hookMethod(targetMethod, additionalInfo);
|
||||
} else {
|
||||
PendingHooks.recordPendingMethod((Method) hookMethod, additionalInfo);
|
||||
}
|
||||
}
|
||||
|
||||
return callback.new Unhook(hookMethod);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the callback for a hooked method/constructor.
|
||||
*
|
||||
* @deprecated Use {@link XC_MethodHook.Unhook#unhook} instead. An instance of the {@code Unhook}
|
||||
* class is returned when you hook the method.
|
||||
*
|
||||
* @param hookMethod The method for which the callback should be removed.
|
||||
* @param callback The reference to the callback as specified in {@link #hookMethod}.
|
||||
*/
|
||||
@Deprecated
|
||||
public static void unhookMethod(Member hookMethod, XC_MethodHook callback) {
|
||||
CopyOnWriteSortedSet<XC_MethodHook> callbacks;
|
||||
synchronized (sHookedMethodCallbacks) {
|
||||
callbacks = sHookedMethodCallbacks.get(hookMethod);
|
||||
if (callbacks == null)
|
||||
return;
|
||||
}
|
||||
callbacks.remove(callback);
|
||||
}
|
||||
/**
|
||||
* Removes the callback for a hooked method/constructor.
|
||||
*
|
||||
* @param hookMethod The method for which the callback should be removed.
|
||||
* @param callback The reference to the callback as specified in {@link #hookMethod}.
|
||||
* @deprecated Use {@link XC_MethodHook.Unhook#unhook} instead. An instance of the {@code Unhook}
|
||||
* class is returned when you hook the method.
|
||||
*/
|
||||
@Deprecated
|
||||
public static void unhookMethod(Member hookMethod, XC_MethodHook callback) {
|
||||
CopyOnWriteSortedSet<XC_MethodHook> callbacks;
|
||||
synchronized (sHookedMethodCallbacks) {
|
||||
callbacks = sHookedMethodCallbacks.get(hookMethod);
|
||||
if (callbacks == null)
|
||||
return;
|
||||
}
|
||||
callbacks.remove(callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hooks all methods with a certain name that were declared in the specified class. Inherited
|
||||
* methods and constructors are not considered. For constructors, use
|
||||
* {@link #hookAllConstructors} instead.
|
||||
*
|
||||
* @param hookClass The class to check for declared methods.
|
||||
* @param methodName The name of the method(s) to hook.
|
||||
* @param callback The callback to be executed when the hooked methods are called.
|
||||
* @return A set containing one object for each found method which can be used to unhook it.
|
||||
*/
|
||||
@SuppressWarnings("UnusedReturnValue")
|
||||
public static Set<XC_MethodHook.Unhook> hookAllMethods(Class<?> hookClass, String methodName, XC_MethodHook callback) {
|
||||
Set<XC_MethodHook.Unhook> unhooks = new HashSet<>();
|
||||
for (Member method : hookClass.getDeclaredMethods())
|
||||
if (method.getName().equals(methodName))
|
||||
unhooks.add(hookMethod(method, callback));
|
||||
return unhooks;
|
||||
}
|
||||
/**
|
||||
* Hooks all methods with a certain name that were declared in the specified class. Inherited
|
||||
* methods and constructors are not considered. For constructors, use
|
||||
* {@link #hookAllConstructors} instead.
|
||||
*
|
||||
* @param hookClass The class to check for declared methods.
|
||||
* @param methodName The name of the method(s) to hook.
|
||||
* @param callback The callback to be executed when the hooked methods are called.
|
||||
* @return A set containing one object for each found method which can be used to unhook it.
|
||||
*/
|
||||
@SuppressWarnings("UnusedReturnValue")
|
||||
public static Set<XC_MethodHook.Unhook> hookAllMethods(Class<?> hookClass, String methodName, XC_MethodHook callback) {
|
||||
Set<XC_MethodHook.Unhook> unhooks = new HashSet<>();
|
||||
for (Member method : hookClass.getDeclaredMethods())
|
||||
if (method.getName().equals(methodName))
|
||||
unhooks.add(hookMethod(method, callback));
|
||||
return unhooks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook all constructors of the specified class.
|
||||
*
|
||||
* @param hookClass The class to check for constructors.
|
||||
* @param callback The callback to be executed when the hooked constructors are called.
|
||||
* @return A set containing one object for each found constructor which can be used to unhook it.
|
||||
*/
|
||||
@SuppressWarnings("UnusedReturnValue")
|
||||
public static Set<XC_MethodHook.Unhook> hookAllConstructors(Class<?> hookClass, XC_MethodHook callback) {
|
||||
Set<XC_MethodHook.Unhook> unhooks = new HashSet<>();
|
||||
for (Member constructor : hookClass.getDeclaredConstructors())
|
||||
unhooks.add(hookMethod(constructor, callback));
|
||||
return unhooks;
|
||||
}
|
||||
/**
|
||||
* Hook all constructors of the specified class.
|
||||
*
|
||||
* @param hookClass The class to check for constructors.
|
||||
* @param callback The callback to be executed when the hooked constructors are called.
|
||||
* @return A set containing one object for each found constructor which can be used to unhook it.
|
||||
*/
|
||||
@SuppressWarnings("UnusedReturnValue")
|
||||
public static Set<XC_MethodHook.Unhook> hookAllConstructors(Class<?> hookClass, XC_MethodHook callback) {
|
||||
Set<XC_MethodHook.Unhook> unhooks = new HashSet<>();
|
||||
for (Member constructor : hookClass.getDeclaredConstructors())
|
||||
unhooks.add(hookMethod(constructor, callback));
|
||||
return unhooks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a callback to be executed when an app ("Android package") is loaded.
|
||||
*
|
||||
* <p class="note">You probably don't need to call this. Simply implement {@link IXposedHookLoadPackage}
|
||||
* in your module class and Xposed will take care of registering it as a callback.
|
||||
*
|
||||
* @param callback The callback to be executed.
|
||||
* @hide
|
||||
*/
|
||||
public static void hookLoadPackage(XC_LoadPackage callback) {
|
||||
synchronized (sLoadedPackageCallbacks) {
|
||||
sLoadedPackageCallbacks.add(callback);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Adds a callback to be executed when an app ("Android package") is loaded.
|
||||
*
|
||||
* <p class="note">You probably don't need to call this. Simply implement {@link IXposedHookLoadPackage}
|
||||
* in your module class and Xposed will take care of registering it as a callback.
|
||||
*
|
||||
* @param callback The callback to be executed.
|
||||
* @hide
|
||||
*/
|
||||
public static void hookLoadPackage(XC_LoadPackage callback) {
|
||||
synchronized (sLoadedPackageCallbacks) {
|
||||
sLoadedPackageCallbacks.add(callback);
|
||||
}
|
||||
}
|
||||
|
||||
public static void clearLoadedPackages() {
|
||||
synchronized (sLoadedPackageCallbacks) {
|
||||
sLoadedPackageCallbacks.clear();
|
||||
}
|
||||
}
|
||||
public static void clearLoadedPackages() {
|
||||
synchronized (sLoadedPackageCallbacks) {
|
||||
sLoadedPackageCallbacks.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a callback to be executed when the resources for an app are initialized.
|
||||
*
|
||||
* <p class="note">You probably don't need to call this. Simply implement {@link IXposedHookInitPackageResources}
|
||||
* in your module class and Xposed will take care of registering it as a callback.
|
||||
*
|
||||
* @param callback The callback to be executed.
|
||||
* @hide
|
||||
*/
|
||||
public static void hookInitPackageResources(XC_InitPackageResources callback) {
|
||||
synchronized (sInitPackageResourcesCallbacks) {
|
||||
sInitPackageResourcesCallbacks.add(callback);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Adds a callback to be executed when the resources for an app are initialized.
|
||||
*
|
||||
* <p class="note">You probably don't need to call this. Simply implement {@link IXposedHookInitPackageResources}
|
||||
* in your module class and Xposed will take care of registering it as a callback.
|
||||
*
|
||||
* @param callback The callback to be executed.
|
||||
* @hide
|
||||
*/
|
||||
public static void hookInitPackageResources(XC_InitPackageResources callback) {
|
||||
synchronized (sInitPackageResourcesCallbacks) {
|
||||
sInitPackageResourcesCallbacks.add(callback);
|
||||
}
|
||||
}
|
||||
|
||||
public static void hookInitZygote(XC_InitZygote callback) {
|
||||
synchronized (sInitZygoteCallbacks) {
|
||||
sInitZygoteCallbacks.add(callback);
|
||||
}
|
||||
}
|
||||
public static void hookInitZygote(XC_InitZygote callback) {
|
||||
synchronized (sInitZygoteCallbacks) {
|
||||
sInitZygoteCallbacks.add(callback);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Basically the same as {@link Method#invoke}, but calls the original method
|
||||
* as it was before the interception by Xposed. Also, access permissions are not checked.
|
||||
*
|
||||
* <p class="caution">There are very few cases where this method is needed. A common mistake is
|
||||
* to replace a method and then invoke the original one based on dynamic conditions. This
|
||||
* creates overhead and skips further hooks by other modules. Instead, just hook (don't replace)
|
||||
* the method and call {@code param.setResult(null)} in {@link XC_MethodHook#beforeHookedMethod}
|
||||
* if the original method should be skipped.
|
||||
*
|
||||
* @param method The method to be called.
|
||||
* @param thisObject For non-static calls, the "this" pointer, otherwise {@code null}.
|
||||
* @param args Arguments for the method call as Object[] array.
|
||||
* @return The result returned from the invoked method.
|
||||
* @throws NullPointerException
|
||||
* if {@code receiver == null} for a non-static method
|
||||
* @throws IllegalAccessException
|
||||
* if this method is not accessible (see {@link AccessibleObject})
|
||||
* @throws IllegalArgumentException
|
||||
* if the number of arguments doesn't match the number of parameters, the receiver
|
||||
* is incompatible with the declaring class, or an argument could not be unboxed
|
||||
* or converted by a widening conversion to the corresponding parameter type
|
||||
* @throws InvocationTargetException
|
||||
* if an exception was thrown by the invoked method
|
||||
*/
|
||||
public static Object invokeOriginalMethod(Member method, Object thisObject, Object[] args)
|
||||
throws Throwable {
|
||||
if (args == null) {
|
||||
args = EMPTY_ARRAY;
|
||||
}
|
||||
/**
|
||||
* Basically the same as {@link Method#invoke}, but calls the original method
|
||||
* as it was before the interception by Xposed. Also, access permissions are not checked.
|
||||
*
|
||||
* <p class="caution">There are very few cases where this method is needed. A common mistake is
|
||||
* to replace a method and then invoke the original one based on dynamic conditions. This
|
||||
* creates overhead and skips further hooks by other modules. Instead, just hook (don't replace)
|
||||
* the method and call {@code param.setResult(null)} in {@link XC_MethodHook#beforeHookedMethod}
|
||||
* if the original method should be skipped.
|
||||
*
|
||||
* @param method The method to be called.
|
||||
* @param thisObject For non-static calls, the "this" pointer, otherwise {@code null}.
|
||||
* @param args Arguments for the method call as Object[] array.
|
||||
* @return The result returned from the invoked method.
|
||||
* @throws NullPointerException if {@code receiver == null} for a non-static method
|
||||
* @throws IllegalAccessException if this method is not accessible (see {@link AccessibleObject})
|
||||
* @throws IllegalArgumentException if the number of arguments doesn't match the number of parameters, the receiver
|
||||
* is incompatible with the declaring class, or an argument could not be unboxed
|
||||
* or converted by a widening conversion to the corresponding parameter type
|
||||
* @throws InvocationTargetException if an exception was thrown by the invoked method
|
||||
*/
|
||||
public static Object invokeOriginalMethod(Member method, Object thisObject, Object[] args)
|
||||
throws Throwable {
|
||||
if (args == null) {
|
||||
args = EMPTY_ARRAY;
|
||||
}
|
||||
|
||||
if (!(method instanceof Executable)) {
|
||||
throw new IllegalArgumentException("method must be of type Method or Constructor");
|
||||
}
|
||||
if (!(method instanceof Executable)) {
|
||||
throw new IllegalArgumentException("method must be of type Method or Constructor");
|
||||
}
|
||||
|
||||
return YahfaHooker.invokeOriginalMethod((Executable) method, thisObject, args);
|
||||
}
|
||||
return YahfaHooker.invokeOriginalMethod((Executable) method, thisObject, args);
|
||||
}
|
||||
|
||||
private static class NoValuesHashMap<K,V> extends HashMap<K,V> {
|
||||
@Override
|
||||
public Collection values() {
|
||||
return Collections.EMPTY_LIST;
|
||||
}
|
||||
private static class NoValuesHashMap<K, V> extends HashMap<K, V> {
|
||||
@Override
|
||||
public Collection values() {
|
||||
return Collections.EMPTY_LIST;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
@Override
|
||||
public void clear() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<K> keySet() {
|
||||
return Collections.EMPTY_SET;
|
||||
}
|
||||
@Override
|
||||
public Set<K> keySet() {
|
||||
return Collections.EMPTY_SET;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Entry<K, V>> entrySet() {
|
||||
return Collections.EMPTY_SET;
|
||||
}
|
||||
@Override
|
||||
public Set<Entry<K, V>> entrySet() {
|
||||
return Collections.EMPTY_SET;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return 0;
|
||||
}
|
||||
@Override
|
||||
public int size() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public static final class CopyOnWriteSortedSet<E> {
|
||||
private transient volatile Object[] elements = EMPTY_ARRAY;
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public static final class CopyOnWriteSortedSet<E> {
|
||||
private transient volatile Object[] elements = EMPTY_ARRAY;
|
||||
|
||||
@SuppressWarnings("UnusedReturnValue")
|
||||
public synchronized boolean add(E e) {
|
||||
int index = indexOf(e);
|
||||
if (index >= 0)
|
||||
return false;
|
||||
@SuppressWarnings("UnusedReturnValue")
|
||||
public synchronized boolean add(E e) {
|
||||
int index = indexOf(e);
|
||||
if (index >= 0)
|
||||
return false;
|
||||
|
||||
Object[] newElements = new Object[elements.length + 1];
|
||||
System.arraycopy(elements, 0, newElements, 0, elements.length);
|
||||
newElements[elements.length] = e;
|
||||
Arrays.sort(newElements);
|
||||
elements = newElements;
|
||||
return true;
|
||||
}
|
||||
Object[] newElements = new Object[elements.length + 1];
|
||||
System.arraycopy(elements, 0, newElements, 0, elements.length);
|
||||
newElements[elements.length] = e;
|
||||
Arrays.sort(newElements);
|
||||
elements = newElements;
|
||||
return true;
|
||||
}
|
||||
|
||||
@SuppressWarnings("UnusedReturnValue")
|
||||
public synchronized boolean remove(E e) {
|
||||
int index = indexOf(e);
|
||||
if (index == -1)
|
||||
return false;
|
||||
@SuppressWarnings("UnusedReturnValue")
|
||||
public synchronized boolean remove(E e) {
|
||||
int index = indexOf(e);
|
||||
if (index == -1)
|
||||
return false;
|
||||
|
||||
Object[] newElements = new Object[elements.length - 1];
|
||||
System.arraycopy(elements, 0, newElements, 0, index);
|
||||
System.arraycopy(elements, index + 1, newElements, index, elements.length - index - 1);
|
||||
elements = newElements;
|
||||
return true;
|
||||
}
|
||||
Object[] newElements = new Object[elements.length - 1];
|
||||
System.arraycopy(elements, 0, newElements, 0, index);
|
||||
System.arraycopy(elements, index + 1, newElements, index, elements.length - index - 1);
|
||||
elements = newElements;
|
||||
return true;
|
||||
}
|
||||
|
||||
private int indexOf(Object o) {
|
||||
for (int i = 0; i < elements.length; i++) {
|
||||
if (o.equals(elements[i]))
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
private int indexOf(Object o) {
|
||||
for (int i = 0; i < elements.length; i++) {
|
||||
if (o.equals(elements[i]))
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public Object[] getSnapshot() {
|
||||
return elements;
|
||||
}
|
||||
public Object[] getSnapshot() {
|
||||
return elements;
|
||||
}
|
||||
|
||||
public synchronized void clear() {
|
||||
elements = EMPTY_ARRAY;
|
||||
}
|
||||
}
|
||||
public synchronized void clear() {
|
||||
elements = EMPTY_ARRAY;
|
||||
}
|
||||
}
|
||||
|
||||
public static class AdditionalHookInfo {
|
||||
public final CopyOnWriteSortedSet<XC_MethodHook> callbacks;
|
||||
public static class AdditionalHookInfo {
|
||||
public final CopyOnWriteSortedSet<XC_MethodHook> callbacks;
|
||||
|
||||
private AdditionalHookInfo(CopyOnWriteSortedSet<XC_MethodHook> callbacks) {
|
||||
this.callbacks = callbacks;
|
||||
}
|
||||
}
|
||||
private AdditionalHookInfo(CopyOnWriteSortedSet<XC_MethodHook> callbacks) {
|
||||
this.callbacks = callbacks;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -20,6 +20,18 @@
|
|||
|
||||
package de.robv.android.xposed;
|
||||
|
||||
import static org.lsposed.lspd.config.LSPApplicationServiceClient.serviceClient;
|
||||
import static de.robv.android.xposed.XposedBridge.hookAllMethods;
|
||||
import static de.robv.android.xposed.XposedBridge.sInitPackageResourcesCallbacks;
|
||||
import static de.robv.android.xposed.XposedBridge.sInitZygoteCallbacks;
|
||||
import static de.robv.android.xposed.XposedBridge.sLoadedPackageCallbacks;
|
||||
import static de.robv.android.xposed.XposedHelpers.callMethod;
|
||||
import static de.robv.android.xposed.XposedHelpers.closeSilently;
|
||||
import static de.robv.android.xposed.XposedHelpers.findAndHookMethod;
|
||||
import static de.robv.android.xposed.XposedHelpers.getObjectField;
|
||||
import static de.robv.android.xposed.XposedHelpers.getParameterIndexByType;
|
||||
import static de.robv.android.xposed.XposedHelpers.setStaticObjectField;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.res.Resources;
|
||||
|
|
@ -32,7 +44,8 @@ import android.os.Process;
|
|||
import android.util.ArraySet;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.os.ZygoteInit;
|
||||
import org.lsposed.lspd.nativebridge.NativeAPI;
|
||||
import org.lsposed.lspd.nativebridge.ResourcesHook;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
|
|
@ -52,56 +65,14 @@ import de.robv.android.xposed.callbacks.XC_InitZygote;
|
|||
import de.robv.android.xposed.callbacks.XC_LoadPackage;
|
||||
import de.robv.android.xposed.callbacks.XCallback;
|
||||
import hidden.HiddenApiBridge;
|
||||
import org.lsposed.lspd.nativebridge.NativeAPI;
|
||||
import org.lsposed.lspd.nativebridge.ResourcesHook;
|
||||
|
||||
import static de.robv.android.xposed.XposedBridge.hookAllMethods;
|
||||
import static de.robv.android.xposed.XposedBridge.sInitPackageResourcesCallbacks;
|
||||
import static de.robv.android.xposed.XposedBridge.sInitZygoteCallbacks;
|
||||
import static de.robv.android.xposed.XposedBridge.sLoadedPackageCallbacks;
|
||||
import static de.robv.android.xposed.XposedHelpers.callMethod;
|
||||
import static de.robv.android.xposed.XposedHelpers.closeSilently;
|
||||
import static de.robv.android.xposed.XposedHelpers.findAndHookMethod;
|
||||
import static de.robv.android.xposed.XposedHelpers.findClass;
|
||||
import static de.robv.android.xposed.XposedHelpers.findFieldIfExists;
|
||||
import static de.robv.android.xposed.XposedHelpers.getObjectField;
|
||||
import static de.robv.android.xposed.XposedHelpers.getParameterIndexByType;
|
||||
import static de.robv.android.xposed.XposedHelpers.setStaticBooleanField;
|
||||
import static de.robv.android.xposed.XposedHelpers.setStaticLongField;
|
||||
import static de.robv.android.xposed.XposedHelpers.setStaticObjectField;
|
||||
import static org.lsposed.lspd.config.LSPApplicationServiceClient.serviceClient;
|
||||
|
||||
public final class XposedInit {
|
||||
private static final String TAG = XposedBridge.TAG;
|
||||
public static boolean startsSystemServer = false;
|
||||
private static final String startClassName = ""; // ed: no support for tool process anymore
|
||||
|
||||
public static volatile boolean disableResources = false;
|
||||
|
||||
private XposedInit() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook some methods which we want to create an easier interface for developers.
|
||||
*/
|
||||
/*package*/
|
||||
public static void initForZygote() throws Throwable {
|
||||
// TODO Are these still needed for us?
|
||||
// MIUI
|
||||
if (findFieldIfExists(ZygoteInit.class, "BOOT_START_TIME") != null) {
|
||||
setStaticLongField(ZygoteInit.class, "BOOT_START_TIME", XposedBridge.BOOT_START_TIME);
|
||||
}
|
||||
// Samsung
|
||||
Class<?> zygote = findClass("com.android.internal.os.Zygote", null);
|
||||
try {
|
||||
setStaticBooleanField(zygote, "isEnhancedZygoteASLREnabled", false);
|
||||
} catch (NoSuchFieldError ignored) {
|
||||
}
|
||||
|
||||
hookResources();
|
||||
}
|
||||
|
||||
private static void hookResources() throws Throwable {
|
||||
public static void hookResources() throws Throwable {
|
||||
if (!serviceClient.isResourcesHookEnabled() || disableResources) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -242,7 +213,7 @@ public final class XposedInit {
|
|||
}
|
||||
}
|
||||
|
||||
public static boolean loadModules(boolean callInitZygote) throws IOException {
|
||||
public static boolean loadModules() throws IOException {
|
||||
boolean hasLoaded = !modulesLoaded.compareAndSet(false, true);
|
||||
if (hasLoaded) {
|
||||
return false;
|
||||
|
|
@ -256,7 +227,7 @@ public final class XposedInit {
|
|||
newLoadedApk.add(apk);
|
||||
} else {
|
||||
loadedModules.add(apk); // temporarily add it for XSharedPreference
|
||||
boolean loadSuccess = loadModule(apk, callInitZygote);
|
||||
boolean loadSuccess = loadModule(apk);
|
||||
if (loadSuccess) {
|
||||
newLoadedApk.add(apk);
|
||||
}
|
||||
|
|
@ -326,7 +297,7 @@ public final class XposedInit {
|
|||
|
||||
}
|
||||
|
||||
private static boolean initModule(ClassLoader mcl, String apk, boolean callInitZygote) {
|
||||
private static boolean initModule(ClassLoader mcl, String apk) {
|
||||
InputStream is = mcl.getResourceAsStream("assets/xposed_init");
|
||||
if (is == null) {
|
||||
return true;
|
||||
|
|
@ -359,9 +330,7 @@ public final class XposedInit {
|
|||
|
||||
XposedBridge.hookInitZygote(new IXposedHookZygoteInit.Wrapper(
|
||||
(IXposedHookZygoteInit) moduleInstance, param));
|
||||
if (callInitZygote) {
|
||||
((IXposedHookZygoteInit) moduleInstance).initZygote(param);
|
||||
}
|
||||
((IXposedHookZygoteInit) moduleInstance).initZygote(param);
|
||||
}
|
||||
|
||||
if (moduleInstance instanceof IXposedHookLoadPackage)
|
||||
|
|
@ -390,7 +359,7 @@ public final class XposedInit {
|
|||
* in <code>assets/xposed_init</code>.
|
||||
*/
|
||||
@SuppressLint("PrivateApi")
|
||||
private static boolean loadModule(String apk, boolean callInitZygote) {
|
||||
private static boolean loadModule(String apk) {
|
||||
Log.i(TAG, "Loading modules from " + apk);
|
||||
|
||||
if (!new File(apk).exists()) {
|
||||
|
|
@ -418,7 +387,7 @@ public final class XposedInit {
|
|||
} catch (ClassNotFoundException ignored) {
|
||||
}
|
||||
|
||||
boolean res = initModule(mcl, apk, callInitZygote);
|
||||
boolean res = initModule(mcl, apk);
|
||||
res = res && initNativeModule(mcl, apk);
|
||||
return res;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,13 +33,13 @@ import de.robv.android.xposed.IXposedHookZygoteInit;
|
|||
* @param <T> The class of the callback.
|
||||
*/
|
||||
public interface IXUnhook<T> {
|
||||
/**
|
||||
* Returns the callback that has been registered.
|
||||
*/
|
||||
T getCallback();
|
||||
/**
|
||||
* Returns the callback that has been registered.
|
||||
*/
|
||||
T getCallback();
|
||||
|
||||
/**
|
||||
* Removes the callback.
|
||||
*/
|
||||
void unhook();
|
||||
/**
|
||||
* Removes the callback.
|
||||
*/
|
||||
void unhook();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,48 +30,55 @@ import de.robv.android.xposed.XposedBridge.CopyOnWriteSortedSet;
|
|||
* subclass.
|
||||
*/
|
||||
public abstract class XC_InitPackageResources extends XCallback implements IXposedHookInitPackageResources {
|
||||
/**
|
||||
* Creates a new callback with default priority.
|
||||
* @hide
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public XC_InitPackageResources() {
|
||||
super();
|
||||
}
|
||||
/**
|
||||
* Creates a new callback with default priority.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public XC_InitPackageResources() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new callback with a specific priority.
|
||||
*
|
||||
* @param priority See {@link XCallback#priority}.
|
||||
* @hide
|
||||
*/
|
||||
public XC_InitPackageResources(int priority) {
|
||||
super(priority);
|
||||
}
|
||||
/**
|
||||
* Creates a new callback with a specific priority.
|
||||
*
|
||||
* @param priority See {@link XCallback#priority}.
|
||||
* @hide
|
||||
*/
|
||||
public XC_InitPackageResources(int priority) {
|
||||
super(priority);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps information about the resources being initialized.
|
||||
*/
|
||||
public static final class InitPackageResourcesParam extends XCallback.Param {
|
||||
/** @hide */
|
||||
public InitPackageResourcesParam(CopyOnWriteSortedSet<XC_InitPackageResources> callbacks) {
|
||||
super(callbacks);
|
||||
}
|
||||
/**
|
||||
* Wraps information about the resources being initialized.
|
||||
*/
|
||||
public static final class InitPackageResourcesParam extends XCallback.Param {
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public InitPackageResourcesParam(CopyOnWriteSortedSet<XC_InitPackageResources> callbacks) {
|
||||
super(callbacks);
|
||||
}
|
||||
|
||||
/** The name of the package for which resources are being loaded. */
|
||||
public String packageName;
|
||||
/**
|
||||
* The name of the package for which resources are being loaded.
|
||||
*/
|
||||
public String packageName;
|
||||
|
||||
/**
|
||||
* Reference to the resources that can be used for calls to
|
||||
* {@link XResources#setReplacement(String, String, String, Object)}.
|
||||
*/
|
||||
public XResources res;
|
||||
}
|
||||
/**
|
||||
* Reference to the resources that can be used for calls to
|
||||
* {@link XResources#setReplacement(String, String, String, Object)}.
|
||||
*/
|
||||
public XResources res;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@Override
|
||||
protected void call(Param param) throws Throwable {
|
||||
if (param instanceof InitPackageResourcesParam)
|
||||
handleInitPackageResources((InitPackageResourcesParam) param);
|
||||
}
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@Override
|
||||
protected void call(Param param) throws Throwable {
|
||||
if (param instanceof InitPackageResourcesParam)
|
||||
handleInitPackageResources((InitPackageResourcesParam) param);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,89 +31,103 @@ import de.robv.android.xposed.XposedBridge.CopyOnWriteSortedSet;
|
|||
* and its variants.
|
||||
*/
|
||||
public abstract class XC_LayoutInflated extends XCallback {
|
||||
/**
|
||||
* Creates a new callback with default priority.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public XC_LayoutInflated() {
|
||||
super();
|
||||
}
|
||||
/**
|
||||
* Creates a new callback with default priority.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public XC_LayoutInflated() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new callback with a specific priority.
|
||||
*
|
||||
* @param priority See {@link XCallback#priority}.
|
||||
*/
|
||||
public XC_LayoutInflated(int priority) {
|
||||
super(priority);
|
||||
}
|
||||
/**
|
||||
* Creates a new callback with a specific priority.
|
||||
*
|
||||
* @param priority See {@link XCallback#priority}.
|
||||
*/
|
||||
public XC_LayoutInflated(int priority) {
|
||||
super(priority);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps information about the inflated layout.
|
||||
*/
|
||||
public static final class LayoutInflatedParam extends XCallback.Param {
|
||||
/** @hide */
|
||||
public LayoutInflatedParam(CopyOnWriteSortedSet<XC_LayoutInflated> callbacks) {
|
||||
super(callbacks);
|
||||
}
|
||||
/**
|
||||
* Wraps information about the inflated layout.
|
||||
*/
|
||||
public static final class LayoutInflatedParam extends XCallback.Param {
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public LayoutInflatedParam(CopyOnWriteSortedSet<XC_LayoutInflated> callbacks) {
|
||||
super(callbacks);
|
||||
}
|
||||
|
||||
/** The view that has been created from the layout. */
|
||||
public View view;
|
||||
/**
|
||||
* The view that has been created from the layout.
|
||||
*/
|
||||
public View view;
|
||||
|
||||
/** Container with the ID and name of the underlying resource. */
|
||||
public ResourceNames resNames;
|
||||
/**
|
||||
* Container with the ID and name of the underlying resource.
|
||||
*/
|
||||
public ResourceNames resNames;
|
||||
|
||||
/** Directory from which the layout was actually loaded (e.g. "layout-sw600dp"). */
|
||||
public String variant;
|
||||
/**
|
||||
* Directory from which the layout was actually loaded (e.g. "layout-sw600dp").
|
||||
*/
|
||||
public String variant;
|
||||
|
||||
/** Resources containing the layout. */
|
||||
public XResources res;
|
||||
}
|
||||
/**
|
||||
* Resources containing the layout.
|
||||
*/
|
||||
public XResources res;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@Override
|
||||
protected void call(Param param) throws Throwable {
|
||||
if (param instanceof LayoutInflatedParam)
|
||||
handleLayoutInflated((LayoutInflatedParam) param);
|
||||
}
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@Override
|
||||
protected void call(Param param) throws Throwable {
|
||||
if (param instanceof LayoutInflatedParam)
|
||||
handleLayoutInflated((LayoutInflatedParam) param);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called when the hooked layout has been inflated.
|
||||
*
|
||||
* @param liparam Information about the layout and the inflated view.
|
||||
* @throws Throwable Everything the callback throws is caught and logged.
|
||||
*/
|
||||
public abstract void handleLayoutInflated(LayoutInflatedParam liparam) throws Throwable;
|
||||
/**
|
||||
* This method is called when the hooked layout has been inflated.
|
||||
*
|
||||
* @param liparam Information about the layout and the inflated view.
|
||||
* @throws Throwable Everything the callback throws is caught and logged.
|
||||
*/
|
||||
public abstract void handleLayoutInflated(LayoutInflatedParam liparam) throws Throwable;
|
||||
|
||||
/**
|
||||
* An object with which the callback can be removed.
|
||||
*/
|
||||
public class Unhook implements IXUnhook<XC_LayoutInflated> {
|
||||
private final String resDir;
|
||||
private final int id;
|
||||
/**
|
||||
* An object with which the callback can be removed.
|
||||
*/
|
||||
public class Unhook implements IXUnhook<XC_LayoutInflated> {
|
||||
private final String resDir;
|
||||
private final int id;
|
||||
|
||||
/** @hide */
|
||||
public Unhook(String resDir, int id) {
|
||||
this.resDir = resDir;
|
||||
this.id = id;
|
||||
}
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public Unhook(String resDir, int id) {
|
||||
this.resDir = resDir;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the resource ID of the hooked layout.
|
||||
*/
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
/**
|
||||
* Returns the resource ID of the hooked layout.
|
||||
*/
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public XC_LayoutInflated getCallback() {
|
||||
return XC_LayoutInflated.this;
|
||||
}
|
||||
@Override
|
||||
public XC_LayoutInflated getCallback() {
|
||||
return XC_LayoutInflated.this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unhook() {
|
||||
XResources.unhookLayout(resDir, id, XC_LayoutInflated.this);
|
||||
}
|
||||
@Override
|
||||
public void unhook() {
|
||||
XResources.unhookLayout(resDir, id, XC_LayoutInflated.this);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,54 +30,69 @@ import de.robv.android.xposed.XposedBridge.CopyOnWriteSortedSet;
|
|||
* subclass.
|
||||
*/
|
||||
public abstract class XC_LoadPackage extends XCallback implements IXposedHookLoadPackage {
|
||||
/**
|
||||
* Creates a new callback with default priority.
|
||||
* @hide
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public XC_LoadPackage() {
|
||||
super();
|
||||
}
|
||||
/**
|
||||
* Creates a new callback with default priority.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public XC_LoadPackage() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new callback with a specific priority.
|
||||
*
|
||||
* @param priority See {@link XCallback#priority}.
|
||||
* @hide
|
||||
*/
|
||||
public XC_LoadPackage(int priority) {
|
||||
super(priority);
|
||||
}
|
||||
/**
|
||||
* Creates a new callback with a specific priority.
|
||||
*
|
||||
* @param priority See {@link XCallback#priority}.
|
||||
* @hide
|
||||
*/
|
||||
public XC_LoadPackage(int priority) {
|
||||
super(priority);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps information about the app being loaded.
|
||||
*/
|
||||
public static final class LoadPackageParam extends XCallback.Param {
|
||||
/** @hide */
|
||||
public LoadPackageParam(CopyOnWriteSortedSet<XC_LoadPackage> callbacks) {
|
||||
super(callbacks);
|
||||
}
|
||||
/**
|
||||
* Wraps information about the app being loaded.
|
||||
*/
|
||||
public static final class LoadPackageParam extends XCallback.Param {
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public LoadPackageParam(CopyOnWriteSortedSet<XC_LoadPackage> callbacks) {
|
||||
super(callbacks);
|
||||
}
|
||||
|
||||
/** The name of the package being loaded. */
|
||||
public String packageName;
|
||||
/**
|
||||
* The name of the package being loaded.
|
||||
*/
|
||||
public String packageName;
|
||||
|
||||
/** The process in which the package is executed. */
|
||||
public String processName;
|
||||
/**
|
||||
* The process in which the package is executed.
|
||||
*/
|
||||
public String processName;
|
||||
|
||||
/** The ClassLoader used for this package. */
|
||||
public ClassLoader classLoader;
|
||||
/**
|
||||
* The ClassLoader used for this package.
|
||||
*/
|
||||
public ClassLoader classLoader;
|
||||
|
||||
/** More information about the application being loaded. */
|
||||
public ApplicationInfo appInfo;
|
||||
/**
|
||||
* More information about the application being loaded.
|
||||
*/
|
||||
public ApplicationInfo appInfo;
|
||||
|
||||
/** Set to {@code true} if this is the first (and main) application for this process. */
|
||||
public boolean isFirstApplication;
|
||||
}
|
||||
/**
|
||||
* Set to {@code true} if this is the first (and main) application for this process.
|
||||
*/
|
||||
public boolean isFirstApplication;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@Override
|
||||
protected void call(Param param) throws Throwable {
|
||||
if (param instanceof LoadPackageParam)
|
||||
handleLoadPackage((LoadPackageParam) param);
|
||||
}
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@Override
|
||||
protected void call(Param param) throws Throwable {
|
||||
if (param instanceof LoadPackageParam)
|
||||
handleLoadPackage((LoadPackageParam) param);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,147 +27,174 @@ import java.io.Serializable;
|
|||
import de.robv.android.xposed.IModuleContext;
|
||||
import de.robv.android.xposed.XposedBridge;
|
||||
import de.robv.android.xposed.XposedBridge.CopyOnWriteSortedSet;
|
||||
|
||||
import org.lsposed.lspd.deopt.PrebuiltMethodsDeopter;
|
||||
|
||||
/**
|
||||
* Base class for Xposed callbacks.
|
||||
*
|
||||
* <p>
|
||||
* This class only keeps a priority for ordering multiple callbacks.
|
||||
* The actual (abstract) callback methods are added by subclasses.
|
||||
*/
|
||||
public abstract class XCallback implements Comparable<XCallback>, IModuleContext {
|
||||
/**
|
||||
* Callback priority, higher number means earlier execution.
|
||||
*
|
||||
* <p>This is usually set to {@link #PRIORITY_DEFAULT}. However, in case a certain callback should
|
||||
* be executed earlier or later a value between {@link #PRIORITY_HIGHEST} and {@link #PRIORITY_LOWEST}
|
||||
* can be set instead. The values are just for orientation though, Xposed doesn't enforce any
|
||||
* boundaries on the priority values.
|
||||
*/
|
||||
public final int priority;
|
||||
/**
|
||||
* Callback priority, higher number means earlier execution.
|
||||
*
|
||||
* <p>This is usually set to {@link #PRIORITY_DEFAULT}. However, in case a certain callback should
|
||||
* be executed earlier or later a value between {@link #PRIORITY_HIGHEST} and {@link #PRIORITY_LOWEST}
|
||||
* can be set instead. The values are just for orientation though, Xposed doesn't enforce any
|
||||
* boundaries on the priority values.
|
||||
*/
|
||||
public final int priority;
|
||||
|
||||
/** @deprecated This constructor can't be hidden for technical reasons. Nevertheless, don't use it! */
|
||||
@Deprecated
|
||||
public XCallback() {
|
||||
this.priority = PRIORITY_DEFAULT;
|
||||
}
|
||||
/**
|
||||
* @deprecated This constructor can't be hidden for technical reasons. Nevertheless, don't use it!
|
||||
*/
|
||||
@Deprecated
|
||||
public XCallback() {
|
||||
this.priority = PRIORITY_DEFAULT;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public XCallback(int priority) {
|
||||
this.priority = priority;
|
||||
}
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public XCallback(int priority) {
|
||||
this.priority = priority;
|
||||
}
|
||||
|
||||
/**
|
||||
* Base class for Xposed callback parameters.
|
||||
*/
|
||||
public static abstract class Param {
|
||||
/** @hide */
|
||||
public final Object[] callbacks;
|
||||
private Bundle extra;
|
||||
/**
|
||||
* Base class for Xposed callback parameters.
|
||||
*/
|
||||
public static abstract class Param {
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public final Object[] callbacks;
|
||||
private Bundle extra;
|
||||
|
||||
/** @deprecated This constructor can't be hidden for technical reasons. Nevertheless, don't use it! */
|
||||
@Deprecated
|
||||
protected Param() {
|
||||
callbacks = null;
|
||||
}
|
||||
/**
|
||||
* @deprecated This constructor can't be hidden for technical reasons. Nevertheless, don't use it!
|
||||
*/
|
||||
@Deprecated
|
||||
protected Param() {
|
||||
callbacks = null;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
protected Param(CopyOnWriteSortedSet<? extends XCallback> callbacks) {
|
||||
this.callbacks = callbacks.getSnapshot();
|
||||
}
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
protected Param(CopyOnWriteSortedSet<? extends XCallback> callbacks) {
|
||||
this.callbacks = callbacks.getSnapshot();
|
||||
}
|
||||
|
||||
/**
|
||||
* This can be used to store any data for the scope of the callback.
|
||||
*
|
||||
* <p>Use this instead of instance variables, as it has a clear reference to e.g. each
|
||||
* separate call to a method, even when the same method is called recursively.
|
||||
*
|
||||
* @see #setObjectExtra
|
||||
* @see #getObjectExtra
|
||||
*/
|
||||
public synchronized Bundle getExtra() {
|
||||
if (extra == null)
|
||||
extra = new Bundle();
|
||||
return extra;
|
||||
}
|
||||
/**
|
||||
* This can be used to store any data for the scope of the callback.
|
||||
*
|
||||
* <p>Use this instead of instance variables, as it has a clear reference to e.g. each
|
||||
* separate call to a method, even when the same method is called recursively.
|
||||
*
|
||||
* @see #setObjectExtra
|
||||
* @see #getObjectExtra
|
||||
*/
|
||||
public synchronized Bundle getExtra() {
|
||||
if (extra == null)
|
||||
extra = new Bundle();
|
||||
return extra;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an object stored with {@link #setObjectExtra}.
|
||||
*/
|
||||
public Object getObjectExtra(String key) {
|
||||
Serializable o = getExtra().getSerializable(key);
|
||||
if (o instanceof SerializeWrapper)
|
||||
return ((SerializeWrapper) o).object;
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* Returns an object stored with {@link #setObjectExtra}.
|
||||
*/
|
||||
public Object getObjectExtra(String key) {
|
||||
Serializable o = getExtra().getSerializable(key);
|
||||
if (o instanceof SerializeWrapper)
|
||||
return ((SerializeWrapper) o).object;
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores any object for the scope of the callback. For data types that support it, use
|
||||
* the {@link Bundle} returned by {@link #getExtra} instead.
|
||||
*/
|
||||
public void setObjectExtra(String key, Object o) {
|
||||
getExtra().putSerializable(key, new SerializeWrapper(o));
|
||||
}
|
||||
/**
|
||||
* Stores any object for the scope of the callback. For data types that support it, use
|
||||
* the {@link Bundle} returned by {@link #getExtra} instead.
|
||||
*/
|
||||
public void setObjectExtra(String key, Object o) {
|
||||
getExtra().putSerializable(key, new SerializeWrapper(o));
|
||||
}
|
||||
|
||||
private static class SerializeWrapper implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private final Object object;
|
||||
public SerializeWrapper(Object o) {
|
||||
object = o;
|
||||
}
|
||||
}
|
||||
}
|
||||
private static class SerializeWrapper implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private final Object object;
|
||||
|
||||
/** @hide */
|
||||
public static void callAll(Param param) {
|
||||
public SerializeWrapper(Object o) {
|
||||
object = o;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (param instanceof XC_LoadPackage.LoadPackageParam) {
|
||||
// deopt methods in system apps or priv-apps, this would be not necessary
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public static void callAll(Param param) {
|
||||
|
||||
if (param instanceof XC_LoadPackage.LoadPackageParam) {
|
||||
// deopt methods in system apps or priv-apps, this would be not necessary
|
||||
// only if we found out how to recompile their apks
|
||||
XC_LoadPackage.LoadPackageParam lpp = (XC_LoadPackage.LoadPackageParam) param;
|
||||
PrebuiltMethodsDeopter.deoptMethods(lpp.packageName, lpp.classLoader);
|
||||
}
|
||||
XC_LoadPackage.LoadPackageParam lpp = (XC_LoadPackage.LoadPackageParam) param;
|
||||
PrebuiltMethodsDeopter.deoptMethods(lpp.packageName, lpp.classLoader);
|
||||
}
|
||||
|
||||
if (param.callbacks == null)
|
||||
throw new IllegalStateException("This object was not created for use with callAll");
|
||||
if (param.callbacks == null)
|
||||
throw new IllegalStateException("This object was not created for use with callAll");
|
||||
|
||||
for (int i = 0; i < param.callbacks.length; i++) {
|
||||
try {
|
||||
((XCallback) param.callbacks[i]).call(param);
|
||||
} catch (Throwable t) { XposedBridge.log(t); }
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < param.callbacks.length; i++) {
|
||||
try {
|
||||
((XCallback) param.callbacks[i]).call(param);
|
||||
} catch (Throwable t) {
|
||||
XposedBridge.log(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
protected void call(Param param) throws Throwable {}
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
protected void call(Param param) throws Throwable {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getApkPath() {
|
||||
return "";
|
||||
}
|
||||
@Override
|
||||
public String getApkPath() {
|
||||
return "";
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@Override
|
||||
public int compareTo(XCallback other) {
|
||||
if (this == other)
|
||||
return 0;
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@Override
|
||||
public int compareTo(XCallback other) {
|
||||
if (this == other)
|
||||
return 0;
|
||||
|
||||
// order descending by priority
|
||||
if (other.priority != this.priority)
|
||||
return other.priority - this.priority;
|
||||
// then randomly
|
||||
else if (System.identityHashCode(this) < System.identityHashCode(other))
|
||||
return -1;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
// order descending by priority
|
||||
if (other.priority != this.priority)
|
||||
return other.priority - this.priority;
|
||||
// then randomly
|
||||
else if (System.identityHashCode(this) < System.identityHashCode(other))
|
||||
return -1;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** The default priority, see {@link #priority}. */
|
||||
public static final int PRIORITY_DEFAULT = 50;
|
||||
/**
|
||||
* The default priority, see {@link #priority}.
|
||||
*/
|
||||
public static final int PRIORITY_DEFAULT = 50;
|
||||
|
||||
/** Execute this callback late, see {@link #priority}. */
|
||||
public static final int PRIORITY_LOWEST = -10000;
|
||||
/**
|
||||
* Execute this callback late, see {@link #priority}.
|
||||
*/
|
||||
public static final int PRIORITY_LOWEST = -10000;
|
||||
|
||||
/** Execute this callback early, see {@link #priority}. */
|
||||
public static final int PRIORITY_HIGHEST = 10000;
|
||||
/**
|
||||
* Execute this callback early, see {@link #priority}.
|
||||
*/
|
||||
public static final int PRIORITY_HIGHEST = 10000;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,167 +33,178 @@ import de.robv.android.xposed.SELinuxHelper;
|
|||
* <p>References to a concrete subclass should generally be retrieved from {@link SELinuxHelper}.
|
||||
*/
|
||||
public abstract class BaseService {
|
||||
/** Flag for {@link #checkFileAccess}: Read access. */
|
||||
public static final int R_OK = 4;
|
||||
/** Flag for {@link #checkFileAccess}: Write access. */
|
||||
public static final int W_OK = 2;
|
||||
/** Flag for {@link #checkFileAccess}: Executable access. */
|
||||
public static final int X_OK = 1;
|
||||
/** Flag for {@link #checkFileAccess}: File/directory exists. */
|
||||
public static final int F_OK = 0;
|
||||
/**
|
||||
* Flag for {@link #checkFileAccess}: Read access.
|
||||
*/
|
||||
public static final int R_OK = 4;
|
||||
/**
|
||||
* Flag for {@link #checkFileAccess}: Write access.
|
||||
*/
|
||||
public static final int W_OK = 2;
|
||||
/**
|
||||
* Flag for {@link #checkFileAccess}: Executable access.
|
||||
*/
|
||||
public static final int X_OK = 1;
|
||||
/**
|
||||
* Flag for {@link #checkFileAccess}: File/directory exists.
|
||||
*/
|
||||
public static final int F_OK = 0;
|
||||
|
||||
/**
|
||||
* Checks whether the services accesses files directly (instead of using IPC).
|
||||
*
|
||||
* @return {@code true} in case direct access is possible.
|
||||
*/
|
||||
public boolean hasDirectFileAccess() {
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* Checks whether the services accesses files directly (instead of using IPC).
|
||||
*
|
||||
* @return {@code true} in case direct access is possible.
|
||||
*/
|
||||
public boolean hasDirectFileAccess() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether a file is accessible. SELinux might enforce stricter checks.
|
||||
*
|
||||
* @param filename The absolute path of the file to check.
|
||||
* @param mode The mode for POSIX's {@code access()} function.
|
||||
* @return The result of the {@code access()} function.
|
||||
*/
|
||||
public abstract boolean checkFileAccess(String filename, int mode);
|
||||
/**
|
||||
* Check whether a file is accessible. SELinux might enforce stricter checks.
|
||||
*
|
||||
* @param filename The absolute path of the file to check.
|
||||
* @param mode The mode for POSIX's {@code access()} function.
|
||||
* @return The result of the {@code access()} function.
|
||||
*/
|
||||
public abstract boolean checkFileAccess(String filename, int mode);
|
||||
|
||||
/**
|
||||
* Check whether a file exists.
|
||||
*
|
||||
* @param filename The absolute path of the file to check.
|
||||
* @return The result of the {@code access()} function.
|
||||
*/
|
||||
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
|
||||
public boolean checkFileExists(String filename) {
|
||||
return checkFileAccess(filename, F_OK);
|
||||
}
|
||||
/**
|
||||
* Check whether a file exists.
|
||||
*
|
||||
* @param filename The absolute path of the file to check.
|
||||
* @return The result of the {@code access()} function.
|
||||
*/
|
||||
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
|
||||
public boolean checkFileExists(String filename) {
|
||||
return checkFileAccess(filename, F_OK);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the size and modification time of a file.
|
||||
*
|
||||
* @param filename The absolute path of the file to check.
|
||||
* @return A {@link FileResult} object holding the result.
|
||||
* @throws IOException In case an error occurred while retrieving the information.
|
||||
*/
|
||||
public abstract FileResult statFile(String filename) throws IOException;
|
||||
/**
|
||||
* Determine the size and modification time of a file.
|
||||
*
|
||||
* @param filename The absolute path of the file to check.
|
||||
* @return A {@link FileResult} object holding the result.
|
||||
* @throws IOException In case an error occurred while retrieving the information.
|
||||
*/
|
||||
public abstract FileResult statFile(String filename) throws IOException;
|
||||
|
||||
/**
|
||||
* Determine the size time of a file.
|
||||
*
|
||||
* @param filename The absolute path of the file to check.
|
||||
* @return The file size.
|
||||
* @throws IOException In case an error occurred while retrieving the information.
|
||||
*/
|
||||
public long getFileSize(String filename) throws IOException {
|
||||
return statFile(filename).size;
|
||||
}
|
||||
/**
|
||||
* Determine the size time of a file.
|
||||
*
|
||||
* @param filename The absolute path of the file to check.
|
||||
* @return The file size.
|
||||
* @throws IOException In case an error occurred while retrieving the information.
|
||||
*/
|
||||
public long getFileSize(String filename) throws IOException {
|
||||
return statFile(filename).size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the size time of a file.
|
||||
*
|
||||
* @param filename The absolute path of the file to check.
|
||||
* @return The file modification time.
|
||||
* @throws IOException In case an error occurred while retrieving the information.
|
||||
*/
|
||||
public long getFileModificationTime(String filename) throws IOException {
|
||||
return statFile(filename).mtime;
|
||||
}
|
||||
/**
|
||||
* Determine the size time of a file.
|
||||
*
|
||||
* @param filename The absolute path of the file to check.
|
||||
* @return The file modification time.
|
||||
* @throws IOException In case an error occurred while retrieving the information.
|
||||
*/
|
||||
public long getFileModificationTime(String filename) throws IOException {
|
||||
return statFile(filename).mtime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a file into memory.
|
||||
*
|
||||
* @param filename The absolute path of the file to read.
|
||||
* @return A {@code byte} array with the file content.
|
||||
* @throws IOException In case an error occurred while reading the file.
|
||||
*/
|
||||
public abstract byte[] readFile(String filename) throws IOException;
|
||||
/**
|
||||
* Read a file into memory.
|
||||
*
|
||||
* @param filename The absolute path of the file to read.
|
||||
* @return A {@code byte} array with the file content.
|
||||
* @throws IOException In case an error occurred while reading the file.
|
||||
*/
|
||||
public abstract byte[] readFile(String filename) throws IOException;
|
||||
|
||||
/**
|
||||
* Read a file into memory, but only if it has changed since the last time.
|
||||
*
|
||||
* @param filename The absolute path of the file to read.
|
||||
* @param previousSize File size of last read.
|
||||
* @param previousTime File modification time of last read.
|
||||
* @return A {@link FileResult} object holding the result.
|
||||
* <p>The {@link FileResult#content} field might be {@code null} if the file
|
||||
* is unmodified ({@code previousSize} and {@code previousTime} are still valid).
|
||||
* @throws IOException In case an error occurred while reading the file.
|
||||
*/
|
||||
public abstract FileResult readFile(String filename, long previousSize, long previousTime) throws IOException;
|
||||
/**
|
||||
* Read a file into memory, but only if it has changed since the last time.
|
||||
*
|
||||
* @param filename The absolute path of the file to read.
|
||||
* @param previousSize File size of last read.
|
||||
* @param previousTime File modification time of last read.
|
||||
* @return A {@link FileResult} object holding the result.
|
||||
* <p>The {@link FileResult#content} field might be {@code null} if the file
|
||||
* is unmodified ({@code previousSize} and {@code previousTime} are still valid).
|
||||
* @throws IOException In case an error occurred while reading the file.
|
||||
*/
|
||||
public abstract FileResult readFile(String filename, long previousSize, long previousTime) throws IOException;
|
||||
|
||||
/**
|
||||
* Read a file into memory, optionally only if it has changed since the last time.
|
||||
*
|
||||
* @param filename The absolute path of the file to read.
|
||||
* @param offset Number of bytes to skip at the beginning of the file.
|
||||
* @param length Number of bytes to read (0 means read to end of file).
|
||||
* @param previousSize Optional: File size of last read.
|
||||
* @param previousTime Optional: File modification time of last read.
|
||||
* @return A {@link FileResult} object holding the result.
|
||||
* <p>The {@link FileResult#content} field might be {@code null} if the file
|
||||
* is unmodified ({@code previousSize} and {@code previousTime} are still valid).
|
||||
* @throws IOException In case an error occurred while reading the file.
|
||||
*/
|
||||
public abstract FileResult readFile(String filename, int offset, int length,
|
||||
long previousSize, long previousTime) throws IOException;
|
||||
/**
|
||||
* Read a file into memory, optionally only if it has changed since the last time.
|
||||
*
|
||||
* @param filename The absolute path of the file to read.
|
||||
* @param offset Number of bytes to skip at the beginning of the file.
|
||||
* @param length Number of bytes to read (0 means read to end of file).
|
||||
* @param previousSize Optional: File size of last read.
|
||||
* @param previousTime Optional: File modification time of last read.
|
||||
* @return A {@link FileResult} object holding the result.
|
||||
* <p>The {@link FileResult#content} field might be {@code null} if the file
|
||||
* is unmodified ({@code previousSize} and {@code previousTime} are still valid).
|
||||
* @throws IOException In case an error occurred while reading the file.
|
||||
*/
|
||||
public abstract FileResult readFile(String filename, int offset, int length,
|
||||
long previousSize, long previousTime) throws IOException;
|
||||
|
||||
/**
|
||||
* Get a stream to the file content.
|
||||
* Depending on the service, it may or may not be read completely into memory.
|
||||
*
|
||||
* @param filename The absolute path of the file to read.
|
||||
* @return An {@link InputStream} to the file content.
|
||||
* @throws IOException In case an error occurred while reading the file.
|
||||
*/
|
||||
public InputStream getFileInputStream(String filename) throws IOException {
|
||||
return new ByteArrayInputStream(readFile(filename));
|
||||
}
|
||||
/**
|
||||
* Get a stream to the file content.
|
||||
* Depending on the service, it may or may not be read completely into memory.
|
||||
*
|
||||
* @param filename The absolute path of the file to read.
|
||||
* @return An {@link InputStream} to the file content.
|
||||
* @throws IOException In case an error occurred while reading the file.
|
||||
*/
|
||||
public InputStream getFileInputStream(String filename) throws IOException {
|
||||
return new ByteArrayInputStream(readFile(filename));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a stream to the file content, but only if it has changed since the last time.
|
||||
* Depending on the service, it may or may not be read completely into memory.
|
||||
*
|
||||
* @param filename The absolute path of the file to read.
|
||||
* @param previousSize Optional: File size of last read.
|
||||
* @param previousTime Optional: File modification time of last read.
|
||||
* @return A {@link FileResult} object holding the result.
|
||||
* <p>The {@link FileResult#stream} field might be {@code null} if the file
|
||||
* is unmodified ({@code previousSize} and {@code previousTime} are still valid).
|
||||
* @throws IOException In case an error occurred while reading the file.
|
||||
*/
|
||||
public FileResult getFileInputStream(String filename, long previousSize, long previousTime) throws IOException {
|
||||
FileResult result = readFile(filename, previousSize, previousTime);
|
||||
if (result.content == null)
|
||||
return result;
|
||||
return new FileResult(new ByteArrayInputStream(result.content), result.size, result.mtime);
|
||||
}
|
||||
/**
|
||||
* Get a stream to the file content, but only if it has changed since the last time.
|
||||
* Depending on the service, it may or may not be read completely into memory.
|
||||
*
|
||||
* @param filename The absolute path of the file to read.
|
||||
* @param previousSize Optional: File size of last read.
|
||||
* @param previousTime Optional: File modification time of last read.
|
||||
* @return A {@link FileResult} object holding the result.
|
||||
* <p>The {@link FileResult#stream} field might be {@code null} if the file
|
||||
* is unmodified ({@code previousSize} and {@code previousTime} are still valid).
|
||||
* @throws IOException In case an error occurred while reading the file.
|
||||
*/
|
||||
public FileResult getFileInputStream(String filename, long previousSize, long previousTime) throws IOException {
|
||||
FileResult result = readFile(filename, previousSize, previousTime);
|
||||
if (result.content == null)
|
||||
return result;
|
||||
return new FileResult(new ByteArrayInputStream(result.content), result.size, result.mtime);
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/*package*/ BaseService() {}
|
||||
// ----------------------------------------------------------------------------
|
||||
/*package*/ BaseService() {
|
||||
}
|
||||
|
||||
/*package*/ static void ensureAbsolutePath(String filename) {
|
||||
if (!filename.startsWith("/")) {
|
||||
throw new IllegalArgumentException("Only absolute filenames are allowed: " + filename);
|
||||
}
|
||||
}
|
||||
/*package*/
|
||||
static void ensureAbsolutePath(String filename) {
|
||||
if (!filename.startsWith("/")) {
|
||||
throw new IllegalArgumentException("Only absolute filenames are allowed: " + filename);
|
||||
}
|
||||
}
|
||||
|
||||
/*package*/ static void throwCommonIOException(int errno, String errorMsg, String filename, String defaultText) throws IOException {
|
||||
switch (errno) {
|
||||
case 1: // EPERM
|
||||
case 13: // EACCES
|
||||
throw new FileNotFoundException(errorMsg != null ? errorMsg : "Permission denied: " + filename);
|
||||
case 2: // ENOENT
|
||||
throw new FileNotFoundException(errorMsg != null ? errorMsg : "No such file or directory: " + filename);
|
||||
case 12: // ENOMEM
|
||||
throw new OutOfMemoryError(errorMsg);
|
||||
case 21: // EISDIR
|
||||
throw new FileNotFoundException(errorMsg != null ? errorMsg : "Is a directory: " + filename);
|
||||
default:
|
||||
throw new IOException(errorMsg != null ? errorMsg : "Error " + errno + defaultText + filename);
|
||||
}
|
||||
}
|
||||
/*package*/
|
||||
static void throwCommonIOException(int errno, String errorMsg, String filename, String defaultText) throws IOException {
|
||||
switch (errno) {
|
||||
case 1: // EPERM
|
||||
case 13: // EACCES
|
||||
throw new FileNotFoundException(errorMsg != null ? errorMsg : "Permission denied: " + filename);
|
||||
case 2: // ENOENT
|
||||
throw new FileNotFoundException(errorMsg != null ? errorMsg : "No such file or directory: " + filename);
|
||||
case 12: // ENOMEM
|
||||
throw new OutOfMemoryError(errorMsg);
|
||||
case 21: // EISDIR
|
||||
throw new FileNotFoundException(errorMsg != null ? errorMsg : "Is a directory: " + filename);
|
||||
default:
|
||||
throw new IOException(errorMsg != null ? errorMsg : "Error " + errno + defaultText + filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,108 +26,110 @@ import java.io.FileInputStream;
|
|||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/** @hide */
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public final class DirectAccessService extends BaseService {
|
||||
@Override
|
||||
public boolean hasDirectFileAccess() {
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public boolean hasDirectFileAccess() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@SuppressWarnings("RedundantIfStatement")
|
||||
@Override
|
||||
public boolean checkFileAccess(String filename, int mode) {
|
||||
File file = new File(filename);
|
||||
if (mode == F_OK && !file.exists()) return false;
|
||||
if ((mode & R_OK) != 0 && !file.canRead()) return false;
|
||||
if ((mode & W_OK) != 0 && !file.canWrite()) return false;
|
||||
if ((mode & X_OK) != 0 && !file.canExecute()) return false;
|
||||
return true;
|
||||
}
|
||||
@SuppressWarnings("RedundantIfStatement")
|
||||
@Override
|
||||
public boolean checkFileAccess(String filename, int mode) {
|
||||
File file = new File(filename);
|
||||
if (mode == F_OK && !file.exists()) return false;
|
||||
if ((mode & R_OK) != 0 && !file.canRead()) return false;
|
||||
if ((mode & W_OK) != 0 && !file.canWrite()) return false;
|
||||
if ((mode & X_OK) != 0 && !file.canExecute()) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkFileExists(String filename) {
|
||||
return new File(filename).exists();
|
||||
}
|
||||
@Override
|
||||
public boolean checkFileExists(String filename) {
|
||||
return new File(filename).exists();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileResult statFile(String filename) throws IOException {
|
||||
File file = new File(filename);
|
||||
return new FileResult(file.length(), file.lastModified());
|
||||
}
|
||||
@Override
|
||||
public FileResult statFile(String filename) throws IOException {
|
||||
File file = new File(filename);
|
||||
return new FileResult(file.length(), file.lastModified());
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] readFile(String filename) throws IOException {
|
||||
File file = new File(filename);
|
||||
byte content[] = new byte[(int)file.length()];
|
||||
FileInputStream fis = new FileInputStream(file);
|
||||
fis.read(content);
|
||||
fis.close();
|
||||
return content;
|
||||
}
|
||||
@Override
|
||||
public byte[] readFile(String filename) throws IOException {
|
||||
File file = new File(filename);
|
||||
byte content[] = new byte[(int) file.length()];
|
||||
FileInputStream fis = new FileInputStream(file);
|
||||
fis.read(content);
|
||||
fis.close();
|
||||
return content;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileResult readFile(String filename, long previousSize, long previousTime) throws IOException {
|
||||
File file = new File(filename);
|
||||
long size = file.length();
|
||||
long time = file.lastModified();
|
||||
if (previousSize == size && previousTime == time)
|
||||
return new FileResult(size, time);
|
||||
return new FileResult(readFile(filename), size, time);
|
||||
}
|
||||
@Override
|
||||
public FileResult readFile(String filename, long previousSize, long previousTime) throws IOException {
|
||||
File file = new File(filename);
|
||||
long size = file.length();
|
||||
long time = file.lastModified();
|
||||
if (previousSize == size && previousTime == time)
|
||||
return new FileResult(size, time);
|
||||
return new FileResult(readFile(filename), size, time);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileResult readFile(String filename, int offset, int length, long previousSize, long previousTime) throws IOException {
|
||||
File file = new File(filename);
|
||||
long size = file.length();
|
||||
long time = file.lastModified();
|
||||
if (previousSize == size && previousTime == time)
|
||||
return new FileResult(size, time);
|
||||
@Override
|
||||
public FileResult readFile(String filename, int offset, int length, long previousSize, long previousTime) throws IOException {
|
||||
File file = new File(filename);
|
||||
long size = file.length();
|
||||
long time = file.lastModified();
|
||||
if (previousSize == size && previousTime == time)
|
||||
return new FileResult(size, time);
|
||||
|
||||
// Shortcut for the simple case
|
||||
if (offset <= 0 && length <= 0)
|
||||
return new FileResult(readFile(filename), size, time);
|
||||
// Shortcut for the simple case
|
||||
if (offset <= 0 && length <= 0)
|
||||
return new FileResult(readFile(filename), size, time);
|
||||
|
||||
// Check range
|
||||
if (offset > 0 && offset >= size) {
|
||||
throw new IllegalArgumentException("Offset " + offset + " is out of range for " + filename);
|
||||
} else if (offset < 0) {
|
||||
offset = 0;
|
||||
}
|
||||
// Check range
|
||||
if (offset > 0 && offset >= size) {
|
||||
throw new IllegalArgumentException("Offset " + offset + " is out of range for " + filename);
|
||||
} else if (offset < 0) {
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
if (length > 0 && (offset + length) > size) {
|
||||
throw new IllegalArgumentException("Length " + length + " is out of range for " + filename);
|
||||
} else if (length <= 0) {
|
||||
length = (int) (size - offset);
|
||||
}
|
||||
if (length > 0 && (offset + length) > size) {
|
||||
throw new IllegalArgumentException("Length " + length + " is out of range for " + filename);
|
||||
} else if (length <= 0) {
|
||||
length = (int) (size - offset);
|
||||
}
|
||||
|
||||
byte content[] = new byte[length];
|
||||
FileInputStream fis = new FileInputStream(file);
|
||||
fis.skip(offset);
|
||||
fis.read(content);
|
||||
fis.close();
|
||||
return new FileResult(content, size, time);
|
||||
}
|
||||
byte content[] = new byte[length];
|
||||
FileInputStream fis = new FileInputStream(file);
|
||||
fis.skip(offset);
|
||||
fis.read(content);
|
||||
fis.close();
|
||||
return new FileResult(content, size, time);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* <p>This implementation returns a BufferedInputStream instead of loading the file into memory.
|
||||
*/
|
||||
@Override
|
||||
public InputStream getFileInputStream(String filename) throws IOException {
|
||||
return new BufferedInputStream(new FileInputStream(filename), 16*1024);
|
||||
}
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* <p>This implementation returns a BufferedInputStream instead of loading the file into memory.
|
||||
*/
|
||||
@Override
|
||||
public InputStream getFileInputStream(String filename) throws IOException {
|
||||
return new BufferedInputStream(new FileInputStream(filename), 16 * 1024);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* <p>This implementation returns a BufferedInputStream instead of loading the file into memory.
|
||||
*/
|
||||
@Override
|
||||
public FileResult getFileInputStream(String filename, long previousSize, long previousTime) throws IOException {
|
||||
File file = new File(filename);
|
||||
long size = file.length();
|
||||
long time = file.lastModified();
|
||||
if (previousSize == size && previousTime == time)
|
||||
return new FileResult(size, time);
|
||||
return new FileResult(new BufferedInputStream(new FileInputStream(filename), 16*1024), size, time);
|
||||
}
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* <p>This implementation returns a BufferedInputStream instead of loading the file into memory.
|
||||
*/
|
||||
@Override
|
||||
public FileResult getFileInputStream(String filename, long previousSize, long previousTime) throws IOException {
|
||||
File file = new File(filename);
|
||||
long size = file.length();
|
||||
long time = file.lastModified();
|
||||
if (previousSize == size && previousTime == time)
|
||||
return new FileResult(size, time);
|
||||
return new FileResult(new BufferedInputStream(new FileInputStream(filename), 16 * 1024), size, time);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,55 +26,65 @@ import java.io.InputStream;
|
|||
* Holder for the result of a {@link BaseService#readFile} or {@link BaseService#statFile} call.
|
||||
*/
|
||||
public final class FileResult {
|
||||
/** File content, might be {@code null} if the file wasn't read. */
|
||||
public final byte[] content;
|
||||
/** File input stream, might be {@code null} if the file wasn't read. */
|
||||
public final InputStream stream;
|
||||
/** File size. */
|
||||
public final long size;
|
||||
/** File last modification time. */
|
||||
public final long mtime;
|
||||
/**
|
||||
* File content, might be {@code null} if the file wasn't read.
|
||||
*/
|
||||
public final byte[] content;
|
||||
/**
|
||||
* File input stream, might be {@code null} if the file wasn't read.
|
||||
*/
|
||||
public final InputStream stream;
|
||||
/**
|
||||
* File size.
|
||||
*/
|
||||
public final long size;
|
||||
/**
|
||||
* File last modification time.
|
||||
*/
|
||||
public final long mtime;
|
||||
|
||||
/*package*/ FileResult(long size, long mtime) {
|
||||
this.content = null;
|
||||
this.stream = null;
|
||||
this.size = size;
|
||||
this.mtime = mtime;
|
||||
}
|
||||
/*package*/ FileResult(long size, long mtime) {
|
||||
this.content = null;
|
||||
this.stream = null;
|
||||
this.size = size;
|
||||
this.mtime = mtime;
|
||||
}
|
||||
|
||||
/*package*/ FileResult(byte[] content, long size, long mtime) {
|
||||
this.content = content;
|
||||
this.stream = null;
|
||||
this.size = size;
|
||||
this.mtime = mtime;
|
||||
}
|
||||
/*package*/ FileResult(byte[] content, long size, long mtime) {
|
||||
this.content = content;
|
||||
this.stream = null;
|
||||
this.size = size;
|
||||
this.mtime = mtime;
|
||||
}
|
||||
|
||||
/*package*/ FileResult(InputStream stream, long size, long mtime) {
|
||||
this.content = null;
|
||||
this.stream = stream;
|
||||
this.size = size;
|
||||
this.mtime = mtime;
|
||||
}
|
||||
/*package*/ FileResult(InputStream stream, long size, long mtime) {
|
||||
this.content = null;
|
||||
this.stream = stream;
|
||||
this.size = size;
|
||||
this.mtime = mtime;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder("{");
|
||||
if (content != null) {
|
||||
sb.append("content.length: ");
|
||||
sb.append(content.length);
|
||||
sb.append(", ");
|
||||
}
|
||||
if (stream != null) {
|
||||
sb.append("stream: ");
|
||||
sb.append(stream.toString());
|
||||
sb.append(", ");
|
||||
}
|
||||
sb.append("size: ");
|
||||
sb.append(size);
|
||||
sb.append(", mtime: ");
|
||||
sb.append(mtime);
|
||||
sb.append("}");
|
||||
return sb.toString();
|
||||
}
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder("{");
|
||||
if (content != null) {
|
||||
sb.append("content.length: ");
|
||||
sb.append(content.length);
|
||||
sb.append(", ");
|
||||
}
|
||||
if (stream != null) {
|
||||
sb.append("stream: ");
|
||||
sb.append(stream.toString());
|
||||
sb.append(", ");
|
||||
}
|
||||
sb.append("size: ");
|
||||
sb.append(size);
|
||||
sb.append(", mtime: ");
|
||||
sb.append(mtime);
|
||||
sb.append("}");
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -79,15 +79,15 @@ public class Main {
|
|||
// Initialize the Xposed framework
|
||||
try {
|
||||
startBootstrapHook(isSystem, appDataDir);
|
||||
XposedInit.initForZygote();
|
||||
XposedInit.hookResources();
|
||||
} catch (Throwable t) {
|
||||
Utils.logE("error during Xposed initialization", t);
|
||||
}
|
||||
}
|
||||
|
||||
private static void loadModulesSafely(boolean callInitZygote) {
|
||||
private static void loadModulesSafely() {
|
||||
try {
|
||||
XposedInit.loadModules(callInitZygote);
|
||||
XposedInit.loadModules();
|
||||
} catch (Exception exception) {
|
||||
Utils.logE("error loading module list", exception);
|
||||
}
|
||||
|
|
@ -101,7 +101,7 @@ public class Main {
|
|||
PrebuiltMethodsDeopter.deoptBootMethods(); // do it once for secondary zygote
|
||||
installBootstrapHooks(isSystem, appDataDir);
|
||||
Utils.logI("Loading modules for " + niceName);
|
||||
loadModulesSafely(true);
|
||||
loadModulesSafely();
|
||||
}
|
||||
|
||||
public static void forkAndSpecializePost(String appDataDir, String niceName, IBinder binder) {
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ import static org.lsposed.lspd.config.LSPApplicationServiceClient.serviceClient;
|
|||
|
||||
// normal process initialization (for new Activity, Service, BroadcastReceiver etc.)
|
||||
public class HandleBindAppHooker extends XC_MethodHook {
|
||||
String appDataDir = null;
|
||||
String appDataDir;
|
||||
|
||||
public HandleBindAppHooker(String appDataDir) {
|
||||
this.appDataDir = appDataDir;
|
||||
|
|
|
|||
|
|
@ -20,8 +20,6 @@
|
|||
|
||||
package org.lsposed.lspd.hooker;
|
||||
|
||||
import android.os.Build;
|
||||
|
||||
import org.lsposed.lspd.util.Hookers;
|
||||
|
||||
import de.robv.android.xposed.XC_MethodHook;
|
||||
|
|
@ -60,7 +58,7 @@ public class StartBootstrapServicesHooker extends XC_MethodHook {
|
|||
}
|
||||
|
||||
try {
|
||||
String className = "com.android.server.pm." + (Build.VERSION.SDK_INT >= 23 ? "PackageDexOptimizer" : "PackageManagerService");
|
||||
String className = "com.android.server.pm.PackageDexOptimizer";
|
||||
findAndHookMethod(className, SystemMainHooker.systemServerCL,
|
||||
"dexEntryExists", String.class,
|
||||
XC_MethodReplacement.returnConstant(true));
|
||||
|
|
|
|||
Loading…
Reference in New Issue