Skip to content

Commit 01ab3d8

Browse files
authored
use java 11 (#60)
JDK 11 required to run AGP 7.0.0 (July 2021)
1 parent d5e2367 commit 01ab3d8

File tree

11 files changed

+248
-161
lines changed

11 files changed

+248
-161
lines changed

library/build.gradle.kts

+36-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
11
import com.android.build.api.artifact.SingleArtifact
2+
import com.android.build.api.instrumentation.AsmClassVisitorFactory
3+
import com.android.build.api.instrumentation.ClassContext
4+
import com.android.build.api.instrumentation.ClassData
5+
import com.android.build.api.instrumentation.InstrumentationParameters
6+
import com.android.build.api.instrumentation.InstrumentationScope
7+
import org.objectweb.asm.ClassVisitor
8+
import org.objectweb.asm.commons.ClassRemapper
9+
import org.objectweb.asm.commons.Remapper
210

311
plugins {
412
alias(libs.plugins.agp.lib)
@@ -30,8 +38,8 @@ android {
3038
}
3139
}
3240
compileOptions {
33-
sourceCompatibility = JavaVersion.VERSION_1_8
34-
targetCompatibility = JavaVersion.VERSION_1_8
41+
sourceCompatibility = JavaVersion.VERSION_11
42+
targetCompatibility = JavaVersion.VERSION_11
3543
}
3644
packaging {
3745
resources {
@@ -55,6 +63,32 @@ dependencies {
5563
androidTestCompileOnly(projects.stub)
5664
}
5765

66+
androidComponents.onVariants { variant ->
67+
variant.instrumentation.transformClassesWith(
68+
ClassVisitorFactory::class.java, InstrumentationScope.PROJECT
69+
) {}
70+
}
71+
72+
abstract class ClassVisitorFactory : AsmClassVisitorFactory<InstrumentationParameters.None> {
73+
override fun createClassVisitor(
74+
classContext: ClassContext,
75+
nextClassVisitor: ClassVisitor
76+
): ClassVisitor {
77+
return ClassRemapper(nextClassVisitor, object : Remapper() {
78+
override fun map(name: String): String {
79+
if (name.startsWith("stub/")) {
80+
return name.substring(name.indexOf('/') + 1)
81+
}
82+
return name
83+
}
84+
})
85+
}
86+
87+
override fun isInstrumentable(classData: ClassData): Boolean {
88+
return classData.className.endsWith("ass")
89+
}
90+
}
91+
5892
@CacheableTask
5993
abstract class ManifestUpdater : DefaultTask() {
6094
@get:InputFile

library/consumer-rules.pro

+6
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,8 @@
11
-dontwarn dalvik.system.VMRuntime
2+
3+
-if class org.lsposed.hiddenapibypass.HiddenApiBypass
24
-keepclassmembers class org.lsposed.hiddenapibypass.Helper$* { *; }
5+
6+
-assumenosideeffects class android.util.Property{
7+
public static *** of(...);
8+
}

library/src/androidTest/java/org/lsposed/hiddenapibypass/HiddenApiBypassTest.java

+19-15
Original file line numberDiff line numberDiff line change
@@ -25,20 +25,23 @@
2525
import java.util.List;
2626
import java.util.Optional;
2727

28-
import dalvik.system.VMRuntime;
29-
3028
@SuppressWarnings("JavaReflectionMemberAccess")
3129
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
3230
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.P)
3331
@RunWith(AndroidJUnit4.class)
3432
public class HiddenApiBypassTest {
3533

34+
private final Class<?> runtime = Class.forName("dalvik.system.VMRuntime");
35+
3636
@Rule
3737
public ExpectedException exception = ExpectedException.none();
3838

39+
public HiddenApiBypassTest() throws ClassNotFoundException {
40+
}
41+
3942
@Test
4043
public void AgetDeclaredMethods() {
41-
List<Executable> methods = HiddenApiBypass.getDeclaredMethods(VMRuntime.class);
44+
List<Executable> methods = HiddenApiBypass.getDeclaredMethods(runtime);
4245
Optional<Executable> getRuntime = methods.stream().filter(it -> it.getName().equals("getRuntime")).findFirst();
4346
assertTrue(getRuntime.isPresent());
4447
Optional<Executable> setHiddenApiExemptions = methods.stream().filter(it -> it.getName().equals("setHiddenApiExemptions")).findFirst();
@@ -52,7 +55,7 @@ public void BusesNonSdkApiIsHiddenApi() throws NoSuchMethodException {
5255

5356
@Test(expected = NoSuchMethodException.class)
5457
public void CsetHiddenApiExemptionsIsHiddenApi() throws NoSuchMethodException {
55-
VMRuntime.class.getMethod("setHiddenApiExemptions", String[].class);
58+
runtime.getMethod("setHiddenApiExemptions", String[].class);
5659
}
5760

5861
@Test(expected = NoSuchMethodException.class)
@@ -69,6 +72,7 @@ public void ElongVersionCodeIsHiddenApi() throws NoSuchFieldException {
6972
public void FHiddenApiEnforcementDefaultIsHiddenApi() throws NoSuchFieldException {
7073
ApplicationInfo.class.getDeclaredField("HIDDEN_API_ENFORCEMENT_DEFAULT");
7174
}
75+
7276
@Test
7377
public void GtestGetInstanceFields() {
7478
assertTrue(HiddenApiBypass.getInstanceFields(ApplicationInfo.class).stream().anyMatch(i -> i.getName().equals("longVersionCode")));
@@ -112,30 +116,30 @@ public void MclearHiddenApiExemptions() throws NoSuchMethodException {
112116
assertTrue(HiddenApiBypass.setHiddenApiExemptions("L"));
113117
ApplicationInfo.class.getMethod("getHiddenApiEnforcementPolicy");
114118
assertTrue(HiddenApiBypass.clearHiddenApiExemptions());
115-
VMRuntime.class.getMethod("setHiddenApiExemptions", String[].class);
119+
runtime.getMethod("setHiddenApiExemptions", String[].class);
116120
}
117121

118122
@Test
119123
public void NaddHiddenApiExemptionsTest() throws NoSuchMethodException {
120124
assertTrue(HiddenApiBypass.addHiddenApiExemptions("Landroid/content/pm/ApplicationInfo;"));
121125
ApplicationInfo.class.getMethod("getHiddenApiEnforcementPolicy");
122126
assertTrue(HiddenApiBypass.addHiddenApiExemptions("Ldalvik/system/VMRuntime;"));
123-
VMRuntime.class.getMethod("setHiddenApiExemptions", String[].class);
127+
runtime.getMethod("setHiddenApiExemptions", String[].class);
124128
}
125129

126130
@Test
127131
public void OtestCheckArgsForInvokeMethod() {
128132
class X {
129133
}
130-
assertFalse(HiddenApiBypass.checkArgsForInvokeMethod(new Class[]{}, new Object[]{new Object()}));
131-
assertTrue(HiddenApiBypass.checkArgsForInvokeMethod(new Class[]{int.class}, new Object[]{1}));
132-
assertFalse(HiddenApiBypass.checkArgsForInvokeMethod(new Class[]{int.class}, new Object[]{1.0}));
133-
assertFalse(HiddenApiBypass.checkArgsForInvokeMethod(new Class[]{int.class}, new Object[]{null}));
134-
assertTrue(HiddenApiBypass.checkArgsForInvokeMethod(new Class[]{Integer.class}, new Object[]{1}));
135-
assertTrue(HiddenApiBypass.checkArgsForInvokeMethod(new Class[]{Integer.class}, new Object[]{null}));
136-
assertTrue(HiddenApiBypass.checkArgsForInvokeMethod(new Class[]{Object.class}, new Object[]{new X()}));
137-
assertFalse(HiddenApiBypass.checkArgsForInvokeMethod(new Class[]{X.class}, new Object[]{new Object()}));
138-
assertTrue(HiddenApiBypass.checkArgsForInvokeMethod(new Class[]{Object.class, int.class, byte.class, short.class, char.class, double.class, float.class, boolean.class, long.class}, new Object[]{new X(), 1, (byte) 0, (short) 2, 'c', 1.1, 1.2f, false, 114514L}));
134+
assertFalse(Helper.checkArgsForInvokeMethod(new Class[]{}, new Object[]{new Object()}));
135+
assertTrue(Helper.checkArgsForInvokeMethod(new Class[]{int.class}, new Object[]{1}));
136+
assertFalse(Helper.checkArgsForInvokeMethod(new Class[]{int.class}, new Object[]{1.0}));
137+
assertFalse(Helper.checkArgsForInvokeMethod(new Class[]{int.class}, new Object[]{null}));
138+
assertTrue(Helper.checkArgsForInvokeMethod(new Class[]{Integer.class}, new Object[]{1}));
139+
assertTrue(Helper.checkArgsForInvokeMethod(new Class[]{Integer.class}, new Object[]{null}));
140+
assertTrue(Helper.checkArgsForInvokeMethod(new Class[]{Object.class}, new Object[]{new X()}));
141+
assertFalse(Helper.checkArgsForInvokeMethod(new Class[]{X.class}, new Object[]{new Object()}));
142+
assertTrue(Helper.checkArgsForInvokeMethod(new Class[]{Object.class, int.class, byte.class, short.class, char.class, double.class, float.class, boolean.class, long.class}, new Object[]{new X(), 1, (byte) 0, (short) 2, 'c', 1.1, 1.2f, false, 114514L}));
139143
}
140144

141145
}

library/src/androidTest/java/org/lsposed/lspass/LSPassTest.java library/src/androidTest/java/org/lsposed/hiddenapibypass/LSPassTest.java

+25-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
package org.lsposed.lspass;
1+
package org.lsposed.hiddenapibypass;
22

3+
import static org.junit.Assert.assertEquals;
34
import static org.junit.Assert.assertNotEquals;
45
import static org.junit.Assert.assertNotNull;
56
import static org.junit.Assert.assertSame;
@@ -17,7 +18,6 @@
1718
import org.junit.runners.MethodSorters;
1819

1920
import java.lang.reflect.InvocationTargetException;
20-
import java.util.Arrays;
2121

2222
@SuppressWarnings("JavaReflectionMemberAccess")
2323
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@@ -41,12 +41,18 @@ public void CmHeightIsHiddenApi() throws NoSuchFieldException {
4141
}
4242

4343
@Test
44-
public void DtestgetDeclaredFields() {
45-
assertTrue(Arrays.stream(LSPass.getDeclaredFields(ActivityOptions.class)).anyMatch(i -> i.getName().equals("mHeight")));
44+
public void DgetDeclaredFieldsTest() {
45+
var fields = LSPass.getDeclaredFields(ActivityOptions.class);
46+
assertTrue(fields.stream().anyMatch(i -> i.getName().equals("mHeight")));
47+
var instance = LSPass.getInstanceFields(ActivityOptions.class);
48+
assertTrue(instance.stream().anyMatch(i -> i.getName().equals("mHeight")));
49+
var staticFields = LSPass.getStaticFields(ActivityOptions.class);
50+
assertTrue(staticFields.stream().anyMatch(i -> i.getName().equals("ANIM_NONE")));
51+
assertEquals(fields.size(), instance.size() + staticFields.size());
4652
}
4753

4854
@Test
49-
public void EtestgetDeclaredFields() throws NoSuchMethodException {
55+
public void EgetDeclaredMethodTest() throws NoSuchMethodException {
5056
assertNotNull(LSPass.getDeclaredMethod(ActivityOptions.class, "getHeight"));
5157
}
5258

@@ -56,4 +62,18 @@ public void FnewActivityOptionsWithoutExemption() throws NoSuchMethodException,
5662
Object instance = LSPass.newInstance(ActivityOptions.class);
5763
assertSame(ActivityOptions.class, instance.getClass());
5864
}
65+
66+
@Test(expected = NoSuchFieldException.class)
67+
public void GclearHiddenApiExemptionsTest() throws NoSuchFieldException {
68+
assertTrue(LSPass.addHiddenApiExemptions("L"));
69+
assertTrue(LSPass.clearHiddenApiExemptions());
70+
ActivityOptions.class.getDeclaredField("mHeight");
71+
}
72+
73+
@Test
74+
public void HaddHiddenApiExemptionsTest() throws NoSuchMethodException {
75+
assertTrue(LSPass.addHiddenApiExemptions("L"));
76+
assertTrue(LSPass.addHiddenApiExemptions("xx"));
77+
ActivityOptions.class.getDeclaredMethod("getHeight");
78+
}
5979
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package org.lsposed.hiddenapibypass;
2+
3+
import android.os.Build;
4+
5+
import androidx.annotation.RequiresApi;
6+
7+
import java.lang.invoke.MethodHandle;
8+
import java.lang.reflect.Executable;
9+
10+
import dalvik.system.PathClassLoader;
11+
12+
@RequiresApi(Build.VERSION_CODES.P)
13+
final class CoreOjClassLoader extends PathClassLoader {
14+
private static String getCoreOjPath() {
15+
String bootClassPath = System.getProperty("java.boot.class.path", "");
16+
assert bootClassPath != null;
17+
return bootClassPath.split(":", 2)[0];
18+
}
19+
20+
CoreOjClassLoader() {
21+
super(getCoreOjPath(), null);
22+
}
23+
24+
@Override
25+
public Class<?> loadClass(String name) throws ClassNotFoundException {
26+
if (Object.class.getName().equals(name)) {
27+
return Object.class;
28+
}
29+
try {
30+
return findClass(name);
31+
} catch (ClassNotFoundException ignored) {
32+
// no class file in jar before art moved to apex.
33+
}
34+
if (Executable.class.getName().equals(name)) {
35+
return Helper.Executable.class;
36+
} else if (MethodHandle.class.getName().equals(name)) {
37+
return Helper.MethodHandle.class;
38+
} else if (Class.class.getName().equals(name)) {
39+
return Helper.Class.class;
40+
}
41+
return super.loadClass(name);
42+
}
43+
}

library/src/main/java/org/lsposed/hiddenapibypass/Helper.java

+21
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,30 @@
1717
package org.lsposed.hiddenapibypass;
1818

1919
import java.lang.invoke.MethodType;
20+
import java.util.HashSet;
21+
import java.util.Set;
2022

2123
@SuppressWarnings("unused")
2224
public class Helper {
25+
static final Set<String> signaturePrefixes = new HashSet<>();
26+
27+
static boolean checkArgsForInvokeMethod(java.lang.Class<?>[] params, Object[] args) {
28+
if (params.length != args.length) return false;
29+
for (int i = 0; i < params.length; ++i) {
30+
if (params[i].isPrimitive()) {
31+
if (params[i] == int.class && !(args[i] instanceof Integer)) return false;
32+
else if (params[i] == byte.class && !(args[i] instanceof Byte)) return false;
33+
else if (params[i] == char.class && !(args[i] instanceof Character)) return false;
34+
else if (params[i] == boolean.class && !(args[i] instanceof Boolean)) return false;
35+
else if (params[i] == double.class && !(args[i] instanceof Double)) return false;
36+
else if (params[i] == float.class && !(args[i] instanceof Float)) return false;
37+
else if (params[i] == long.class && !(args[i] instanceof Long)) return false;
38+
else if (params[i] == short.class && !(args[i] instanceof Short)) return false;
39+
} else if (args[i] != null && !params[i].isInstance(args[i])) return false;
40+
}
41+
return true;
42+
}
43+
2344
static public class MethodHandle {
2445
private final MethodType type = null;
2546
private MethodType nominalType;

0 commit comments

Comments
 (0)