diff --git a/android/android_framework/base/build.gradle.kts b/android/android_framework/base/build.gradle.kts index a925f3a2e..cc67f6a9a 100644 --- a/android/android_framework/base/build.gradle.kts +++ b/android/android_framework/base/build.gradle.kts @@ -23,8 +23,8 @@ dependencies { } java { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 } tasks.withType { diff --git a/android/android_framework/dex-maker/build.gradle.kts b/android/android_framework/dex-maker/build.gradle.kts index c4ea4112d..b518e8c32 100755 --- a/android/android_framework/dex-maker/build.gradle.kts +++ b/android/android_framework/dex-maker/build.gradle.kts @@ -10,6 +10,6 @@ dependencies { } java { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 } \ No newline at end of file diff --git a/android/android_framework/hidden-api/build.gradle.kts b/android/android_framework/hidden-api/build.gradle.kts index b683dba53..a0bb8daaf 100644 --- a/android/android_framework/hidden-api/build.gradle.kts +++ b/android/android_framework/hidden-api/build.gradle.kts @@ -3,8 +3,8 @@ plugins { } java { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 } dependencies { diff --git a/android/android_framework/patch-common/build.gradle.kts b/android/android_framework/patch-common/build.gradle.kts index b217af559..b67c9a5e0 100755 --- a/android/android_framework/patch-common/build.gradle.kts +++ b/android/android_framework/patch-common/build.gradle.kts @@ -12,6 +12,6 @@ dependencies { } java { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 } \ No newline at end of file diff --git a/android/android_framework/patch-magisk/bridge-dex-app/build.gradle.kts b/android/android_framework/patch-magisk/bridge-dex-app/build.gradle.kts index fa8e5e382..544d33d80 100644 --- a/android/android_framework/patch-magisk/bridge-dex-app/build.gradle.kts +++ b/android/android_framework/patch-magisk/bridge-dex-app/build.gradle.kts @@ -33,8 +33,8 @@ android { } compileOptions { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 } buildFeatures { diff --git a/android/android_framework/patch-magisk/bridge/build.gradle.kts b/android/android_framework/patch-magisk/bridge/build.gradle.kts index 14fde5502..053eb0d7b 100755 --- a/android/android_framework/patch-magisk/bridge/build.gradle.kts +++ b/android/android_framework/patch-magisk/bridge/build.gradle.kts @@ -14,6 +14,6 @@ dependencies { } java { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 } \ No newline at end of file diff --git a/android/android_framework/patch-magisk/module/build.gradle.kts b/android/android_framework/patch-magisk/module/build.gradle.kts index 8b0c4bebf..fd3145b3d 100644 --- a/android/android_framework/patch-magisk/module/build.gradle.kts +++ b/android/android_framework/patch-magisk/module/build.gradle.kts @@ -39,8 +39,8 @@ android { } compileOptions { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 } externalNativeBuild { diff --git a/android/android_framework/patch-magisk/patch-framework/build.gradle.kts b/android/android_framework/patch-magisk/patch-framework/build.gradle.kts index d37e40508..e0ac8c6c5 100644 --- a/android/android_framework/patch-magisk/patch-framework/build.gradle.kts +++ b/android/android_framework/patch-magisk/patch-framework/build.gradle.kts @@ -17,6 +17,6 @@ dependencies { } java { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 } \ No newline at end of file diff --git a/android/android_framework/patchx-lib/build.gradle.kts b/android/android_framework/patchx-lib/build.gradle.kts index 99898e90b..b1fc542cc 100755 --- a/android/android_framework/patchx-lib/build.gradle.kts +++ b/android/android_framework/patchx-lib/build.gradle.kts @@ -11,6 +11,6 @@ dependencies { } java { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 } \ No newline at end of file diff --git a/android/android_framework/res/build.gradle.kts b/android/android_framework/res/build.gradle.kts index 7c1c5f817..be18642ba 100644 --- a/android/android_framework/res/build.gradle.kts +++ b/android/android_framework/res/build.gradle.kts @@ -14,8 +14,8 @@ android { } compileOptions { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 } buildFeatures { diff --git a/android/annotation_processors/permission-requester-annotation/build.gradle.kts b/android/annotation_processors/permission-requester-annotation/build.gradle.kts index 76786b8cb..85ba2aad1 100755 --- a/android/annotation_processors/permission-requester-annotation/build.gradle.kts +++ b/android/annotation_processors/permission-requester-annotation/build.gradle.kts @@ -3,6 +3,6 @@ plugins { } java { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 } \ No newline at end of file diff --git a/android/annotation_processors/permission-requester-compiler/build.gradle.kts b/android/annotation_processors/permission-requester-compiler/build.gradle.kts index 29737fae9..362b6c637 100755 --- a/android/annotation_processors/permission-requester-compiler/build.gradle.kts +++ b/android/annotation_processors/permission-requester-compiler/build.gradle.kts @@ -12,6 +12,6 @@ dependencies { } java { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 } \ No newline at end of file diff --git a/android/annotation_processors/xposed_hook_annotation/build.gradle.kts b/android/annotation_processors/xposed_hook_annotation/build.gradle.kts index 895f5e6f7..c533406b6 100755 --- a/android/annotation_processors/xposed_hook_annotation/build.gradle.kts +++ b/android/annotation_processors/xposed_hook_annotation/build.gradle.kts @@ -7,6 +7,6 @@ dependencies { } java { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 } \ No newline at end of file diff --git a/android/annotation_processors/xposed_hook_compiler/build.gradle.kts b/android/annotation_processors/xposed_hook_compiler/build.gradle.kts index 18fefdcf7..6a2583ea1 100755 --- a/android/annotation_processors/xposed_hook_compiler/build.gradle.kts +++ b/android/annotation_processors/xposed_hook_compiler/build.gradle.kts @@ -12,6 +12,6 @@ dependencies { } java { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 } \ No newline at end of file diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts index 04fed2be4..264994180 100644 --- a/android/app/build.gradle.kts +++ b/android/app/build.gradle.kts @@ -76,8 +76,8 @@ android { } compileOptions { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 } kotlinOptions { diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 24e2738e1..688f24379 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -8,13 +8,14 @@ android:allowBackup="false" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" + android:description="@string/app_description" android:networkSecurityConfig="@xml/network_security_config" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppThemeLight.NoActionBar" tools:ignore="GoogleAppIndexingWarning" tools:replace="android:allowBackup" - tools:targetApi="n"> + > packageSets) .apply(); } } - - public static boolean isAutoRequestXposedScopeEnabled(Context context) { - return PreferenceManager.getDefaultSharedPreferences(context) - .getBoolean(PREF_KEY_AUTO_REQUEST_XPOSED_SCOPE, true); - } - - public static void setAutoRequestXposedScopeEnabled(Context context, boolean value) { - PreferenceManager.getDefaultSharedPreferences(context) - .edit() - .putBoolean(PREF_KEY_AUTO_REQUEST_XPOSED_SCOPE, value) - .apply(); - } } diff --git a/android/app/src/main/java/github/tornaco/android/thanos/settings/SettingsDashboardFragment.java b/android/app/src/main/java/github/tornaco/android/thanos/settings/SettingsDashboardFragment.java index 41ef6d5a9..3af781bbc 100644 --- a/android/app/src/main/java/github/tornaco/android/thanos/settings/SettingsDashboardFragment.java +++ b/android/app/src/main/java/github/tornaco/android/thanos/settings/SettingsDashboardFragment.java @@ -45,7 +45,6 @@ import github.tornaco.android.thanos.BuildProp; import github.tornaco.android.thanos.R; import github.tornaco.android.thanos.ThanosApp; -import github.tornaco.android.thanos.XposedScope; import github.tornaco.android.thanos.app.donate.DonateActivity; import github.tornaco.android.thanos.app.donate.DonateSettings; import github.tornaco.android.thanos.apps.AppDetailsActivity; @@ -204,14 +203,6 @@ private void invalidateIconPack(IconPack pack) { } protected void onBindStrategyPreferences() { - SwitchPreferenceCompat autoXposedScope = findPreference(getString(R.string.key_new_auto_request_xposed_scope)); - Objects.requireNonNull(autoXposedScope).setVisible(XposedScope.INSTANCE.getService() != null); - autoXposedScope.setChecked(AppPreference.isAutoRequestXposedScopeEnabled(requireContext())); - autoXposedScope.setOnPreferenceChangeListener((preference, newValue) -> { - AppPreference.setAutoRequestXposedScopeEnabled(requireContext(), (Boolean) newValue); - return true; - }); - ThanosManager thanos = ThanosManager.from(getContext()); if (!thanos.isServiceInstalled()) { return; diff --git a/android/app/src/main/res/values/pref_keys.xml b/android/app/src/main/res/values/pref_keys.xml index 55b76649d..7a13e1522 100644 --- a/android/app/src/main/res/values/pref_keys.xml +++ b/android/app/src/main/res/values/pref_keys.xml @@ -175,7 +175,6 @@ key_app_feature_config_redaction_notification_text key_strategy - key_new_auto_request_xposed_scope key_new_installed_apps_config key_new_installed_apps_config_enabled key_config_template_category diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml index f3174050c..d47aa4509 100644 --- a/android/app/src/main/res/values/strings.xml +++ b/android/app/src/main/res/values/strings.xml @@ -1,5 +1,6 @@ Thanox + I am Thanos! 😈👌 On diff --git a/android/app/src/main/res/xml/settings_dashboard.xml b/android/app/src/main/res/xml/settings_dashboard.xml index a707069c7..f84848b8f 100644 --- a/android/app/src/main/res/xml/settings_dashboard.xml +++ b/android/app/src/main/res/xml/settings_dashboard.xml @@ -90,12 +90,6 @@ app:summary="@string/pref_summary_enable_power_save" app:title="@string/pref_title_enable_power_save" /> - - - * This class should be extended by the Xposed framework as the implementation of Xposed interfaces.
- * Modules should not use this class directly. - */ -public abstract class XposedContext extends Context implements XposedInterface { - -} diff --git a/android/third_party/libxposed/api/src/main/java/io/github/libxposed/api/XposedContextWrapper.java b/android/third_party/libxposed/api/src/main/java/io/github/libxposed/api/XposedContextWrapper.java deleted file mode 100644 index 2f9eb1018..000000000 --- a/android/third_party/libxposed/api/src/main/java/io/github/libxposed/api/XposedContextWrapper.java +++ /dev/null @@ -1,289 +0,0 @@ -package io.github.libxposed.api; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.SuppressLint; -import android.content.Context; -import android.content.ContextWrapper; - -import java.io.IOException; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.nio.ByteBuffer; - -import io.github.libxposed.api.utils.DexParser; - -/** - * Wrap of {@link XposedContext} used by the modules for the purpose of shielding framework implementation details. - */ -@SuppressWarnings({"unused"}) -@SuppressLint("DiscouragedApi") -public class XposedContextWrapper extends ContextWrapper implements XposedInterface { - - XposedContextWrapper(@NonNull XposedContext base) { - super(base); - } - - XposedContextWrapper(@NonNull XposedContextWrapper base) { - super(base); - } - - /** - * Get the Xposed API version of current implementation. - * - * @return API version - */ - public final int getAPIVersion() { - return API; - } - - /** - * {@inheritDoc} - */ - @NonNull - @Override - public final XposedContext getBaseContext() { - return (XposedContext) super.getBaseContext(); - } - - /** - * {@inheritDoc} - */ - @NonNull - @Override - public final String getFrameworkName() { - return getBaseContext().getFrameworkName(); - } - - /** - * {@inheritDoc} - */ - @NonNull - @Override - public final String getFrameworkVersion() { - return getBaseContext().getFrameworkVersion(); - } - - /** - * {@inheritDoc} - */ - @Override - public final long getFrameworkVersionCode() { - return getBaseContext().getFrameworkVersionCode(); - } - - /** - * {@inheritDoc} - */ - @Override - public final int getFrameworkPrivilege() { - return getBaseContext().getFrameworkPrivilege(); - } - - /** - * {@inheritDoc} - */ - @Nullable - @Override - public final Object featuredMethod(String name, Object... args) { - return getBaseContext().featuredMethod(name, args); - } - - /** - * {@inheritDoc} - */ - @NonNull - @Override - public final MethodUnhooker, Method> hookBefore(@NonNull Method origin, @NonNull BeforeHooker hooker) { - return getBaseContext().hookBefore(origin, hooker); - } - - /** - * {@inheritDoc} - */ - @NonNull - @Override - public final MethodUnhooker, Method> hookAfter(@NonNull Method origin, @NonNull AfterHooker hooker) { - return getBaseContext().hookAfter(origin, hooker); - } - - /** - * {@inheritDoc} - */ - @NonNull - @Override - public final MethodUnhooker, Method> hook(@NonNull Method origin, @NonNull Hooker hooker) { - return getBaseContext().hook(origin, hooker); - } - - /** - * {@inheritDoc} - */ - @NonNull - @Override - public final MethodUnhooker, Method> hookBefore(@NonNull Method origin, int priority, @NonNull BeforeHooker hooker) { - return getBaseContext().hookBefore(origin, priority, hooker); - } - - /** - * {@inheritDoc} - */ - @NonNull - @Override - public final MethodUnhooker, Method> hookAfter(@NonNull Method origin, int priority, @NonNull AfterHooker hooker) { - return getBaseContext().hookAfter(origin, priority, hooker); - } - - /** - * {@inheritDoc} - */ - @NonNull - @Override - public final MethodUnhooker, Method> hook(@NonNull Method origin, int priority, @NonNull Hooker hooker) { - return getBaseContext().hook(origin, priority, hooker); - } - - /** - * {@inheritDoc} - */ - @NonNull - @Override - public final MethodUnhooker>, Constructor> hookBefore(@NonNull Constructor origin, @NonNull BeforeHooker> hooker) { - return getBaseContext().hookBefore(origin, hooker); - } - - /** - * {@inheritDoc} - */ - @NonNull - @Override - public final MethodUnhooker>, Constructor> hookAfter(@NonNull Constructor origin, @NonNull AfterHooker> hooker) { - return getBaseContext().hookAfter(origin, hooker); - } - - /** - * {@inheritDoc} - */ - @NonNull - @Override - public final MethodUnhooker>, Constructor> hook(@NonNull Constructor origin, @NonNull Hooker> hooker) { - return getBaseContext().hook(origin, hooker); - } - - /** - * {@inheritDoc} - */ - @NonNull - @Override - public final MethodUnhooker>, Constructor> hookBefore(@NonNull Constructor origin, int priority, @NonNull BeforeHooker> hooker) { - return getBaseContext().hookBefore(origin, priority, hooker); - } - - /** - * {@inheritDoc} - */ - @NonNull - @Override - public final MethodUnhooker>, Constructor> hookAfter(@NonNull Constructor origin, int priority, @NonNull AfterHooker> hooker) { - return getBaseContext().hookAfter(origin, priority, hooker); - } - - /** - * {@inheritDoc} - */ - @NonNull - @Override - public final MethodUnhooker>, Constructor> hook(@NonNull Constructor origin, int priority, @NonNull Hooker> hooker) { - return getBaseContext().hook(origin, priority, hooker); - } - - /** - * {@inheritDoc} - */ - @Override - public final boolean deoptimize(@NonNull Method method) { - return getBaseContext().deoptimize(method); - } - - /** - * {@inheritDoc} - */ - @Override - public final boolean deoptimize(@NonNull Constructor constructor) { - return getBaseContext().deoptimize(constructor); - } - - /** - * {@inheritDoc} - */ - @Nullable - @Override - public final Object invokeOrigin(@NonNull Method method, @Nullable Object thisObject, Object... args) throws InvocationTargetException, IllegalArgumentException, IllegalAccessException { - return getBaseContext().invokeOrigin(method, thisObject, args); - } - - /** - * {@inheritDoc} - */ - @Nullable - @Override - public final Object invokeSpecial(@NonNull Method method, @NonNull Object thisObject, Object... args) throws InvocationTargetException, IllegalArgumentException, IllegalAccessException { - return getBaseContext().invokeSpecial(method, thisObject, args); - } - - /** - * {@inheritDoc} - */ - @NonNull - @Override - public final T newInstanceOrigin(@NonNull Constructor constructor, Object... args) throws InvocationTargetException, IllegalArgumentException, IllegalAccessException, InstantiationException { - return getBaseContext().newInstanceOrigin(constructor, args); - } - - /** - * {@inheritDoc} - */ - @NonNull - @Override - public final U newInstanceSpecial(@NonNull Constructor constructor, @NonNull Class subClass, Object... args) throws InvocationTargetException, IllegalArgumentException, IllegalAccessException, InstantiationException { - return getBaseContext().newInstanceSpecial(constructor, subClass, args); - } - - /** - * {@inheritDoc} - */ - @Override - public final void log(@NonNull String message) { - getBaseContext().log(message); - } - - /** - * {@inheritDoc} - */ - @Override - public final void log(@NonNull String message, @NonNull Throwable throwable) { - getBaseContext().log(message, throwable); - } - - /** - * {@inheritDoc} - */ - @Nullable - @Override - public final DexParser parseDex(@NonNull ByteBuffer dexData, boolean includeAnnotations) throws IOException { - return getBaseContext().parseDex(dexData, includeAnnotations); - } - - /** - * {@inheritDoc} - */ - @Override - protected final void attachBaseContext(Context base) { - if (base instanceof XposedContext || base instanceof XposedContextWrapper) { - super.attachBaseContext(base); - } else { - throw new IllegalArgumentException(); - } - } -} diff --git a/android/third_party/libxposed/api/src/main/java/io/github/libxposed/api/XposedInterface.java b/android/third_party/libxposed/api/src/main/java/io/github/libxposed/api/XposedInterface.java index d66bc03e9..c3f8a11f0 100644 --- a/android/third_party/libxposed/api/src/main/java/io/github/libxposed/api/XposedInterface.java +++ b/android/third_party/libxposed/api/src/main/java/io/github/libxposed/api/XposedInterface.java @@ -4,18 +4,19 @@ import android.annotation.Nullable; import android.content.SharedPreferences; import android.content.pm.ApplicationInfo; -import android.content.res.Resources; +import android.os.ParcelFileDescriptor; - -import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Member; import java.lang.reflect.Method; import java.nio.ByteBuffer; -import java.util.ConcurrentModificationException; +import io.github.libxposed.api.annotations.AfterInvocation; +import io.github.libxposed.api.annotations.BeforeInvocation; +import io.github.libxposed.api.annotations.XposedHooker; import io.github.libxposed.api.errors.HookFailedError; import io.github.libxposed.api.utils.DexParser; @@ -43,7 +44,7 @@ public interface XposedInterface { int FRAMEWORK_PRIVILEGE_APP = 2; /** * Indicates that the framework is embedded in the hooked app, - * which means {@link #getSharedPreferences} will be null and remote file is unsupported. + * which means {@link #getRemotePreferences} will be null and remote file is unsupported. */ int FRAMEWORK_PRIVILEGE_EMBEDDED = 3; @@ -61,245 +62,183 @@ public interface XposedInterface { int PRIORITY_HIGHEST = 10000; /** - * The interface Before hook callback. - * - * @param the type parameter + * Contextual interface for before invocation callbacks. */ - interface BeforeHookCallback { + interface BeforeHookCallback { /** - * Gets origin. - * - * @return the origin + * Gets the method / constructor to be hooked. */ @NonNull - T getOrigin(); + Member getMember(); /** - * Gets this. - * - * @return the this + * Gets the {@code this} object, or {@code null} if the method is static. */ @Nullable - Object getThis(); + Object getThisObject(); /** - * Get args object [ ]. - * - * @return the object [ ] + * Gets the arguments passed to the method / constructor. You can modify the arguments. */ @NonNull Object[] getArgs(); /** - * Gets arg. - * - * @param the type parameter - * @param index the index - * @return the arg - */ - @Nullable - U getArg(int index); - - /** - * Sets arg. + * Sets the return value of the method and skip the invocation. If the procedure is a constructor, + * the {@code result} param will be ignored. + * Note that the after invocation callback will still be called. * - * @param the type parameter - * @param index the index - * @param value the value + * @param result The return value */ - void setArg(int index, U value); + void returnAndSkip(@Nullable Object result); /** - * Return and skip. + * Throw an exception from the method / constructor and skip the invocation. + * Note that the after invocation callback will still be called. * - * @param returnValue the return value - */ - void returnAndSkip(@Nullable Object returnValue); - - /** - * Throw and skip. - * - * @param throwable the throwable + * @param throwable The exception to be thrown */ void throwAndSkip(@Nullable Throwable throwable); - - /** - * Invoke origin object. - * - * @return the object - * @throws InvocationTargetException the invocation target exception - * @throws IllegalArgumentException the illegal argument exception - * @throws IllegalAccessException the illegal access exception - */ - @Nullable - Object invokeOrigin() throws InvocationTargetException, IllegalArgumentException, IllegalAccessException; - - /** - * Sets extra. - * - * @param the type parameter - * @param key the key - * @param value the value - * @throws ConcurrentModificationException the concurrent modification exception - */ - void setExtra(@NonNull String key, @Nullable U value) throws ConcurrentModificationException; } /** - * The interface After hook callback. - * - * @param the type parameter + * Contextual interface for after invocation callbacks. */ - interface AfterHookCallback { + interface AfterHookCallback { /** - * Gets origin. - * - * @return the origin + * Gets the method / constructor to be hooked. */ @NonNull - T getOrigin(); + Member getMember(); /** - * Gets this. - * - * @return the this + * Gets the {@code this} object, or {@code null} if the method is static. */ @Nullable - Object getThis(); + Object getThisObject(); /** - * Get args object [ ]. - * - * @return the object [ ] + * Gets all arguments passed to the method / constructor. */ @NonNull Object[] getArgs(); /** - * Gets result. - * - * @return the result + * Gets the return value of the method or the before invocation callback. If the procedure is a + * constructor, a void method or an exception was thrown, the return value will be {@code null}. */ @Nullable Object getResult(); /** - * Gets throwable. - * - * @return the throwable + * Gets the exception thrown by the method / constructor or the before invocation callback. If the + * procedure call was successful, the return value will be {@code null}. */ @Nullable Throwable getThrowable(); /** - * Is skipped boolean. - * - * @return the boolean + * Gets whether the invocation was skipped by the before invocation callback. */ boolean isSkipped(); /** - * Sets result. + * Sets the return value of the method and skip the invocation. If the procedure is a constructor, + * the {@code result} param will be ignored. * - * @param result the result + * @param result The return value */ void setResult(@Nullable Object result); /** - * Sets throwable. + * Sets the exception thrown by the method / constructor. * - * @param throwable the throwable + * @param throwable The exception to be thrown. */ void setThrowable(@Nullable Throwable throwable); - - /** - * Invoke origin object. - * - * @return the object - * @throws InvocationTargetException the invocation target exception - * @throws IllegalAccessException the illegal access exception - */ - @Nullable - Object invokeOrigin() throws InvocationTargetException, IllegalAccessException; - - /** - * Gets extra. - * - * @param the type parameter - * @param key the key - * @return the extra - */ - @Nullable - U getExtra(@NonNull String key); - } - - /** - * The interface Before hooker. - * - * @param the type parameter - */ - interface BeforeHooker { - /** - * Before. - * - * @param callback the callback - */ - void before(@NonNull BeforeHookCallback callback); - } - - /** - * The interface After hooker. - * - * @param the type parameter - */ - interface AfterHooker { - /** - * After. - * - * @param callback the callback - */ - void after(@NonNull AfterHookCallback callback); } /** - * The interface Hooker. - * - * @param the type parameter - */ - interface Hooker extends BeforeHooker, AfterHooker { + * Interface for method / constructor hooking. Xposed modules should define their own hooker class + * and implement this interface. Normally, a hooker class corresponds to a method / constructor, but + * there could also be a single hooker class for all of them. By this way you can implement an interface + * like the old API. + * + *

+ * Classes implementing this interface should be annotated with {@link XposedHooker} and should provide + * two public static methods that are annotated with {@link BeforeInvocation} and {@link AfterInvocation}, + * respectively. + *

+ * + *

+ * The before invocation method should have the following signature:
+ * Param {@code callback}: The {@link BeforeHookCallback} of the procedure call.
+ * Return value: If you want to save contextual information of one procedure call between the before + * and after callback, it could be a self-defined class, otherwise it should be {@code void}. + *

+ * + *

+ * The after invocation method should have the following signature:
+ * Param {@code callback}: The {@link AfterHookCallback} of the procedure call.
+ * Param {@code context} (optional): The contextual object returned by the before invocation. + *

+ * + *

Example usage:

+ * + *
{@code
+     *   @XposedHooker
+     *   public class ExampleHooker implements Hooker {
+     *
+     *       @BeforeInvocation
+     *       public static void before(@NonNull BeforeHookCallback callback) {
+     *           // Pre-hooking logic goes here
+     *       }
+     *
+     *       @AfterInvocation
+     *       public static void after(@NonNull AfterHookCallback callback) {
+     *           // Post-hooking logic goes here
+     *       }
+     *   }
+     *
+     *   @XposedHooker
+     *   public class ExampleHookerWithContext implements Hooker {
+     *
+     *       @BeforeInvocation
+     *       public static MyContext before(@NonNull BeforeHookCallback callback) {
+     *           // Pre-hooking logic goes here
+     *           return new MyContext();
+     *       }
+     *
+     *       @AfterInvocation
+     *       public static void after(@NonNull AfterHookCallback callback, MyContext context) {
+     *           // Post-hooking logic goes here
+     *       }
+     *   }
+     * }
+ */ + interface Hooker { } /** - * The interface Method unhooker. + * Interface for canceling a hook. * - * @param the type parameter - * @param the type parameter + * @param {@link Method} or {@link Constructor} */ - interface MethodUnhooker { + interface MethodUnhooker { /** - * Gets origin. - * - * @return the origin + * Gets the method or constructor being hooked. */ @NonNull - U getOrigin(); - - /** - * Gets hooker. - * - * @return the hooker - */ - @NonNull - T getHooker(); + T getOrigin(); /** - * Unhook. + * Cancels the hook. The behavior of calling this method multiple times is undefined. */ void unhook(); } /** - * Get the Xposed framework name of current implementation. + * Gets the Xposed framework name of current implementation. * * @return Framework name */ @@ -307,7 +246,7 @@ interface MethodUnhooker { String getFrameworkName(); /** - * Get the Xposed framework version of current implementation. + * Gets the Xposed framework version of current implementation. * * @return Framework version */ @@ -315,337 +254,223 @@ interface MethodUnhooker { String getFrameworkVersion(); /** - * Get the Xposed framework version code of current implementation. + * Gets the Xposed framework version code of current implementation. * * @return Framework version code */ long getFrameworkVersionCode(); /** - * Get the Xposed framework privilege of current implementation. + * Gets the Xposed framework privilege of current implementation. * * @return Framework privilege */ int getFrameworkPrivilege(); /** - * Additional methods provided by specific Xposed framework. - * - * @param name Featured method name - * @param args Featured method arguments - * @return Featured method result - * @throws UnsupportedOperationException If the framework does not provide a method with given name - */ - // @Discouraged(message = "Normally, modules should never rely on specific implementation of the Xposed framework. But if really necessary, this method can be used to acquire such information.") - @Nullable - Object featuredMethod(String name, Object... args); - - /** - * Hook before method unhooker. + * Hook a method with default priority. * - * @param origin the origin - * @param hooker the hooker - * @return the method unhooker - * @throws IllegalArgumentException if origin is abstract, framework internal or {@link Method#invoke} + * @param origin The method to be hooked + * @param hooker The hooker class + * @return Unhooker for canceling the hook + * @throws IllegalArgumentException if origin is abstract, framework internal or {@link Method#invoke}, + * or hooker is invalid * @throws HookFailedError if hook fails due to framework internal error */ @NonNull - MethodUnhooker, Method> hookBefore(@NonNull Method origin, @NonNull BeforeHooker hooker); + MethodUnhooker hook(@NonNull Method origin, @NonNull Class hooker); /** - * Hook after method unhooker. + * Hook a method with specified priority. * - * @param origin the origin - * @param hooker the hooker - * @return the method unhooker - * @throws IllegalArgumentException if origin is abstract, framework internal or {@link Method#invoke} + * @param origin The method to be hooked + * @param priority The hook priority + * @param hooker The hooker class + * @return Unhooker for canceling the hook + * @throws IllegalArgumentException if origin is abstract, framework internal or {@link Method#invoke}, + * or hooker is invalid * @throws HookFailedError if hook fails due to framework internal error */ @NonNull - MethodUnhooker, Method> hookAfter(@NonNull Method origin, @NonNull AfterHooker hooker); + MethodUnhooker hook(@NonNull Method origin, int priority, @NonNull Class hooker); /** - * Hook method unhooker. + * Hook a constructor with default priority. * - * @param origin the origin - * @param hooker the hooker - * @return the method unhooker - * @throws IllegalArgumentException if origin is abstract, framework internal or {@link Method#invoke} + * @param The type of the constructor + * @param origin The constructor to be hooked + * @param hooker The hooker class + * @return Unhooker for canceling the hook + * @throws IllegalArgumentException if origin is abstract, framework internal or {@link Method#invoke}, + * or hooker is invalid * @throws HookFailedError if hook fails due to framework internal error */ @NonNull - MethodUnhooker, Method> hook(@NonNull Method origin, @NonNull Hooker hooker); + MethodUnhooker> hook(@NonNull Constructor origin, @NonNull Class hooker); /** - * Hook before method unhooker. + * Hook a constructor with specified priority. * - * @param origin the origin - * @param priority the priority - * @param hooker the hooker - * @return the method unhooker - * @throws IllegalArgumentException if origin is abstract, framework internal or {@link Method#invoke} + * @param The type of the constructor + * @param origin The constructor to be hooked + * @param priority The hook priority + * @param hooker The hooker class + * @return Unhooker for canceling the hook + * @throws IllegalArgumentException if origin is abstract, framework internal or {@link Method#invoke}, + * or hooker is invalid * @throws HookFailedError if hook fails due to framework internal error */ @NonNull - MethodUnhooker, Method> hookBefore(@NonNull Method origin, int priority, @NonNull BeforeHooker hooker); + MethodUnhooker> hook(@NonNull Constructor origin, int priority, @NonNull Class hooker); /** - * Hook after method unhooker. + * Deoptimizes a method in case hooked callee is not called because of inline. * - * @param origin the origin - * @param priority the priority - * @param hooker the hooker - * @return the method unhooker - * @throws IllegalArgumentException if origin is abstract, framework internal or {@link Method#invoke} - * @throws HookFailedError if hook fails due to framework internal error - */ - @NonNull - MethodUnhooker, Method> hookAfter(@NonNull Method origin, int priority, @NonNull AfterHooker hooker); - - /** - * Hook method unhooker. + *

By deoptimizing the method, the method will back all callee without inlining. + * For example, when a short hooked method B is invoked by method A, the callback to B is not invoked + * after hooking, which may mean A has inlined B inside its method body. To force A to call the hooked B, + * you can deoptimize A and then your hook can take effect.

* - * @param origin the origin - * @param priority the priority - * @param hooker the hooker - * @return the method unhooker - * @throws IllegalArgumentException if origin is abstract, framework internal or {@link Method#invoke} - * @throws HookFailedError if hook fails due to framework internal error - */ - @NonNull - MethodUnhooker, Method> hook(@NonNull Method origin, int priority, @NonNull Hooker hooker); - - /** - * Hook before method unhooker. + *

Generally, you need to find all the callers of your hooked callee and that can be hardly achieve + * (but you can still search all callers by using {@link DexParser}). Use this method if you are sure + * the deoptimized callers are all you need. Otherwise, it would be better to change the hook point or + * to deoptimize the whole app manually (by simply reinstalling the app without uninstall).

* - * @param the type parameter - * @param origin the origin - * @param hooker the hooker - * @return the method unhooker - * @throws IllegalArgumentException if origin is abstract, framework internal or {@link Method#invoke} - * @throws HookFailedError if hook fails due to framework internal error - */ - @NonNull - MethodUnhooker>, Constructor> hookBefore(@NonNull Constructor origin, @NonNull BeforeHooker> hooker); - - /** - * Hook after method unhooker. - * - * @param the type parameter - * @param origin the origin - * @param hooker the hooker - * @return the method unhooker - * @throws IllegalArgumentException if origin is abstract, framework internal or {@link Method#invoke} - * @throws HookFailedError if hook fails due to framework internal error - */ - @NonNull - MethodUnhooker>, Constructor> hookAfter(@NonNull Constructor origin, @NonNull AfterHooker> hooker); - - /** - * Hook method unhooker. - * - * @param the type parameter - * @param origin the origin - * @param hooker the hooker - * @return the method unhooker - * @throws IllegalArgumentException if origin is abstract, framework internal or {@link Method#invoke} - * @throws HookFailedError if hook fails due to framework internal error - */ - @NonNull - MethodUnhooker>, Constructor> hook(@NonNull Constructor origin, @NonNull Hooker> hooker); - - /** - * Hook before method unhooker. - * - * @param the type parameter - * @param origin the origin - * @param priority the priority - * @param hooker the hooker - * @return the method unhooker - * @throws IllegalArgumentException if origin is abstract, framework internal or {@link Method#invoke} - * @throws HookFailedError if hook fails due to framework internal error - */ - @NonNull - MethodUnhooker>, Constructor> hookBefore(@NonNull Constructor origin, int priority, @NonNull BeforeHooker> hooker); - - /** - * Hook after method unhooker. - * - * @param the type parameter - * @param origin the origin - * @param priority the priority - * @param hooker the hooker - * @return the method unhooker - * @throws IllegalArgumentException if origin is abstract, framework internal or {@link Method#invoke} - * @throws HookFailedError if hook fails due to framework internal error - */ - @NonNull - MethodUnhooker>, Constructor> hookAfter(@NonNull Constructor origin, int priority, @NonNull AfterHooker> hooker); - - /** - * Hook method unhooker. - * - * @param the type parameter - * @param origin the origin - * @param priority the priority - * @param hooker the hooker - * @return the method unhooker - * @throws IllegalArgumentException if origin is abstract, framework internal or {@link Method#invoke} - * @throws HookFailedError if hook fails due to framework internal error - */ - @NonNull - MethodUnhooker>, Constructor> hook(@NonNull Constructor origin, int priority, @NonNull Hooker> hooker); - - /** - * Deoptimize boolean. - * - * @param method the method - * @return the boolean + * @param method The method to deoptimize + * @return Indicate whether the deoptimizing succeed or not */ boolean deoptimize(@NonNull Method method); /** - * Deoptimize boolean. + * Deoptimizes a constructor in case hooked callee is not called because of inline. * - * @param the type parameter - * @param constructor the constructor - * @return the boolean + * @param The type of the constructor + * @param constructor The constructor to deoptimize + * @return Indicate whether the deoptimizing succeed or not + * @see #deoptimize(Method) */ boolean deoptimize(@NonNull Constructor constructor); /** - * Invoke origin object. + * Basically the same as {@link Method#invoke(Object, Object...)}, but calls the original method + * as it was before the interception by Xposed. * - * @param method the method - * @param thisObject the this object - * @param args the args - * @return the object - * @throws InvocationTargetException the invocation target exception - * @throws IllegalArgumentException the illegal argument exception - * @throws IllegalAccessException the illegal access exception + * @param method The method to be called + * @param thisObject For non-static calls, the {@code this} pointer, otherwise {@code null} + * @param args The arguments used for the method call + * @return The result returned from the invoked method + * @see Method#invoke(Object, Object...) */ @Nullable Object invokeOrigin(@NonNull Method method, @Nullable Object thisObject, Object... args) throws InvocationTargetException, IllegalArgumentException, IllegalAccessException; /** - * Invoke special object. + * Invokes a special (non-virtual) method on a given object instance, similar to the functionality of + * {@code CallNonVirtualMethod} in JNI, which invokes an instance (nonstatic) method on a Java + * object. This method is useful when you need to call a specific method on an object, bypassing any + * overridden methods in subclasses and directly invoking the method defined in the specified class. + * + *

This method is useful when you need to call {@code super.xxx()} in a hooked constructor.

* - * @param method the method - * @param thisObject the this object - * @param args the args - * @return the object - * @throws InvocationTargetException the invocation target exception - * @throws IllegalArgumentException the illegal argument exception - * @throws IllegalAccessException the illegal access exception + * @param method The method to be called + * @param thisObject For non-static calls, the {@code this} pointer, otherwise {@code null} + * @param args The arguments used for the method call + * @return The result returned from the invoked method + * @see Method#invoke(Object, Object...) */ @Nullable Object invokeSpecial(@NonNull Method method, @NonNull Object thisObject, Object... args) throws InvocationTargetException, IllegalArgumentException, IllegalAccessException; /** - * new origin object. + * Basically the same as {@link Constructor#newInstance(Object...)}, but calls the original constructor + * as it was before the interception by Xposed. * - * @param the type parameter - * @param constructor the constructor - * @param args the args - * @return the object - * @throws InvocationTargetException the invocation target exception - * @throws IllegalArgumentException the illegal argument exception - * @throws IllegalAccessException the illegal access exception - * @throws InstantiationException the instantiation exception + * @param The type of the constructor + * @param constructor The constructor to create and initialize a new instance + * @param args The arguments used for the construction + * @return The instance created and initialized by the constructor + * @see Constructor#newInstance(Object...) */ @NonNull T newInstanceOrigin(@NonNull Constructor constructor, Object... args) throws InvocationTargetException, IllegalArgumentException, IllegalAccessException, InstantiationException; - /** - * New instance special u. + * Creates a new instance of the given subclass, but initialize it with a parent constructor. This could + * leave the object in an invalid state, where the subclass constructor are not called and the fields + * of the subclass are not initialized. + * + *

This method is useful when you need to initialize some fields in the subclass by yourself.

* - * @param the type parameter - * @param the type parameter - * @param constructor the constructor - * @param subClass the sub class - * @param args the args - * @return the u - * @throws InvocationTargetException the invocation target exception - * @throws IllegalArgumentException the illegal argument exception - * @throws IllegalAccessException the illegal access exception - * @throws InstantiationException the instantiation exception + * @param The type of the parent constructor + * @param The type of the subclass + * @param constructor The parent constructor to initialize a new instance + * @param subClass The subclass to create a new instance + * @param args The arguments used for the construction + * @return The instance of subclass initialized by the constructor + * @see Constructor#newInstance(Object...) */ @NonNull U newInstanceSpecial(@NonNull Constructor constructor, @NonNull Class subClass, Object... args) throws InvocationTargetException, IllegalArgumentException, IllegalAccessException, InstantiationException; /** - * Log. + * Writes a message to the Xposed log. * - * @param message the message + * @param message The log message */ void log(@NonNull String message); /** - * Log. + * Writes a message with a stack trace to the Xposed log. * - * @param message the message - * @param throwable the throwable + * @param message The log message + * @param throwable The Throwable object for the stack trace */ void log(@NonNull String message, @NonNull Throwable throwable); /** - * Parse dex dex parser. + * Parse a dex file in memory. * - * @param dexData the dex data - * @param includeAnnotations the include annotations - * @return the dex parser - * @throws IOException the io exception + * @param dexData The content of the dex file + * @param includeAnnotations Whether to include annotations + * @return The {@link DexParser} of the dex file + * @throws IOException if the dex file is invalid */ @Nullable DexParser parseDex(@NonNull ByteBuffer dexData, boolean includeAnnotations) throws IOException; - - // Methods the same with Context - /** - * Gets shared preferences. - * - * @param name the name - * @param mode the mode - * @return the shared preferences + * Gets the application info of the module. */ - SharedPreferences getSharedPreferences(String name, int mode); - - /** - * Open file input file input stream. - * - * @param name the name - * @return the file input stream - * @throws FileNotFoundException the file not found exception - */ - FileInputStream openFileInput(String name) throws FileNotFoundException; - - /** - * File list string [ ]. - * - * @return the string [ ] - */ - String[] fileList(); + @NonNull + ApplicationInfo getApplicationInfo(); /** - * Gets resources. + * Gets remote preferences stored in Xposed framework. Note that those are read-only in hooked apps. * - * @return the resources + * @param group Group name + * @return The preferences + * @throws UnsupportedOperationException If the framework is embedded */ - Resources getResources(); + @NonNull + SharedPreferences getRemotePreferences(@NonNull String group); /** - * Gets class loader. + * List all files in the module's shared data directory. * - * @return the class loader + * @return The file list + * @throws UnsupportedOperationException If the framework is embedded */ - ClassLoader getClassLoader(); + @NonNull + String[] listRemoteFiles(); /** - * Gets application info. + * Open a file in the module's shared data directory. The file is opened in read-only mode. * - * @return the application info + * @param name File name, must not contain path separators and . or .. + * @return The file descriptor + * @throws FileNotFoundException If the file does not exist or the path is forbidden + * @throws UnsupportedOperationException If the framework is embedded */ - ApplicationInfo getApplicationInfo(); + @NonNull + ParcelFileDescriptor openRemoteFile(@NonNull String name) throws FileNotFoundException; } diff --git a/android/third_party/libxposed/api/src/main/java/io/github/libxposed/api/XposedInterfaceWrapper.java b/android/third_party/libxposed/api/src/main/java/io/github/libxposed/api/XposedInterfaceWrapper.java new file mode 100644 index 000000000..26f9ddff4 --- /dev/null +++ b/android/third_party/libxposed/api/src/main/java/io/github/libxposed/api/XposedInterfaceWrapper.java @@ -0,0 +1,148 @@ +package io.github.libxposed.api; + +import android.content.SharedPreferences; +import android.content.pm.ApplicationInfo; +import android.os.ParcelFileDescriptor; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.nio.ByteBuffer; +import android.annotation.NonNull; +import android.annotation.Nullable; + +import io.github.libxposed.api.utils.DexParser; + +/** + * Wrap of {@link XposedInterface} used by the modules for the purpose of shielding framework implementation details. + */ +public class XposedInterfaceWrapper implements XposedInterface { + + private final XposedInterface mBase; + + XposedInterfaceWrapper(@NonNull XposedInterface base) { + mBase = base; + } + + @NonNull + @Override + public final String getFrameworkName() { + return mBase.getFrameworkName(); + } + + @NonNull + @Override + public final String getFrameworkVersion() { + return mBase.getFrameworkVersion(); + } + + @Override + public final long getFrameworkVersionCode() { + return mBase.getFrameworkVersionCode(); + } + + @Override + public final int getFrameworkPrivilege() { + return mBase.getFrameworkPrivilege(); + } + + @NonNull + @Override + public final MethodUnhooker hook(@NonNull Method origin, @NonNull Class hooker) { + return mBase.hook(origin, hooker); + } + + @NonNull + @Override + public final MethodUnhooker hook(@NonNull Method origin, int priority, @NonNull Class hooker) { + return mBase.hook(origin, priority, hooker); + } + + @NonNull + @Override + public final MethodUnhooker> hook(@NonNull Constructor origin, @NonNull Class hooker) { + return mBase.hook(origin, hooker); + } + + @NonNull + @Override + public final MethodUnhooker> hook(@NonNull Constructor origin, int priority, @NonNull Class hooker) { + return mBase.hook(origin, priority, hooker); + } + + @Override + public final boolean deoptimize(@NonNull Method method) { + return mBase.deoptimize(method); + } + + @Override + public final boolean deoptimize(@NonNull Constructor constructor) { + return mBase.deoptimize(constructor); + } + + @Nullable + @Override + public final Object invokeOrigin(@NonNull Method method, @Nullable Object thisObject, Object... args) throws InvocationTargetException, IllegalArgumentException, IllegalAccessException { + return mBase.invokeOrigin(method, thisObject, args); + } + + @Nullable + @Override + public final Object invokeSpecial(@NonNull Method method, @NonNull Object thisObject, Object... args) throws InvocationTargetException, IllegalArgumentException, IllegalAccessException { + return mBase.invokeSpecial(method, thisObject, args); + } + + @NonNull + @Override + public final T newInstanceOrigin(@NonNull Constructor constructor, Object... args) throws InvocationTargetException, IllegalArgumentException, IllegalAccessException, InstantiationException { + return mBase.newInstanceOrigin(constructor, args); + } + + @NonNull + @Override + public final U newInstanceSpecial(@NonNull Constructor constructor, @NonNull Class subClass, Object... args) throws InvocationTargetException, IllegalArgumentException, IllegalAccessException, InstantiationException { + return mBase.newInstanceSpecial(constructor, subClass, args); + } + + @Override + public final void log(@NonNull String message) { + mBase.log(message); + } + + @Override + public final void log(@NonNull String message, @NonNull Throwable throwable) { + mBase.log(message, throwable); + } + + @Nullable + @Override + public final DexParser parseDex(@NonNull ByteBuffer dexData, boolean includeAnnotations) throws IOException { + return mBase.parseDex(dexData, includeAnnotations); + } + + @NonNull + @Override + public SharedPreferences getRemotePreferences(@NonNull String name) { + return mBase.getRemotePreferences(name); + } + + @NonNull + @Override + public ApplicationInfo getApplicationInfo() { + return mBase.getApplicationInfo(); + } + + @NonNull + @Override + public String[] listRemoteFiles() { + return mBase.listRemoteFiles(); + } + + @NonNull + @Override + public ParcelFileDescriptor openRemoteFile(@NonNull String name) throws FileNotFoundException { + return mBase.openRemoteFile(name); + } +} diff --git a/android/third_party/libxposed/api/src/main/java/io/github/libxposed/api/XposedModule.java b/android/third_party/libxposed/api/src/main/java/io/github/libxposed/api/XposedModule.java index 3d6531169..e8ae0ee9e 100644 --- a/android/third_party/libxposed/api/src/main/java/io/github/libxposed/api/XposedModule.java +++ b/android/third_party/libxposed/api/src/main/java/io/github/libxposed/api/XposedModule.java @@ -1,38 +1,22 @@ package io.github.libxposed.api; - import android.annotation.NonNull; +import android.annotation.Nullable; /** * Super class which all Xposed module entry classes should extend.
* Entry classes will be instantiated exactly once for each process. */ @SuppressWarnings("unused") -public abstract class XposedModule extends XposedContextWrapper implements XposedModuleInterface { +public abstract class XposedModule extends XposedInterfaceWrapper implements XposedModuleInterface { /** * Instantiates a new Xposed module.
* When the module is loaded into the target process, the constructor will be called. * - * @param base The base context provided by the framework, should not be used by the module + * @param base The implementation interface provided by the framework, should not be used by the module * @param param Information about the process in which the module is loaded */ - public XposedModule(@NonNull XposedContext base, @NonNull ModuleLoadedParam param) { + public XposedModule(@NonNull XposedInterface base, @NonNull ModuleLoadedParam param) { super(base); } - - /** - * {@inheritDoc} - */ - @Override - public void onPackageLoaded(@NonNull PackageLoadedParam param) { - - } - - /** - * {@inheritDoc} - */ - @Override - public void onSystemServerLoaded(@NonNull SystemServerLoadedParam param) { - - } } diff --git a/android/third_party/libxposed/api/src/main/java/io/github/libxposed/api/XposedModuleInterface.java b/android/third_party/libxposed/api/src/main/java/io/github/libxposed/api/XposedModuleInterface.java index 11a029324..69711a2f3 100644 --- a/android/third_party/libxposed/api/src/main/java/io/github/libxposed/api/XposedModuleInterface.java +++ b/android/third_party/libxposed/api/src/main/java/io/github/libxposed/api/XposedModuleInterface.java @@ -4,7 +4,6 @@ import android.content.pm.ApplicationInfo; import android.os.Build; - /** * Interface for module initialization. */ @@ -15,14 +14,14 @@ public interface XposedModuleInterface { */ interface ModuleLoadedParam { /** - * Get information about whether the module is running in system server. + * Gets information about whether the module is running in system server. * * @return {@code true} if the module is running in system server */ boolean isSystemServer(); /** - * Get the process name. + * Gets the process name. * * @return The process name */ @@ -35,7 +34,7 @@ interface ModuleLoadedParam { */ interface SystemServerLoadedParam { /** - * Get the class loader of system server. + * Gets the class loader of system server. * * @return The class loader */ @@ -48,7 +47,7 @@ interface SystemServerLoadedParam { */ interface PackageLoadedParam { /** - * Get the package name of the package being loaded. + * Gets the package name of the package being loaded. * * @return The package name. */ @@ -56,12 +55,12 @@ interface PackageLoadedParam { String getPackageName(); /** - * Get the ApplicationInfo of the package being loaded. + * Gets the {@link ApplicationInfo} of the package being loaded. * * @return The ApplicationInfo. */ @NonNull - ApplicationInfo getAppInfo(); + ApplicationInfo getApplicationInfo(); /** * Gets default class loader. @@ -73,7 +72,7 @@ interface PackageLoadedParam { ClassLoader getDefaultClassLoader(); /** - * Get the class loader of the package being loaded. + * Gets the class loader of the package being loaded. * * @return The class loader. */ @@ -81,7 +80,7 @@ interface PackageLoadedParam { ClassLoader getClassLoader(); /** - * Get information about whether is this package the first and main package of the app process. + * Gets information about whether is this package the first and main package of the app process. * * @return {@code true} if this is the first package. */ @@ -89,17 +88,19 @@ interface PackageLoadedParam { } /** - * Get notified when a package is loaded into the app process.
+ * Gets notified when a package is loaded into the app process.
* This callback could be invoked multiple times for the same process on each package. * * @param param Information about the package being loaded */ - void onPackageLoaded(@NonNull PackageLoadedParam param); + default void onPackageLoaded(@NonNull PackageLoadedParam param) { + } /** - * Get notified when the system server is loaded. + * Gets notified when the system server is loaded. * * @param param Information about system server */ - void onSystemServerLoaded(@NonNull SystemServerLoadedParam param); + default void onSystemServerLoaded(@NonNull SystemServerLoadedParam param) { + } } diff --git a/android/third_party/libxposed/api/src/main/java/io/github/libxposed/api/annotations/AfterInvocation.java b/android/third_party/libxposed/api/src/main/java/io/github/libxposed/api/annotations/AfterInvocation.java new file mode 100644 index 000000000..e26b3188b --- /dev/null +++ b/android/third_party/libxposed/api/src/main/java/io/github/libxposed/api/annotations/AfterInvocation.java @@ -0,0 +1,11 @@ +package io.github.libxposed.api.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface AfterInvocation { +} diff --git a/android/third_party/libxposed/api/src/main/java/io/github/libxposed/api/annotations/BeforeInvocation.java b/android/third_party/libxposed/api/src/main/java/io/github/libxposed/api/annotations/BeforeInvocation.java new file mode 100644 index 000000000..7b4a17b8a --- /dev/null +++ b/android/third_party/libxposed/api/src/main/java/io/github/libxposed/api/annotations/BeforeInvocation.java @@ -0,0 +1,11 @@ +package io.github.libxposed.api.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface BeforeInvocation { +} diff --git a/android/third_party/libxposed/api/src/main/java/io/github/libxposed/api/annotations/XposedHooker.java b/android/third_party/libxposed/api/src/main/java/io/github/libxposed/api/annotations/XposedHooker.java new file mode 100644 index 000000000..acff8c038 --- /dev/null +++ b/android/third_party/libxposed/api/src/main/java/io/github/libxposed/api/annotations/XposedHooker.java @@ -0,0 +1,11 @@ +package io.github.libxposed.api.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE, ElementType.TYPE_USE}) +public @interface XposedHooker { +} diff --git a/android/third_party/libxposed/api/src/main/java/io/github/libxposed/api/errors/XposedFrameworkError.java b/android/third_party/libxposed/api/src/main/java/io/github/libxposed/api/errors/XposedFrameworkError.java index c75d385a0..0b3bba005 100644 --- a/android/third_party/libxposed/api/src/main/java/io/github/libxposed/api/errors/XposedFrameworkError.java +++ b/android/third_party/libxposed/api/src/main/java/io/github/libxposed/api/errors/XposedFrameworkError.java @@ -3,7 +3,7 @@ /** * Thrown to indicate that the Xposed framework function is broken. */ -public abstract class XposedFrameworkError extends Error { +public class XposedFrameworkError extends Error { public XposedFrameworkError(String message) { super(message); diff --git a/android/third_party/libxposed/api/src/main/java/io/github/libxposed/api/utils/DexParser.java b/android/third_party/libxposed/api/src/main/java/io/github/libxposed/api/utils/DexParser.java index 3d33ec416..8f26ff22d 100644 --- a/android/third_party/libxposed/api/src/main/java/io/github/libxposed/api/utils/DexParser.java +++ b/android/third_party/libxposed/api/src/main/java/io/github/libxposed/api/utils/DexParser.java @@ -1,13 +1,12 @@ package io.github.libxposed.api.utils; - import android.annotation.NonNull; import android.annotation.Nullable; import java.io.Closeable; /** - * The interface Dex parser. + * Xposed interface for parsing dex files. */ @SuppressWarnings("unused") public interface DexParser extends Closeable { diff --git a/android/third_party/libxposed/interface/build.gradle.kts b/android/third_party/libxposed/interface/build.gradle.kts index 6d94bc6c1..5edcea0e1 100644 --- a/android/third_party/libxposed/interface/build.gradle.kts +++ b/android/third_party/libxposed/interface/build.gradle.kts @@ -18,8 +18,8 @@ android { } compileOptions { - targetCompatibility = JavaVersion.VERSION_1_8 - sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_11 + sourceCompatibility = JavaVersion.VERSION_11 } publishing { diff --git a/android/third_party/libxposed/interface/src/main/aidl/io/github/libxposed/service/IXposedService.aidl b/android/third_party/libxposed/interface/src/main/aidl/io/github/libxposed/service/IXposedService.aidl index eff604fcb..58fcae80d 100644 --- a/android/third_party/libxposed/interface/src/main/aidl/io/github/libxposed/service/IXposedService.aidl +++ b/android/third_party/libxposed/interface/src/main/aidl/io/github/libxposed/service/IXposedService.aidl @@ -18,7 +18,6 @@ interface IXposedService { String getFrameworkVersion() = 3; long getFrameworkVersionCode() = 4; int getFrameworkPrivilege() = 5; - Bundle featuredMethod(String name, in Bundle args) = 6; // scope utilities List getScope() = 10; @@ -31,7 +30,7 @@ interface IXposedService { void deleteRemotePreferences(String group) = 22; // remote file utilities - ParcelFileDescriptor openRemoteFile(String path, int mode) = 30; - boolean deleteRemoteFile(String path) = 31; - String[] listRemoteFiles() = 32; + String[] listRemoteFiles() = 30; + ParcelFileDescriptor openRemoteFile(String name) = 31; + boolean deleteRemoteFile(String name) = 32; } diff --git a/android/third_party/libxposed/service/src/main/java/io/github/libxposed/service/XposedService.java b/android/third_party/libxposed/service/src/main/java/io/github/libxposed/service/XposedService.java index 1ec4ad4b1..77a7a1fc1 100644 --- a/android/third_party/libxposed/service/src/main/java/io/github/libxposed/service/XposedService.java +++ b/android/third_party/libxposed/service/src/main/java/io/github/libxposed/service/XposedService.java @@ -1,28 +1,27 @@ package io.github.libxposed.service; -import static android.os.ParcelFileDescriptor.MODE_READ_ONLY; - import android.content.SharedPreferences; -import android.os.Bundle; +import android.os.ParcelFileDescriptor; import android.os.RemoteException; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.WeakHashMap; import java.util.concurrent.locks.ReentrantReadWriteLock; -@SuppressWarnings({"resource", "unused"}) +@SuppressWarnings("unused") public final class XposedService { public final static class ServiceException extends RuntimeException { - private ServiceException(RemoteException e) { + ServiceException(String message) { + super(message); + } + + ServiceException(RemoteException e) { super("Xposed service error", e); } } @@ -148,7 +147,7 @@ IXposedService getRaw() { * Get the Xposed API version of current implementation. * * @return API version - * @throws ServiceException If the service is dead or error occurred + * @throws ServiceException If the service is dead or an error occurred */ public int getAPIVersion() { try { @@ -162,7 +161,7 @@ public int getAPIVersion() { * Get the Xposed framework name of current implementation. * * @return Framework name - * @throws ServiceException If the service is dead or error occurred + * @throws ServiceException If the service is dead or an error occurred */ @NonNull public String getFrameworkName() { @@ -177,7 +176,7 @@ public String getFrameworkName() { * Get the Xposed framework version of current implementation. * * @return Framework version - * @throws ServiceException If the service is dead or error occurred + * @throws ServiceException If the service is dead or an error occurred */ @NonNull public String getFrameworkVersion() { @@ -192,7 +191,7 @@ public String getFrameworkVersion() { * Get the Xposed framework version code of current implementation. * * @return Framework version code - * @throws ServiceException If the service is dead or error occurred + * @throws ServiceException If the service is dead or an error occurred */ public long getFrameworkVersionCode() { try { @@ -206,7 +205,7 @@ public long getFrameworkVersionCode() { * Get the Xposed framework privilege of current implementation. * * @return Framework privilege - * @throws ServiceException If the service is dead or error occurred + * @throws ServiceException If the service is dead or an error occurred */ @NonNull public Privilege getFrameworkPrivilege() { @@ -218,32 +217,11 @@ public Privilege getFrameworkPrivilege() { } } - /** - * Additional methods provided by specific Xposed framework. - * - * @param name Featured method name - * @param args Featured method arguments - * @return Featured method result - * @throws UnsupportedOperationException If the framework does not provide a method with given name - * @throws ServiceException If the service is dead or error occurred - * @deprecated Normally, modules should never rely on implementation details about the Xposed framework, - * but if really necessary, this method can be used to acquire such information - */ - @Deprecated - @Nullable - public Bundle featuredMethod(@NonNull String name, @Nullable Bundle args) { - try { - return mService.featuredMethod(name, args); - } catch (RemoteException e) { - throw new ServiceException(e); - } - } - /** * Get the application scope of current module. * * @return Module scope - * @throws ServiceException If the service is dead or error occurred + * @throws ServiceException If the service is dead or an error occurred */ @NonNull public List getScope() { @@ -259,7 +237,7 @@ public List getScope() { * * @param packageName Package name of the app to be added * @param callback Callback to be invoked when the request is completed or error occurred - * @throws ServiceException If the service is dead or error occurred + * @throws ServiceException If the service is dead or an error occurred */ public void requestScope(@NonNull String packageName, @NonNull OnScopeEventListener callback) { try { @@ -274,7 +252,7 @@ public void requestScope(@NonNull String packageName, @NonNull OnScopeEventListe * * @param packageName Package name of the app to be added * @return null if successful, or non-null with error message - * @throws ServiceException If the service is dead or error occurred + * @throws ServiceException If the service is dead or an error occurred */ @Nullable public String removeScope(@NonNull String packageName) { @@ -286,17 +264,22 @@ public String removeScope(@NonNull String packageName) { } /** - * Get remote preferences from Xposed framework. + * Get remote preferences from Xposed framework. If the group does not exist, it will be created. * * @param group Group name - * @return The preferences, null if the framework is embedded - * @throws ServiceException If the service is dead or error occurred + * @return The preferences + * @throws ServiceException If the service is dead or an error occurred + * @throws UnsupportedOperationException If the framework is embedded */ - @Nullable + @NonNull public SharedPreferences getRemotePreferences(@NonNull String group) { return mRemotePrefs.computeIfAbsent(group, k -> { try { - return RemotePreferences.newInstance(this, k); + var instance = RemotePreferences.newInstance(this, k); + if (instance == null) { + throw new ServiceException("Framework returns null"); + } + return instance; } catch (RemoteException e) { throw new ServiceException(e); } @@ -307,7 +290,8 @@ public SharedPreferences getRemotePreferences(@NonNull String group) { * Delete a group of remote preferences. * * @param group Group name - * @throws ServiceException If the service is dead or error occurred + * @throws ServiceException If the service is dead or an error occurred + * @throws UnsupportedOperationException If the framework is embedded */ public void deleteRemotePreferences(@NonNull String group) { deletionLock.writeLock().lock(); @@ -325,39 +309,39 @@ public void deleteRemotePreferences(@NonNull String group) { } /** - * Open an InputStream to read a file from the module's shared data directory. + * List all files in the module's shared data directory. * - * @param name File name, must not contain path separators and . or .. - * @return The InputStream - * @throws FileNotFoundException If the file does not exist, the path is forbidden or remote file is not supported by the framework + * @return The file list + * @throws ServiceException If the service is dead or an error occurred + * @throws UnsupportedOperationException If the framework is embedded */ @NonNull - public FileInputStream openRemoteFileInput(@NonNull String name) throws FileNotFoundException { + public String[] listRemoteFiles() { try { - var file = mService.openRemoteFile(name, MODE_READ_ONLY); - if (file == null) throw new FileNotFoundException(); - return new FileInputStream(file.getFileDescriptor()); + var files = mService.listRemoteFiles(); + if (files == null) throw new ServiceException("Framework returns null"); + return files; } catch (RemoteException e) { - throw new FileNotFoundException(e.getMessage()); + throw new ServiceException(e); } } /** - * Open an OutputStream to write a file to the module's shared data directory. + * Open a file in the module's shared data directory. The file will be created if not exists. * * @param name File name, must not contain path separators and . or .. - * @param mode Operating mode - * @return The OutputStream - * @throws FileNotFoundException If the path is forbidden or remote file is not supported by the framework + * @return The file descriptor + * @throws ServiceException If the service is dead or an error occurred + * @throws UnsupportedOperationException If the framework is embedded */ @NonNull - public FileOutputStream openRemoteFileOutput(@NonNull String name, int mode) throws FileNotFoundException { + public ParcelFileDescriptor openRemoteFile(@NonNull String name) { try { - var file = mService.openRemoteFile(name, mode); - if (file == null) throw new FileNotFoundException(); - return new FileOutputStream(file.getFileDescriptor()); + var file = mService.openRemoteFile(name); + if (file == null) throw new ServiceException("Framework returns null"); + return file; } catch (RemoteException e) { - throw new FileNotFoundException(e.getMessage()); + throw new ServiceException(e); } } @@ -366,30 +350,14 @@ public FileOutputStream openRemoteFileOutput(@NonNull String name, int mode) thr * * @param name File name, must not contain path separators and . or .. * @return true if successful, false if the file does not exist - * @throws FileNotFoundException If the path is forbidden or remote file is not supported by the framework + * @throws ServiceException If the service is dead or an error occurred + * @throws UnsupportedOperationException If the framework is embedded */ - public boolean deleteRemoteFile(@NonNull String name) throws FileNotFoundException { + public boolean deleteRemoteFile(@NonNull String name) { try { return mService.deleteRemoteFile(name); } catch (RemoteException e) { - throw new FileNotFoundException(e.getMessage()); - } - } - - /** - * List all files in the module's shared data directory. - * - * @return The file list - * @throws FileNotFoundException If remote file is not supported by the framework - */ - @NonNull - public String[] listRemoteFiles() throws FileNotFoundException { - try { - var files = mService.listRemoteFiles(); - if (files == null) throw new FileNotFoundException(); - return files; - } catch (RemoteException e) { - throw new FileNotFoundException(e.getMessage()); + throw new ServiceException(e); } } } diff --git a/android/third_party/recyclerview-fastscroll/build.gradle.kts b/android/third_party/recyclerview-fastscroll/build.gradle.kts index 4769cb922..e12915296 100644 --- a/android/third_party/recyclerview-fastscroll/build.gradle.kts +++ b/android/third_party/recyclerview-fastscroll/build.gradle.kts @@ -15,8 +15,8 @@ android { } compileOptions { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 } buildFeatures { diff --git a/android/third_party/remix/build.gradle.kts b/android/third_party/remix/build.gradle.kts index 7c1c5f817..be18642ba 100644 --- a/android/third_party/remix/build.gradle.kts +++ b/android/third_party/remix/build.gradle.kts @@ -14,8 +14,8 @@ android { } compileOptions { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 } buildFeatures { diff --git a/android/third_party/reorderable/build.gradle.kts b/android/third_party/reorderable/build.gradle.kts index 9ccc14b9b..bf959f550 100644 --- a/android/third_party/reorderable/build.gradle.kts +++ b/android/third_party/reorderable/build.gradle.kts @@ -19,8 +19,8 @@ android { } compileOptions { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 } buildFeatures { diff --git a/android/third_party/search/build.gradle.kts b/android/third_party/search/build.gradle.kts index c8227ca46..38d785b17 100644 --- a/android/third_party/search/build.gradle.kts +++ b/android/third_party/search/build.gradle.kts @@ -15,8 +15,8 @@ android { } compileOptions { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 } buildFeatures { diff --git a/android/third_party/time-duration-picker/build.gradle.kts b/android/third_party/time-duration-picker/build.gradle.kts index c8227ca46..38d785b17 100644 --- a/android/third_party/time-duration-picker/build.gradle.kts +++ b/android/third_party/time-duration-picker/build.gradle.kts @@ -15,8 +15,8 @@ android { } compileOptions { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 } buildFeatures {