OSDN Git Service

Bump targetSdkVersion to 30 + related changes
authorBraden Farmer <farmerbb@gmail.com>
Fri, 1 Oct 2021 03:08:37 +0000 (21:08 -0600)
committerBraden Farmer <farmerbb@gmail.com>
Fri, 1 Oct 2021 03:12:14 +0000 (21:12 -0600)
app/build.gradle
app/src/androidx86/java/org/lsposed/hiddenapibypass/Helper.java [new file with mode: 0644]
app/src/androidx86/java/org/lsposed/hiddenapibypass/HiddenApiBypass.java [new file with mode: 0644]
app/src/main/java/com/farmerbb/taskbar/util/U.java
app/src/playstore/AndroidManifest.xml
dependencies.gradle

index c6227e1..9cbfe38 100644 (file)
@@ -143,6 +143,7 @@ dependencies {
     implementation 'com.mikepenz:foundation-icons-typeface:3.0.0.5'
     implementation 'moe.banana:toast-compat:1.0.5'
     implementation group:'com.twofortyfouram', name:'android-plugin-api-for-locale', version:'[1.0.2,2.0['
+    implementation "org.lsposed.hiddenapibypass:hiddenapibypass:$HIDDEN_API_BYPASS_VERSION"
 
     testImplementation "com.google.truth:truth:1.1.3"
     testImplementation 'junit:junit:4.13.2'
diff --git a/app/src/androidx86/java/org/lsposed/hiddenapibypass/Helper.java b/app/src/androidx86/java/org/lsposed/hiddenapibypass/Helper.java
new file mode 100644 (file)
index 0000000..4e53d13
--- /dev/null
@@ -0,0 +1,77 @@
+// Mirror of https://github.com/LSPosed/AndroidHiddenApiBypass/blob/b47b8c258518b21232a3ff5534e06eeae0e5d847/library/src/main/java/org/lsposed/hiddenapibypass/Helper.java
+
+/*
+ * Copyright (C) 2021 LSPosed
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.lsposed.hiddenapibypass;
+
+import java.lang.invoke.MethodHandleInfo;
+import java.lang.invoke.MethodType;
+import java.lang.reflect.Member;
+
+public class Helper {
+    static public class MethodHandle {
+        private final MethodType type = null;
+        private MethodType nominalType;
+        private MethodHandle cachedSpreadInvoker;
+        protected final int handleKind = 0;
+
+        // The ArtMethod* or ArtField* associated with this method handle (used by the runtime).
+        protected final long artFieldOrMethod = 0;
+    }
+
+    static final public class MethodHandleImpl extends MethodHandle {
+        private final MethodHandleInfo info = null;
+    }
+
+    static final public class HandleInfo {
+        private final Member member = null;
+        private final MethodHandle handle = null;
+    }
+
+    static final public class Class {
+        private transient ClassLoader classLoader;
+        private transient java.lang.Class<?> componentType;
+        private transient Object dexCache;
+        private transient Object extData;
+        private transient Object[] ifTable;
+        private transient String name;
+        private transient java.lang.Class<?> superClass;
+        private transient Object vtable;
+        private transient long iFields;
+        private transient long methods;
+        private transient long sFields;
+        private transient int accessFlags;
+        private transient int classFlags;
+        private transient int classSize;
+        private transient int clinitThreadId;
+        private transient int dexClassDefIndex;
+        private transient volatile int dexTypeIndex;
+        private transient int numReferenceInstanceFields;
+        private transient int numReferenceStaticFields;
+        private transient int objectSize;
+        private transient int objectSizeAllocFastPath;
+        private transient int primitiveType;
+        private transient int referenceInstanceOffsets;
+        private transient int status;
+        private transient short copiedMethodsOffset;
+        private transient short virtualMethodsOffset;
+    }
+    public static class NeverCall {
+        static void a(){}
+        static void b(){}
+    }
+}
diff --git a/app/src/androidx86/java/org/lsposed/hiddenapibypass/HiddenApiBypass.java b/app/src/androidx86/java/org/lsposed/hiddenapibypass/HiddenApiBypass.java
new file mode 100644 (file)
index 0000000..ce62fd9
--- /dev/null
@@ -0,0 +1,166 @@
+// Mirror of https://github.com/LSPosed/AndroidHiddenApiBypass/blob/8c90d70dcdacd3d05c0d9454c7594c8f658cde6a/library/src/main/java/org/lsposed/hiddenapibypass/HiddenApiBypass.java
+
+/*
+ * Copyright (C) 2021 LSPosed
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.lsposed.hiddenapibypass;
+
+import android.os.Build;
+import android.util.Log;
+
+import com.farmerbb.taskbar.BuildConfig;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandleInfo;
+import java.lang.invoke.MethodHandles;
+import java.lang.reflect.Executable;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import dalvik.system.VMRuntime;
+import sun.misc.Unsafe;
+
+public final class HiddenApiBypass {
+    private static final String TAG = "HiddenApiBypass";
+    private static final Unsafe unsafe;
+    private static final long artOffset;
+    private static final long infoOffset;
+    private static final long methodsOffset;
+    private static final long memberOffset;
+    private static final long size;
+    private static final long bias;
+    private static final Set<String> signaturePrefixes = new HashSet<>();
+
+    static {
+        try {
+            //noinspection JavaReflectionMemberAccess DiscouragedPrivateApi
+            unsafe = (Unsafe) Unsafe.class.getDeclaredMethod("getUnsafe").invoke(null);
+            assert unsafe != null;
+            artOffset = unsafe.objectFieldOffset(Helper.MethodHandle.class.getDeclaredField("artFieldOrMethod"));
+            infoOffset = unsafe.objectFieldOffset(Helper.MethodHandleImpl.class.getDeclaredField("info"));
+            methodsOffset = unsafe.objectFieldOffset(Helper.Class.class.getDeclaredField("methods"));
+            memberOffset = unsafe.objectFieldOffset(Helper.HandleInfo.class.getDeclaredField("member"));
+            MethodHandle mhA = MethodHandles.lookup().unreflect(Helper.NeverCall.class.getDeclaredMethod("a"));
+            MethodHandle mhB = MethodHandles.lookup().unreflect(Helper.NeverCall.class.getDeclaredMethod("b"));
+            long aAddr = unsafe.getLong(mhA, artOffset);
+            long bAddr = unsafe.getLong(mhB, artOffset);
+            long aMethods = unsafe.getLong(Helper.NeverCall.class, methodsOffset);
+            size = bAddr - aAddr;
+            if (BuildConfig.DEBUG) Log.v(TAG, size + " " +
+                    Long.toString(aAddr, 16) + ", " +
+                    Long.toString(bAddr, 16) + ", " +
+                    Long.toString(aMethods, 16));
+            bias = aAddr - aMethods - size;
+        } catch (ReflectiveOperationException e) {
+            throw new ExceptionInInitializerError(e);
+        }
+    }
+
+    /**
+     * get declared methods of given class without hidden api restriction
+     *
+     * @param clazz the class to fetch declared methods
+     * @return list of declared methods of {@code clazz}
+     */
+    public static List<Executable> getDeclaredMethods(Class<?> clazz) {
+        ArrayList<Executable> list = new ArrayList<>();
+        if (clazz.isPrimitive() || clazz.isArray()) return list;
+        MethodHandle mh;
+        try {
+            mh = MethodHandles.lookup().unreflect(Helper.NeverCall.class.getDeclaredMethod("a"));
+        } catch (NoSuchMethodException | IllegalAccessException e) {
+            return list;
+        }
+        long methods = unsafe.getLong(clazz, methodsOffset);
+        int numMethods = unsafe.getInt(methods);
+        if (BuildConfig.DEBUG) Log.d(TAG, clazz + " has " + numMethods + " methods");
+        for (int i = 0; i < numMethods; i++) {
+            long method = methods + i * size + bias;
+            unsafe.putLong(mh, artOffset, method);
+            unsafe.putObject(mh, infoOffset, null);
+            try {
+                MethodHandles.lookup().revealDirect(mh);
+            } catch (Throwable ignored) {
+            }
+            MethodHandleInfo info = (MethodHandleInfo) unsafe.getObject(mh, infoOffset);
+            Executable member = (Executable) unsafe.getObject(info, memberOffset);
+            if (BuildConfig.DEBUG) Log.v(TAG, "got " + clazz.getTypeName() + "." + member +
+                    "(" + Arrays.stream(member.getTypeParameters()).map(Type::getTypeName).collect(Collectors.joining()) + ")");
+            list.add(member);
+        }
+        return list;
+    }
+
+    /**
+     * Sets the list of exemptions from hidden API access enforcement.
+     *
+     * @param signaturePrefixes A list of class signature prefixes. Each item in the list is a prefix match on the type
+     *                          signature of a blacklisted API. All matching APIs are treated as if they were on
+     *                          the whitelist: access permitted, and no logging..
+     * @return whether the operation is successful
+     */
+    public static boolean setHiddenApiExemptions(String... signaturePrefixes) {
+        List<Executable> methods = getDeclaredMethods(VMRuntime.class);
+        Optional<Executable> getRuntime = methods.stream().filter(it -> it.getName().equals("getRuntime")).findFirst();
+        Optional<Executable> setHiddenApiExemptions = methods.stream().filter(it -> it.getName().equals("setHiddenApiExemptions")).findFirst();
+        if (getRuntime.isPresent() && setHiddenApiExemptions.isPresent()) {
+            getRuntime.get().setAccessible(true);
+            try {
+                Object runtime = ((Method) getRuntime.get()).invoke(null);
+                setHiddenApiExemptions.get().setAccessible(true);
+                ((Method) setHiddenApiExemptions.get()).invoke(runtime, (Object) signaturePrefixes);
+                return true;
+            } catch (IllegalAccessException | InvocationTargetException ignored) {
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Adds the list of exemptions from hidden API access enforcement.
+     *
+     * @param signaturePrefixes A list of class signature prefixes. Each item in the list is a prefix match on the type
+     *                          signature of a blacklisted API. All matching APIs are treated as if they were on
+     *                          the whitelist: access permitted, and no logging..
+     * @return whether the operation is successful
+     */
+    public static boolean addHiddenApiExemptions(String... signaturePrefixes) {
+        HiddenApiBypass.signaturePrefixes.addAll(Arrays.asList(signaturePrefixes));
+        String[] strings = new String[HiddenApiBypass.signaturePrefixes.size()];
+        HiddenApiBypass.signaturePrefixes.toArray(strings);
+        return setHiddenApiExemptions(strings);
+    }
+
+    /**
+     * Clear the list of exemptions from hidden API access enforcement.
+     * Android runtime will cache access flags, so if a hidden API has been accessed unrestrictedly,
+     * running this method will not restore the restriction on it.
+     *
+     * @return whether the operation is successful
+     */
+    public static boolean clearHiddenApiExemptions() {
+        HiddenApiBypass.signaturePrefixes.clear();
+        return setHiddenApiExemptions();
+    }
+}
index a5336bd..ff2a447 100644 (file)
@@ -108,6 +108,8 @@ import java.util.regex.Pattern;
 
 import static com.farmerbb.taskbar.util.Constants.*;
 
+import org.lsposed.hiddenapibypass.HiddenApiBypass;
+
 public class U {
 
     private U() {}
@@ -2115,22 +2117,12 @@ public class U {
                 && !isLibrary(context);
     }
 
+    @TargetApi(Build.VERSION_CODES.P)
     public static void allowReflection() {
         GlobalHelper helper = GlobalHelper.getInstance();
         if(helper.isReflectionAllowed()) return;
 
-        try {
-            Method forName = Class.class.getDeclaredMethod("forName", String.class);
-            Method getDeclaredMethod = Class.class.getDeclaredMethod("getDeclaredMethod", String.class, Class[].class);
-
-            Class<?> vmRuntimeClass = (Class<?>) forName.invoke(null, "dalvik.system.VMRuntime");
-            Method getRuntime = (Method) getDeclaredMethod.invoke(vmRuntimeClass, "getRuntime", null);
-            Method setHiddenApiExemptions = (Method) getDeclaredMethod.invoke(vmRuntimeClass, "setHiddenApiExemptions", new Class[]{String[].class});
-
-            Object vmRuntime = getRuntime.invoke(null);
-            setHiddenApiExemptions.invoke(vmRuntime, new Object[]{new String[]{"L"}});
-        } catch (Throwable ignored) {}
-
+        HiddenApiBypass.addHiddenApiExemptions("");
         helper.setReflectionAllowed(true);
     }
 
index 39c77de..ddc467c 100644 (file)
@@ -48,6 +48,7 @@
     <uses-permission-sdk-23 android:name="android.permission.ACCESS_NETWORK_STATE" />
     <uses-permission-sdk-23 android:name="android.permission.ACCESS_WIFI_STATE" />
     <uses-permission-sdk-23 android:name="android.permission.BLUETOOTH" />
+    <uses-permission-sdk-23 android:name="android.permission.QUERY_ALL_PACKAGES" />
 
     <uses-permission-sdk-23 android:name="com.farmerbb.taskbar.support.USE_SUPPORT_LIBRARY" />
 
index 1286ed5..4d6a2cf 100644 (file)
@@ -8,8 +8,7 @@ allprojects {
         COMPILE_SDK_VERSION = 30
         BUILD_TOOLS_VERSION = "30.0.2"
 
-        // Keep at 29 for now, since bumping to 30 will break freeform mode on Android 11
-        TARGET_SDK_VERSION = 29
+        TARGET_SDK_VERSION = 30
 
         SUPPORT_V4_VERSION = "1.0.0"
         APPCOMPAT_VERSION = "1.3.0"
@@ -17,5 +16,6 @@ allprojects {
         MATERIAL_VERSION = "1.3.0"
         POWERMOCK_VERSION = "2.0.9"
         AGP_VERSION = "4.2.1"
+        HIDDEN_API_BYPASS_VERSION = "2.0"
     }
 }