diff options
Diffstat (limited to 'test')
125 files changed, 5965 insertions, 2819 deletions
diff --git a/test/623-checker-loop-regressions/src/Main.java b/test/623-checker-loop-regressions/src/Main.java index f0b327840c..2b30986ab3 100644 --- a/test/623-checker-loop-regressions/src/Main.java +++ b/test/623-checker-loop-regressions/src/Main.java @@ -288,6 +288,28 @@ public class Main { } } + // A strange function that does not inline. + private static void $noinline$foo(boolean x, int n) { + if (n < 0) + throw new Error("oh no"); + if (n > 100) { + $noinline$foo(!x, n - 1); + $noinline$foo(!x, n - 2); + $noinline$foo(!x, n - 3); + $noinline$foo(!x, n - 4); + } + } + + // A loop with environment uses of x (the terminating condition). As exposed by bug + // b/37247891, the loop can be unrolled, but should handle the (unlikely, but clearly + // not impossible) environment uses of the terminating condition in a correct manner. + private static void envUsesInCond() { + boolean x = false; + for (int i = 0; !(x = i >= 1); i++) { + $noinline$foo(true, i); + } + } + public static void main(String[] args) { expectEquals(10, earlyExitFirst(-1)); for (int i = 0; i <= 10; i++) { @@ -369,6 +391,8 @@ public class Main { expectEquals(aa[i], bb.charAt(i)); } + envUsesInCond(); + System.out.println("passed"); } diff --git a/test/902-hello-transformation/src/Main.java b/test/902-hello-transformation/src/Main.java index ed8a5007c8..af49cb4eaa 100644 --- a/test/902-hello-transformation/src/Main.java +++ b/test/902-hello-transformation/src/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,53 +14,8 @@ * limitations under the License. */ -import java.util.Base64; public class Main { - - /** - * base64 encoded class/dex file for - * class Transform { - * public void sayHi() { - * System.out.println("Goodbye"); - * } - * } - */ - private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( - "yv66vgAAADQAHAoABgAOCQAPABAIABEKABIAEwcAFAcAFQEABjxpbml0PgEAAygpVgEABENvZGUB" + - "AA9MaW5lTnVtYmVyVGFibGUBAAVzYXlIaQEAClNvdXJjZUZpbGUBAA5UcmFuc2Zvcm0uamF2YQwA" + - "BwAIBwAWDAAXABgBAAdHb29kYnllBwAZDAAaABsBAAlUcmFuc2Zvcm0BABBqYXZhL2xhbmcvT2Jq" + - "ZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2ph" + - "dmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWACAABQAG" + - "AAAAAAACAAAABwAIAAEACQAAAB0AAQABAAAABSq3AAGxAAAAAQAKAAAABgABAAAAEQABAAsACAAB" + - "AAkAAAAlAAIAAQAAAAmyAAISA7YABLEAAAABAAoAAAAKAAIAAAATAAgAFAABAAwAAAACAA0="); - private static final byte[] DEX_BYTES = Base64.getDecoder().decode( - "ZGV4CjAzNQCLXSBQ5FiS3f16krSYZFF8xYZtFVp0GRXMAgAAcAAAAHhWNBIAAAAAAAAAACwCAAAO" + - "AAAAcAAAAAYAAACoAAAAAgAAAMAAAAABAAAA2AAAAAQAAADgAAAAAQAAAAABAACsAQAAIAEAAGIB" + - "AABqAQAAcwEAAIABAACXAQAAqwEAAL8BAADTAQAA4wEAAOYBAADqAQAA/gEAAAMCAAAMAgAAAgAA" + - "AAMAAAAEAAAABQAAAAYAAAAIAAAACAAAAAUAAAAAAAAACQAAAAUAAABcAQAABAABAAsAAAAAAAAA" + - "AAAAAAAAAAANAAAAAQABAAwAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAHAAAAAAAAAB4CAAAA" + - "AAAAAQABAAEAAAATAgAABAAAAHAQAwAAAA4AAwABAAIAAAAYAgAACQAAAGIAAAAbAQEAAABuIAIA" + - "EAAOAAAAAQAAAAMABjxpbml0PgAHR29vZGJ5ZQALTFRyYW5zZm9ybTsAFUxqYXZhL2lvL1ByaW50" + - "U3RyZWFtOwASTGphdmEvbGFuZy9PYmplY3Q7ABJMamF2YS9sYW5nL1N0cmluZzsAEkxqYXZhL2xh" + - "bmcvU3lzdGVtOwAOVHJhbnNmb3JtLmphdmEAAVYAAlZMABJlbWl0dGVyOiBqYWNrLTMuMzYAA291" + - "dAAHcHJpbnRsbgAFc2F5SGkAEQAHDgATAAcOhQAAAAEBAICABKACAQG4Ag0AAAAAAAAAAQAAAAAA" + - "AAABAAAADgAAAHAAAAACAAAABgAAAKgAAAADAAAAAgAAAMAAAAAEAAAAAQAAANgAAAAFAAAABAAA" + - "AOAAAAAGAAAAAQAAAAABAAABIAAAAgAAACABAAABEAAAAQAAAFwBAAACIAAADgAAAGIBAAADIAAA" + - "AgAAABMCAAAAIAAAAQAAAB4CAAAAEAAAAQAAACwCAAA="); - - public static void main(String[] args) { - art.Main.bindAgentJNIForClass(Main.class); - doTest(new Transform()); + public static void main(String[] args) throws Exception { + art.Test902.run(); } - - public static void doTest(Transform t) { - t.sayHi(); - doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES); - t.sayHi(); - } - - // Transforms the class - private static native void doCommonClassRedefinition(Class<?> target, - byte[] class_file, - byte[] dex_file); } diff --git a/test/902-hello-transformation/src/Transform.java b/test/902-hello-transformation/src/Transform.java deleted file mode 100644 index 8e8af355da..0000000000 --- a/test/902-hello-transformation/src/Transform.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * 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. - */ - -class Transform { - public void sayHi() { - // Use lower 'h' to make sure the string will have a different string id - // than the transformation (the transformation code is the same except - // the actual printed String, which was making the test inacurately passing - // in JIT mode when loading the string from the dex cache, as the string ids - // of the two different strings were the same). - // We know the string ids will be different because lexicographically: - // "Goodbye" < "LTransform;" < "hello". - System.out.println("hello"); - } -} diff --git a/test/902-hello-transformation/src/art/Redefinition.java b/test/902-hello-transformation/src/art/Redefinition.java new file mode 100644 index 0000000000..0350ab42ad --- /dev/null +++ b/test/902-hello-transformation/src/art/Redefinition.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.util.ArrayList; +// Common Redefinition functions. Placed here for use by CTS +public class Redefinition { + // Bind native functions. + static { + Main.bindAgentJNIForClass(Redefinition.class); + } + + public static final class CommonClassDefinition { + public final Class<?> target; + public final byte[] class_file_bytes; + public final byte[] dex_file_bytes; + + public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { + this.target = target; + this.class_file_bytes = class_file_bytes; + this.dex_file_bytes = dex_file_bytes; + } + } + + // A set of possible test configurations. Test should set this if they need to. + // This must be kept in sync with the defines in ti-agent/common_helper.cc + public static enum Config { + COMMON_REDEFINE(0), + COMMON_RETRANSFORM(1), + COMMON_TRANSFORM(2); + + private final int val; + private Config(int val) { + this.val = val; + } + } + + public static void setTestConfiguration(Config type) { + nativeSetTestConfiguration(type.val); + } + + private static native void nativeSetTestConfiguration(int type); + + // Transforms the class + public static native void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile); + + public static void doMultiClassRedefinition(CommonClassDefinition... defs) { + ArrayList<Class<?>> classes = new ArrayList<>(); + ArrayList<byte[]> class_files = new ArrayList<>(); + ArrayList<byte[]> dex_files = new ArrayList<>(); + + for (CommonClassDefinition d : defs) { + classes.add(d.target); + class_files.add(d.class_file_bytes); + dex_files.add(d.dex_file_bytes); + } + doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), + class_files.toArray(new byte[0][]), + dex_files.toArray(new byte[0][])); + } + + public static void addMultiTransformationResults(CommonClassDefinition... defs) { + for (CommonClassDefinition d : defs) { + addCommonTransformationResult(d.target.getCanonicalName(), + d.class_file_bytes, + d.dex_file_bytes); + } + } + + public static native void doCommonMultiClassRedefinition(Class<?>[] targets, + byte[][] classfiles, + byte[][] dexfiles); + public static native void doCommonClassRetransformation(Class<?>... target); + public static native void setPopRetransformations(boolean pop); + public static native void popTransformationFor(String name); + public static native void enableCommonRetransformation(boolean enable); + public static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); +} diff --git a/test/902-hello-transformation/src/art/Test902.java b/test/902-hello-transformation/src/art/Test902.java new file mode 100644 index 0000000000..e95558f7c7 --- /dev/null +++ b/test/902-hello-transformation/src/art/Test902.java @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * 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 art; + +import java.util.Base64; +public class Test902 { + + static class Transform { + public void sayHi() { + // Use lower 'h' to make sure the string will have a different string id + // than the transformation (the transformation code is the same except + // the actual printed String, which was making the test inacurately passing + // in JIT mode when loading the string from the dex cache, as the string ids + // of the two different strings were the same). + // We know the string ids will be different because lexicographically: + // "Goodbye" < "LTransform;" < "hello". + System.out.println("hello"); + } + } + + /** + * base64 encoded class/dex file for + * class Transform { + * public void sayHi() { + * System.out.println("Goodbye"); + * } + * } + */ + private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( + "yv66vgAAADQAIAoABgAOCQAPABAIABEKABIAEwcAFQcAGAEABjxpbml0PgEAAygpVgEABENvZGUB" + + "AA9MaW5lTnVtYmVyVGFibGUBAAVzYXlIaQEAClNvdXJjZUZpbGUBAAxUZXN0OTAyLmphdmEMAAcA" + + "CAcAGQwAGgAbAQAHR29vZGJ5ZQcAHAwAHQAeBwAfAQAVYXJ0L1Rlc3Q5MDIkVHJhbnNmb3JtAQAJ" + + "VHJhbnNmb3JtAQAMSW5uZXJDbGFzc2VzAQAQamF2YS9sYW5nL09iamVjdAEAEGphdmEvbGFuZy9T" + + "eXN0ZW0BAANvdXQBABVMamF2YS9pby9QcmludFN0cmVhbTsBABNqYXZhL2lvL1ByaW50U3RyZWFt" + + "AQAHcHJpbnRsbgEAFShMamF2YS9sYW5nL1N0cmluZzspVgEAC2FydC9UZXN0OTAyACAABQAGAAAA" + + "AAACAAAABwAIAAEACQAAAB0AAQABAAAABSq3AAGxAAAAAQAKAAAABgABAAAAJQABAAsACAABAAkA" + + "AAAlAAIAAQAAAAmyAAISA7YABLEAAAABAAoAAAAKAAIAAAAnAAgAKAACAAwAAAACAA0AFwAAAAoA" + + "AQAFABQAFgAI"); + private static final byte[] DEX_BYTES = Base64.getDecoder().decode( + "ZGV4CjAzNQCpghS3AAAAAAAAAAAAAAAAAAAAAAAAAAC4AwAAcAAAAHhWNBIAAAAAAAAAAPQCAAAU" + + "AAAAcAAAAAkAAADAAAAAAgAAAOQAAAABAAAA/AAAAAQAAAAEAQAAAQAAACQBAAB0AgAARAEAAEQB" + + "AABMAQAAVQEAAG4BAAB9AQAAoQEAAMEBAADYAQAA7AEAAAACAAAUAgAAIgIAAC0CAAAwAgAANAIA" + + "AEECAABHAgAATAIAAFUCAABcAgAAAgAAAAMAAAAEAAAABQAAAAYAAAAHAAAACAAAAAkAAAAMAAAA" + + "DAAAAAgAAAAAAAAADQAAAAgAAABkAgAABwAEABAAAAAAAAAAAAAAAAAAAAASAAAABAABABEAAAAF" + + "AAAAAAAAAAAAAAAAAAAABQAAAAAAAAAKAAAA5AIAALgCAAAAAAAABjxpbml0PgAHR29vZGJ5ZQAX" + + "TGFydC9UZXN0OTAyJFRyYW5zZm9ybTsADUxhcnQvVGVzdDkwMjsAIkxkYWx2aWsvYW5ub3RhdGlv" + + "bi9FbmNsb3NpbmdDbGFzczsAHkxkYWx2aWsvYW5ub3RhdGlvbi9Jbm5lckNsYXNzOwAVTGphdmEv" + + "aW8vUHJpbnRTdHJlYW07ABJMamF2YS9sYW5nL09iamVjdDsAEkxqYXZhL2xhbmcvU3RyaW5nOwAS" + + "TGphdmEvbGFuZy9TeXN0ZW07AAxUZXN0OTAyLmphdmEACVRyYW5zZm9ybQABVgACVkwAC2FjY2Vz" + + "c0ZsYWdzAARuYW1lAANvdXQAB3ByaW50bG4ABXNheUhpAAV2YWx1ZQAAAQAAAAYAAAAlAAcOACcA" + + "Bw4BCA8AAAAAAQABAAEAAABsAgAABAAAAHAQAwAAAA4AAwABAAIAAABxAgAACQAAAGIAAAAbAQEA" + + "AABuIAIAEAAOAAAAAAABAQCAgAT8BAEBlAUAAAICARMYAQIDAg4ECA8XCwACAAAAyAIAAM4CAADY" + + "AgAAAAAAAAAAAAAAAAAAEAAAAAAAAAABAAAAAAAAAAEAAAAUAAAAcAAAAAIAAAAJAAAAwAAAAAMA" + + "AAACAAAA5AAAAAQAAAABAAAA/AAAAAUAAAAEAAAABAEAAAYAAAABAAAAJAEAAAIgAAAUAAAARAEA" + + "AAEQAAABAAAAZAIAAAMgAAACAAAAbAIAAAEgAAACAAAAfAIAAAAgAAABAAAAuAIAAAQgAAACAAAA" + + "yAIAAAMQAAABAAAA2AIAAAYgAAABAAAA5AIAAAAQAAABAAAA9AIAAA=="); + + public static void run() { + Redefinition.setTestConfiguration(Redefinition.Config.COMMON_REDEFINE); + doTest(new Transform()); + } + + public static void doTest(Transform t) { + t.sayHi(); + Redefinition.doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES); + t.sayHi(); + } +} diff --git a/test/913-heaps/expected.txt b/test/913-heaps/expected.txt index 2a183ee06b..702b247819 100644 --- a/test/913-heaps/expected.txt +++ b/test/913-heaps/expected.txt @@ -1,9 +1,10 @@ --- true true +root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 3000@0 [size=136, length=-1] root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonRoot,vreg=13,location= 32])--> 1@1000 [size=16, length=-1] -root@root --(stack-local[id=1,tag=3000,depth=3,method=doFollowReferencesTest,vreg=1,location= 28])--> 3000@0 [size=132, length=-1] -root@root --(thread)--> 3000@0 [size=132, length=-1] -0@0 --(array-element@0)--> 1@1000 [size=16, length=-1] +root@root --(stack-local[id=1,tag=3000,depth=3,method=doFollowReferencesTest,vreg=1,location= 28])--> 3000@0 [size=136, length=-1] +root@root --(stack-local[id=1,tag=3000,depth=5,method=run,vreg=2,location= 0])--> 3000@0 [size=136, length=-1] +root@root --(thread)--> 3000@0 [size=136, length=-1] 1001@0 --(superclass)--> 1000@0 [size=123, length=-1] 1002@0 --(interface)--> 2001@0 [size=124, length=-1] 1002@0 --(superclass)--> 1001@0 [size=123, length=-1] @@ -14,11 +15,13 @@ root@root --(thread)--> 3000@0 [size=132, length=-1] 2@1000 --(class)--> 1000@0 [size=123, length=-1] 3@1001 --(class)--> 1001@0 [size=123, length=-1] 3@1001 --(field@4)--> 4@1000 [size=16, length=-1] -3@1001 --(field@5)--> 5@1002 [size=32, length=-1] +3@1001 --(field@5)--> 5@1002 [size=36, length=-1] 4@1000 --(class)--> 1000@0 [size=123, length=-1] +500@0 --(array-element@1)--> 2@1000 [size=16, length=-1] 5@1002 --(class)--> 1002@0 [size=123, length=-1] -5@1002 --(field@8)--> 6@1000 [size=16, length=-1] -5@1002 --(field@9)--> 1@1000 [size=16, length=-1] +5@1002 --(field@10)--> 1@1000 [size=16, length=-1] +5@1002 --(field@8)--> 500@0 [size=20, length=2] +5@1002 --(field@9)--> 6@1000 [size=16, length=-1] 6@1000 --(class)--> 1000@0 [size=123, length=-1] --- 1001@0 --(superclass)--> 1000@0 [size=123, length=-1] @@ -31,20 +34,24 @@ root@root --(thread)--> 3000@0 [size=132, length=-1] 2@1000 --(class)--> 1000@0 [size=123, length=-1] 3@1001 --(class)--> 1001@0 [size=123, length=-1] 3@1001 --(field@4)--> 4@1000 [size=16, length=-1] -3@1001 --(field@5)--> 5@1002 [size=32, length=-1] +3@1001 --(field@5)--> 5@1002 [size=36, length=-1] 4@1000 --(class)--> 1000@0 [size=123, length=-1] +500@0 --(array-element@1)--> 2@1000 [size=16, length=-1] 5@1002 --(class)--> 1002@0 [size=123, length=-1] -5@1002 --(field@8)--> 6@1000 [size=16, length=-1] -5@1002 --(field@9)--> 1@1000 [size=16, length=-1] +5@1002 --(field@10)--> 1@1000 [size=16, length=-1] +5@1002 --(field@8)--> 500@0 [size=20, length=2] +5@1002 --(field@9)--> 6@1000 [size=16, length=-1] 6@1000 --(class)--> 1000@0 [size=123, length=-1] --- root@root --(jni-global)--> 1@1000 [size=16, length=-1] root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 1@1000 [size=16, length=-1] +root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 3000@0 [size=136, length=-1] root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=13,location= 10])--> 1@1000 [size=16, length=-1] root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=5,location= 10])--> 1@1000 [size=16, length=-1] root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=4,location= 19])--> 1@1000 [size=16, length=-1] +root@root --(stack-local[id=1,tag=3000,depth=5,method=run,vreg=2,location= 0])--> 3000@0 [size=136, length=-1] root@root --(thread)--> 1@1000 [size=16, length=-1] -root@root --(thread)--> 3000@0 [size=132, length=-1] +root@root --(thread)--> 3000@0 [size=136, length=-1] 1001@0 --(superclass)--> 1000@0 [size=123, length=-1] 1002@0 --(interface)--> 2001@0 [size=124, length=-1] 1002@0 --(superclass)--> 1001@0 [size=123, length=-1] @@ -55,11 +62,13 @@ root@root --(thread)--> 3000@0 [size=132, length=-1] 2@1000 --(class)--> 1000@0 [size=123, length=-1] 3@1001 --(class)--> 1001@0 [size=123, length=-1] 3@1001 --(field@4)--> 4@1000 [size=16, length=-1] -3@1001 --(field@5)--> 5@1002 [size=32, length=-1] +3@1001 --(field@5)--> 5@1002 [size=36, length=-1] 4@1000 --(class)--> 1000@0 [size=123, length=-1] +500@0 --(array-element@1)--> 2@1000 [size=16, length=-1] 5@1002 --(class)--> 1002@0 [size=123, length=-1] -5@1002 --(field@8)--> 6@1000 [size=16, length=-1] -5@1002 --(field@9)--> 1@1000 [size=16, length=-1] +5@1002 --(field@10)--> 1@1000 [size=16, length=-1] +5@1002 --(field@8)--> 500@0 [size=20, length=2] +5@1002 --(field@9)--> 6@1000 [size=16, length=-1] 6@1000 --(class)--> 1000@0 [size=123, length=-1] --- 1001@0 --(superclass)--> 1000@0 [size=123, length=-1] @@ -72,43 +81,48 @@ root@root --(thread)--> 3000@0 [size=132, length=-1] 2@1000 --(class)--> 1000@0 [size=123, length=-1] 3@1001 --(class)--> 1001@0 [size=123, length=-1] 3@1001 --(field@4)--> 4@1000 [size=16, length=-1] -3@1001 --(field@5)--> 5@1002 [size=32, length=-1] +3@1001 --(field@5)--> 5@1002 [size=36, length=-1] 4@1000 --(class)--> 1000@0 [size=123, length=-1] +500@0 --(array-element@1)--> 2@1000 [size=16, length=-1] 5@1002 --(class)--> 1002@0 [size=123, length=-1] -5@1002 --(field@8)--> 6@1000 [size=16, length=-1] -5@1002 --(field@9)--> 1@1000 [size=16, length=-1] +5@1002 --(field@10)--> 1@1000 [size=16, length=-1] +5@1002 --(field@8)--> 500@0 [size=20, length=2] +5@1002 --(field@9)--> 6@1000 [size=16, length=-1] 6@1000 --(class)--> 1000@0 [size=123, length=-1] --- -root@root --(thread)--> 3000@0 [size=132, length=-1] +root@root --(thread)--> 3000@0 [size=136, length=-1] --- 3@1001 --(class)--> 1001@0 [size=123, length=-1] --- -root@root --(thread)--> 3000@0 [size=132, length=-1] +root@root --(thread)--> 3000@0 [size=136, length=-1] --- 3@1001 --(class)--> 1001@0 [size=123, length=-1] --- +root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 3000@0 [size=136, length=-1] root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonRoot,vreg=13,location= 32])--> 1@1000 [size=16, length=-1] -root@root --(stack-local[id=1,tag=3000,depth=3,method=doFollowReferencesTest,vreg=1,location= 28])--> 3000@0 [size=132, length=-1] -root@root --(thread)--> 3000@0 [size=132, length=-1] -0@0 --(array-element@0)--> 1@1000 [size=16, length=-1] +root@root --(stack-local[id=1,tag=3000,depth=3,method=doFollowReferencesTest,vreg=1,location= 28])--> 3000@0 [size=136, length=-1] +root@root --(stack-local[id=1,tag=3000,depth=5,method=run,vreg=2,location= 0])--> 3000@0 [size=136, length=-1] +root@root --(thread)--> 3000@0 [size=136, length=-1] --- 1001@0 --(superclass)--> 1000@0 [size=123, length=-1] 3@1001 --(class)--> 1001@0 [size=123, length=-1] 3@1001 --(field@4)--> 4@1000 [size=16, length=-1] -3@1001 --(field@5)--> 5@1002 [size=32, length=-1] +3@1001 --(field@5)--> 5@1002 [size=36, length=-1] --- root@root --(jni-global)--> 1@1000 [size=16, length=-1] root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 1@1000 [size=16, length=-1] +root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 3000@0 [size=136, length=-1] root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=13,location= 10])--> 1@1000 [size=16, length=-1] root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=5,location= 10])--> 1@1000 [size=16, length=-1] root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=4,location= 19])--> 1@1000 [size=16, length=-1] +root@root --(stack-local[id=1,tag=3000,depth=5,method=run,vreg=2,location= 0])--> 3000@0 [size=136, length=-1] root@root --(thread)--> 1@1000 [size=16, length=-1] -root@root --(thread)--> 3000@0 [size=132, length=-1] +root@root --(thread)--> 3000@0 [size=136, length=-1] --- 1001@0 --(superclass)--> 1000@0 [size=123, length=-1] 3@1001 --(class)--> 1001@0 [size=123, length=-1] 3@1001 --(field@4)--> 4@1000 [size=16, length=-1] -3@1001 --(field@5)--> 5@1002 [size=32, length=-1] +3@1001 --(field@5)--> 5@1002 [size=36, length=-1] --- [1@0 (32, 'HelloWorld'), 2@0 (16, '')] 2 @@ -148,16 +162,17 @@ root@root --(thread)--> 3000@0 [size=132, length=-1] 10008 --- klass --- root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonRoot,vreg=13,location= 32])--> 1@1000 [size=16, length=-1] -0@0 --(array-element@0)--> 1@1000 [size=16, length=-1] 1@1000 --(field@2)--> 2@1000 [size=16, length=-1] 3@1001 --(field@4)--> 4@1000 [size=16, length=-1] -5@1002 --(field@8)--> 6@1000 [size=16, length=-1] -5@1002 --(field@9)--> 1@1000 [size=16, length=-1] +500@0 --(array-element@1)--> 2@1000 [size=16, length=-1] +5@1002 --(field@10)--> 1@1000 [size=16, length=-1] +5@1002 --(field@9)--> 6@1000 [size=16, length=-1] --- 1@1000 --(field@2)--> 2@1000 [size=16, length=-1] 3@1001 --(field@4)--> 4@1000 [size=16, length=-1] -5@1002 --(field@8)--> 6@1000 [size=16, length=-1] -5@1002 --(field@9)--> 1@1000 [size=16, length=-1] +500@0 --(array-element@1)--> 2@1000 [size=16, length=-1] +5@1002 --(field@10)--> 1@1000 [size=16, length=-1] +5@1002 --(field@9)--> 6@1000 [size=16, length=-1] --- root@root --(jni-global)--> 1@1000 [size=16, length=-1] root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 1@1000 [size=16, length=-1] @@ -167,13 +182,15 @@ root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot root@root --(thread)--> 1@1000 [size=16, length=-1] 1@1000 --(field@2)--> 2@1000 [size=16, length=-1] 3@1001 --(field@4)--> 4@1000 [size=16, length=-1] -5@1002 --(field@8)--> 6@1000 [size=16, length=-1] -5@1002 --(field@9)--> 1@1000 [size=16, length=-1] +500@0 --(array-element@1)--> 2@1000 [size=16, length=-1] +5@1002 --(field@10)--> 1@1000 [size=16, length=-1] +5@1002 --(field@9)--> 6@1000 [size=16, length=-1] --- 1@1000 --(field@2)--> 2@1000 [size=16, length=-1] 3@1001 --(field@4)--> 4@1000 [size=16, length=-1] -5@1002 --(field@8)--> 6@1000 [size=16, length=-1] -5@1002 --(field@9)--> 1@1000 [size=16, length=-1] +500@0 --(array-element@1)--> 2@1000 [size=16, length=-1] +5@1002 --(field@10)--> 1@1000 [size=16, length=-1] +5@1002 --(field@9)--> 6@1000 [size=16, length=-1] --- --- heap_filter --- ---- tagged objects @@ -182,10 +199,11 @@ root@root --(thread)--> 1@1000 [size=16, length=-1] --- --- ---- untagged objects +root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 3000@0 [size=136, length=-1] root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonRoot,vreg=13,location= 32])--> 1@1000 [size=16, length=-1] -root@root --(stack-local[id=1,tag=3000,depth=3,method=doFollowReferencesTest,vreg=1,location= 28])--> 3000@0 [size=132, length=-1] -root@root --(thread)--> 3000@0 [size=132, length=-1] -0@0 --(array-element@0)--> 1@1000 [size=16, length=-1] +root@root --(stack-local[id=1,tag=3000,depth=3,method=doFollowReferencesTest,vreg=1,location= 28])--> 3000@0 [size=136, length=-1] +root@root --(stack-local[id=1,tag=3000,depth=5,method=run,vreg=2,location= 0])--> 3000@0 [size=136, length=-1] +root@root --(thread)--> 3000@0 [size=136, length=-1] 1001@0 --(superclass)--> 1000@0 [size=123, length=-1] 1002@0 --(interface)--> 2001@0 [size=124, length=-1] 1002@0 --(superclass)--> 1001@0 [size=123, length=-1] @@ -196,11 +214,13 @@ root@root --(thread)--> 3000@0 [size=132, length=-1] 2@1000 --(class)--> 1000@0 [size=123, length=-1] 3@1001 --(class)--> 1001@0 [size=123, length=-1] 3@1001 --(field@4)--> 4@1000 [size=16, length=-1] -3@1001 --(field@5)--> 5@1002 [size=32, length=-1] +3@1001 --(field@5)--> 5@1002 [size=36, length=-1] 4@1000 --(class)--> 1000@0 [size=123, length=-1] +500@0 --(array-element@1)--> 2@1000 [size=16, length=-1] 5@1002 --(class)--> 1002@0 [size=123, length=-1] -5@1002 --(field@8)--> 6@1000 [size=16, length=-1] -5@1002 --(field@9)--> 1@1000 [size=16, length=-1] +5@1002 --(field@10)--> 1@1000 [size=16, length=-1] +5@1002 --(field@8)--> 500@0 [size=20, length=2] +5@1002 --(field@9)--> 6@1000 [size=16, length=-1] 6@1000 --(class)--> 1000@0 [size=123, length=-1] --- 1001@0 --(superclass)--> 1000@0 [size=123, length=-1] @@ -213,20 +233,24 @@ root@root --(thread)--> 3000@0 [size=132, length=-1] 2@1000 --(class)--> 1000@0 [size=123, length=-1] 3@1001 --(class)--> 1001@0 [size=123, length=-1] 3@1001 --(field@4)--> 4@1000 [size=16, length=-1] -3@1001 --(field@5)--> 5@1002 [size=32, length=-1] +3@1001 --(field@5)--> 5@1002 [size=36, length=-1] 4@1000 --(class)--> 1000@0 [size=123, length=-1] +500@0 --(array-element@1)--> 2@1000 [size=16, length=-1] 5@1002 --(class)--> 1002@0 [size=123, length=-1] -5@1002 --(field@8)--> 6@1000 [size=16, length=-1] -5@1002 --(field@9)--> 1@1000 [size=16, length=-1] +5@1002 --(field@10)--> 1@1000 [size=16, length=-1] +5@1002 --(field@8)--> 500@0 [size=20, length=2] +5@1002 --(field@9)--> 6@1000 [size=16, length=-1] 6@1000 --(class)--> 1000@0 [size=123, length=-1] --- root@root --(jni-global)--> 1@1000 [size=16, length=-1] root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 1@1000 [size=16, length=-1] +root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 3000@0 [size=136, length=-1] root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=13,location= 10])--> 1@1000 [size=16, length=-1] root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=5,location= 10])--> 1@1000 [size=16, length=-1] root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=4,location= 19])--> 1@1000 [size=16, length=-1] +root@root --(stack-local[id=1,tag=3000,depth=5,method=run,vreg=2,location= 0])--> 3000@0 [size=136, length=-1] root@root --(thread)--> 1@1000 [size=16, length=-1] -root@root --(thread)--> 3000@0 [size=132, length=-1] +root@root --(thread)--> 3000@0 [size=136, length=-1] 1001@0 --(superclass)--> 1000@0 [size=123, length=-1] 1002@0 --(interface)--> 2001@0 [size=124, length=-1] 1002@0 --(superclass)--> 1001@0 [size=123, length=-1] @@ -237,11 +261,13 @@ root@root --(thread)--> 3000@0 [size=132, length=-1] 2@1000 --(class)--> 1000@0 [size=123, length=-1] 3@1001 --(class)--> 1001@0 [size=123, length=-1] 3@1001 --(field@4)--> 4@1000 [size=16, length=-1] -3@1001 --(field@5)--> 5@1002 [size=32, length=-1] +3@1001 --(field@5)--> 5@1002 [size=36, length=-1] 4@1000 --(class)--> 1000@0 [size=123, length=-1] +500@0 --(array-element@1)--> 2@1000 [size=16, length=-1] 5@1002 --(class)--> 1002@0 [size=123, length=-1] -5@1002 --(field@8)--> 6@1000 [size=16, length=-1] -5@1002 --(field@9)--> 1@1000 [size=16, length=-1] +5@1002 --(field@10)--> 1@1000 [size=16, length=-1] +5@1002 --(field@8)--> 500@0 [size=20, length=2] +5@1002 --(field@9)--> 6@1000 [size=16, length=-1] 6@1000 --(class)--> 1000@0 [size=123, length=-1] --- 1001@0 --(superclass)--> 1000@0 [size=123, length=-1] @@ -254,16 +280,20 @@ root@root --(thread)--> 3000@0 [size=132, length=-1] 2@1000 --(class)--> 1000@0 [size=123, length=-1] 3@1001 --(class)--> 1001@0 [size=123, length=-1] 3@1001 --(field@4)--> 4@1000 [size=16, length=-1] -3@1001 --(field@5)--> 5@1002 [size=32, length=-1] +3@1001 --(field@5)--> 5@1002 [size=36, length=-1] 4@1000 --(class)--> 1000@0 [size=123, length=-1] +500@0 --(array-element@1)--> 2@1000 [size=16, length=-1] 5@1002 --(class)--> 1002@0 [size=123, length=-1] -5@1002 --(field@8)--> 6@1000 [size=16, length=-1] -5@1002 --(field@9)--> 1@1000 [size=16, length=-1] +5@1002 --(field@10)--> 1@1000 [size=16, length=-1] +5@1002 --(field@8)--> 500@0 [size=20, length=2] +5@1002 --(field@9)--> 6@1000 [size=16, length=-1] 6@1000 --(class)--> 1000@0 [size=123, length=-1] --- ---- tagged classes -root@root --(stack-local[id=1,tag=3000,depth=3,method=doFollowReferencesTest,vreg=1,location= 28])--> 3000@0 [size=132, length=-1] -root@root --(thread)--> 3000@0 [size=132, length=-1] +root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 3000@0 [size=136, length=-1] +root@root --(stack-local[id=1,tag=3000,depth=3,method=doFollowReferencesTest,vreg=1,location= 28])--> 3000@0 [size=136, length=-1] +root@root --(stack-local[id=1,tag=3000,depth=5,method=run,vreg=2,location= 0])--> 3000@0 [size=136, length=-1] +root@root --(thread)--> 3000@0 [size=136, length=-1] 1001@0 --(superclass)--> 1000@0 [size=123, length=-1] 1002@0 --(interface)--> 2001@0 [size=124, length=-1] 1002@0 --(superclass)--> 1001@0 [size=123, length=-1] @@ -273,6 +303,7 @@ root@root --(thread)--> 3000@0 [size=132, length=-1] 3@1001 --(class)--> 1001@0 [size=123, length=-1] 4@1000 --(class)--> 1000@0 [size=123, length=-1] 5@1002 --(class)--> 1002@0 [size=123, length=-1] +5@1002 --(field@8)--> 500@0 [size=20, length=2] 6@1000 --(class)--> 1000@0 [size=123, length=-1] --- 1001@0 --(superclass)--> 1000@0 [size=123, length=-1] @@ -284,9 +315,12 @@ root@root --(thread)--> 3000@0 [size=132, length=-1] 3@1001 --(class)--> 1001@0 [size=123, length=-1] 4@1000 --(class)--> 1000@0 [size=123, length=-1] 5@1002 --(class)--> 1002@0 [size=123, length=-1] +5@1002 --(field@8)--> 500@0 [size=20, length=2] 6@1000 --(class)--> 1000@0 [size=123, length=-1] --- -root@root --(thread)--> 3000@0 [size=132, length=-1] +root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 3000@0 [size=136, length=-1] +root@root --(stack-local[id=1,tag=3000,depth=5,method=run,vreg=2,location= 0])--> 3000@0 [size=136, length=-1] +root@root --(thread)--> 3000@0 [size=136, length=-1] 1001@0 --(superclass)--> 1000@0 [size=123, length=-1] 1002@0 --(interface)--> 2001@0 [size=124, length=-1] 1002@0 --(superclass)--> 1001@0 [size=123, length=-1] @@ -296,6 +330,7 @@ root@root --(thread)--> 3000@0 [size=132, length=-1] 3@1001 --(class)--> 1001@0 [size=123, length=-1] 4@1000 --(class)--> 1000@0 [size=123, length=-1] 5@1002 --(class)--> 1002@0 [size=123, length=-1] +5@1002 --(field@8)--> 500@0 [size=20, length=2] 6@1000 --(class)--> 1000@0 [size=123, length=-1] --- 1001@0 --(superclass)--> 1000@0 [size=123, length=-1] @@ -307,24 +342,26 @@ root@root --(thread)--> 3000@0 [size=132, length=-1] 3@1001 --(class)--> 1001@0 [size=123, length=-1] 4@1000 --(class)--> 1000@0 [size=123, length=-1] 5@1002 --(class)--> 1002@0 [size=123, length=-1] +5@1002 --(field@8)--> 500@0 [size=20, length=2] 6@1000 --(class)--> 1000@0 [size=123, length=-1] --- ---- untagged classes root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonRoot,vreg=13,location= 32])--> 1@1000 [size=16, length=-1] -0@0 --(array-element@0)--> 1@1000 [size=16, length=-1] 1@1000 --(field@2)--> 2@1000 [size=16, length=-1] 1@1000 --(field@3)--> 3@1001 [size=24, length=-1] 3@1001 --(field@4)--> 4@1000 [size=16, length=-1] -3@1001 --(field@5)--> 5@1002 [size=32, length=-1] -5@1002 --(field@8)--> 6@1000 [size=16, length=-1] -5@1002 --(field@9)--> 1@1000 [size=16, length=-1] +3@1001 --(field@5)--> 5@1002 [size=36, length=-1] +500@0 --(array-element@1)--> 2@1000 [size=16, length=-1] +5@1002 --(field@10)--> 1@1000 [size=16, length=-1] +5@1002 --(field@9)--> 6@1000 [size=16, length=-1] --- 1@1000 --(field@2)--> 2@1000 [size=16, length=-1] 1@1000 --(field@3)--> 3@1001 [size=24, length=-1] 3@1001 --(field@4)--> 4@1000 [size=16, length=-1] -3@1001 --(field@5)--> 5@1002 [size=32, length=-1] -5@1002 --(field@8)--> 6@1000 [size=16, length=-1] -5@1002 --(field@9)--> 1@1000 [size=16, length=-1] +3@1001 --(field@5)--> 5@1002 [size=36, length=-1] +500@0 --(array-element@1)--> 2@1000 [size=16, length=-1] +5@1002 --(field@10)--> 1@1000 [size=16, length=-1] +5@1002 --(field@9)--> 6@1000 [size=16, length=-1] --- root@root --(jni-global)--> 1@1000 [size=16, length=-1] root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 1@1000 [size=16, length=-1] @@ -335,14 +372,16 @@ root@root --(thread)--> 1@1000 [size=16, length=-1] 1@1000 --(field@2)--> 2@1000 [size=16, length=-1] 1@1000 --(field@3)--> 3@1001 [size=24, length=-1] 3@1001 --(field@4)--> 4@1000 [size=16, length=-1] -3@1001 --(field@5)--> 5@1002 [size=32, length=-1] -5@1002 --(field@8)--> 6@1000 [size=16, length=-1] -5@1002 --(field@9)--> 1@1000 [size=16, length=-1] +3@1001 --(field@5)--> 5@1002 [size=36, length=-1] +500@0 --(array-element@1)--> 2@1000 [size=16, length=-1] +5@1002 --(field@10)--> 1@1000 [size=16, length=-1] +5@1002 --(field@9)--> 6@1000 [size=16, length=-1] --- 1@1000 --(field@2)--> 2@1000 [size=16, length=-1] 1@1000 --(field@3)--> 3@1001 [size=24, length=-1] 3@1001 --(field@4)--> 4@1000 [size=16, length=-1] -3@1001 --(field@5)--> 5@1002 [size=32, length=-1] -5@1002 --(field@8)--> 6@1000 [size=16, length=-1] -5@1002 --(field@9)--> 1@1000 [size=16, length=-1] +3@1001 --(field@5)--> 5@1002 [size=36, length=-1] +500@0 --(array-element@1)--> 2@1000 [size=16, length=-1] +5@1002 --(field@10)--> 1@1000 [size=16, length=-1] +5@1002 --(field@9)--> 6@1000 [size=16, length=-1] --- diff --git a/test/913-heaps/heaps.cc b/test/913-heaps/heaps.cc index 6a06b29152..19e12ae731 100644 --- a/test/913-heaps/heaps.cc +++ b/test/913-heaps/heaps.cc @@ -19,40 +19,35 @@ #include <string.h> #include <iostream> +#include <sstream> #include <vector> #include "android-base/macros.h" #include "android-base/logging.h" #include "android-base/stringprintf.h" -#include "jit/jit.h" #include "jni.h" -#include "native_stack_dump.h" #include "jvmti.h" -#include "runtime.h" -#include "scoped_thread_state_change-inl.h" -#include "thread-inl.h" -#include "thread_list.h" // Test infrastructure #include "jni_helper.h" #include "jvmti_helper.h" #include "test_env.h" +#include "ti_utf.h" namespace art { namespace Test913Heaps { using android::base::StringPrintf; +#define FINAL final +#define OVERRIDE override +#define UNREACHABLE __builtin_unreachable + extern "C" JNIEXPORT void JNICALL Java_art_Test913_forceGarbageCollection( - JNIEnv* env ATTRIBUTE_UNUSED, jclass klass ATTRIBUTE_UNUSED) { + JNIEnv* env, jclass klass ATTRIBUTE_UNUSED) { jvmtiError ret = jvmti_env->ForceGarbageCollection(); - if (ret != JVMTI_ERROR_NONE) { - char* err; - jvmti_env->GetErrorName(ret, &err); - printf("Error forcing a garbage collection: %s\n", err); - jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(err)); - } + JvmtiErrorToException(env, jvmti_env, ret); } class IterationConfig { @@ -92,7 +87,8 @@ static jint JNICALL HeapReferenceCallback(jvmtiHeapReferenceKind reference_kind, user_data); } -static bool Run(jint heap_filter, +static bool Run(JNIEnv* env, + jint heap_filter, jclass klass_filter, jobject initial_object, IterationConfig* config) { @@ -105,14 +101,7 @@ static bool Run(jint heap_filter, initial_object, &callbacks, config); - if (ret != JVMTI_ERROR_NONE) { - char* err; - jvmti_env->GetErrorName(ret, &err); - printf("Failure running FollowReferences: %s\n", err); - jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(err)); - return false; - } - return true; + return !JvmtiErrorToException(env, jvmti_env, ret); } extern "C" JNIEXPORT jobjectArray JNICALL Java_art_Test913_followReferences( @@ -142,6 +131,27 @@ extern "C" JNIEXPORT jobjectArray JNICALL Java_art_Test913_followReferences( jint length, void* user_data ATTRIBUTE_UNUSED) OVERRIDE { jlong tag = *tag_ptr; + + // Ignore any jni-global roots with untagged classes. These can be from the environment, + // or the JIT. + if (reference_kind == JVMTI_HEAP_REFERENCE_JNI_GLOBAL && class_tag == 0) { + return 0; + } + // Ignore classes (1000-1002@0) for thread objects. These can be held by the JIT. + if (reference_kind == JVMTI_HEAP_REFERENCE_THREAD && class_tag == 0 && + (1000 <= *tag_ptr && *tag_ptr <= 1002)) { + return 0; + } + // Ignore stack-locals of untagged threads. That is the environment. + if (reference_kind == JVMTI_HEAP_REFERENCE_STACK_LOCAL && + reference_info->stack_local.thread_tag != 3000) { + return 0; + } + // Ignore array elements with an untagged source. These are from the environment. + if (reference_kind == JVMTI_HEAP_REFERENCE_ARRAY_ELEMENT && *referrer_tag_ptr == 0) { + return 0; + } + // Only check tagged objects. if (tag == 0) { return JVMTI_VISIT_OBJECTS; @@ -201,10 +211,6 @@ extern "C" JNIEXPORT jobjectArray JNICALL Java_art_Test913_followReferences( reference_info, adapted_size, length)); - - if (reference_kind == JVMTI_HEAP_REFERENCE_THREAD && *tag_ptr == 1000) { - DumpStacks(); - } } std::vector<std::string> GetLines() const { @@ -259,9 +265,15 @@ extern "C" JNIEXPORT jobjectArray JNICALL Java_art_Test913_followReferences( if (info_.jni_local.method != nullptr) { jvmti_env->GetMethodName(info_.jni_local.method, &name, nullptr, nullptr); } + // Normalize the thread id, as this depends on the number of other threads + // and which thread is running the test. Should be: + // jlong thread_id = info_.jni_local.thread_id; + // TODO: A pre-pass before the test should be able fetch this number, so it can + // be compared explicitly. + jlong thread_id = 1; std::string ret = StringPrintf("jni-local[id=%" PRId64 ",tag=%" PRId64 ",depth=%d," "method=%s]", - info_.jni_local.thread_id, + thread_id, info_.jni_local.thread_tag, info_.jni_local.depth, name == nullptr ? "<null>" : name); @@ -284,13 +296,12 @@ extern "C" JNIEXPORT jobjectArray JNICALL Java_art_Test913_followReferences( jlong size, jint length, const jvmtiHeapReferenceInfo* reference_info) - REQUIRES_SHARED(Locks::mutator_lock_) : Elem(referrer, referree, size, length) { memcpy(&info_, reference_info, sizeof(jvmtiHeapReferenceInfo)); - // Debug stack trace for failure condition. Remove when done. - if (info_.stack_local.depth == 3 && info_.stack_local.slot == 13) { - DumpNativeStack(std::cerr, GetTid()); - Thread::Current()->DumpJavaStack(std::cerr, false, false); + + // Debug code. Try to figure out where bad depth is coming from. + if (reference_info->stack_local.depth == 6) { + LOG(FATAL) << "Unexpected depth of 6"; } } @@ -300,9 +311,15 @@ extern "C" JNIEXPORT jobjectArray JNICALL Java_art_Test913_followReferences( if (info_.stack_local.method != nullptr) { jvmti_env->GetMethodName(info_.stack_local.method, &name, nullptr, nullptr); } + // Normalize the thread id, as this depends on the number of other threads + // and which thread is running the test. Should be: + // jlong thread_id = info_.stack_local.thread_id; + // TODO: A pre-pass before the test should be able fetch this number, so it can + // be compared explicitly. + jlong thread_id = 1; std::string ret = StringPrintf("stack-local[id=%" PRId64 ",tag=%" PRId64 ",depth=%d," "method=%s,vreg=%d,location=% " PRId64 "]", - info_.stack_local.thread_id, + thread_id, info_.stack_local.thread_tag, info_.stack_local.depth, name == nullptr ? "<null>" : name, @@ -361,7 +378,13 @@ extern "C" JNIEXPORT jobjectArray JNICALL Java_art_Test913_followReferences( tmp)); } case JVMTI_HEAP_REFERENCE_ARRAY_ELEMENT: { - std::string tmp = StringPrintf("array-element@%d", reference_info->array.index); + jint index = reference_info->array.index; + // Normalize if it's "0@0" -> "3000@1". + // TODO: A pre-pass could probably give us this index to check explicitly. + if (referrer == "0@0" && referree == "3000@0") { + index = 0; + } + std::string tmp = StringPrintf("array-element@%d", index); return std::unique_ptr<Elem>(new StringElement(referrer, referree, size, @@ -459,16 +482,6 @@ extern "C" JNIEXPORT jobjectArray JNICALL Java_art_Test913_followReferences( UNREACHABLE(); } - static void DumpStacks() NO_THREAD_SAFETY_ANALYSIS { - auto dump_function = [](art::Thread* t, void* data ATTRIBUTE_UNUSED) { - std::string name; - t->GetThreadName(name); - LOG(ERROR) << name; - art::DumpNativeStack(LOG_STREAM(ERROR), t->GetTid()); - }; - art::Runtime::Current()->GetThreadList()->ForEach(dump_function, nullptr); - } - jint counter_; const jint stop_after_; const jint follow_set_; @@ -476,8 +489,6 @@ extern "C" JNIEXPORT jobjectArray JNICALL Java_art_Test913_followReferences( std::vector<std::unique_ptr<Elem>> lines_; }; - jit::ScopedJitSuspend sjs; // Wait to avoid JIT influence (e.g., JNI globals). - // If jniRef isn't null, add a local and a global ref. ScopedLocalRef<jobject> jni_local_ref(env, nullptr); jobject jni_global_ref = nullptr; @@ -487,7 +498,9 @@ extern "C" JNIEXPORT jobjectArray JNICALL Java_art_Test913_followReferences( } PrintIterationConfig config(stop_after, follow_set); - Run(heap_filter, klass_filter, initial_object, &config); + if (!Run(env, heap_filter, klass_filter, initial_object, &config)) { + return nullptr; + } std::vector<std::string> lines = config.GetLines(); jobjectArray ret = CreateObjectArray(env, @@ -528,10 +541,10 @@ extern "C" JNIEXPORT jobjectArray JNICALL Java_art_Test913_followReferencesStrin void* user_data) { FindStringCallbacks* p = reinterpret_cast<FindStringCallbacks*>(user_data); if (*tag_ptr != 0) { - size_t utf_byte_count = CountUtf8Bytes(value, value_length); + size_t utf_byte_count = ti::CountUtf8Bytes(value, value_length); std::unique_ptr<char[]> mod_utf(new char[utf_byte_count + 1]); memset(mod_utf.get(), 0, utf_byte_count + 1); - ConvertUtf16ToModifiedUtf8(mod_utf.get(), utf_byte_count, value, value_length); + ti::ConvertUtf16ToModifiedUtf8(mod_utf.get(), utf_byte_count, value, value_length); p->data.push_back(android::base::StringPrintf("%" PRId64 "@%" PRId64 " (%" PRId64 ", '%s')", *tag_ptr, class_tag, diff --git a/test/913-heaps/src/art/Test913.java b/test/913-heaps/src/art/Test913.java index c54ecb049f..d3b29cf2b5 100644 --- a/test/913-heaps/src/art/Test913.java +++ b/test/913-heaps/src/art/Test913.java @@ -21,12 +21,34 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; +import java.util.concurrent.CountDownLatch; public class Test913 { public static void run() throws Exception { Main.bindAgentJNIForClass(Test913.class); doTest(); + + // Use a countdown latch for synchronization, as join() will introduce more roots. + final CountDownLatch cdl1 = new CountDownLatch(1); + + // Run the follow-references tests on a dedicated thread so we know the specific Thread type. + Thread t = new Thread() { + @Override + public void run() { + try { + Test913.runFollowReferences(); + } catch (Exception e) { + throw new RuntimeException(e); + } + cdl1.countDown(); + } + }; + t.start(); + cdl1.await(); + } + + public static void runFollowReferences() throws Exception { new TestConfig().doFollowReferencesTest(); Runtime.getRuntime().gc(); @@ -349,6 +371,14 @@ public class Test913 { cInst.baz2 = aInst; v.add(cInstStr, aInstStr); // C -->(field) --> A. + A[] aArray = new A[2]; + setTag(aArray, 500); + aArray[1] = a2Inst; + cInst.array = aArray; + String aArrayStr = "500@0"; + v.add(cInstStr, aArrayStr); + v.add(aArrayStr, a2InstStr); + return aInst; } } @@ -386,6 +416,7 @@ public class Test913 { public static class C extends B implements I2 { public A baz; public A baz2; + public A[] array; public C() {} public C(A a, A b) { @@ -481,7 +512,8 @@ public class Test913 { if (currentHead == null) { currentHead = referrer; } else { - if (!currentHead.equals(referrer)) { + // Ignore 0@0, as it can happen at any time (as it stands for all other objects). + if (!currentHead.equals(referrer) && !referrer.equals("0@0")) { completedReferrers.add(currentHead); currentHead = referrer; if (completedReferrers.contains(referrer)) { diff --git a/test/914-hello-obsolescence/src/Main.java b/test/914-hello-obsolescence/src/Main.java index 2ec7664f0f..ab5c7f421f 100644 --- a/test/914-hello-obsolescence/src/Main.java +++ b/test/914-hello-obsolescence/src/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,60 +14,8 @@ * limitations under the License. */ -import java.util.Base64; - public class Main { - // class Transform { - // public void sayHi(Runnable r) { - // System.out.println("Hello - Transformed"); - // r.run(); - // System.out.println("Goodbye - Transformed"); - // } - // } - private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( - "yv66vgAAADQAJAoACAARCQASABMIABQKABUAFgsAFwAYCAAZBwAaBwAbAQAGPGluaXQ+AQADKClW" + - "AQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEABXNheUhpAQAXKExqYXZhL2xhbmcvUnVubmFibGU7" + - "KVYBAApTb3VyY2VGaWxlAQAOVHJhbnNmb3JtLmphdmEMAAkACgcAHAwAHQAeAQATSGVsbG8gLSBU" + - "cmFuc2Zvcm1lZAcAHwwAIAAhBwAiDAAjAAoBABVHb29kYnllIC0gVHJhbnNmb3JtZWQBAAlUcmFu" + - "c2Zvcm0BABBqYXZhL2xhbmcvT2JqZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZh" + - "L2lvL1ByaW50U3RyZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZh" + - "L2xhbmcvU3RyaW5nOylWAQASamF2YS9sYW5nL1J1bm5hYmxlAQADcnVuACAABwAIAAAAAAACAAAA" + - "CQAKAAEACwAAAB0AAQABAAAABSq3AAGxAAAAAQAMAAAABgABAAAAAQABAA0ADgABAAsAAAA7AAIA" + - "AgAAABeyAAISA7YABCu5AAUBALIAAhIGtgAEsQAAAAEADAAAABIABAAAAAMACAAEAA4ABQAWAAYA" + - "AQAPAAAAAgAQ"); - private static final byte[] DEX_BYTES = Base64.getDecoder().decode( - "ZGV4CjAzNQAYeAMMXgYWxoeSHAS9EWKCCtVRSAGpqZVQAwAAcAAAAHhWNBIAAAAAAAAAALACAAAR" + - "AAAAcAAAAAcAAAC0AAAAAwAAANAAAAABAAAA9AAAAAUAAAD8AAAAAQAAACQBAAAMAgAARAEAAKIB" + - "AACqAQAAwQEAANYBAADjAQAA+gEAAA4CAAAkAgAAOAIAAEwCAABcAgAAXwIAAGMCAAB3AgAAfAIA" + - "AIUCAACKAgAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAACgAAAAoAAAAGAAAAAAAAAAsAAAAGAAAA" + - "lAEAAAsAAAAGAAAAnAEAAAUAAQANAAAAAAAAAAAAAAAAAAEAEAAAAAEAAgAOAAAAAgAAAAAAAAAD" + - "AAAADwAAAAAAAAAAAAAAAgAAAAAAAAAJAAAAAAAAAJ8CAAAAAAAAAQABAAEAAACRAgAABAAAAHAQ" + - "AwAAAA4ABAACAAIAAACWAgAAFAAAAGIAAAAbAQIAAABuIAIAEAByEAQAAwBiAAAAGwEBAAAAbiAC" + - "ABAADgABAAAAAwAAAAEAAAAEAAY8aW5pdD4AFUdvb2RieWUgLSBUcmFuc2Zvcm1lZAATSGVsbG8g" + - "LSBUcmFuc2Zvcm1lZAALTFRyYW5zZm9ybTsAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwASTGphdmEv" + - "bGFuZy9PYmplY3Q7ABRMamF2YS9sYW5nL1J1bm5hYmxlOwASTGphdmEvbGFuZy9TdHJpbmc7ABJM" + - "amF2YS9sYW5nL1N5c3RlbTsADlRyYW5zZm9ybS5qYXZhAAFWAAJWTAASZW1pdHRlcjogamFjay00" + - "LjEzAANvdXQAB3ByaW50bG4AA3J1bgAFc2F5SGkAAQAHDgADAQAHDoc8hwAAAAEBAICABMQCAQHc" + - "AgAAAA0AAAAAAAAAAQAAAAAAAAABAAAAEQAAAHAAAAACAAAABwAAALQAAAADAAAAAwAAANAAAAAE" + - "AAAAAQAAAPQAAAAFAAAABQAAAPwAAAAGAAAAAQAAACQBAAABIAAAAgAAAEQBAAABEAAAAgAAAJQB" + - "AAACIAAAEQAAAKIBAAADIAAAAgAAAJECAAAAIAAAAQAAAJ8CAAAAEAAAAQAAALACAAA="); - - public static void main(String[] args) { - art.Main.bindAgentJNIForClass(Main.class); - doTest(new Transform()); + public static void main(String[] args) throws Exception { + art.Test914.run(); } - - public static void doTest(Transform t) { - t.sayHi(() -> { System.out.println("Not doing anything here"); }); - t.sayHi(() -> { - System.out.println("transforming calling function"); - doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES); - }); - t.sayHi(() -> { System.out.println("Not doing anything here"); }); - } - - // Transforms the class - private static native void doCommonClassRedefinition(Class<?> target, - byte[] classfile, - byte[] dexfile); } diff --git a/test/914-hello-obsolescence/src/Transform.java b/test/914-hello-obsolescence/src/Transform.java deleted file mode 100644 index 8cda6cdf53..0000000000 --- a/test/914-hello-obsolescence/src/Transform.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * 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. - */ - -class Transform { - public void sayHi(Runnable r) { - // Use lower 'h' to make sure the string will have a different string id - // than the transformation (the transformation code is the same except - // the actual printed String, which was making the test inacurately passing - // in JIT mode when loading the string from the dex cache, as the string ids - // of the two different strings were the same). - // We know the string ids will be different because lexicographically: - // "Hello" < "LTransform;" < "hello". - System.out.println("hello"); - r.run(); - System.out.println("goodbye"); - } -} diff --git a/test/914-hello-obsolescence/src/art/Redefinition.java b/test/914-hello-obsolescence/src/art/Redefinition.java new file mode 100644 index 0000000000..0350ab42ad --- /dev/null +++ b/test/914-hello-obsolescence/src/art/Redefinition.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.util.ArrayList; +// Common Redefinition functions. Placed here for use by CTS +public class Redefinition { + // Bind native functions. + static { + Main.bindAgentJNIForClass(Redefinition.class); + } + + public static final class CommonClassDefinition { + public final Class<?> target; + public final byte[] class_file_bytes; + public final byte[] dex_file_bytes; + + public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { + this.target = target; + this.class_file_bytes = class_file_bytes; + this.dex_file_bytes = dex_file_bytes; + } + } + + // A set of possible test configurations. Test should set this if they need to. + // This must be kept in sync with the defines in ti-agent/common_helper.cc + public static enum Config { + COMMON_REDEFINE(0), + COMMON_RETRANSFORM(1), + COMMON_TRANSFORM(2); + + private final int val; + private Config(int val) { + this.val = val; + } + } + + public static void setTestConfiguration(Config type) { + nativeSetTestConfiguration(type.val); + } + + private static native void nativeSetTestConfiguration(int type); + + // Transforms the class + public static native void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile); + + public static void doMultiClassRedefinition(CommonClassDefinition... defs) { + ArrayList<Class<?>> classes = new ArrayList<>(); + ArrayList<byte[]> class_files = new ArrayList<>(); + ArrayList<byte[]> dex_files = new ArrayList<>(); + + for (CommonClassDefinition d : defs) { + classes.add(d.target); + class_files.add(d.class_file_bytes); + dex_files.add(d.dex_file_bytes); + } + doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), + class_files.toArray(new byte[0][]), + dex_files.toArray(new byte[0][])); + } + + public static void addMultiTransformationResults(CommonClassDefinition... defs) { + for (CommonClassDefinition d : defs) { + addCommonTransformationResult(d.target.getCanonicalName(), + d.class_file_bytes, + d.dex_file_bytes); + } + } + + public static native void doCommonMultiClassRedefinition(Class<?>[] targets, + byte[][] classfiles, + byte[][] dexfiles); + public static native void doCommonClassRetransformation(Class<?>... target); + public static native void setPopRetransformations(boolean pop); + public static native void popTransformationFor(String name); + public static native void enableCommonRetransformation(boolean enable); + public static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); +} diff --git a/test/914-hello-obsolescence/src/art/Test914.java b/test/914-hello-obsolescence/src/art/Test914.java new file mode 100644 index 0000000000..ef2710da5b --- /dev/null +++ b/test/914-hello-obsolescence/src/art/Test914.java @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * 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 art; + +import java.util.Base64; + +public class Test914 { + + // The class we will be transforming. + static class Transform { + public void sayHi(Runnable r) { + System.out.println("hello"); + r.run(); + System.out.println("goodbye"); + } + } + + // static class Transform { + // public void sayHi(Runnable r) { + // System.out.println("Hello - Transformed"); + // r.run(); + // System.out.println("Goodbye - Transformed"); + // } + // } + private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( + "yv66vgAAADQAKAoACAARCQASABMIABQKABUAFgsAFwAYCAAZBwAbBwAeAQAGPGluaXQ+AQADKClW" + + "AQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEABXNheUhpAQAXKExqYXZhL2xhbmcvUnVubmFibGU7" + + "KVYBAApTb3VyY2VGaWxlAQAMVGVzdDkxNC5qYXZhDAAJAAoHAB8MACAAIQEAE0hlbGxvIC0gVHJh" + + "bnNmb3JtZWQHACIMACMAJAcAJQwAJgAKAQAVR29vZGJ5ZSAtIFRyYW5zZm9ybWVkBwAnAQAVYXJ0" + + "L1Rlc3Q5MTQkVHJhbnNmb3JtAQAJVHJhbnNmb3JtAQAMSW5uZXJDbGFzc2VzAQAQamF2YS9sYW5n" + + "L09iamVjdAEAEGphdmEvbGFuZy9TeXN0ZW0BAANvdXQBABVMamF2YS9pby9QcmludFN0cmVhbTsB" + + "ABNqYXZhL2lvL1ByaW50U3RyZWFtAQAHcHJpbnRsbgEAFShMamF2YS9sYW5nL1N0cmluZzspVgEA" + + "EmphdmEvbGFuZy9SdW5uYWJsZQEAA3J1bgEAC2FydC9UZXN0OTE0ACAABwAIAAAAAAACAAAACQAK" + + "AAEACwAAAB0AAQABAAAABSq3AAGxAAAAAQAMAAAABgABAAAABQABAA0ADgABAAsAAAA7AAIAAgAA" + + "ABeyAAISA7YABCu5AAUBALIAAhIGtgAEsQAAAAEADAAAABIABAAAAAcACAAIAA4ACQAWAAoAAgAP" + + "AAAAAgAQAB0AAAAKAAEABwAaABwACA=="); + private static final byte[] DEX_BYTES = Base64.getDecoder().decode( + "ZGV4CjAzNQBlmxNYAAAAAAAAAAAAAAAAAAAAAAAAAAA8BAAAcAAAAHhWNBIAAAAAAAAAAHgDAAAX" + + "AAAAcAAAAAoAAADMAAAAAwAAAPQAAAABAAAAGAEAAAUAAAAgAQAAAQAAAEgBAADUAgAAaAEAAGgB" + + "AABwAQAAhwEAAJwBAAC1AQAAxAEAAOgBAAAIAgAAHwIAADMCAABJAgAAXQIAAHECAAB/AgAAigIA" + + "AI0CAACRAgAAngIAAKQCAACpAgAAsgIAALcCAAC+AgAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAA" + + "CQAAAAoAAAALAAAADgAAAA4AAAAJAAAAAAAAAA8AAAAJAAAAyAIAAA8AAAAJAAAA0AIAAAgABAAS" + + "AAAAAAAAAAAAAAAAAAEAFQAAAAQAAgATAAAABQAAAAAAAAAGAAAAFAAAAAAAAAAAAAAABQAAAAAA" + + "AAAMAAAAaAMAADwDAAAAAAAABjxpbml0PgAVR29vZGJ5ZSAtIFRyYW5zZm9ybWVkABNIZWxsbyAt" + + "IFRyYW5zZm9ybWVkABdMYXJ0L1Rlc3Q5MTQkVHJhbnNmb3JtOwANTGFydC9UZXN0OTE0OwAiTGRh" + + "bHZpay9hbm5vdGF0aW9uL0VuY2xvc2luZ0NsYXNzOwAeTGRhbHZpay9hbm5vdGF0aW9uL0lubmVy" + + "Q2xhc3M7ABVMamF2YS9pby9QcmludFN0cmVhbTsAEkxqYXZhL2xhbmcvT2JqZWN0OwAUTGphdmEv" + + "bGFuZy9SdW5uYWJsZTsAEkxqYXZhL2xhbmcvU3RyaW5nOwASTGphdmEvbGFuZy9TeXN0ZW07AAxU" + + "ZXN0OTE0LmphdmEACVRyYW5zZm9ybQABVgACVkwAC2FjY2Vzc0ZsYWdzAARuYW1lAANvdXQAB3By" + + "aW50bG4AA3J1bgAFc2F5SGkABXZhbHVlAAAAAAEAAAAGAAAAAQAAAAcAAAAFAAcOAAcBAAcOAQgP" + + "AQMPAQgPAAEAAQABAAAA2AIAAAQAAABwEAMAAAAOAAQAAgACAAAA3QIAABQAAABiAAAAGwECAAAA" + + "biACABAAchAEAAMAYgAAABsBAQAAAG4gAgAQAA4AAAABAQCAgATsBQEBhAYAAAICARYYAQIDAhAE" + + "CBEXDQACAAAATAMAAFIDAABcAwAAAAAAAAAAAAAAAAAAEAAAAAAAAAABAAAAAAAAAAEAAAAXAAAA" + + "cAAAAAIAAAAKAAAAzAAAAAMAAAADAAAA9AAAAAQAAAABAAAAGAEAAAUAAAAFAAAAIAEAAAYAAAAB" + + "AAAASAEAAAIgAAAXAAAAaAEAAAEQAAACAAAAyAIAAAMgAAACAAAA2AIAAAEgAAACAAAA7AIAAAAg" + + "AAABAAAAPAMAAAQgAAACAAAATAMAAAMQAAABAAAAXAMAAAYgAAABAAAAaAMAAAAQAAABAAAAeAMA" + + "AA=="); + + public static void run() { + Redefinition.setTestConfiguration(Redefinition.Config.COMMON_REDEFINE); + doTest(new Transform()); + } + + public static void doTest(Transform t) { + t.sayHi(() -> { System.out.println("Not doing anything here"); }); + t.sayHi(() -> { + System.out.println("transforming calling function"); + Redefinition.doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES); + }); + t.sayHi(() -> { System.out.println("Not doing anything here"); }); + } +} diff --git a/test/915-obsolete-2/src/Main.java b/test/915-obsolete-2/src/Main.java index fc73ee86fc..be51234c87 100644 --- a/test/915-obsolete-2/src/Main.java +++ b/test/915-obsolete-2/src/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,86 +14,8 @@ * limitations under the License. */ -import java.util.Base64; - public class Main { - // class Transform { - // private void Start() { - // System.out.println("Hello - private - Transformed"); - // } - // - // private void Finish() { - // System.out.println("Goodbye - private - Transformed"); - // } - // - // public void sayHi(Runnable r) { - // System.out.println("Pre Start private method call - Transformed"); - // Start(); - // System.out.println("Post Start private method call - Transformed"); - // r.run(); - // System.out.println("Pre Finish private method call - Transformed"); - // Finish(); - // System.out.println("Post Finish private method call - Transformed"); - // } - // } - private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( - "yv66vgAAADQAMgoADgAZCQAaABsIABwKAB0AHggAHwgAIAoADQAhCAAiCwAjACQIACUKAA0AJggA" + - "JwcAKAcAKQEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAAVTdGFydAEA" + - "BkZpbmlzaAEABXNheUhpAQAXKExqYXZhL2xhbmcvUnVubmFibGU7KVYBAApTb3VyY2VGaWxlAQAO" + - "VHJhbnNmb3JtLmphdmEMAA8AEAcAKgwAKwAsAQAdSGVsbG8gLSBwcml2YXRlIC0gVHJhbnNmb3Jt" + - "ZWQHAC0MAC4ALwEAH0dvb2RieWUgLSBwcml2YXRlIC0gVHJhbnNmb3JtZWQBACtQcmUgU3RhcnQg" + - "cHJpdmF0ZSBtZXRob2QgY2FsbCAtIFRyYW5zZm9ybWVkDAATABABACxQb3N0IFN0YXJ0IHByaXZh" + - "dGUgbWV0aG9kIGNhbGwgLSBUcmFuc2Zvcm1lZAcAMAwAMQAQAQAsUHJlIEZpbmlzaCBwcml2YXRl" + - "IG1ldGhvZCBjYWxsIC0gVHJhbnNmb3JtZWQMABQAEAEALVBvc3QgRmluaXNoIHByaXZhdGUgbWV0" + - "aG9kIGNhbGwgLSBUcmFuc2Zvcm1lZAEACVRyYW5zZm9ybQEAEGphdmEvbGFuZy9PYmplY3QBABBq" + - "YXZhL2xhbmcvU3lzdGVtAQADb3V0AQAVTGphdmEvaW8vUHJpbnRTdHJlYW07AQATamF2YS9pby9Q" + - "cmludFN0cmVhbQEAB3ByaW50bG4BABUoTGphdmEvbGFuZy9TdHJpbmc7KVYBABJqYXZhL2xhbmcv" + - "UnVubmFibGUBAANydW4AIAANAA4AAAAAAAQAAAAPABAAAQARAAAAHQABAAEAAAAFKrcAAbEAAAAB" + - "ABIAAAAGAAEAAAABAAIAEwAQAAEAEQAAACUAAgABAAAACbIAAhIDtgAEsQAAAAEAEgAAAAoAAgAA" + - "AAMACAAEAAIAFAAQAAEAEQAAACUAAgABAAAACbIAAhIFtgAEsQAAAAEAEgAAAAoAAgAAAAcACAAI" + - "AAEAFQAWAAEAEQAAAGMAAgACAAAAL7IAAhIGtgAEKrcAB7IAAhIItgAEK7kACQEAsgACEgq2AAQq" + - "twALsgACEgy2AASxAAAAAQASAAAAIgAIAAAACwAIAAwADAANABQADgAaAA8AIgAQACYAEQAuABIA" + - "AQAXAAAAAgAY"); - private static final byte[] DEX_BYTES = Base64.getDecoder().decode( - "ZGV4CjAzNQCM0QYTJmX+NsZXkImojgSkJtXyuew3oaXcBAAAcAAAAHhWNBIAAAAAAAAAADwEAAAX" + - "AAAAcAAAAAcAAADMAAAAAwAAAOgAAAABAAAADAEAAAcAAAAUAQAAAQAAAEwBAABwAwAAbAEAAD4C" + - "AABGAgAATgIAAG8CAACOAgAAmwIAALICAADGAgAA3AIAAPACAAAEAwAAMwMAAGEDAACPAwAAvAMA" + - "AMMDAADTAwAA1gMAANoDAADuAwAA8wMAAPwDAAABBAAABAAAAAUAAAAGAAAABwAAAAgAAAAJAAAA" + - "EAAAABAAAAAGAAAAAAAAABEAAAAGAAAAMAIAABEAAAAGAAAAOAIAAAUAAQATAAAAAAAAAAAAAAAA" + - "AAAAAQAAAAAAAAAOAAAAAAABABYAAAABAAIAFAAAAAIAAAAAAAAAAwAAABUAAAAAAAAAAAAAAAIA" + - "AAAAAAAADwAAAAAAAAAmBAAAAAAAAAEAAQABAAAACAQAAAQAAABwEAUAAAAOAAMAAQACAAAADQQA" + - "AAkAAABiAAAAGwECAAAAbiAEABAADgAAAAMAAQACAAAAEwQAAAkAAABiAAAAGwEDAAAAbiAEABAA" + - "DgAAAAQAAgACAAAAGQQAACoAAABiAAAAGwENAAAAbiAEABAAcBACAAIAYgAAABsBCwAAAG4gBAAQ" + - "AHIQBgADAGIAAAAbAQwAAABuIAQAEABwEAEAAgBiAAAAGwEKAAAAbiAEABAADgABAAAAAwAAAAEA" + - "AAAEAAY8aW5pdD4ABkZpbmlzaAAfR29vZGJ5ZSAtIHByaXZhdGUgLSBUcmFuc2Zvcm1lZAAdSGVs" + - "bG8gLSBwcml2YXRlIC0gVHJhbnNmb3JtZWQAC0xUcmFuc2Zvcm07ABVMamF2YS9pby9QcmludFN0" + - "cmVhbTsAEkxqYXZhL2xhbmcvT2JqZWN0OwAUTGphdmEvbGFuZy9SdW5uYWJsZTsAEkxqYXZhL2xh" + - "bmcvU3RyaW5nOwASTGphdmEvbGFuZy9TeXN0ZW07AC1Qb3N0IEZpbmlzaCBwcml2YXRlIG1ldGhv" + - "ZCBjYWxsIC0gVHJhbnNmb3JtZWQALFBvc3QgU3RhcnQgcHJpdmF0ZSBtZXRob2QgY2FsbCAtIFRy" + - "YW5zZm9ybWVkACxQcmUgRmluaXNoIHByaXZhdGUgbWV0aG9kIGNhbGwgLSBUcmFuc2Zvcm1lZAAr" + - "UHJlIFN0YXJ0IHByaXZhdGUgbWV0aG9kIGNhbGwgLSBUcmFuc2Zvcm1lZAAFU3RhcnQADlRyYW5z" + - "Zm9ybS5qYXZhAAFWAAJWTAASZW1pdHRlcjogamFjay00LjEzAANvdXQAB3ByaW50bG4AA3J1bgAF" + - "c2F5SGkAAQAHDgAHAAcOhwADAAcOhwALAQAHDoc8hzyHPIcAAAADAQCAgATsAgEChAMBAqgDAwHM" + - "Aw0AAAAAAAAAAQAAAAAAAAABAAAAFwAAAHAAAAACAAAABwAAAMwAAAADAAAAAwAAAOgAAAAEAAAA" + - "AQAAAAwBAAAFAAAABwAAABQBAAAGAAAAAQAAAEwBAAABIAAABAAAAGwBAAABEAAAAgAAADACAAAC" + - "IAAAFwAAAD4CAAADIAAABAAAAAgEAAAAIAAAAQAAACYEAAAAEAAAAQAAADwEAAA="); - - public static void main(String[] args) { - art.Main.bindAgentJNIForClass(Main.class); - doTest(new Transform()); + public static void main(String[] args) throws Exception { + art.Test915.run(); } - - public static void doTest(Transform t) { - t.sayHi(() -> { System.out.println("Not doing anything here"); }); - t.sayHi(() -> { - System.out.println("transforming calling function"); - doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES); - }); - t.sayHi(() -> { System.out.println("Not doing anything here"); }); - } - - // Transforms the class - private static native void doCommonClassRedefinition(Class<?> target, - byte[] classfile, - byte[] dexfile); } diff --git a/test/915-obsolete-2/src/art/Redefinition.java b/test/915-obsolete-2/src/art/Redefinition.java new file mode 100644 index 0000000000..0350ab42ad --- /dev/null +++ b/test/915-obsolete-2/src/art/Redefinition.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.util.ArrayList; +// Common Redefinition functions. Placed here for use by CTS +public class Redefinition { + // Bind native functions. + static { + Main.bindAgentJNIForClass(Redefinition.class); + } + + public static final class CommonClassDefinition { + public final Class<?> target; + public final byte[] class_file_bytes; + public final byte[] dex_file_bytes; + + public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { + this.target = target; + this.class_file_bytes = class_file_bytes; + this.dex_file_bytes = dex_file_bytes; + } + } + + // A set of possible test configurations. Test should set this if they need to. + // This must be kept in sync with the defines in ti-agent/common_helper.cc + public static enum Config { + COMMON_REDEFINE(0), + COMMON_RETRANSFORM(1), + COMMON_TRANSFORM(2); + + private final int val; + private Config(int val) { + this.val = val; + } + } + + public static void setTestConfiguration(Config type) { + nativeSetTestConfiguration(type.val); + } + + private static native void nativeSetTestConfiguration(int type); + + // Transforms the class + public static native void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile); + + public static void doMultiClassRedefinition(CommonClassDefinition... defs) { + ArrayList<Class<?>> classes = new ArrayList<>(); + ArrayList<byte[]> class_files = new ArrayList<>(); + ArrayList<byte[]> dex_files = new ArrayList<>(); + + for (CommonClassDefinition d : defs) { + classes.add(d.target); + class_files.add(d.class_file_bytes); + dex_files.add(d.dex_file_bytes); + } + doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), + class_files.toArray(new byte[0][]), + dex_files.toArray(new byte[0][])); + } + + public static void addMultiTransformationResults(CommonClassDefinition... defs) { + for (CommonClassDefinition d : defs) { + addCommonTransformationResult(d.target.getCanonicalName(), + d.class_file_bytes, + d.dex_file_bytes); + } + } + + public static native void doCommonMultiClassRedefinition(Class<?>[] targets, + byte[][] classfiles, + byte[][] dexfiles); + public static native void doCommonClassRetransformation(Class<?>... target); + public static native void setPopRetransformations(boolean pop); + public static native void popTransformationFor(String name); + public static native void enableCommonRetransformation(boolean enable); + public static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); +} diff --git a/test/915-obsolete-2/src/art/Test915.java b/test/915-obsolete-2/src/art/Test915.java new file mode 100644 index 0000000000..63c7f344dd --- /dev/null +++ b/test/915-obsolete-2/src/art/Test915.java @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * 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 art; + +import java.util.Base64; + +public class Test915 { + + static class Transform { + private void Start() { + System.out.println("hello - private"); + } + + private void Finish() { + System.out.println("goodbye - private"); + } + + public void sayHi(Runnable r) { + System.out.println("Pre Start private method call"); + Start(); + System.out.println("Post Start private method call"); + r.run(); + System.out.println("Pre Finish private method call"); + Finish(); + System.out.println("Post Finish private method call"); + } + } + + // static class Transform { + // private void Start() { + // System.out.println("Hello - private - Transformed"); + // } + // + // private void Finish() { + // System.out.println("Goodbye - private - Transformed"); + // } + // + // public void sayHi(Runnable r) { + // System.out.println("Pre Start private method call - Transformed"); + // Start(); + // System.out.println("Post Start private method call - Transformed"); + // r.run(); + // System.out.println("Pre Finish private method call - Transformed"); + // Finish(); + // System.out.println("Post Finish private method call - Transformed"); + // } + // } + private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( + "yv66vgAAADQANgoADgAZCQAaABsIABwKAB0AHggAHwgAIAoADQAhCAAiCwAjACQIACUKAA0AJggA" + + "JwcAKQcALAEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAAVTdGFydAEA" + + "BkZpbmlzaAEABXNheUhpAQAXKExqYXZhL2xhbmcvUnVubmFibGU7KVYBAApTb3VyY2VGaWxlAQAM" + + "VGVzdDkxNS5qYXZhDAAPABAHAC0MAC4ALwEAHUhlbGxvIC0gcHJpdmF0ZSAtIFRyYW5zZm9ybWVk" + + "BwAwDAAxADIBAB9Hb29kYnllIC0gcHJpdmF0ZSAtIFRyYW5zZm9ybWVkAQArUHJlIFN0YXJ0IHBy" + + "aXZhdGUgbWV0aG9kIGNhbGwgLSBUcmFuc2Zvcm1lZAwAEwAQAQAsUG9zdCBTdGFydCBwcml2YXRl" + + "IG1ldGhvZCBjYWxsIC0gVHJhbnNmb3JtZWQHADMMADQAEAEALFByZSBGaW5pc2ggcHJpdmF0ZSBt" + + "ZXRob2QgY2FsbCAtIFRyYW5zZm9ybWVkDAAUABABAC1Qb3N0IEZpbmlzaCBwcml2YXRlIG1ldGhv" + + "ZCBjYWxsIC0gVHJhbnNmb3JtZWQHADUBABVhcnQvVGVzdDkxNSRUcmFuc2Zvcm0BAAlUcmFuc2Zv" + + "cm0BAAxJbm5lckNsYXNzZXMBABBqYXZhL2xhbmcvT2JqZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEA" + + "A291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmlu" + + "dGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWAQASamF2YS9sYW5nL1J1bm5hYmxlAQADcnVuAQAL" + + "YXJ0L1Rlc3Q5MTUAIAANAA4AAAAAAAQAAAAPABAAAQARAAAAHQABAAEAAAAFKrcAAbEAAAABABIA" + + "AAAGAAEAAAAFAAIAEwAQAAEAEQAAACUAAgABAAAACbIAAhIDtgAEsQAAAAEAEgAAAAoAAgAAAAcA" + + "CAAIAAIAFAAQAAEAEQAAACUAAgABAAAACbIAAhIFtgAEsQAAAAEAEgAAAAoAAgAAAAoACAALAAEA" + + "FQAWAAEAEQAAAGMAAgACAAAAL7IAAhIGtgAEKrcAB7IAAhIItgAEK7kACQEAsgACEgq2AAQqtwAL" + + "sgACEgy2AASxAAAAAQASAAAAIgAIAAAADQAIAA4ADAAPABQAEAAaABEAIgASACYAEwAuABQAAgAX" + + "AAAAAgAYACsAAAAKAAEADQAoACoACA=="); + private static final byte[] DEX_BYTES = Base64.getDecoder().decode( + "ZGV4CjAzNQAQ+GYcAAAAAAAAAAAAAAAAAAAAAAAAAADUBQAAcAAAAHhWNBIAAAAAAAAAABAFAAAd" + + "AAAAcAAAAAoAAADkAAAAAwAAAAwBAAABAAAAMAEAAAcAAAA4AQAAAQAAAHABAABEBAAAkAEAAJAB" + + "AACYAQAAoAEAAMEBAADgAQAA+QEAAAgCAAAsAgAATAIAAGMCAAB3AgAAjQIAAKECAAC1AgAA5AIA" + + "ABIDAABAAwAAbQMAAHQDAACCAwAAjQMAAJADAACUAwAAoQMAAKcDAACsAwAAtQMAALoDAADBAwAA" + + "BAAAAAUAAAAGAAAABwAAAAgAAAAJAAAACgAAAAsAAAAMAAAAFAAAABQAAAAJAAAAAAAAABUAAAAJ" + + "AAAA0AMAABUAAAAJAAAAyAMAAAgABAAYAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAARAAAAAAABABsA" + + "AAAEAAIAGQAAAAUAAAAAAAAABgAAABoAAAAAAAAAAAAAAAUAAAAAAAAAEgAAAAAFAADMBAAAAAAA" + + "AAY8aW5pdD4ABkZpbmlzaAAfR29vZGJ5ZSAtIHByaXZhdGUgLSBUcmFuc2Zvcm1lZAAdSGVsbG8g" + + "LSBwcml2YXRlIC0gVHJhbnNmb3JtZWQAF0xhcnQvVGVzdDkxNSRUcmFuc2Zvcm07AA1MYXJ0L1Rl" + + "c3Q5MTU7ACJMZGFsdmlrL2Fubm90YXRpb24vRW5jbG9zaW5nQ2xhc3M7AB5MZGFsdmlrL2Fubm90" + + "YXRpb24vSW5uZXJDbGFzczsAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwASTGphdmEvbGFuZy9PYmpl" + + "Y3Q7ABRMamF2YS9sYW5nL1J1bm5hYmxlOwASTGphdmEvbGFuZy9TdHJpbmc7ABJMamF2YS9sYW5n" + + "L1N5c3RlbTsALVBvc3QgRmluaXNoIHByaXZhdGUgbWV0aG9kIGNhbGwgLSBUcmFuc2Zvcm1lZAAs" + + "UG9zdCBTdGFydCBwcml2YXRlIG1ldGhvZCBjYWxsIC0gVHJhbnNmb3JtZWQALFByZSBGaW5pc2gg" + + "cHJpdmF0ZSBtZXRob2QgY2FsbCAtIFRyYW5zZm9ybWVkACtQcmUgU3RhcnQgcHJpdmF0ZSBtZXRo" + + "b2QgY2FsbCAtIFRyYW5zZm9ybWVkAAVTdGFydAAMVGVzdDkxNS5qYXZhAAlUcmFuc2Zvcm0AAVYA" + + "AlZMAAthY2Nlc3NGbGFncwAEbmFtZQADb3V0AAdwcmludGxuAANydW4ABXNheUhpAAV2YWx1ZQAB" + + "AAAABwAAAAEAAAAGAAAABQAHDgAKAAcOAQgPAAcABw4BCA8ADQEABw4BCA8BAw8BCA8BAw8BCA8B" + + "Aw8BCA8AAQABAAEAAADYAwAABAAAAHAQBQAAAA4AAwABAAIAAADdAwAACQAAAGIAAAAbAQIAAABu" + + "IAQAEAAOAAAAAwABAAIAAADlAwAACQAAAGIAAAAbAQMAAABuIAQAEAAOAAAABAACAAIAAADtAwAA" + + "KgAAAGIAAAAbARAAAABuIAQAEABwEAIAAgBiAAAAGwEOAAAAbiAEABAAchAGAAMAYgAAABsBDwAA" + + "AG4gBAAQAHAQAQACAGIAAAAbAQ0AAABuIAQAEAAOAAAAAwEAgIAEiAgBAqAIAQLECAMB6AgAAAIC" + + "ARwYAQIDAhYECBcXEwACAAAA5AQAAOoEAAD0BAAAAAAAAAAAAAAAAAAAEAAAAAAAAAABAAAAAAAA" + + "AAEAAAAdAAAAcAAAAAIAAAAKAAAA5AAAAAMAAAADAAAADAEAAAQAAAABAAAAMAEAAAUAAAAHAAAA" + + "OAEAAAYAAAABAAAAcAEAAAIgAAAdAAAAkAEAAAEQAAACAAAAyAMAAAMgAAAEAAAA2AMAAAEgAAAE" + + "AAAACAQAAAAgAAABAAAAzAQAAAQgAAACAAAA5AQAAAMQAAABAAAA9AQAAAYgAAABAAAAAAUAAAAQ" + + "AAABAAAAEAUAAA=="); + + public static void run() { + Redefinition.setTestConfiguration(Redefinition.Config.COMMON_REDEFINE); + doTest(new Transform()); + } + + public static void doTest(Transform t) { + t.sayHi(() -> { System.out.println("Not doing anything here"); }); + t.sayHi(() -> { + System.out.println("transforming calling function"); + Redefinition.doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES); + }); + t.sayHi(() -> { System.out.println("Not doing anything here"); }); + } +} diff --git a/test/916-obsolete-jit/src/Main.java b/test/916-obsolete-jit/src/Main.java index 3453261f44..cb202e400d 100644 --- a/test/916-obsolete-jit/src/Main.java +++ b/test/916-obsolete-jit/src/Main.java @@ -14,6 +14,9 @@ * limitations under the License. */ + +import art.Redefinition; + import java.util.function.Consumer; import java.lang.reflect.Method; import java.util.Base64; @@ -144,7 +147,7 @@ public class Main { // Actually do the redefinition. The stack looks good. retry = false; w.accept("transforming calling function"); - doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES); + Redefinition.doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES); } }; // This just prints something out to show we are running the Runnable. @@ -168,9 +171,4 @@ public class Main { private static native boolean isInterpretedFunction(Method m, boolean require_deoptimizable); private static native void ensureJitCompiled(Class c, String name); - - // Transforms the class - private static native void doCommonClassRedefinition(Class<?> target, - byte[] classfile, - byte[] dexfile); } diff --git a/test/916-obsolete-jit/src/art/Redefinition.java b/test/916-obsolete-jit/src/art/Redefinition.java new file mode 100644 index 0000000000..0350ab42ad --- /dev/null +++ b/test/916-obsolete-jit/src/art/Redefinition.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.util.ArrayList; +// Common Redefinition functions. Placed here for use by CTS +public class Redefinition { + // Bind native functions. + static { + Main.bindAgentJNIForClass(Redefinition.class); + } + + public static final class CommonClassDefinition { + public final Class<?> target; + public final byte[] class_file_bytes; + public final byte[] dex_file_bytes; + + public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { + this.target = target; + this.class_file_bytes = class_file_bytes; + this.dex_file_bytes = dex_file_bytes; + } + } + + // A set of possible test configurations. Test should set this if they need to. + // This must be kept in sync with the defines in ti-agent/common_helper.cc + public static enum Config { + COMMON_REDEFINE(0), + COMMON_RETRANSFORM(1), + COMMON_TRANSFORM(2); + + private final int val; + private Config(int val) { + this.val = val; + } + } + + public static void setTestConfiguration(Config type) { + nativeSetTestConfiguration(type.val); + } + + private static native void nativeSetTestConfiguration(int type); + + // Transforms the class + public static native void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile); + + public static void doMultiClassRedefinition(CommonClassDefinition... defs) { + ArrayList<Class<?>> classes = new ArrayList<>(); + ArrayList<byte[]> class_files = new ArrayList<>(); + ArrayList<byte[]> dex_files = new ArrayList<>(); + + for (CommonClassDefinition d : defs) { + classes.add(d.target); + class_files.add(d.class_file_bytes); + dex_files.add(d.dex_file_bytes); + } + doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), + class_files.toArray(new byte[0][]), + dex_files.toArray(new byte[0][])); + } + + public static void addMultiTransformationResults(CommonClassDefinition... defs) { + for (CommonClassDefinition d : defs) { + addCommonTransformationResult(d.target.getCanonicalName(), + d.class_file_bytes, + d.dex_file_bytes); + } + } + + public static native void doCommonMultiClassRedefinition(Class<?>[] targets, + byte[][] classfiles, + byte[][] dexfiles); + public static native void doCommonClassRetransformation(Class<?>... target); + public static native void setPopRetransformations(boolean pop); + public static native void popTransformationFor(String name); + public static native void enableCommonRetransformation(boolean enable); + public static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); +} diff --git a/test/917-fields-transformation/src/Main.java b/test/917-fields-transformation/src/Main.java index 588af49cca..289b89f2f6 100644 --- a/test/917-fields-transformation/src/Main.java +++ b/test/917-fields-transformation/src/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,67 +14,8 @@ * limitations under the License. */ -import java.util.Base64; public class Main { - - // base64 encoded class/dex file for - // class Transform { - // public String take1; - // public String take2; - // - // public Transform(String a, String b) { - // take1 = a; - // take2 = b; - // } - // - // public String getResult() { - // return take2; - // } - // } - private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( - "yv66vgAAADQAFwoABQARCQAEABIJAAQAEwcAFAcAFQEABXRha2UxAQASTGphdmEvbGFuZy9TdHJp" + - "bmc7AQAFdGFrZTIBAAY8aW5pdD4BACcoTGphdmEvbGFuZy9TdHJpbmc7TGphdmEvbGFuZy9TdHJp" + - "bmc7KVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQAJZ2V0UmVzdWx0AQAUKClMamF2YS9sYW5n" + - "L1N0cmluZzsBAApTb3VyY2VGaWxlAQAOVHJhbnNmb3JtLmphdmEMAAkAFgwABgAHDAAIAAcBAAlU" + - "cmFuc2Zvcm0BABBqYXZhL2xhbmcvT2JqZWN0AQADKClWACAABAAFAAAAAgABAAYABwAAAAEACAAH" + - "AAAAAgABAAkACgABAAsAAAAzAAIAAwAAAA8qtwABKiu1AAIqLLUAA7EAAAABAAwAAAASAAQAAAAU" + - "AAQAFQAJABYADgAXAAEADQAOAAEACwAAAB0AAQABAAAABSq0AAOwAAAAAQAMAAAABgABAAAAGgAB" + - "AA8AAAACABA="); - private static final byte[] DEX_BYTES = Base64.getDecoder().decode( - "ZGV4CjAzNQAGUTBb4jIABRlaI9rejdk7RCfyqR2kmNSkAgAAcAAAAHhWNBIAAAAAAAAAAAQCAAAM" + - "AAAAcAAAAAQAAACgAAAAAwAAALAAAAACAAAA1AAAAAMAAADkAAAAAQAAAPwAAACIAQAAHAEAAFwB" + - "AABkAQAAZwEAAHQBAACIAQAAnAEAAKwBAACvAQAAtAEAAMgBAADTAQAA2gEAAAIAAAADAAAABAAA" + - "AAYAAAABAAAAAgAAAAAAAAAGAAAAAwAAAAAAAAAHAAAAAwAAAFQBAAAAAAIACgAAAAAAAgALAAAA" + - "AAACAAAAAAAAAAAACQAAAAEAAQAAAAAAAAAAAAAAAAABAAAAAAAAAAUAAAAAAAAA8AEAAAAAAAAD" + - "AAMAAQAAAOEBAAAIAAAAcBACAAAAWwEAAFsCAQAOAAIAAQAAAAAA6wEAAAMAAABUEAEAEQAAAAIA" + - "AAACAAIABjxpbml0PgABTAALTFRyYW5zZm9ybTsAEkxqYXZhL2xhbmcvT2JqZWN0OwASTGphdmEv" + - "bGFuZy9TdHJpbmc7AA5UcmFuc2Zvcm0uamF2YQABVgADVkxMABJlbWl0dGVyOiBqYWNrLTQuMTkA" + - "CWdldFJlc3VsdAAFdGFrZTEABXRha2UyABQCAAAHDjwtLQAaAAcOAAACAQEAAQEBAIGABJwCAQG8" + - "AgAADQAAAAAAAAABAAAAAAAAAAEAAAAMAAAAcAAAAAIAAAAEAAAAoAAAAAMAAAADAAAAsAAAAAQA" + - "AAACAAAA1AAAAAUAAAADAAAA5AAAAAYAAAABAAAA/AAAAAEgAAACAAAAHAEAAAEQAAABAAAAVAEA" + - "AAIgAAAMAAAAXAEAAAMgAAACAAAA4QEAAAAgAAABAAAA8AEAAAAQAAABAAAABAIAAA=="); - - public static void main(String[] args) { - art.Main.bindAgentJNIForClass(Main.class); - doTest(new Transform("Hello", "Goodbye"), - new Transform("start", "end")); - } - - private static void printTransform(Transform t) { - System.out.println("Result is " + t.getResult()); - System.out.println("take1 is " + t.take1); - System.out.println("take2 is " + t.take2); - } - public static void doTest(Transform t1, Transform t2) { - printTransform(t1); - printTransform(t2); - doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES); - printTransform(t1); - printTransform(t2); + public static void main(String[] args) throws Exception { + art.Test917.run(); } - - // Transforms the class - private static native void doCommonClassRedefinition(Class<?> target, - byte[] class_file, - byte[] dex_file); } diff --git a/test/917-fields-transformation/src/Transform.java b/test/917-fields-transformation/src/Transform.java deleted file mode 100644 index 6fe6223776..0000000000 --- a/test/917-fields-transformation/src/Transform.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * 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. - */ - -class Transform { - public String take1; - public String take2; - - public Transform(String take1, String take2) { - this.take1 = take1; - this.take2 = take2; - } - - public String getResult() { - return take1; - } -} diff --git a/test/917-fields-transformation/src/art/Redefinition.java b/test/917-fields-transformation/src/art/Redefinition.java new file mode 100644 index 0000000000..0350ab42ad --- /dev/null +++ b/test/917-fields-transformation/src/art/Redefinition.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.util.ArrayList; +// Common Redefinition functions. Placed here for use by CTS +public class Redefinition { + // Bind native functions. + static { + Main.bindAgentJNIForClass(Redefinition.class); + } + + public static final class CommonClassDefinition { + public final Class<?> target; + public final byte[] class_file_bytes; + public final byte[] dex_file_bytes; + + public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { + this.target = target; + this.class_file_bytes = class_file_bytes; + this.dex_file_bytes = dex_file_bytes; + } + } + + // A set of possible test configurations. Test should set this if they need to. + // This must be kept in sync with the defines in ti-agent/common_helper.cc + public static enum Config { + COMMON_REDEFINE(0), + COMMON_RETRANSFORM(1), + COMMON_TRANSFORM(2); + + private final int val; + private Config(int val) { + this.val = val; + } + } + + public static void setTestConfiguration(Config type) { + nativeSetTestConfiguration(type.val); + } + + private static native void nativeSetTestConfiguration(int type); + + // Transforms the class + public static native void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile); + + public static void doMultiClassRedefinition(CommonClassDefinition... defs) { + ArrayList<Class<?>> classes = new ArrayList<>(); + ArrayList<byte[]> class_files = new ArrayList<>(); + ArrayList<byte[]> dex_files = new ArrayList<>(); + + for (CommonClassDefinition d : defs) { + classes.add(d.target); + class_files.add(d.class_file_bytes); + dex_files.add(d.dex_file_bytes); + } + doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), + class_files.toArray(new byte[0][]), + dex_files.toArray(new byte[0][])); + } + + public static void addMultiTransformationResults(CommonClassDefinition... defs) { + for (CommonClassDefinition d : defs) { + addCommonTransformationResult(d.target.getCanonicalName(), + d.class_file_bytes, + d.dex_file_bytes); + } + } + + public static native void doCommonMultiClassRedefinition(Class<?>[] targets, + byte[][] classfiles, + byte[][] dexfiles); + public static native void doCommonClassRetransformation(Class<?>... target); + public static native void setPopRetransformations(boolean pop); + public static native void popTransformationFor(String name); + public static native void enableCommonRetransformation(boolean enable); + public static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); +} diff --git a/test/917-fields-transformation/src/art/Test917.java b/test/917-fields-transformation/src/art/Test917.java new file mode 100644 index 0000000000..245e92e200 --- /dev/null +++ b/test/917-fields-transformation/src/art/Test917.java @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * 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 art; + +import java.util.Base64; +public class Test917 { + + static class Transform { + public String take1; + public String take2; + + public Transform(String take1, String take2) { + this.take1 = take1; + this.take2 = take2; + } + + public String getResult() { + return take1; + } + } + + + // base64 encoded class/dex file for + // static class Transform { + // public String take1; + // public String take2; + // + // public Transform(String a, String b) { + // take1 = a; + // take2 = b; + // } + // + // public String getResult() { + // return take2; + // } + // } + private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( + "yv66vgAAADQAGwoABQARCQAEABIJAAQAEwcAFQcAGAEABXRha2UxAQASTGphdmEvbGFuZy9TdHJp" + + "bmc7AQAFdGFrZTIBAAY8aW5pdD4BACcoTGphdmEvbGFuZy9TdHJpbmc7TGphdmEvbGFuZy9TdHJp" + + "bmc7KVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQAJZ2V0UmVzdWx0AQAUKClMamF2YS9sYW5n" + + "L1N0cmluZzsBAApTb3VyY2VGaWxlAQAMVGVzdDkxNy5qYXZhDAAJABkMAAYABwwACAAHBwAaAQAV" + + "YXJ0L1Rlc3Q5MTckVHJhbnNmb3JtAQAJVHJhbnNmb3JtAQAMSW5uZXJDbGFzc2VzAQAQamF2YS9s" + + "YW5nL09iamVjdAEAAygpVgEAC2FydC9UZXN0OTE3ACAABAAFAAAAAgABAAYABwAAAAEACAAHAAAA" + + "AgABAAkACgABAAsAAAAzAAIAAwAAAA8qtwABKiu1AAIqLLUAA7EAAAABAAwAAAASAAQAAAAJAAQA" + + "CgAJAAsADgAMAAEADQAOAAEACwAAAB0AAQABAAAABSq0AAOwAAAAAQAMAAAABgABAAAADwACAA8A" + + "AAACABAAFwAAAAoAAQAEABQAFgAI"); + private static final byte[] DEX_BYTES = Base64.getDecoder().decode( + "ZGV4CjAzNQBdcPySAAAAAAAAAAAAAAAAAAAAAAAAAACQAwAAcAAAAHhWNBIAAAAAAAAAAMwCAAAS" + + "AAAAcAAAAAcAAAC4AAAAAwAAANQAAAACAAAA+AAAAAMAAAAIAQAAAQAAACABAABQAgAAQAEAAEAB" + + "AABIAQAASwEAAGQBAABzAQAAlwEAALcBAADLAQAA3wEAAO0BAAD4AQAA+wEAAAACAAANAgAAGAIA" + + "AB4CAAAlAgAALAIAAAIAAAADAAAABAAAAAUAAAAGAAAABwAAAAoAAAABAAAABQAAAAAAAAAKAAAA" + + "BgAAAAAAAAALAAAABgAAADQCAAAAAAUADwAAAAAABQAQAAAAAAACAAAAAAAAAAAADQAAAAQAAQAA" + + "AAAAAAAAAAAAAAAEAAAAAAAAAAgAAAC8AgAAjAIAAAAAAAAGPGluaXQ+AAFMABdMYXJ0L1Rlc3Q5" + + "MTckVHJhbnNmb3JtOwANTGFydC9UZXN0OTE3OwAiTGRhbHZpay9hbm5vdGF0aW9uL0VuY2xvc2lu" + + "Z0NsYXNzOwAeTGRhbHZpay9hbm5vdGF0aW9uL0lubmVyQ2xhc3M7ABJMamF2YS9sYW5nL09iamVj" + + "dDsAEkxqYXZhL2xhbmcvU3RyaW5nOwAMVGVzdDkxNy5qYXZhAAlUcmFuc2Zvcm0AAVYAA1ZMTAAL" + + "YWNjZXNzRmxhZ3MACWdldFJlc3VsdAAEbmFtZQAFdGFrZTEABXRha2UyAAV2YWx1ZQAAAgAAAAUA" + + "BQAJAgAABw4BAw8BAg8BAg8ADwAHDgAAAAADAAMAAQAAADwCAAAIAAAAcBACAAAAWwEAAFsCAQAO" + + "AAIAAQAAAAAATAIAAAMAAABUEAEAEQAAAAACAQEAAQEBAIGABNQEAQH0BAAAAgIBERgBAgMCDAQI" + + "DhcJAAIAAACgAgAApgIAALACAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAEAAAAAAAAAAQAAABIAAABw" + + "AAAAAgAAAAcAAAC4AAAAAwAAAAMAAADUAAAABAAAAAIAAAD4AAAABQAAAAMAAAAIAQAABgAAAAEA" + + "AAAgAQAAAiAAABIAAABAAQAAARAAAAEAAAA0AgAAAyAAAAIAAAA8AgAAASAAAAIAAABUAgAAACAA" + + "AAEAAACMAgAABCAAAAIAAACgAgAAAxAAAAEAAACwAgAABiAAAAEAAAC8AgAAABAAAAEAAADMAgAA"); + + public static void run() { + Redefinition.setTestConfiguration(Redefinition.Config.COMMON_REDEFINE); + doTest(new Transform("Hello", "Goodbye"), + new Transform("start", "end")); + } + + private static void printTransform(Transform t) { + System.out.println("Result is " + t.getResult()); + System.out.println("take1 is " + t.take1); + System.out.println("take2 is " + t.take2); + } + public static void doTest(Transform t1, Transform t2) { + printTransform(t1); + printTransform(t2); + Redefinition.doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES); + printTransform(t1); + printTransform(t2); + } +} diff --git a/test/919-obsolete-fields/src/Main.java b/test/919-obsolete-fields/src/Main.java index 34ee2a97f5..10eadb271e 100644 --- a/test/919-obsolete-fields/src/Main.java +++ b/test/919-obsolete-fields/src/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,135 +14,8 @@ * limitations under the License. */ -import java.util.function.Consumer; -import java.util.Base64; - public class Main { - - // What follows is the base64 encoded representation of the following class: - // - // import java.util.function.Consumer; - // - // class Transform { - // private Consumer<String> reporter; - // public Transform(Consumer<String> reporter) { - // this.reporter = reporter; - // } - // - // private void Start() { - // reporter.accept("Hello - private - Transformed"); - // } - // - // private void Finish() { - // reporter.accept("Goodbye - private - Transformed"); - // } - // - // public void sayHi(Runnable r) { - // reporter.accept("pre Start private method call - Transformed"); - // Start(); - // reporter.accept("post Start private method call - Transformed"); - // r.run(); - // reporter.accept("pre Finish private method call - Transformed"); - // Finish(); - // reporter.accept("post Finish private method call - Transformed"); - // } - // } - private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( - "yv66vgAAADQANAoADgAfCQANACAIACELACIAIwgAJAgAJQoADQAmCAAnCwAoACkIACoKAA0AKwgA" + - "LAcALQcALgEACHJlcG9ydGVyAQAdTGphdmEvdXRpbC9mdW5jdGlvbi9Db25zdW1lcjsBAAlTaWdu" + - "YXR1cmUBADFMamF2YS91dGlsL2Z1bmN0aW9uL0NvbnN1bWVyPExqYXZhL2xhbmcvU3RyaW5nOz47" + - "AQAGPGluaXQ+AQAgKExqYXZhL3V0aWwvZnVuY3Rpb24vQ29uc3VtZXI7KVYBAARDb2RlAQAPTGlu" + - "ZU51bWJlclRhYmxlAQA0KExqYXZhL3V0aWwvZnVuY3Rpb24vQ29uc3VtZXI8TGphdmEvbGFuZy9T" + - "dHJpbmc7PjspVgEABVN0YXJ0AQADKClWAQAGRmluaXNoAQAFc2F5SGkBABcoTGphdmEvbGFuZy9S" + - "dW5uYWJsZTspVgEAClNvdXJjZUZpbGUBAA5UcmFuc2Zvcm0uamF2YQwAEwAZDAAPABABAB1IZWxs" + - "byAtIHByaXZhdGUgLSBUcmFuc2Zvcm1lZAcALwwAMAAxAQAfR29vZGJ5ZSAtIHByaXZhdGUgLSBU" + - "cmFuc2Zvcm1lZAEAK3ByZSBTdGFydCBwcml2YXRlIG1ldGhvZCBjYWxsIC0gVHJhbnNmb3JtZWQM" + - "ABgAGQEALHBvc3QgU3RhcnQgcHJpdmF0ZSBtZXRob2QgY2FsbCAtIFRyYW5zZm9ybWVkBwAyDAAz" + - "ABkBACxwcmUgRmluaXNoIHByaXZhdGUgbWV0aG9kIGNhbGwgLSBUcmFuc2Zvcm1lZAwAGgAZAQAt" + - "cG9zdCBGaW5pc2ggcHJpdmF0ZSBtZXRob2QgY2FsbCAtIFRyYW5zZm9ybWVkAQAJVHJhbnNmb3Jt" + - "AQAQamF2YS9sYW5nL09iamVjdAEAG2phdmEvdXRpbC9mdW5jdGlvbi9Db25zdW1lcgEABmFjY2Vw" + - "dAEAFShMamF2YS9sYW5nL09iamVjdDspVgEAEmphdmEvbGFuZy9SdW5uYWJsZQEAA3J1bgAgAA0A" + - "DgAAAAEAAgAPABAAAQARAAAAAgASAAQAAQATABQAAgAVAAAAKgACAAIAAAAKKrcAASortQACsQAA" + - "AAEAFgAAAA4AAwAAABUABAAWAAkAFwARAAAAAgAXAAIAGAAZAAEAFQAAACgAAgABAAAADCq0AAIS" + - "A7kABAIAsQAAAAEAFgAAAAoAAgAAABoACwAbAAIAGgAZAAEAFQAAACgAAgABAAAADCq0AAISBbkA" + - "BAIAsQAAAAEAFgAAAAoAAgAAAB4ACwAfAAEAGwAcAAEAFQAAAG8AAgACAAAAOyq0AAISBrkABAIA" + - "KrcAByq0AAISCLkABAIAK7kACQEAKrQAAhIKuQAEAgAqtwALKrQAAhIMuQAEAgCxAAAAAQAWAAAA" + - "IgAIAAAAIgALACMADwAkABoAJQAgACYAKwAnAC8AKAA6ACkAAQAdAAAAAgAe"); - private static final byte[] DEX_BYTES = Base64.getDecoder().decode( - "ZGV4CjAzNQAw/b59wCwTlSVDmuhPEezuK3oe0rtT4ujMBQAAcAAAAHhWNBIAAAAAAAAAAAgFAAAd" + - "AAAAcAAAAAYAAADkAAAABAAAAPwAAAABAAAALAEAAAcAAAA0AQAAAQAAAGwBAABABAAAjAEAAJoC" + - "AACdAgAAoAIAAKgCAACsAgAAsgIAALoCAADbAgAA+gIAAAcDAAAmAwAAOgMAAFADAABkAwAAggMA" + - "AKEDAACoAwAAuAMAALsDAAC/AwAAxwMAANsDAAAKBAAAOAQAAGYEAACTBAAAnQQAAKIEAACpBAAA" + - "CAAAAAkAAAAKAAAACwAAAA4AAAARAAAAEQAAAAUAAAAAAAAAEgAAAAUAAACEAgAAEgAAAAUAAACM" + - "AgAAEgAAAAUAAACUAgAAAAAEABkAAAAAAAMAAgAAAAAAAAAFAAAAAAAAAA8AAAAAAAIAGwAAAAIA" + - "AAACAAAAAwAAABoAAAAEAAEAEwAAAAAAAAAAAAAAAgAAAAAAAAAQAAAAZAIAAO8EAAAAAAAAAQAA" + - "ANEEAAABAAAA3wQAAAIAAgABAAAAsAQAAAYAAABwEAQAAABbAQAADgADAAEAAgAAALgEAAAJAAAA" + - "VCAAABsBBgAAAHIgBgAQAA4AAAADAAEAAgAAAL4EAAAJAAAAVCAAABsBBwAAAHIgBgAQAA4AAAAE" + - "AAIAAgAAAMQEAAAqAAAAVCAAABsBGAAAAHIgBgAQAHAQAgACAFQgAAAbARYAAAByIAYAEAByEAUA" + - "AwBUIAAAGwEXAAAAciAGABAAcBABAAIAVCAAABsBFQAAAHIgBgAQAA4AAAAAAAEAAAABAAAAAAAA" + - "AAAAAACMAQAAAAAAAJQBAAABAAAAAgAAAAEAAAADAAAAAQAAAAQAASgAATwABjxpbml0PgACPjsA" + - "BD47KVYABkZpbmlzaAAfR29vZGJ5ZSAtIHByaXZhdGUgLSBUcmFuc2Zvcm1lZAAdSGVsbG8gLSBw" + - "cml2YXRlIC0gVHJhbnNmb3JtZWQAC0xUcmFuc2Zvcm07AB1MZGFsdmlrL2Fubm90YXRpb24vU2ln" + - "bmF0dXJlOwASTGphdmEvbGFuZy9PYmplY3Q7ABRMamF2YS9sYW5nL1J1bm5hYmxlOwASTGphdmEv" + - "bGFuZy9TdHJpbmc7ABxMamF2YS91dGlsL2Z1bmN0aW9uL0NvbnN1bWVyAB1MamF2YS91dGlsL2Z1" + - "bmN0aW9uL0NvbnN1bWVyOwAFU3RhcnQADlRyYW5zZm9ybS5qYXZhAAFWAAJWTAAGYWNjZXB0ABJl" + - "bWl0dGVyOiBqYWNrLTQuMTkALXBvc3QgRmluaXNoIHByaXZhdGUgbWV0aG9kIGNhbGwgLSBUcmFu" + - "c2Zvcm1lZAAscG9zdCBTdGFydCBwcml2YXRlIG1ldGhvZCBjYWxsIC0gVHJhbnNmb3JtZWQALHBy" + - "ZSBGaW5pc2ggcHJpdmF0ZSBtZXRob2QgY2FsbCAtIFRyYW5zZm9ybWVkACtwcmUgU3RhcnQgcHJp" + - "dmF0ZSBtZXRob2QgY2FsbCAtIFRyYW5zZm9ybWVkAAhyZXBvcnRlcgADcnVuAAVzYXlIaQAFdmFs" + - "dWUAFQEABw48LQAeAAcOhwAaAAcOhwAiAQAHDoc8hzyHPIcAAgEBHBwEFw0XARcMFwMCAQEcHAUX" + - "ABcNFwEXDBcEAAEDAQACAIGABJwDAQK4AwEC3AMDAYAEABAAAAAAAAAAAQAAAAAAAAABAAAAHQAA" + - "AHAAAAACAAAABgAAAOQAAAADAAAABAAAAPwAAAAEAAAAAQAAACwBAAAFAAAABwAAADQBAAAGAAAA" + - "AQAAAGwBAAADEAAAAgAAAIwBAAABIAAABAAAAJwBAAAGIAAAAQAAAGQCAAABEAAAAwAAAIQCAAAC" + - "IAAAHQAAAJoCAAADIAAABAAAALAEAAAEIAAAAgAAANEEAAAAIAAAAQAAAO8EAAAAEAAAAQAAAAgF" + - "AAA="); - - // A class that we can use to keep track of the output of this test. - private static class TestWatcher implements Consumer<String> { - private StringBuilder sb; - public TestWatcher() { - sb = new StringBuilder(); - } - - @Override - public void accept(String s) { - sb.append(s); - sb.append('\n'); - } - - public String getOutput() { - return sb.toString(); - } - } - - public static void main(String[] args) { - art.Main.bindAgentJNIForClass(Main.class); - TestWatcher w = new TestWatcher(); - doTest(new Transform(w), w); + public static void main(String[] args) throws Exception { + art.Test919.run(); } - - private static boolean interpreting = true; - private static boolean retry = false; - - public static void doTest(Transform t, TestWatcher w) { - Runnable do_redefinition = () -> { - w.accept("transforming calling function"); - doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES); - }; - // This just prints something out to show we are running the Runnable. - Runnable say_nothing = () -> { w.accept("Not doing anything here"); }; - - // Try and redefine. - t.sayHi(say_nothing); - t.sayHi(do_redefinition); - t.sayHi(say_nothing); - - // Print output of last run. - System.out.print(w.getOutput()); - } - - // Transforms the class - private static native void doCommonClassRedefinition(Class<?> target, - byte[] classfile, - byte[] dexfile); } diff --git a/test/919-obsolete-fields/src/Transform.java b/test/919-obsolete-fields/src/Transform.java deleted file mode 100644 index c8e3cbd934..0000000000 --- a/test/919-obsolete-fields/src/Transform.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * 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. - */ - -import java.util.function.Consumer; - -class Transform { - private Consumer<String> reporter; - public Transform(Consumer<String> reporter) { - this.reporter = reporter; - } - - private void Start() { - reporter.accept("hello - private"); - } - - private void Finish() { - reporter.accept("goodbye - private"); - } - - public void sayHi(Runnable r) { - reporter.accept("Pre Start private method call"); - Start(); - reporter.accept("Post Start private method call"); - r.run(); - reporter.accept("Pre Finish private method call"); - Finish(); - reporter.accept("Post Finish private method call"); - } -} diff --git a/test/919-obsolete-fields/src/art/Redefinition.java b/test/919-obsolete-fields/src/art/Redefinition.java new file mode 100644 index 0000000000..0350ab42ad --- /dev/null +++ b/test/919-obsolete-fields/src/art/Redefinition.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.util.ArrayList; +// Common Redefinition functions. Placed here for use by CTS +public class Redefinition { + // Bind native functions. + static { + Main.bindAgentJNIForClass(Redefinition.class); + } + + public static final class CommonClassDefinition { + public final Class<?> target; + public final byte[] class_file_bytes; + public final byte[] dex_file_bytes; + + public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { + this.target = target; + this.class_file_bytes = class_file_bytes; + this.dex_file_bytes = dex_file_bytes; + } + } + + // A set of possible test configurations. Test should set this if they need to. + // This must be kept in sync with the defines in ti-agent/common_helper.cc + public static enum Config { + COMMON_REDEFINE(0), + COMMON_RETRANSFORM(1), + COMMON_TRANSFORM(2); + + private final int val; + private Config(int val) { + this.val = val; + } + } + + public static void setTestConfiguration(Config type) { + nativeSetTestConfiguration(type.val); + } + + private static native void nativeSetTestConfiguration(int type); + + // Transforms the class + public static native void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile); + + public static void doMultiClassRedefinition(CommonClassDefinition... defs) { + ArrayList<Class<?>> classes = new ArrayList<>(); + ArrayList<byte[]> class_files = new ArrayList<>(); + ArrayList<byte[]> dex_files = new ArrayList<>(); + + for (CommonClassDefinition d : defs) { + classes.add(d.target); + class_files.add(d.class_file_bytes); + dex_files.add(d.dex_file_bytes); + } + doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), + class_files.toArray(new byte[0][]), + dex_files.toArray(new byte[0][])); + } + + public static void addMultiTransformationResults(CommonClassDefinition... defs) { + for (CommonClassDefinition d : defs) { + addCommonTransformationResult(d.target.getCanonicalName(), + d.class_file_bytes, + d.dex_file_bytes); + } + } + + public static native void doCommonMultiClassRedefinition(Class<?>[] targets, + byte[][] classfiles, + byte[][] dexfiles); + public static native void doCommonClassRetransformation(Class<?>... target); + public static native void setPopRetransformations(boolean pop); + public static native void popTransformationFor(String name); + public static native void enableCommonRetransformation(boolean enable); + public static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); +} diff --git a/test/919-obsolete-fields/src/art/Test919.java b/test/919-obsolete-fields/src/art/Test919.java new file mode 100644 index 0000000000..11971ef2e8 --- /dev/null +++ b/test/919-obsolete-fields/src/art/Test919.java @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * 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 art; + +import java.util.function.Consumer; +import java.util.Base64; + +public class Test919 { + + static class Transform { + private Consumer<String> reporter; + public Transform(Consumer<String> reporter) { + this.reporter = reporter; + } + + private void Start() { + reporter.accept("hello - private"); + } + + private void Finish() { + reporter.accept("goodbye - private"); + } + + public void sayHi(Runnable r) { + reporter.accept("Pre Start private method call"); + Start(); + reporter.accept("Post Start private method call"); + r.run(); + reporter.accept("Pre Finish private method call"); + Finish(); + reporter.accept("Post Finish private method call"); + } + } + + + // What follows is the base64 encoded representation of the following class: + // + // import java.util.function.Consumer; + // + // static class Transform { + // private Consumer<String> reporter; + // public Transform(Consumer<String> reporter) { + // this.reporter = reporter; + // } + // + // private void Start() { + // reporter.accept("Hello - private - Transformed"); + // } + // + // private void Finish() { + // reporter.accept("Goodbye - private - Transformed"); + // } + // + // public void sayHi(Runnable r) { + // reporter.accept("pre Start private method call - Transformed"); + // Start(); + // reporter.accept("post Start private method call - Transformed"); + // r.run(); + // reporter.accept("pre Finish private method call - Transformed"); + // Finish(); + // reporter.accept("post Finish private method call - Transformed"); + // } + // } + private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( + "yv66vgAAADQAOAoADgAfCQANACAIACELACIAIwgAJAgAJQoADQAmCAAnCwAoACkIACoKAA0AKwgA" + + "LAcALgcAMQEACHJlcG9ydGVyAQAdTGphdmEvdXRpbC9mdW5jdGlvbi9Db25zdW1lcjsBAAlTaWdu" + + "YXR1cmUBADFMamF2YS91dGlsL2Z1bmN0aW9uL0NvbnN1bWVyPExqYXZhL2xhbmcvU3RyaW5nOz47" + + "AQAGPGluaXQ+AQAgKExqYXZhL3V0aWwvZnVuY3Rpb24vQ29uc3VtZXI7KVYBAARDb2RlAQAPTGlu" + + "ZU51bWJlclRhYmxlAQA0KExqYXZhL3V0aWwvZnVuY3Rpb24vQ29uc3VtZXI8TGphdmEvbGFuZy9T" + + "dHJpbmc7PjspVgEABVN0YXJ0AQADKClWAQAGRmluaXNoAQAFc2F5SGkBABcoTGphdmEvbGFuZy9S" + + "dW5uYWJsZTspVgEAClNvdXJjZUZpbGUBAAxUZXN0OTE5LmphdmEMABMAGQwADwAQAQAdSGVsbG8g" + + "LSBwcml2YXRlIC0gVHJhbnNmb3JtZWQHADIMADMANAEAH0dvb2RieWUgLSBwcml2YXRlIC0gVHJh" + + "bnNmb3JtZWQBACtwcmUgU3RhcnQgcHJpdmF0ZSBtZXRob2QgY2FsbCAtIFRyYW5zZm9ybWVkDAAY" + + "ABkBACxwb3N0IFN0YXJ0IHByaXZhdGUgbWV0aG9kIGNhbGwgLSBUcmFuc2Zvcm1lZAcANQwANgAZ" + + "AQAscHJlIEZpbmlzaCBwcml2YXRlIG1ldGhvZCBjYWxsIC0gVHJhbnNmb3JtZWQMABoAGQEALXBv" + + "c3QgRmluaXNoIHByaXZhdGUgbWV0aG9kIGNhbGwgLSBUcmFuc2Zvcm1lZAcANwEAFWFydC9UZXN0" + + "OTE5JFRyYW5zZm9ybQEACVRyYW5zZm9ybQEADElubmVyQ2xhc3NlcwEAEGphdmEvbGFuZy9PYmpl" + + "Y3QBABtqYXZhL3V0aWwvZnVuY3Rpb24vQ29uc3VtZXIBAAZhY2NlcHQBABUoTGphdmEvbGFuZy9P" + + "YmplY3Q7KVYBABJqYXZhL2xhbmcvUnVubmFibGUBAANydW4BAAthcnQvVGVzdDkxOQAgAA0ADgAA" + + "AAEAAgAPABAAAQARAAAAAgASAAQAAQATABQAAgAVAAAAKgACAAIAAAAKKrcAASortQACsQAAAAEA" + + "FgAAAA4AAwAAAAgABAAJAAkACgARAAAAAgAXAAIAGAAZAAEAFQAAACgAAgABAAAADCq0AAISA7kA" + + "BAIAsQAAAAEAFgAAAAoAAgAAAA0ACwAOAAIAGgAZAAEAFQAAACgAAgABAAAADCq0AAISBbkABAIA" + + "sQAAAAEAFgAAAAoAAgAAABEACwASAAEAGwAcAAEAFQAAAG8AAgACAAAAOyq0AAISBrkABAIAKrcA" + + "Byq0AAISCLkABAIAK7kACQEAKrQAAhIKuQAEAgAqtwALKrQAAhIMuQAEAgCxAAAAAQAWAAAAIgAI" + + "AAAAFQALABYADwAXABoAGAAgABkAKwAaAC8AGwA6ABwAAgAdAAAAAgAeADAAAAAKAAEADQAtAC8A" + + "CA=="); + private static final byte[] DEX_BYTES = Base64.getDecoder().decode( + "ZGV4CjAzNQBeEZYBAAAAAAAAAAAAAAAAAAAAAAAAAACMBgAAcAAAAHhWNBIAAAAAAAAAAMgFAAAi" + + "AAAAcAAAAAkAAAD4AAAABAAAABwBAAABAAAATAEAAAcAAABUAQAAAQAAAIwBAADgBAAArAEAAKwB" + + "AACvAQAAsgEAALoBAAC+AQAAxAEAAMwBAADtAQAADAIAACUCAAA0AgAAWAIAAHgCAACXAgAAqwIA" + + "AMECAADVAgAA8wIAABIDAAAZAwAAJwMAADIDAAA1AwAAOQMAAEEDAABOAwAAVAMAAIMDAACxAwAA" + + "3wMAAAwEAAAWBAAAGwQAACIEAAAIAAAACQAAAAoAAAALAAAADAAAAA0AAAAOAAAAEQAAABUAAAAV" + + "AAAACAAAAAAAAAAWAAAACAAAADQEAAAWAAAACAAAADwEAAAWAAAACAAAACwEAAAAAAcAHgAAAAAA" + + "AwACAAAAAAAAAAUAAAAAAAAAEgAAAAAAAgAgAAAABQAAAAIAAAAGAAAAHwAAAAcAAQAXAAAAAAAA" + + "AAAAAAAFAAAAAAAAABMAAACoBQAARAUAAAAAAAABKAABPAAGPGluaXQ+AAI+OwAEPjspVgAGRmlu" + + "aXNoAB9Hb29kYnllIC0gcHJpdmF0ZSAtIFRyYW5zZm9ybWVkAB1IZWxsbyAtIHByaXZhdGUgLSBU" + + "cmFuc2Zvcm1lZAAXTGFydC9UZXN0OTE5JFRyYW5zZm9ybTsADUxhcnQvVGVzdDkxOTsAIkxkYWx2" + + "aWsvYW5ub3RhdGlvbi9FbmNsb3NpbmdDbGFzczsAHkxkYWx2aWsvYW5ub3RhdGlvbi9Jbm5lckNs" + + "YXNzOwAdTGRhbHZpay9hbm5vdGF0aW9uL1NpZ25hdHVyZTsAEkxqYXZhL2xhbmcvT2JqZWN0OwAU" + + "TGphdmEvbGFuZy9SdW5uYWJsZTsAEkxqYXZhL2xhbmcvU3RyaW5nOwAcTGphdmEvdXRpbC9mdW5j" + + "dGlvbi9Db25zdW1lcgAdTGphdmEvdXRpbC9mdW5jdGlvbi9Db25zdW1lcjsABVN0YXJ0AAxUZXN0" + + "OTE5LmphdmEACVRyYW5zZm9ybQABVgACVkwABmFjY2VwdAALYWNjZXNzRmxhZ3MABG5hbWUALXBv" + + "c3QgRmluaXNoIHByaXZhdGUgbWV0aG9kIGNhbGwgLSBUcmFuc2Zvcm1lZAAscG9zdCBTdGFydCBw" + + "cml2YXRlIG1ldGhvZCBjYWxsIC0gVHJhbnNmb3JtZWQALHByZSBGaW5pc2ggcHJpdmF0ZSBtZXRo" + + "b2QgY2FsbCAtIFRyYW5zZm9ybWVkACtwcmUgU3RhcnQgcHJpdmF0ZSBtZXRob2QgY2FsbCAtIFRy" + + "YW5zZm9ybWVkAAhyZXBvcnRlcgADcnVuAAVzYXlIaQAFdmFsdWUAAAAAAQAAAAcAAAABAAAABQAA" + + "AAEAAAAGAAAACAEABw4BAw8BAg8AEQAHDgEIDwANAAcOAQgPABUBAAcOAQgPAQMPAQgPAQMPAQgP" + + "AQMPAQgPAAACAAIAAQAAAEQEAAAGAAAAcBAEAAAAWwEAAA4AAwABAAIAAABQBAAACQAAAFQgAAAb" + + "AQYAAAByIAYAEAAOAAAAAwABAAIAAABYBAAACQAAAFQgAAAbAQcAAAByIAYAEAAOAAAABAACAAIA" + + "AABgBAAAKgAAAFQgAAAbAR0AAAByIAYAEABwEAIAAgBUIAAAGwEbAAAAciAGABAAchAFAAMAVCAA" + + "ABsBHAAAAHIgBgAQAHAQAQACAFQgAAAbARoAAAByIAYAEAAOAAABAwEAAgCBgAT8CAECmAkBArwJ" + + "AwHgCQICASEYAQIDAhgECBkXFAIEASEcBBcQFwEXDxcDAgQBIRwFFwAXEBcBFw8XBAAAAAIAAABc" + + "BQAAYgUAAAEAAABrBQAAAQAAAHkFAACMBQAAAQAAAAEAAAAAAAAAAAAAAJgFAAAAAAAAoAUAABAA" + + "AAAAAAAAAQAAAAAAAAABAAAAIgAAAHAAAAACAAAACQAAAPgAAAADAAAABAAAABwBAAAEAAAAAQAA" + + "AEwBAAAFAAAABwAAAFQBAAAGAAAAAQAAAIwBAAACIAAAIgAAAKwBAAABEAAAAwAAACwEAAADIAAA" + + "BAAAAEQEAAABIAAABAAAAHwEAAAAIAAAAQAAAEQFAAAEIAAABAAAAFwFAAADEAAAAwAAAIwFAAAG" + + "IAAAAQAAAKgFAAAAEAAAAQAAAMgFAAA="); + + // A class that we can use to keep track of the output of this test. + private static class TestWatcher implements Consumer<String> { + private StringBuilder sb; + public TestWatcher() { + sb = new StringBuilder(); + } + + @Override + public void accept(String s) { + sb.append(s); + sb.append('\n'); + } + + public String getOutput() { + return sb.toString(); + } + } + + public static void run() { + Redefinition.setTestConfiguration(Redefinition.Config.COMMON_REDEFINE); + TestWatcher w = new TestWatcher(); + doTest(new Transform(w), w); + } + + public static void doTest(Transform t, TestWatcher w) { + Runnable do_redefinition = () -> { + w.accept("transforming calling function"); + Redefinition.doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES); + }; + // This just prints something out to show we are running the Runnable. + Runnable say_nothing = () -> { w.accept("Not doing anything here"); }; + + // Try and redefine. + t.sayHi(say_nothing); + t.sayHi(do_redefinition); + t.sayHi(say_nothing); + + // Print output of last run. + System.out.print(w.getOutput()); + } +} diff --git a/test/921-hello-failure/src/Main.java b/test/921-hello-failure/src/Main.java index d9a49489f0..cfdcdc250f 100644 --- a/test/921-hello-failure/src/Main.java +++ b/test/921-hello-failure/src/Main.java @@ -14,12 +14,12 @@ * limitations under the License. */ -import java.util.ArrayList; +import art.Redefinition; +import java.util.Arrays; + public class Main { public static void main(String[] args) { - art.Main.bindAgentJNIForClass(Main.class); - Verification.doTest(new Transform()); NewName.doTest(new Transform()); DifferentAccess.doTest(new Transform()); @@ -37,40 +37,40 @@ public class Main { Unmodifiable.doTest(new Transform[] { new Transform(), }); } - // Transforms the class. This throws an exception if something goes wrong. - public static native void doCommonClassRedefinition(Class<?> target, - byte[] classfile, - byte[] dexfile) throws Exception; - - public static void doMultiClassRedefinition(CommonClassDefinition... defs) throws Exception { - ArrayList<Class<?>> classes = new ArrayList<>(); - ArrayList<byte[]> class_files = new ArrayList<>(); - ArrayList<byte[]> dex_files = new ArrayList<>(); + // TODO Replace this shim with a better re-write of this test. + private static Redefinition.CommonClassDefinition mapCCD(CommonClassDefinition d) { + return new Redefinition.CommonClassDefinition(d.target, d.class_file_bytes, d.dex_file_bytes); + } - for (CommonClassDefinition d : defs) { - classes.add(d.target); - class_files.add(d.class_file_bytes); - dex_files.add(d.dex_file_bytes); - } - doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), - class_files.toArray(new byte[0][]), - dex_files.toArray(new byte[0][])); + private static Redefinition.CommonClassDefinition[] toCCDA(CommonClassDefinition[] ds) { + return Arrays.stream(ds).map(Main::mapCCD).toArray(Redefinition.CommonClassDefinition[]::new); } + public static void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile) throws Exception { + Redefinition.doCommonClassRedefinition(target, classfile, dexfile); + } + public static void doMultiClassRedefinition(CommonClassDefinition... defs) throws Exception { + Redefinition.doMultiClassRedefinition(toCCDA(defs)); + } public static void addMultiTransformationResults(CommonClassDefinition... defs) throws Exception { - for (CommonClassDefinition d : defs) { - addCommonTransformationResult(d.target.getCanonicalName(), - d.class_file_bytes, - d.dex_file_bytes); - } + Redefinition.addMultiTransformationResults(toCCDA(defs)); + } + public static void doCommonMultiClassRedefinition(Class<?>[] targets, + byte[][] classfiles, + byte[][] dexfiles) throws Exception { + Redefinition.doCommonMultiClassRedefinition(targets, classfiles, dexfiles); + } + public static void doCommonClassRetransformation(Class<?>... target) throws Exception { + Redefinition.doCommonClassRetransformation(target); + } + public static void enableCommonRetransformation(boolean enable) { + Redefinition.enableCommonRetransformation(enable); + } + public static void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes) { + Redefinition.addCommonTransformationResult(target_name, class_bytes, dex_bytes); } - - public static native void doCommonMultiClassRedefinition(Class<?>[] targets, - byte[][] classfiles, - byte[][] dexfiles) throws Exception; - public static native void doCommonClassRetransformation(Class<?>... target) throws Exception; - public static native void enableCommonRetransformation(boolean enable); - public static native void addCommonTransformationResult(String target_name, - byte[] class_bytes, - byte[] dex_bytes); } diff --git a/test/921-hello-failure/src/art/Redefinition.java b/test/921-hello-failure/src/art/Redefinition.java new file mode 100644 index 0000000000..0350ab42ad --- /dev/null +++ b/test/921-hello-failure/src/art/Redefinition.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.util.ArrayList; +// Common Redefinition functions. Placed here for use by CTS +public class Redefinition { + // Bind native functions. + static { + Main.bindAgentJNIForClass(Redefinition.class); + } + + public static final class CommonClassDefinition { + public final Class<?> target; + public final byte[] class_file_bytes; + public final byte[] dex_file_bytes; + + public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { + this.target = target; + this.class_file_bytes = class_file_bytes; + this.dex_file_bytes = dex_file_bytes; + } + } + + // A set of possible test configurations. Test should set this if they need to. + // This must be kept in sync with the defines in ti-agent/common_helper.cc + public static enum Config { + COMMON_REDEFINE(0), + COMMON_RETRANSFORM(1), + COMMON_TRANSFORM(2); + + private final int val; + private Config(int val) { + this.val = val; + } + } + + public static void setTestConfiguration(Config type) { + nativeSetTestConfiguration(type.val); + } + + private static native void nativeSetTestConfiguration(int type); + + // Transforms the class + public static native void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile); + + public static void doMultiClassRedefinition(CommonClassDefinition... defs) { + ArrayList<Class<?>> classes = new ArrayList<>(); + ArrayList<byte[]> class_files = new ArrayList<>(); + ArrayList<byte[]> dex_files = new ArrayList<>(); + + for (CommonClassDefinition d : defs) { + classes.add(d.target); + class_files.add(d.class_file_bytes); + dex_files.add(d.dex_file_bytes); + } + doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), + class_files.toArray(new byte[0][]), + dex_files.toArray(new byte[0][])); + } + + public static void addMultiTransformationResults(CommonClassDefinition... defs) { + for (CommonClassDefinition d : defs) { + addCommonTransformationResult(d.target.getCanonicalName(), + d.class_file_bytes, + d.dex_file_bytes); + } + } + + public static native void doCommonMultiClassRedefinition(Class<?>[] targets, + byte[][] classfiles, + byte[][] dexfiles); + public static native void doCommonClassRetransformation(Class<?>... target); + public static native void setPopRetransformations(boolean pop); + public static native void popTransformationFor(String name); + public static native void enableCommonRetransformation(boolean enable); + public static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); +} diff --git a/test/926-multi-obsolescence/src/CommonClassDefinition.java b/test/926-multi-obsolescence/src/CommonClassDefinition.java deleted file mode 100644 index 62602a02e9..0000000000 --- a/test/926-multi-obsolescence/src/CommonClassDefinition.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * 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. - */ - -class CommonClassDefinition { - public final Class<?> target; - public final byte[] class_file_bytes; - public final byte[] dex_file_bytes; - - CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { - this.target = target; - this.class_file_bytes = class_file_bytes; - this.dex_file_bytes = dex_file_bytes; - } -} diff --git a/test/926-multi-obsolescence/src/Main.java b/test/926-multi-obsolescence/src/Main.java index 2440908c07..8e21b8f633 100644 --- a/test/926-multi-obsolescence/src/Main.java +++ b/test/926-multi-obsolescence/src/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,115 +14,8 @@ * limitations under the License. */ -import java.util.ArrayList; -import java.util.Base64; - public class Main { - // class Transform { - // public void sayHi(Runnable r) { - // System.out.println("Hello - Transformed"); - // r.run(); - // System.out.println("Goodbye - Transformed"); - // } - // } - private static CommonClassDefinition VALID_DEFINITION_T1 = new CommonClassDefinition( - Transform.class, - Base64.getDecoder().decode( - "yv66vgAAADQAJAoACAARCQASABMIABQKABUAFgsAFwAYCAAZBwAaBwAbAQAGPGluaXQ+AQADKClW" + - "AQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEABXNheUhpAQAXKExqYXZhL2xhbmcvUnVubmFibGU7" + - "KVYBAApTb3VyY2VGaWxlAQAOVHJhbnNmb3JtLmphdmEMAAkACgcAHAwAHQAeAQATSGVsbG8gLSBU" + - "cmFuc2Zvcm1lZAcAHwwAIAAhBwAiDAAjAAoBABVHb29kYnllIC0gVHJhbnNmb3JtZWQBAAlUcmFu" + - "c2Zvcm0BABBqYXZhL2xhbmcvT2JqZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZh" + - "L2lvL1ByaW50U3RyZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZh" + - "L2xhbmcvU3RyaW5nOylWAQASamF2YS9sYW5nL1J1bm5hYmxlAQADcnVuACAABwAIAAAAAAACAAAA" + - "CQAKAAEACwAAAB0AAQABAAAABSq3AAGxAAAAAQAMAAAABgABAAAAAQABAA0ADgABAAsAAAA7AAIA" + - "AgAAABeyAAISA7YABCu5AAUBALIAAhIGtgAEsQAAAAEADAAAABIABAAAAAMACAAEAA4ABQAWAAYA" + - "AQAPAAAAAgAQ"), - Base64.getDecoder().decode( - "ZGV4CjAzNQAYeAMMXgYWxoeSHAS9EWKCCtVRSAGpqZVQAwAAcAAAAHhWNBIAAAAAAAAAALACAAAR" + - "AAAAcAAAAAcAAAC0AAAAAwAAANAAAAABAAAA9AAAAAUAAAD8AAAAAQAAACQBAAAMAgAARAEAAKIB" + - "AACqAQAAwQEAANYBAADjAQAA+gEAAA4CAAAkAgAAOAIAAEwCAABcAgAAXwIAAGMCAAB3AgAAfAIA" + - "AIUCAACKAgAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAACgAAAAoAAAAGAAAAAAAAAAsAAAAGAAAA" + - "lAEAAAsAAAAGAAAAnAEAAAUAAQANAAAAAAAAAAAAAAAAAAEAEAAAAAEAAgAOAAAAAgAAAAAAAAAD" + - "AAAADwAAAAAAAAAAAAAAAgAAAAAAAAAJAAAAAAAAAJ8CAAAAAAAAAQABAAEAAACRAgAABAAAAHAQ" + - "AwAAAA4ABAACAAIAAACWAgAAFAAAAGIAAAAbAQIAAABuIAIAEAByEAQAAwBiAAAAGwEBAAAAbiAC" + - "ABAADgABAAAAAwAAAAEAAAAEAAY8aW5pdD4AFUdvb2RieWUgLSBUcmFuc2Zvcm1lZAATSGVsbG8g" + - "LSBUcmFuc2Zvcm1lZAALTFRyYW5zZm9ybTsAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwASTGphdmEv" + - "bGFuZy9PYmplY3Q7ABRMamF2YS9sYW5nL1J1bm5hYmxlOwASTGphdmEvbGFuZy9TdHJpbmc7ABJM" + - "amF2YS9sYW5nL1N5c3RlbTsADlRyYW5zZm9ybS5qYXZhAAFWAAJWTAASZW1pdHRlcjogamFjay00" + - "LjEzAANvdXQAB3ByaW50bG4AA3J1bgAFc2F5SGkAAQAHDgADAQAHDoc8hwAAAAEBAICABMQCAQHc" + - "AgAAAA0AAAAAAAAAAQAAAAAAAAABAAAAEQAAAHAAAAACAAAABwAAALQAAAADAAAAAwAAANAAAAAE" + - "AAAAAQAAAPQAAAAFAAAABQAAAPwAAAAGAAAAAQAAACQBAAABIAAAAgAAAEQBAAABEAAAAgAAAJQB" + - "AAACIAAAEQAAAKIBAAADIAAAAgAAAJECAAAAIAAAAQAAAJ8CAAAAEAAAAQAAALACAAA=")); - // class Transform2 { - // public void sayHi(Runnable r) { - // System.out.println("Hello 2 - Transformed"); - // r.run(); - // System.out.println("Goodbye 2 - Transformed"); - // } - // } - private static CommonClassDefinition VALID_DEFINITION_T2 = new CommonClassDefinition( - Transform2.class, - Base64.getDecoder().decode( - "yv66vgAAADQAJAoACAARCQASABMIABQKABUAFgsAFwAYCAAZBwAaBwAbAQAGPGluaXQ+AQADKClW" + - "AQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEABXNheUhpAQAXKExqYXZhL2xhbmcvUnVubmFibGU7" + - "KVYBAApTb3VyY2VGaWxlAQAPVHJhbnNmb3JtMi5qYXZhDAAJAAoHABwMAB0AHgEAFUhlbGxvIDIg" + - "LSBUcmFuc2Zvcm1lZAcAHwwAIAAhBwAiDAAjAAoBABdHb29kYnllIDIgLSBUcmFuc2Zvcm1lZAEA" + - "ClRyYW5zZm9ybTIBABBqYXZhL2xhbmcvT2JqZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEA" + - "FUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAV" + - "KExqYXZhL2xhbmcvU3RyaW5nOylWAQASamF2YS9sYW5nL1J1bm5hYmxlAQADcnVuACAABwAIAAAA" + - "AAACAAAACQAKAAEACwAAAB0AAQABAAAABSq3AAGxAAAAAQAMAAAABgABAAAAAQABAA0ADgABAAsA" + - "AAA7AAIAAgAAABeyAAISA7YABCu5AAUBALIAAhIGtgAEsQAAAAEADAAAABIABAAAAAMACAAEAA4A" + - "BQAWAAYAAQAPAAAAAgAQ"), - Base64.getDecoder().decode( - "ZGV4CjAzNQCee5Z6+AuFcjnPjjn7QYgZmKSmFQCO4nxUAwAAcAAAAHhWNBIAAAAAAAAAALQCAAAR" + - "AAAAcAAAAAcAAAC0AAAAAwAAANAAAAABAAAA9AAAAAUAAAD8AAAAAQAAACQBAAAQAgAARAEAAKIB" + - "AACqAQAAwwEAANoBAADoAQAA/wEAABMCAAApAgAAPQIAAFECAABiAgAAZQIAAGkCAAB9AgAAggIA" + - "AIsCAACQAgAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAACgAAAAoAAAAGAAAAAAAAAAsAAAAGAAAA" + - "lAEAAAsAAAAGAAAAnAEAAAUAAQANAAAAAAAAAAAAAAAAAAEAEAAAAAEAAgAOAAAAAgAAAAAAAAAD" + - "AAAADwAAAAAAAAAAAAAAAgAAAAAAAAAJAAAAAAAAAKUCAAAAAAAAAQABAAEAAACXAgAABAAAAHAQ" + - "AwAAAA4ABAACAAIAAACcAgAAFAAAAGIAAAAbAQIAAABuIAIAEAByEAQAAwBiAAAAGwEBAAAAbiAC" + - "ABAADgABAAAAAwAAAAEAAAAEAAY8aW5pdD4AF0dvb2RieWUgMiAtIFRyYW5zZm9ybWVkABVIZWxs" + - "byAyIC0gVHJhbnNmb3JtZWQADExUcmFuc2Zvcm0yOwAVTGphdmEvaW8vUHJpbnRTdHJlYW07ABJM" + - "amF2YS9sYW5nL09iamVjdDsAFExqYXZhL2xhbmcvUnVubmFibGU7ABJMamF2YS9sYW5nL1N0cmlu" + - "ZzsAEkxqYXZhL2xhbmcvU3lzdGVtOwAPVHJhbnNmb3JtMi5qYXZhAAFWAAJWTAASZW1pdHRlcjog" + - "amFjay00LjIwAANvdXQAB3ByaW50bG4AA3J1bgAFc2F5SGkAAQAHDgADAQAHDoc8hwAAAAEBAICA" + - "BMQCAQHcAgANAAAAAAAAAAEAAAAAAAAAAQAAABEAAABwAAAAAgAAAAcAAAC0AAAAAwAAAAMAAADQ" + - "AAAABAAAAAEAAAD0AAAABQAAAAUAAAD8AAAABgAAAAEAAAAkAQAAASAAAAIAAABEAQAAARAAAAIA" + - "AACUAQAAAiAAABEAAACiAQAAAyAAAAIAAACXAgAAACAAAAEAAAClAgAAABAAAAEAAAC0AgAA")); - - public static void main(String[] args) { - art.Main.bindAgentJNIForClass(Main.class); - doTest(new Transform(), new Transform2()); - } - - public static void doTest(final Transform t1, final Transform2 t2) { - t1.sayHi(() -> { t2.sayHi(() -> { System.out.println("Not doing anything here"); }); }); - t1.sayHi(() -> { - t2.sayHi(() -> { - System.out.println("transforming calling functions"); - doMultiClassRedefinition(VALID_DEFINITION_T1, VALID_DEFINITION_T2); - }); - }); - t1.sayHi(() -> { t2.sayHi(() -> { System.out.println("Not doing anything here"); }); }); + public static void main(String[] args) throws Exception { + art.Test926.run(); } - - public static void doMultiClassRedefinition(CommonClassDefinition... defs) { - ArrayList<Class<?>> classes = new ArrayList<>(); - ArrayList<byte[]> class_files = new ArrayList<>(); - ArrayList<byte[]> dex_files = new ArrayList<>(); - - for (CommonClassDefinition d : defs) { - classes.add(d.target); - class_files.add(d.class_file_bytes); - dex_files.add(d.dex_file_bytes); - } - doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), - class_files.toArray(new byte[0][]), - dex_files.toArray(new byte[0][])); - } - - public static native void doCommonMultiClassRedefinition(Class<?>[] targets, - byte[][] classfiles, - byte[][] dexfiles); } diff --git a/test/926-multi-obsolescence/src/Transform.java b/test/926-multi-obsolescence/src/Transform.java deleted file mode 100644 index 8cda6cdf53..0000000000 --- a/test/926-multi-obsolescence/src/Transform.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * 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. - */ - -class Transform { - public void sayHi(Runnable r) { - // Use lower 'h' to make sure the string will have a different string id - // than the transformation (the transformation code is the same except - // the actual printed String, which was making the test inacurately passing - // in JIT mode when loading the string from the dex cache, as the string ids - // of the two different strings were the same). - // We know the string ids will be different because lexicographically: - // "Hello" < "LTransform;" < "hello". - System.out.println("hello"); - r.run(); - System.out.println("goodbye"); - } -} diff --git a/test/926-multi-obsolescence/src/Transform2.java b/test/926-multi-obsolescence/src/Transform2.java deleted file mode 100644 index 4877f8455b..0000000000 --- a/test/926-multi-obsolescence/src/Transform2.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * 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. - */ - -class Transform2 { - public void sayHi(Runnable r) { - System.out.println("hello - 2"); - r.run(); - System.out.println("goodbye - 2"); - } -} diff --git a/test/926-multi-obsolescence/src/art/Redefinition.java b/test/926-multi-obsolescence/src/art/Redefinition.java new file mode 100644 index 0000000000..0350ab42ad --- /dev/null +++ b/test/926-multi-obsolescence/src/art/Redefinition.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.util.ArrayList; +// Common Redefinition functions. Placed here for use by CTS +public class Redefinition { + // Bind native functions. + static { + Main.bindAgentJNIForClass(Redefinition.class); + } + + public static final class CommonClassDefinition { + public final Class<?> target; + public final byte[] class_file_bytes; + public final byte[] dex_file_bytes; + + public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { + this.target = target; + this.class_file_bytes = class_file_bytes; + this.dex_file_bytes = dex_file_bytes; + } + } + + // A set of possible test configurations. Test should set this if they need to. + // This must be kept in sync with the defines in ti-agent/common_helper.cc + public static enum Config { + COMMON_REDEFINE(0), + COMMON_RETRANSFORM(1), + COMMON_TRANSFORM(2); + + private final int val; + private Config(int val) { + this.val = val; + } + } + + public static void setTestConfiguration(Config type) { + nativeSetTestConfiguration(type.val); + } + + private static native void nativeSetTestConfiguration(int type); + + // Transforms the class + public static native void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile); + + public static void doMultiClassRedefinition(CommonClassDefinition... defs) { + ArrayList<Class<?>> classes = new ArrayList<>(); + ArrayList<byte[]> class_files = new ArrayList<>(); + ArrayList<byte[]> dex_files = new ArrayList<>(); + + for (CommonClassDefinition d : defs) { + classes.add(d.target); + class_files.add(d.class_file_bytes); + dex_files.add(d.dex_file_bytes); + } + doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), + class_files.toArray(new byte[0][]), + dex_files.toArray(new byte[0][])); + } + + public static void addMultiTransformationResults(CommonClassDefinition... defs) { + for (CommonClassDefinition d : defs) { + addCommonTransformationResult(d.target.getCanonicalName(), + d.class_file_bytes, + d.dex_file_bytes); + } + } + + public static native void doCommonMultiClassRedefinition(Class<?>[] targets, + byte[][] classfiles, + byte[][] dexfiles); + public static native void doCommonClassRetransformation(Class<?>... target); + public static native void setPopRetransformations(boolean pop); + public static native void popTransformationFor(String name); + public static native void enableCommonRetransformation(boolean enable); + public static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); +} diff --git a/test/926-multi-obsolescence/src/art/Test926.java b/test/926-multi-obsolescence/src/art/Test926.java new file mode 100644 index 0000000000..843d05c3fc --- /dev/null +++ b/test/926-multi-obsolescence/src/art/Test926.java @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * 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 art; + +import static art.Redefinition.CommonClassDefinition; +import java.util.ArrayList; +import java.util.Base64; + +public class Test926 { + + static class Transform { + public void sayHi(Runnable r) { + System.out.println("hello"); + r.run(); + System.out.println("goodbye"); + } + } + + static class Transform2 { + public void sayHi(Runnable r) { + System.out.println("hello - 2"); + r.run(); + System.out.println("goodbye - 2"); + } + } + // static class Transform { + // public void sayHi(Runnable r) { + // System.out.println("Hello - Transformed"); + // r.run(); + // System.out.println("Goodbye - Transformed"); + // } + // } + private static CommonClassDefinition VALID_DEFINITION_T1 = new CommonClassDefinition( + Transform.class, + Base64.getDecoder().decode( + "yv66vgAAADQAKAoACAARCQASABMIABQKABUAFgsAFwAYCAAZBwAbBwAeAQAGPGluaXQ+AQADKClW" + + "AQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEABXNheUhpAQAXKExqYXZhL2xhbmcvUnVubmFibGU7" + + "KVYBAApTb3VyY2VGaWxlAQAMVGVzdDkyNi5qYXZhDAAJAAoHAB8MACAAIQEAE0hlbGxvIC0gVHJh" + + "bnNmb3JtZWQHACIMACMAJAcAJQwAJgAKAQAVR29vZGJ5ZSAtIFRyYW5zZm9ybWVkBwAnAQAVYXJ0" + + "L1Rlc3Q5MjYkVHJhbnNmb3JtAQAJVHJhbnNmb3JtAQAMSW5uZXJDbGFzc2VzAQAQamF2YS9sYW5n" + + "L09iamVjdAEAEGphdmEvbGFuZy9TeXN0ZW0BAANvdXQBABVMamF2YS9pby9QcmludFN0cmVhbTsB" + + "ABNqYXZhL2lvL1ByaW50U3RyZWFtAQAHcHJpbnRsbgEAFShMamF2YS9sYW5nL1N0cmluZzspVgEA" + + "EmphdmEvbGFuZy9SdW5uYWJsZQEAA3J1bgEAC2FydC9UZXN0OTI2ACAABwAIAAAAAAACAAAACQAK" + + "AAEACwAAAB0AAQABAAAABSq3AAGxAAAAAQAMAAAABgABAAAADAABAA0ADgABAAsAAAA7AAIAAgAA" + + "ABeyAAISA7YABCu5AAUBALIAAhIGtgAEsQAAAAEADAAAABIABAAAAA4ACAAPAA4AEAAWABEAAgAP" + + "AAAAAgAQAB0AAAAKAAEABwAaABwACA=="), + Base64.getDecoder().decode( + "ZGV4CjAzNQB8m+R/AAAAAAAAAAAAAAAAAAAAAAAAAAA8BAAAcAAAAHhWNBIAAAAAAAAAAHgDAAAX" + + "AAAAcAAAAAoAAADMAAAAAwAAAPQAAAABAAAAGAEAAAUAAAAgAQAAAQAAAEgBAADUAgAAaAEAAGgB" + + "AABwAQAAhwEAAJwBAAC1AQAAxAEAAOgBAAAIAgAAHwIAADMCAABJAgAAXQIAAHECAAB/AgAAigIA" + + "AI0CAACRAgAAngIAAKQCAACpAgAAsgIAALcCAAC+AgAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAA" + + "CQAAAAoAAAALAAAADgAAAA4AAAAJAAAAAAAAAA8AAAAJAAAAyAIAAA8AAAAJAAAA0AIAAAgABAAS" + + "AAAAAAAAAAAAAAAAAAEAFQAAAAQAAgATAAAABQAAAAAAAAAGAAAAFAAAAAAAAAAAAAAABQAAAAAA" + + "AAAMAAAAaAMAADwDAAAAAAAABjxpbml0PgAVR29vZGJ5ZSAtIFRyYW5zZm9ybWVkABNIZWxsbyAt" + + "IFRyYW5zZm9ybWVkABdMYXJ0L1Rlc3Q5MjYkVHJhbnNmb3JtOwANTGFydC9UZXN0OTI2OwAiTGRh" + + "bHZpay9hbm5vdGF0aW9uL0VuY2xvc2luZ0NsYXNzOwAeTGRhbHZpay9hbm5vdGF0aW9uL0lubmVy" + + "Q2xhc3M7ABVMamF2YS9pby9QcmludFN0cmVhbTsAEkxqYXZhL2xhbmcvT2JqZWN0OwAUTGphdmEv" + + "bGFuZy9SdW5uYWJsZTsAEkxqYXZhL2xhbmcvU3RyaW5nOwASTGphdmEvbGFuZy9TeXN0ZW07AAxU" + + "ZXN0OTI2LmphdmEACVRyYW5zZm9ybQABVgACVkwAC2FjY2Vzc0ZsYWdzAARuYW1lAANvdXQAB3By" + + "aW50bG4AA3J1bgAFc2F5SGkABXZhbHVlAAAAAAEAAAAGAAAAAQAAAAcAAAAMAAcOAA4BAAcOAQgP" + + "AQMPAQgPAAEAAQABAAAA2AIAAAQAAABwEAMAAAAOAAQAAgACAAAA3QIAABQAAABiAAAAGwECAAAA" + + "biACABAAchAEAAMAYgAAABsBAQAAAG4gAgAQAA4AAAABAQCAgATsBQEBhAYAAAICARYYAQIDAhAE" + + "CBEXDQACAAAATAMAAFIDAABcAwAAAAAAAAAAAAAAAAAAEAAAAAAAAAABAAAAAAAAAAEAAAAXAAAA" + + "cAAAAAIAAAAKAAAAzAAAAAMAAAADAAAA9AAAAAQAAAABAAAAGAEAAAUAAAAFAAAAIAEAAAYAAAAB" + + "AAAASAEAAAIgAAAXAAAAaAEAAAEQAAACAAAAyAIAAAMgAAACAAAA2AIAAAEgAAACAAAA7AIAAAAg" + + "AAABAAAAPAMAAAQgAAACAAAATAMAAAMQAAABAAAAXAMAAAYgAAABAAAAaAMAAAAQAAABAAAAeAMA" + + "AA==")); + // static class Transform2 { + // public void sayHi(Runnable r) { + // System.out.println("Hello 2 - Transformed"); + // r.run(); + // System.out.println("Goodbye 2 - Transformed"); + // } + // } + private static CommonClassDefinition VALID_DEFINITION_T2 = new CommonClassDefinition( + Transform2.class, + Base64.getDecoder().decode( + "yv66vgAAADQAKAoACAARCQASABMIABQKABUAFgsAFwAYCAAZBwAbBwAeAQAGPGluaXQ+AQADKClW" + + "AQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEABXNheUhpAQAXKExqYXZhL2xhbmcvUnVubmFibGU7" + + "KVYBAApTb3VyY2VGaWxlAQAMVGVzdDkyNi5qYXZhDAAJAAoHAB8MACAAIQEAFUhlbGxvIDIgLSBU" + + "cmFuc2Zvcm1lZAcAIgwAIwAkBwAlDAAmAAoBABdHb29kYnllIDIgLSBUcmFuc2Zvcm1lZAcAJwEA" + + "FmFydC9UZXN0OTI2JFRyYW5zZm9ybTIBAApUcmFuc2Zvcm0yAQAMSW5uZXJDbGFzc2VzAQAQamF2" + + "YS9sYW5nL09iamVjdAEAEGphdmEvbGFuZy9TeXN0ZW0BAANvdXQBABVMamF2YS9pby9QcmludFN0" + + "cmVhbTsBABNqYXZhL2lvL1ByaW50U3RyZWFtAQAHcHJpbnRsbgEAFShMamF2YS9sYW5nL1N0cmlu" + + "ZzspVgEAEmphdmEvbGFuZy9SdW5uYWJsZQEAA3J1bgEAC2FydC9UZXN0OTI2ACAABwAIAAAAAAAC" + + "AAAACQAKAAEACwAAAB0AAQABAAAABSq3AAGxAAAAAQAMAAAABgABAAAABQABAA0ADgABAAsAAAA7" + + "AAIAAgAAABeyAAISA7YABCu5AAUBALIAAhIGtgAEsQAAAAEADAAAABIABAAAAAcACAAIAA4ACQAW" + + "AAoAAgAPAAAAAgAQAB0AAAAKAAEABwAaABwACA=="), + Base64.getDecoder().decode( + "ZGV4CjAzNQBCnaUuAAAAAAAAAAAAAAAAAAAAAAAAAABABAAAcAAAAHhWNBIAAAAAAAAAAHwDAAAX" + + "AAAAcAAAAAoAAADMAAAAAwAAAPQAAAABAAAAGAEAAAUAAAAgAQAAAQAAAEgBAADYAgAAaAEAAGgB" + + "AABwAQAAiQEAAKABAAC6AQAAyQEAAO0BAAANAgAAJAIAADgCAABOAgAAYgIAAHYCAACEAgAAkAIA" + + "AJMCAACXAgAApAIAAKoCAACvAgAAuAIAAL0CAADEAgAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAA" + + "CQAAAAoAAAALAAAADgAAAA4AAAAJAAAAAAAAAA8AAAAJAAAAzAIAAA8AAAAJAAAA1AIAAAgABAAS" + + "AAAAAAAAAAAAAAAAAAEAFQAAAAQAAgATAAAABQAAAAAAAAAGAAAAFAAAAAAAAAAAAAAABQAAAAAA" + + "AAAMAAAAbAMAAEADAAAAAAAABjxpbml0PgAXR29vZGJ5ZSAyIC0gVHJhbnNmb3JtZWQAFUhlbGxv" + + "IDIgLSBUcmFuc2Zvcm1lZAAYTGFydC9UZXN0OTI2JFRyYW5zZm9ybTI7AA1MYXJ0L1Rlc3Q5MjY7" + + "ACJMZGFsdmlrL2Fubm90YXRpb24vRW5jbG9zaW5nQ2xhc3M7AB5MZGFsdmlrL2Fubm90YXRpb24v" + + "SW5uZXJDbGFzczsAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwASTGphdmEvbGFuZy9PYmplY3Q7ABRM" + + "amF2YS9sYW5nL1J1bm5hYmxlOwASTGphdmEvbGFuZy9TdHJpbmc7ABJMamF2YS9sYW5nL1N5c3Rl" + + "bTsADFRlc3Q5MjYuamF2YQAKVHJhbnNmb3JtMgABVgACVkwAC2FjY2Vzc0ZsYWdzAARuYW1lAANv" + + "dXQAB3ByaW50bG4AA3J1bgAFc2F5SGkABXZhbHVlAAABAAAABgAAAAEAAAAHAAAABQAHDgAHAQAH" + + "DgEIDwEDDwEIDwABAAEAAQAAANwCAAAEAAAAcBADAAAADgAEAAIAAgAAAOECAAAUAAAAYgAAABsB" + + "AgAAAG4gAgAQAHIQBAADAGIAAAAbAQEAAABuIAIAEAAOAAAAAQEAgIAE8AUBAYgGAAACAgEWGAEC" + + "AwIQBAgRFw0AAgAAAFADAABWAwAAYAMAAAAAAAAAAAAAAAAAABAAAAAAAAAAAQAAAAAAAAABAAAA" + + "FwAAAHAAAAACAAAACgAAAMwAAAADAAAAAwAAAPQAAAAEAAAAAQAAABgBAAAFAAAABQAAACABAAAG" + + "AAAAAQAAAEgBAAACIAAAFwAAAGgBAAABEAAAAgAAAMwCAAADIAAAAgAAANwCAAABIAAAAgAAAPAC" + + "AAAAIAAAAQAAAEADAAAEIAAAAgAAAFADAAADEAAAAQAAAGADAAAGIAAAAQAAAGwDAAAAEAAAAQAA" + + "AHwDAAA=")); + + public static void run() throws Exception { + Redefinition.setTestConfiguration(Redefinition.Config.COMMON_REDEFINE); + doTest(new Transform(), new Transform2()); + } + + public static void doTest(final Transform t1, final Transform2 t2) throws Exception { + t1.sayHi(() -> { t2.sayHi(() -> { System.out.println("Not doing anything here"); }); }); + t1.sayHi(() -> { + t2.sayHi(() -> { + System.out.println("transforming calling functions"); + Redefinition.doMultiClassRedefinition(VALID_DEFINITION_T1, VALID_DEFINITION_T2); + }); + }); + t1.sayHi(() -> { t2.sayHi(() -> { System.out.println("Not doing anything here"); }); }); + } +} diff --git a/test/930-hello-retransform/src/Main.java b/test/930-hello-retransform/src/Main.java index da59c7440b..38c1d363b6 100644 --- a/test/930-hello-retransform/src/Main.java +++ b/test/930-hello-retransform/src/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,57 +14,8 @@ * limitations under the License. */ -import java.util.Base64; public class Main { - - /** - * base64 encoded class/dex file for - * class Transform { - * public void sayHi() { - * System.out.println("Goodbye"); - * } - * } - */ - private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( - "yv66vgAAADQAHAoABgAOCQAPABAIABEKABIAEwcAFAcAFQEABjxpbml0PgEAAygpVgEABENvZGUB" + - "AA9MaW5lTnVtYmVyVGFibGUBAAVzYXlIaQEAClNvdXJjZUZpbGUBAA5UcmFuc2Zvcm0uamF2YQwA" + - "BwAIBwAWDAAXABgBAAdHb29kYnllBwAZDAAaABsBAAlUcmFuc2Zvcm0BABBqYXZhL2xhbmcvT2Jq" + - "ZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2ph" + - "dmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWACAABQAG" + - "AAAAAAACAAAABwAIAAEACQAAAB0AAQABAAAABSq3AAGxAAAAAQAKAAAABgABAAAAEQABAAsACAAB" + - "AAkAAAAlAAIAAQAAAAmyAAISA7YABLEAAAABAAoAAAAKAAIAAAATAAgAFAABAAwAAAACAA0="); - private static final byte[] DEX_BYTES = Base64.getDecoder().decode( - "ZGV4CjAzNQCLXSBQ5FiS3f16krSYZFF8xYZtFVp0GRXMAgAAcAAAAHhWNBIAAAAAAAAAACwCAAAO" + - "AAAAcAAAAAYAAACoAAAAAgAAAMAAAAABAAAA2AAAAAQAAADgAAAAAQAAAAABAACsAQAAIAEAAGIB" + - "AABqAQAAcwEAAIABAACXAQAAqwEAAL8BAADTAQAA4wEAAOYBAADqAQAA/gEAAAMCAAAMAgAAAgAA" + - "AAMAAAAEAAAABQAAAAYAAAAIAAAACAAAAAUAAAAAAAAACQAAAAUAAABcAQAABAABAAsAAAAAAAAA" + - "AAAAAAAAAAANAAAAAQABAAwAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAHAAAAAAAAAB4CAAAA" + - "AAAAAQABAAEAAAATAgAABAAAAHAQAwAAAA4AAwABAAIAAAAYAgAACQAAAGIAAAAbAQEAAABuIAIA" + - "EAAOAAAAAQAAAAMABjxpbml0PgAHR29vZGJ5ZQALTFRyYW5zZm9ybTsAFUxqYXZhL2lvL1ByaW50" + - "U3RyZWFtOwASTGphdmEvbGFuZy9PYmplY3Q7ABJMamF2YS9sYW5nL1N0cmluZzsAEkxqYXZhL2xh" + - "bmcvU3lzdGVtOwAOVHJhbnNmb3JtLmphdmEAAVYAAlZMABJlbWl0dGVyOiBqYWNrLTMuMzYAA291" + - "dAAHcHJpbnRsbgAFc2F5SGkAEQAHDgATAAcOhQAAAAEBAICABKACAQG4Ag0AAAAAAAAAAQAAAAAA" + - "AAABAAAADgAAAHAAAAACAAAABgAAAKgAAAADAAAAAgAAAMAAAAAEAAAAAQAAANgAAAAFAAAABAAA" + - "AOAAAAAGAAAAAQAAAAABAAABIAAAAgAAACABAAABEAAAAQAAAFwBAAACIAAADgAAAGIBAAADIAAA" + - "AgAAABMCAAAAIAAAAQAAAB4CAAAAEAAAAQAAACwCAAA="); - - public static void main(String[] args) { - art.Main.bindAgentJNIForClass(Main.class); - doTest(new Transform()); + public static void main(String[] args) throws Exception { + art.Test930.run(); } - - public static void doTest(Transform t) { - t.sayHi(); - addCommonTransformationResult("Transform", CLASS_BYTES, DEX_BYTES); - enableCommonRetransformation(true); - doCommonClassRetransformation(Transform.class); - t.sayHi(); - } - - // Transforms the class - private static native void doCommonClassRetransformation(Class<?>... target); - private static native void enableCommonRetransformation(boolean enable); - private static native void addCommonTransformationResult(String target_name, - byte[] class_bytes, - byte[] dex_bytes); } diff --git a/test/930-hello-retransform/src/Transform.java b/test/930-hello-retransform/src/Transform.java deleted file mode 100644 index 8e8af355da..0000000000 --- a/test/930-hello-retransform/src/Transform.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * 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. - */ - -class Transform { - public void sayHi() { - // Use lower 'h' to make sure the string will have a different string id - // than the transformation (the transformation code is the same except - // the actual printed String, which was making the test inacurately passing - // in JIT mode when loading the string from the dex cache, as the string ids - // of the two different strings were the same). - // We know the string ids will be different because lexicographically: - // "Goodbye" < "LTransform;" < "hello". - System.out.println("hello"); - } -} diff --git a/test/930-hello-retransform/src/art/Redefinition.java b/test/930-hello-retransform/src/art/Redefinition.java new file mode 100644 index 0000000000..0350ab42ad --- /dev/null +++ b/test/930-hello-retransform/src/art/Redefinition.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.util.ArrayList; +// Common Redefinition functions. Placed here for use by CTS +public class Redefinition { + // Bind native functions. + static { + Main.bindAgentJNIForClass(Redefinition.class); + } + + public static final class CommonClassDefinition { + public final Class<?> target; + public final byte[] class_file_bytes; + public final byte[] dex_file_bytes; + + public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { + this.target = target; + this.class_file_bytes = class_file_bytes; + this.dex_file_bytes = dex_file_bytes; + } + } + + // A set of possible test configurations. Test should set this if they need to. + // This must be kept in sync with the defines in ti-agent/common_helper.cc + public static enum Config { + COMMON_REDEFINE(0), + COMMON_RETRANSFORM(1), + COMMON_TRANSFORM(2); + + private final int val; + private Config(int val) { + this.val = val; + } + } + + public static void setTestConfiguration(Config type) { + nativeSetTestConfiguration(type.val); + } + + private static native void nativeSetTestConfiguration(int type); + + // Transforms the class + public static native void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile); + + public static void doMultiClassRedefinition(CommonClassDefinition... defs) { + ArrayList<Class<?>> classes = new ArrayList<>(); + ArrayList<byte[]> class_files = new ArrayList<>(); + ArrayList<byte[]> dex_files = new ArrayList<>(); + + for (CommonClassDefinition d : defs) { + classes.add(d.target); + class_files.add(d.class_file_bytes); + dex_files.add(d.dex_file_bytes); + } + doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), + class_files.toArray(new byte[0][]), + dex_files.toArray(new byte[0][])); + } + + public static void addMultiTransformationResults(CommonClassDefinition... defs) { + for (CommonClassDefinition d : defs) { + addCommonTransformationResult(d.target.getCanonicalName(), + d.class_file_bytes, + d.dex_file_bytes); + } + } + + public static native void doCommonMultiClassRedefinition(Class<?>[] targets, + byte[][] classfiles, + byte[][] dexfiles); + public static native void doCommonClassRetransformation(Class<?>... target); + public static native void setPopRetransformations(boolean pop); + public static native void popTransformationFor(String name); + public static native void enableCommonRetransformation(boolean enable); + public static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); +} diff --git a/test/930-hello-retransform/src/art/Test930.java b/test/930-hello-retransform/src/art/Test930.java new file mode 100644 index 0000000000..6c0fc16dad --- /dev/null +++ b/test/930-hello-retransform/src/art/Test930.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * 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 art; + +import java.util.Base64; +public class Test930 { + + static class Transform { + public void sayHi() { + System.out.println("hello"); + } + } + + + /** + * base64 encoded class/dex file for + * static class Transform { + * public void sayHi() { + * System.out.println("Goodbye"); + * } + * } + */ + private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( + "yv66vgAAADQAIAoABgAOCQAPABAIABEKABIAEwcAFQcAGAEABjxpbml0PgEAAygpVgEABENvZGUB" + + "AA9MaW5lTnVtYmVyVGFibGUBAAVzYXlIaQEAClNvdXJjZUZpbGUBAAxUZXN0OTMwLmphdmEMAAcA" + + "CAcAGQwAGgAbAQAHR29vZGJ5ZQcAHAwAHQAeBwAfAQAVYXJ0L1Rlc3Q5MzAkVHJhbnNmb3JtAQAJ" + + "VHJhbnNmb3JtAQAMSW5uZXJDbGFzc2VzAQAQamF2YS9sYW5nL09iamVjdAEAEGphdmEvbGFuZy9T" + + "eXN0ZW0BAANvdXQBABVMamF2YS9pby9QcmludFN0cmVhbTsBABNqYXZhL2lvL1ByaW50U3RyZWFt" + + "AQAHcHJpbnRsbgEAFShMamF2YS9sYW5nL1N0cmluZzspVgEAC2FydC9UZXN0OTMwACAABQAGAAAA" + + "AAACAAAABwAIAAEACQAAAB0AAQABAAAABSq3AAGxAAAAAQAKAAAABgABAAAABQABAAsACAABAAkA" + + "AAAlAAIAAQAAAAmyAAISA7YABLEAAAABAAoAAAAKAAIAAAAHAAgACAACAAwAAAACAA0AFwAAAAoA" + + "AQAFABQAFgAI"); + private static final byte[] DEX_BYTES = Base64.getDecoder().decode( + "ZGV4CjAzNQBsgu9qAAAAAAAAAAAAAAAAAAAAAAAAAAC4AwAAcAAAAHhWNBIAAAAAAAAAAPQCAAAU" + + "AAAAcAAAAAkAAADAAAAAAgAAAOQAAAABAAAA/AAAAAQAAAAEAQAAAQAAACQBAAB0AgAARAEAAEQB" + + "AABMAQAAVQEAAG4BAAB9AQAAoQEAAMEBAADYAQAA7AEAAAACAAAUAgAAIgIAAC0CAAAwAgAANAIA" + + "AEECAABHAgAATAIAAFUCAABcAgAAAgAAAAMAAAAEAAAABQAAAAYAAAAHAAAACAAAAAkAAAAMAAAA" + + "DAAAAAgAAAAAAAAADQAAAAgAAABkAgAABwAEABAAAAAAAAAAAAAAAAAAAAASAAAABAABABEAAAAF" + + "AAAAAAAAAAAAAAAAAAAABQAAAAAAAAAKAAAA5AIAALgCAAAAAAAABjxpbml0PgAHR29vZGJ5ZQAX" + + "TGFydC9UZXN0OTMwJFRyYW5zZm9ybTsADUxhcnQvVGVzdDkzMDsAIkxkYWx2aWsvYW5ub3RhdGlv" + + "bi9FbmNsb3NpbmdDbGFzczsAHkxkYWx2aWsvYW5ub3RhdGlvbi9Jbm5lckNsYXNzOwAVTGphdmEv" + + "aW8vUHJpbnRTdHJlYW07ABJMamF2YS9sYW5nL09iamVjdDsAEkxqYXZhL2xhbmcvU3RyaW5nOwAS" + + "TGphdmEvbGFuZy9TeXN0ZW07AAxUZXN0OTMwLmphdmEACVRyYW5zZm9ybQABVgACVkwAC2FjY2Vz" + + "c0ZsYWdzAARuYW1lAANvdXQAB3ByaW50bG4ABXNheUhpAAV2YWx1ZQAAAQAAAAYAAAAFAAcOAAcA" + + "Bw4BCA8AAAAAAQABAAEAAABsAgAABAAAAHAQAwAAAA4AAwABAAIAAABxAgAACQAAAGIAAAAbAQEA" + + "AABuIAIAEAAOAAAAAAABAQCAgAT8BAEBlAUAAAICARMYAQIDAg4ECA8XCwACAAAAyAIAAM4CAADY" + + "AgAAAAAAAAAAAAAAAAAAEAAAAAAAAAABAAAAAAAAAAEAAAAUAAAAcAAAAAIAAAAJAAAAwAAAAAMA" + + "AAACAAAA5AAAAAQAAAABAAAA/AAAAAUAAAAEAAAABAEAAAYAAAABAAAAJAEAAAIgAAAUAAAARAEA" + + "AAEQAAABAAAAZAIAAAMgAAACAAAAbAIAAAEgAAACAAAAfAIAAAAgAAABAAAAuAIAAAQgAAACAAAA" + + "yAIAAAMQAAABAAAA2AIAAAYgAAABAAAA5AIAAAAQAAABAAAA9AIAAA=="); + + public static void run() { + Redefinition.setTestConfiguration(Redefinition.Config.COMMON_RETRANSFORM); + doTest(new Transform()); + } + + public static void doTest(Transform t) { + t.sayHi(); + Redefinition.addCommonTransformationResult("art/Test930$Transform", CLASS_BYTES, DEX_BYTES); + Redefinition.enableCommonRetransformation(true); + Redefinition.doCommonClassRetransformation(Transform.class); + t.sayHi(); + } +} diff --git a/test/932-transform-saves/src/Main.java b/test/932-transform-saves/src/Main.java index 14e5da0d91..fba40f6828 100644 --- a/test/932-transform-saves/src/Main.java +++ b/test/932-transform-saves/src/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,103 +14,8 @@ * limitations under the License. */ -import java.util.Base64; public class Main { - /** - * base64 encoded class/dex file for - * class Transform { - * public void sayHi() { - * System.out.println("hello"); - * } - * } - */ - private static final byte[] CLASS_BYTES_A = Base64.getDecoder().decode( - "yv66vgAAADQAHAoABgAOCQAPABAIABEKABIAEwcAFAcAFQEABjxpbml0PgEAAygpVgEABENvZGUB" + - "AA9MaW5lTnVtYmVyVGFibGUBAAVzYXlIaQEAClNvdXJjZUZpbGUBAA5UcmFuc2Zvcm0uamF2YQwA" + - "BwAIBwAWDAAXABgBAAVoZWxsbwcAGQwAGgAbAQAJVHJhbnNmb3JtAQAQamF2YS9sYW5nL09iamVj" + - "dAEAEGphdmEvbGFuZy9TeXN0ZW0BAANvdXQBABVMamF2YS9pby9QcmludFN0cmVhbTsBABNqYXZh" + - "L2lvL1ByaW50U3RyZWFtAQAHcHJpbnRsbgEAFShMamF2YS9sYW5nL1N0cmluZzspVgAgAAUABgAA" + - "AAAAAgAAAAcACAABAAkAAAAdAAEAAQAAAAUqtwABsQAAAAEACgAAAAYAAQAAABEAAQALAAgAAQAJ" + - "AAAAJQACAAEAAAAJsgACEgO2AASxAAAAAQAKAAAACgACAAAAGgAIABsAAQAMAAAAAgAN"); - private static final byte[] DEX_BYTES_A = Base64.getDecoder().decode( - "ZGV4CjAzNQC6XWInnnDd1H4NdQ3P3inH8eCVmQI6W7LMAgAAcAAAAHhWNBIAAAAAAAAAACwCAAAO" + - "AAAAcAAAAAYAAACoAAAAAgAAAMAAAAABAAAA2AAAAAQAAADgAAAAAQAAAAABAACsAQAAIAEAAGIB" + - "AABqAQAAdwEAAI4BAACiAQAAtgEAAMoBAADaAQAA3QEAAOEBAAD1AQAA/AEAAAECAAAKAgAAAQAA" + - "AAIAAAADAAAABAAAAAUAAAAHAAAABwAAAAUAAAAAAAAACAAAAAUAAABcAQAABAABAAsAAAAAAAAA" + - "AAAAAAAAAAANAAAAAQABAAwAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAGAAAAAAAAABwCAAAA" + - "AAAAAQABAAEAAAARAgAABAAAAHAQAwAAAA4AAwABAAIAAAAWAgAACQAAAGIAAAAbAQoAAABuIAIA" + - "EAAOAAAAAQAAAAMABjxpbml0PgALTFRyYW5zZm9ybTsAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwAS" + - "TGphdmEvbGFuZy9PYmplY3Q7ABJMamF2YS9sYW5nL1N0cmluZzsAEkxqYXZhL2xhbmcvU3lzdGVt" + - "OwAOVHJhbnNmb3JtLmphdmEAAVYAAlZMABJlbWl0dGVyOiBqYWNrLTQuMjIABWhlbGxvAANvdXQA" + - "B3ByaW50bG4ABXNheUhpABEABw4AGgAHDocAAAABAQCAgASgAgEBuAIAAA0AAAAAAAAAAQAAAAAA" + - "AAABAAAADgAAAHAAAAACAAAABgAAAKgAAAADAAAAAgAAAMAAAAAEAAAAAQAAANgAAAAFAAAABAAA" + - "AOAAAAAGAAAAAQAAAAABAAABIAAAAgAAACABAAABEAAAAQAAAFwBAAACIAAADgAAAGIBAAADIAAA" + - "AgAAABECAAAAIAAAAQAAABwCAAAAEAAAAQAAACwCAAA="); - - /** - * base64 encoded class/dex file for - * class Transform { - * public void sayHi() { - * System.out.println("Goodbye"); - * } - * } - */ - private static final byte[] CLASS_BYTES_B = Base64.getDecoder().decode( - "yv66vgAAADQAHAoABgAOCQAPABAIABEKABIAEwcAFAcAFQEABjxpbml0PgEAAygpVgEABENvZGUB" + - "AA9MaW5lTnVtYmVyVGFibGUBAAVzYXlIaQEAClNvdXJjZUZpbGUBAA5UcmFuc2Zvcm0uamF2YQwA" + - "BwAIBwAWDAAXABgBAAdHb29kYnllBwAZDAAaABsBAAlUcmFuc2Zvcm0BABBqYXZhL2xhbmcvT2Jq" + - "ZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2ph" + - "dmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWACAABQAG" + - "AAAAAAACAAAABwAIAAEACQAAAB0AAQABAAAABSq3AAGxAAAAAQAKAAAABgABAAAAEQABAAsACAAB" + - "AAkAAAAlAAIAAQAAAAmyAAISA7YABLEAAAABAAoAAAAKAAIAAAATAAgAFAABAAwAAAACAA0="); - private static final byte[] DEX_BYTES_B = Base64.getDecoder().decode( - "ZGV4CjAzNQCLXSBQ5FiS3f16krSYZFF8xYZtFVp0GRXMAgAAcAAAAHhWNBIAAAAAAAAAACwCAAAO" + - "AAAAcAAAAAYAAACoAAAAAgAAAMAAAAABAAAA2AAAAAQAAADgAAAAAQAAAAABAACsAQAAIAEAAGIB" + - "AABqAQAAcwEAAIABAACXAQAAqwEAAL8BAADTAQAA4wEAAOYBAADqAQAA/gEAAAMCAAAMAgAAAgAA" + - "AAMAAAAEAAAABQAAAAYAAAAIAAAACAAAAAUAAAAAAAAACQAAAAUAAABcAQAABAABAAsAAAAAAAAA" + - "AAAAAAAAAAANAAAAAQABAAwAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAHAAAAAAAAAB4CAAAA" + - "AAAAAQABAAEAAAATAgAABAAAAHAQAwAAAA4AAwABAAIAAAAYAgAACQAAAGIAAAAbAQEAAABuIAIA" + - "EAAOAAAAAQAAAAMABjxpbml0PgAHR29vZGJ5ZQALTFRyYW5zZm9ybTsAFUxqYXZhL2lvL1ByaW50" + - "U3RyZWFtOwASTGphdmEvbGFuZy9PYmplY3Q7ABJMamF2YS9sYW5nL1N0cmluZzsAEkxqYXZhL2xh" + - "bmcvU3lzdGVtOwAOVHJhbnNmb3JtLmphdmEAAVYAAlZMABJlbWl0dGVyOiBqYWNrLTMuMzYAA291" + - "dAAHcHJpbnRsbgAFc2F5SGkAEQAHDgATAAcOhQAAAAEBAICABKACAQG4Ag0AAAAAAAAAAQAAAAAA" + - "AAABAAAADgAAAHAAAAACAAAABgAAAKgAAAADAAAAAgAAAMAAAAAEAAAAAQAAANgAAAAFAAAABAAA" + - "AOAAAAAGAAAAAQAAAAABAAABIAAAAgAAACABAAABEAAAAQAAAFwBAAACIAAADgAAAGIBAAADIAAA" + - "AgAAABMCAAAAIAAAAQAAAB4CAAAAEAAAAQAAACwCAAA="); - - public static void main(String[] args) { - art.Main.bindAgentJNIForClass(Main.class); - doTest(new Transform()); + public static void main(String[] args) throws Exception { + art.Test932.run(); } - - public static void doTest(Transform t) { - // TODO We currently need to do this transform call since we don't have any way to make the - // original-dex-file a single-class dex-file letting us restore it easily. We should use the - // manipulation library that is being made when we store the original dex file. - // TODO REMOVE this theoretically does nothing but it ensures the original-dex-file we have set - // is one we can return to unaltered. - doCommonClassRedefinition(Transform.class, CLASS_BYTES_A, DEX_BYTES_A); - t.sayHi(); - - // Now turn it into DEX_BYTES_B so it says 'Goodbye' - addCommonTransformationResult("Transform", CLASS_BYTES_B, DEX_BYTES_B); - enableCommonRetransformation(true); - doCommonClassRetransformation(Transform.class); - t.sayHi(); - - // Now turn it back to normal by removing the load-hook and transforming again. - enableCommonRetransformation(false); - doCommonClassRetransformation(Transform.class); - t.sayHi(); - } - - // Transforms the class - private static native void doCommonClassRedefinition(Class<?> target, - byte[] class_bytes, - byte[] dex_bytes); - private static native void doCommonClassRetransformation(Class<?>... target); - private static native void enableCommonRetransformation(boolean enable); - private static native void addCommonTransformationResult(String target_name, - byte[] class_bytes, - byte[] dex_bytes); } diff --git a/test/932-transform-saves/src/Transform.java b/test/932-transform-saves/src/Transform.java deleted file mode 100644 index 83f7aa4b4d..0000000000 --- a/test/932-transform-saves/src/Transform.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * 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. - */ - -class Transform { - public void sayHi() { - // Use lower 'h' to make sure the string will have a different string id - // than the transformation (the transformation code is the same except - // the actual printed String, which was making the test inacurately passing - // in JIT mode when loading the string from the dex cache, as the string ids - // of the two different strings were the same). - // We know the string ids will be different because lexicographically: - // "Goodbye" < "LTransform;" < "hello". - System.out.println("foobar"); - } -} diff --git a/test/932-transform-saves/src/art/Redefinition.java b/test/932-transform-saves/src/art/Redefinition.java new file mode 100644 index 0000000000..0350ab42ad --- /dev/null +++ b/test/932-transform-saves/src/art/Redefinition.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.util.ArrayList; +// Common Redefinition functions. Placed here for use by CTS +public class Redefinition { + // Bind native functions. + static { + Main.bindAgentJNIForClass(Redefinition.class); + } + + public static final class CommonClassDefinition { + public final Class<?> target; + public final byte[] class_file_bytes; + public final byte[] dex_file_bytes; + + public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { + this.target = target; + this.class_file_bytes = class_file_bytes; + this.dex_file_bytes = dex_file_bytes; + } + } + + // A set of possible test configurations. Test should set this if they need to. + // This must be kept in sync with the defines in ti-agent/common_helper.cc + public static enum Config { + COMMON_REDEFINE(0), + COMMON_RETRANSFORM(1), + COMMON_TRANSFORM(2); + + private final int val; + private Config(int val) { + this.val = val; + } + } + + public static void setTestConfiguration(Config type) { + nativeSetTestConfiguration(type.val); + } + + private static native void nativeSetTestConfiguration(int type); + + // Transforms the class + public static native void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile); + + public static void doMultiClassRedefinition(CommonClassDefinition... defs) { + ArrayList<Class<?>> classes = new ArrayList<>(); + ArrayList<byte[]> class_files = new ArrayList<>(); + ArrayList<byte[]> dex_files = new ArrayList<>(); + + for (CommonClassDefinition d : defs) { + classes.add(d.target); + class_files.add(d.class_file_bytes); + dex_files.add(d.dex_file_bytes); + } + doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), + class_files.toArray(new byte[0][]), + dex_files.toArray(new byte[0][])); + } + + public static void addMultiTransformationResults(CommonClassDefinition... defs) { + for (CommonClassDefinition d : defs) { + addCommonTransformationResult(d.target.getCanonicalName(), + d.class_file_bytes, + d.dex_file_bytes); + } + } + + public static native void doCommonMultiClassRedefinition(Class<?>[] targets, + byte[][] classfiles, + byte[][] dexfiles); + public static native void doCommonClassRetransformation(Class<?>... target); + public static native void setPopRetransformations(boolean pop); + public static native void popTransformationFor(String name); + public static native void enableCommonRetransformation(boolean enable); + public static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); +} diff --git a/test/932-transform-saves/src/art/Test932.java b/test/932-transform-saves/src/art/Test932.java new file mode 100644 index 0000000000..3a622322aa --- /dev/null +++ b/test/932-transform-saves/src/art/Test932.java @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * 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 art; + +import java.util.Base64; +public class Test932 { + + // This class is never used so just have it print out a bogus value so we can detect if something + // goes very wrong. + static class Transform { + public void sayHi() { + System.out.println("foobar"); + } + } + + /** + * base64 encoded class/dex file for + * static class Transform { + * public void sayHi() { + * System.out.println("hello"); + * } + * } + */ + private static final byte[] CLASS_BYTES_A = Base64.getDecoder().decode( + "yv66vgAAADQAIAoABgAOCQAPABAIABEKABIAEwcAFQcAGAEABjxpbml0PgEAAygpVgEABENvZGUB" + + "AA9MaW5lTnVtYmVyVGFibGUBAAVzYXlIaQEAClNvdXJjZUZpbGUBAAxUZXN0OTMyLmphdmEMAAcA" + + "CAcAGQwAGgAbAQAFaGVsbG8HABwMAB0AHgcAHwEAFWFydC9UZXN0OTMyJFRyYW5zZm9ybQEACVRy" + + "YW5zZm9ybQEADElubmVyQ2xhc3NlcwEAEGphdmEvbGFuZy9PYmplY3QBABBqYXZhL2xhbmcvU3lz" + + "dGVtAQADb3V0AQAVTGphdmEvaW8vUHJpbnRTdHJlYW07AQATamF2YS9pby9QcmludFN0cmVhbQEA" + + "B3ByaW50bG4BABUoTGphdmEvbGFuZy9TdHJpbmc7KVYBAAthcnQvVGVzdDkzMgAgAAUABgAAAAAA" + + "AgAAAAcACAABAAkAAAAdAAEAAQAAAAUqtwABsQAAAAEACgAAAAYAAQAAAAUAAQALAAgAAQAJAAAA" + + "JQACAAEAAAAJsgACEgO2AASxAAAAAQAKAAAACgACAAAABwAIAAgAAgAMAAAAAgANABcAAAAKAAEA" + + "BQAUABYACA=="); + private static final byte[] DEX_BYTES_A = Base64.getDecoder().decode( + "ZGV4CjAzNQAngjnzAAAAAAAAAAAAAAAAAAAAAAAAAAC4AwAAcAAAAHhWNBIAAAAAAAAAAPQCAAAU" + + "AAAAcAAAAAkAAADAAAAAAgAAAOQAAAABAAAA/AAAAAQAAAAEAQAAAQAAACQBAAB0AgAARAEAAEQB" + + "AABMAQAAZQEAAHQBAACYAQAAuAEAAM8BAADjAQAA9wEAAAsCAAAZAgAAJAIAACcCAAArAgAAOAIA" + + "AD8CAABFAgAASgIAAFMCAABaAgAAAQAAAAIAAAADAAAABAAAAAUAAAAGAAAABwAAAAgAAAALAAAA" + + "CwAAAAgAAAAAAAAADAAAAAgAAABkAgAABwAEABAAAAAAAAAAAAAAAAAAAAASAAAABAABABEAAAAF" + + "AAAAAAAAAAAAAAAAAAAABQAAAAAAAAAJAAAA5AIAALgCAAAAAAAABjxpbml0PgAXTGFydC9UZXN0" + + "OTMyJFRyYW5zZm9ybTsADUxhcnQvVGVzdDkzMjsAIkxkYWx2aWsvYW5ub3RhdGlvbi9FbmNsb3Np" + + "bmdDbGFzczsAHkxkYWx2aWsvYW5ub3RhdGlvbi9Jbm5lckNsYXNzOwAVTGphdmEvaW8vUHJpbnRT" + + "dHJlYW07ABJMamF2YS9sYW5nL09iamVjdDsAEkxqYXZhL2xhbmcvU3RyaW5nOwASTGphdmEvbGFu" + + "Zy9TeXN0ZW07AAxUZXN0OTMyLmphdmEACVRyYW5zZm9ybQABVgACVkwAC2FjY2Vzc0ZsYWdzAAVo" + + "ZWxsbwAEbmFtZQADb3V0AAdwcmludGxuAAVzYXlIaQAFdmFsdWUAAAAAAQAAAAYAAAAFAAcOAAcA" + + "Bw4BCA8AAAAAAQABAAEAAABsAgAABAAAAHAQAwAAAA4AAwABAAIAAABxAgAACQAAAGIAAAAbAQ4A" + + "AABuIAIAEAAOAAAAAAABAQCAgAT8BAEBlAUAAAICARMYAQIDAg0ECA8XCgACAAAAyAIAAM4CAADY" + + "AgAAAAAAAAAAAAAAAAAAEAAAAAAAAAABAAAAAAAAAAEAAAAUAAAAcAAAAAIAAAAJAAAAwAAAAAMA" + + "AAACAAAA5AAAAAQAAAABAAAA/AAAAAUAAAAEAAAABAEAAAYAAAABAAAAJAEAAAIgAAAUAAAARAEA" + + "AAEQAAABAAAAZAIAAAMgAAACAAAAbAIAAAEgAAACAAAAfAIAAAAgAAABAAAAuAIAAAQgAAACAAAA" + + "yAIAAAMQAAABAAAA2AIAAAYgAAABAAAA5AIAAAAQAAABAAAA9AIAAA=="); + + /** + * base64 encoded class/dex file for + * static class Transform { + * public void sayHi() { + * System.out.println("Goodbye"); + * } + * } + */ + private static final byte[] CLASS_BYTES_B = Base64.getDecoder().decode( + "yv66vgAAADQAIAoABgAOCQAPABAIABEKABIAEwcAFQcAGAEABjxpbml0PgEAAygpVgEABENvZGUB" + + "AA9MaW5lTnVtYmVyVGFibGUBAAVzYXlIaQEAClNvdXJjZUZpbGUBAAxUZXN0OTMyLmphdmEMAAcA" + + "CAcAGQwAGgAbAQAHR29vZGJ5ZQcAHAwAHQAeBwAfAQAVYXJ0L1Rlc3Q5MzIkVHJhbnNmb3JtAQAJ" + + "VHJhbnNmb3JtAQAMSW5uZXJDbGFzc2VzAQAQamF2YS9sYW5nL09iamVjdAEAEGphdmEvbGFuZy9T" + + "eXN0ZW0BAANvdXQBABVMamF2YS9pby9QcmludFN0cmVhbTsBABNqYXZhL2lvL1ByaW50U3RyZWFt" + + "AQAHcHJpbnRsbgEAFShMamF2YS9sYW5nL1N0cmluZzspVgEAC2FydC9UZXN0OTMyACAABQAGAAAA" + + "AAACAAAABwAIAAEACQAAAB0AAQABAAAABSq3AAGxAAAAAQAKAAAABgABAAAABQABAAsACAABAAkA" + + "AAAlAAIAAQAAAAmyAAISA7YABLEAAAABAAoAAAAKAAIAAAAHAAgACAACAAwAAAACAA0AFwAAAAoA" + + "AQAFABQAFgAI"); + private static final byte[] DEX_BYTES_B = Base64.getDecoder().decode( + "ZGV4CjAzNQByglN3AAAAAAAAAAAAAAAAAAAAAAAAAAC4AwAAcAAAAHhWNBIAAAAAAAAAAPQCAAAU" + + "AAAAcAAAAAkAAADAAAAAAgAAAOQAAAABAAAA/AAAAAQAAAAEAQAAAQAAACQBAAB0AgAARAEAAEQB" + + "AABMAQAAVQEAAG4BAAB9AQAAoQEAAMEBAADYAQAA7AEAAAACAAAUAgAAIgIAAC0CAAAwAgAANAIA" + + "AEECAABHAgAATAIAAFUCAABcAgAAAgAAAAMAAAAEAAAABQAAAAYAAAAHAAAACAAAAAkAAAAMAAAA" + + "DAAAAAgAAAAAAAAADQAAAAgAAABkAgAABwAEABAAAAAAAAAAAAAAAAAAAAASAAAABAABABEAAAAF" + + "AAAAAAAAAAAAAAAAAAAABQAAAAAAAAAKAAAA5AIAALgCAAAAAAAABjxpbml0PgAHR29vZGJ5ZQAX" + + "TGFydC9UZXN0OTMyJFRyYW5zZm9ybTsADUxhcnQvVGVzdDkzMjsAIkxkYWx2aWsvYW5ub3RhdGlv" + + "bi9FbmNsb3NpbmdDbGFzczsAHkxkYWx2aWsvYW5ub3RhdGlvbi9Jbm5lckNsYXNzOwAVTGphdmEv" + + "aW8vUHJpbnRTdHJlYW07ABJMamF2YS9sYW5nL09iamVjdDsAEkxqYXZhL2xhbmcvU3RyaW5nOwAS" + + "TGphdmEvbGFuZy9TeXN0ZW07AAxUZXN0OTMyLmphdmEACVRyYW5zZm9ybQABVgACVkwAC2FjY2Vz" + + "c0ZsYWdzAARuYW1lAANvdXQAB3ByaW50bG4ABXNheUhpAAV2YWx1ZQAAAQAAAAYAAAAFAAcOAAcA" + + "Bw4BCA8AAAAAAQABAAEAAABsAgAABAAAAHAQAwAAAA4AAwABAAIAAABxAgAACQAAAGIAAAAbAQEA" + + "AABuIAIAEAAOAAAAAAABAQCAgAT8BAEBlAUAAAICARMYAQIDAg4ECA8XCwACAAAAyAIAAM4CAADY" + + "AgAAAAAAAAAAAAAAAAAAEAAAAAAAAAABAAAAAAAAAAEAAAAUAAAAcAAAAAIAAAAJAAAAwAAAAAMA" + + "AAACAAAA5AAAAAQAAAABAAAA/AAAAAUAAAAEAAAABAEAAAYAAAABAAAAJAEAAAIgAAAUAAAARAEA" + + "AAEQAAABAAAAZAIAAAMgAAACAAAAbAIAAAEgAAACAAAAfAIAAAAgAAABAAAAuAIAAAQgAAACAAAA" + + "yAIAAAMQAAABAAAA2AIAAAYgAAABAAAA5AIAAAAQAAABAAAA9AIAAA=="); + + public static void run() { + Redefinition.setTestConfiguration(Redefinition.Config.COMMON_RETRANSFORM); + doTest(new Transform()); + } + + public static void doTest(Transform t) { + // TODO We currently need to do this transform call since we don't have any way to make the + // original-dex-file a single-class dex-file letting us restore it easily. We should use the + // manipulation library that is being made when we store the original dex file. + // TODO REMOVE this theoretically does nothing but it ensures the original-dex-file we have set + // is one we can return to unaltered. + Redefinition.doCommonClassRedefinition(Transform.class, CLASS_BYTES_A, DEX_BYTES_A); + t.sayHi(); + + // Now turn it into DEX_BYTES_B so it says 'Goodbye' + Redefinition.addCommonTransformationResult("art/Test932$Transform", CLASS_BYTES_B, DEX_BYTES_B); + Redefinition.enableCommonRetransformation(true); + Redefinition.doCommonClassRetransformation(Transform.class); + t.sayHi(); + + // Now turn it back to normal by removing the load-hook and transforming again. + Redefinition.enableCommonRetransformation(false); + Redefinition.doCommonClassRetransformation(Transform.class); + t.sayHi(); + } +} diff --git a/test/934-load-transform/src/Main.java b/test/934-load-transform/src/Main.java index 606ce78a5b..69c839fdb2 100644 --- a/test/934-load-transform/src/Main.java +++ b/test/934-load-transform/src/Main.java @@ -14,6 +14,10 @@ * limitations under the License. */ +import static art.Redefinition.addCommonTransformationResult; +import static art.Redefinition.enableCommonRetransformation; +import static art.Redefinition.setPopRetransformations; + import java.lang.reflect.*; import java.util.Base64; @@ -86,11 +90,4 @@ class Main { e.printStackTrace(); } } - - private static native void setPopRetransformations(boolean should_pop); - // Transforms the class - private static native void enableCommonRetransformation(boolean enable); - private static native void addCommonTransformationResult(String target_name, - byte[] class_bytes, - byte[] dex_bytes); } diff --git a/test/934-load-transform/src/art/Redefinition.java b/test/934-load-transform/src/art/Redefinition.java new file mode 100644 index 0000000000..0350ab42ad --- /dev/null +++ b/test/934-load-transform/src/art/Redefinition.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.util.ArrayList; +// Common Redefinition functions. Placed here for use by CTS +public class Redefinition { + // Bind native functions. + static { + Main.bindAgentJNIForClass(Redefinition.class); + } + + public static final class CommonClassDefinition { + public final Class<?> target; + public final byte[] class_file_bytes; + public final byte[] dex_file_bytes; + + public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { + this.target = target; + this.class_file_bytes = class_file_bytes; + this.dex_file_bytes = dex_file_bytes; + } + } + + // A set of possible test configurations. Test should set this if they need to. + // This must be kept in sync with the defines in ti-agent/common_helper.cc + public static enum Config { + COMMON_REDEFINE(0), + COMMON_RETRANSFORM(1), + COMMON_TRANSFORM(2); + + private final int val; + private Config(int val) { + this.val = val; + } + } + + public static void setTestConfiguration(Config type) { + nativeSetTestConfiguration(type.val); + } + + private static native void nativeSetTestConfiguration(int type); + + // Transforms the class + public static native void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile); + + public static void doMultiClassRedefinition(CommonClassDefinition... defs) { + ArrayList<Class<?>> classes = new ArrayList<>(); + ArrayList<byte[]> class_files = new ArrayList<>(); + ArrayList<byte[]> dex_files = new ArrayList<>(); + + for (CommonClassDefinition d : defs) { + classes.add(d.target); + class_files.add(d.class_file_bytes); + dex_files.add(d.dex_file_bytes); + } + doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), + class_files.toArray(new byte[0][]), + dex_files.toArray(new byte[0][])); + } + + public static void addMultiTransformationResults(CommonClassDefinition... defs) { + for (CommonClassDefinition d : defs) { + addCommonTransformationResult(d.target.getCanonicalName(), + d.class_file_bytes, + d.dex_file_bytes); + } + } + + public static native void doCommonMultiClassRedefinition(Class<?>[] targets, + byte[][] classfiles, + byte[][] dexfiles); + public static native void doCommonClassRetransformation(Class<?>... target); + public static native void setPopRetransformations(boolean pop); + public static native void popTransformationFor(String name); + public static native void enableCommonRetransformation(boolean enable); + public static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); +} diff --git a/test/935-non-retransformable/src/Main.java b/test/935-non-retransformable/src/Main.java index df92561784..f240224977 100644 --- a/test/935-non-retransformable/src/Main.java +++ b/test/935-non-retransformable/src/Main.java @@ -17,6 +17,8 @@ import java.lang.reflect.*; import java.util.Base64; +import art.Redefinition; + class Main { public static String TEST_NAME = "935-non-retransformable"; @@ -74,10 +76,9 @@ class Main { } public static void main(String[] args) { - art.Main.bindAgentJNIForClass(Main.class); - setPopRetransformations(false); - addCommonTransformationResult("Transform", CLASS_BYTES, DEX_BYTES); - enableCommonRetransformation(true); + Redefinition.setPopRetransformations(false); + Redefinition.addCommonTransformationResult("Transform", CLASS_BYTES, DEX_BYTES); + Redefinition.enableCommonRetransformation(true); try { /* this is the "alternate" DEX/Jar file */ ClassLoader new_loader = getClassLoaderFor(System.getenv("DEX_LOCATION")); @@ -89,23 +90,14 @@ class Main { run_test.invoke(null); // Remove the original transformation. It has been used by now. - popTransformationFor("Transform"); + Redefinition.popTransformationFor("Transform"); // Make sure we don't get called for transformation again. - addCommonTransformationResult("Transform", new byte[0], new byte[0]); - doCommonClassRetransformation(new_loader.loadClass("Transform")); + Redefinition.addCommonTransformationResult("Transform", new byte[0], new byte[0]); + Redefinition.doCommonClassRetransformation(new_loader.loadClass("Transform")); run_test.invoke(null); } catch (Exception e) { System.out.println(e.toString()); e.printStackTrace(); } } - - // Transforms the class - private static native void doCommonClassRetransformation(Class<?>... classes); - private static native void enableCommonRetransformation(boolean enable); - private static native void addCommonTransformationResult(String target_name, - byte[] class_bytes, - byte[] dex_bytes); - private static native void setPopRetransformations(boolean should_pop); - private static native void popTransformationFor(String target_name); } diff --git a/test/935-non-retransformable/src/art/Redefinition.java b/test/935-non-retransformable/src/art/Redefinition.java new file mode 100644 index 0000000000..0350ab42ad --- /dev/null +++ b/test/935-non-retransformable/src/art/Redefinition.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.util.ArrayList; +// Common Redefinition functions. Placed here for use by CTS +public class Redefinition { + // Bind native functions. + static { + Main.bindAgentJNIForClass(Redefinition.class); + } + + public static final class CommonClassDefinition { + public final Class<?> target; + public final byte[] class_file_bytes; + public final byte[] dex_file_bytes; + + public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { + this.target = target; + this.class_file_bytes = class_file_bytes; + this.dex_file_bytes = dex_file_bytes; + } + } + + // A set of possible test configurations. Test should set this if they need to. + // This must be kept in sync with the defines in ti-agent/common_helper.cc + public static enum Config { + COMMON_REDEFINE(0), + COMMON_RETRANSFORM(1), + COMMON_TRANSFORM(2); + + private final int val; + private Config(int val) { + this.val = val; + } + } + + public static void setTestConfiguration(Config type) { + nativeSetTestConfiguration(type.val); + } + + private static native void nativeSetTestConfiguration(int type); + + // Transforms the class + public static native void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile); + + public static void doMultiClassRedefinition(CommonClassDefinition... defs) { + ArrayList<Class<?>> classes = new ArrayList<>(); + ArrayList<byte[]> class_files = new ArrayList<>(); + ArrayList<byte[]> dex_files = new ArrayList<>(); + + for (CommonClassDefinition d : defs) { + classes.add(d.target); + class_files.add(d.class_file_bytes); + dex_files.add(d.dex_file_bytes); + } + doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), + class_files.toArray(new byte[0][]), + dex_files.toArray(new byte[0][])); + } + + public static void addMultiTransformationResults(CommonClassDefinition... defs) { + for (CommonClassDefinition d : defs) { + addCommonTransformationResult(d.target.getCanonicalName(), + d.class_file_bytes, + d.dex_file_bytes); + } + } + + public static native void doCommonMultiClassRedefinition(Class<?>[] targets, + byte[][] classfiles, + byte[][] dexfiles); + public static native void doCommonClassRetransformation(Class<?>... target); + public static native void setPopRetransformations(boolean pop); + public static native void popTransformationFor(String name); + public static native void enableCommonRetransformation(boolean enable); + public static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); +} diff --git a/test/937-hello-retransform-package/src/Main.java b/test/937-hello-retransform-package/src/Main.java index 866f75d5e6..eef56c2c34 100644 --- a/test/937-hello-retransform-package/src/Main.java +++ b/test/937-hello-retransform-package/src/Main.java @@ -17,6 +17,8 @@ import java.util.Base64; import testing.*; +import art.Redefinition; + public class Main { /** @@ -53,22 +55,14 @@ public class Main { "YgEAAAMgAAACAAAAGwIAAAAgAAABAAAAJgIAAAAQAAABAAAANAIAAA=="); public static void main(String[] args) { - art.Main.bindAgentJNIForClass(Main.class); doTest(new Transform()); } public static void doTest(Transform t) { t.sayHi(); - addCommonTransformationResult("testing/Transform", CLASS_BYTES, DEX_BYTES); - enableCommonRetransformation(true); - doCommonClassRetransformation(Transform.class); + Redefinition.addCommonTransformationResult("testing/Transform", CLASS_BYTES, DEX_BYTES); + Redefinition.enableCommonRetransformation(true); + Redefinition.doCommonClassRetransformation(Transform.class); t.sayHi(); } - - // Transforms the class - private static native void doCommonClassRetransformation(Class<?>... target); - private static native void enableCommonRetransformation(boolean enable); - private static native void addCommonTransformationResult(String target_name, - byte[] class_bytes, - byte[] dex_bytes); } diff --git a/test/937-hello-retransform-package/src/art/Redefinition.java b/test/937-hello-retransform-package/src/art/Redefinition.java new file mode 100644 index 0000000000..0350ab42ad --- /dev/null +++ b/test/937-hello-retransform-package/src/art/Redefinition.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.util.ArrayList; +// Common Redefinition functions. Placed here for use by CTS +public class Redefinition { + // Bind native functions. + static { + Main.bindAgentJNIForClass(Redefinition.class); + } + + public static final class CommonClassDefinition { + public final Class<?> target; + public final byte[] class_file_bytes; + public final byte[] dex_file_bytes; + + public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { + this.target = target; + this.class_file_bytes = class_file_bytes; + this.dex_file_bytes = dex_file_bytes; + } + } + + // A set of possible test configurations. Test should set this if they need to. + // This must be kept in sync with the defines in ti-agent/common_helper.cc + public static enum Config { + COMMON_REDEFINE(0), + COMMON_RETRANSFORM(1), + COMMON_TRANSFORM(2); + + private final int val; + private Config(int val) { + this.val = val; + } + } + + public static void setTestConfiguration(Config type) { + nativeSetTestConfiguration(type.val); + } + + private static native void nativeSetTestConfiguration(int type); + + // Transforms the class + public static native void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile); + + public static void doMultiClassRedefinition(CommonClassDefinition... defs) { + ArrayList<Class<?>> classes = new ArrayList<>(); + ArrayList<byte[]> class_files = new ArrayList<>(); + ArrayList<byte[]> dex_files = new ArrayList<>(); + + for (CommonClassDefinition d : defs) { + classes.add(d.target); + class_files.add(d.class_file_bytes); + dex_files.add(d.dex_file_bytes); + } + doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), + class_files.toArray(new byte[0][]), + dex_files.toArray(new byte[0][])); + } + + public static void addMultiTransformationResults(CommonClassDefinition... defs) { + for (CommonClassDefinition d : defs) { + addCommonTransformationResult(d.target.getCanonicalName(), + d.class_file_bytes, + d.dex_file_bytes); + } + } + + public static native void doCommonMultiClassRedefinition(Class<?>[] targets, + byte[][] classfiles, + byte[][] dexfiles); + public static native void doCommonClassRetransformation(Class<?>... target); + public static native void setPopRetransformations(boolean pop); + public static native void popTransformationFor(String name); + public static native void enableCommonRetransformation(boolean enable); + public static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); +} diff --git a/test/938-load-transform-bcp/src/Main.java b/test/938-load-transform-bcp/src/Main.java index 21b841f06a..e560942729 100644 --- a/test/938-load-transform-bcp/src/Main.java +++ b/test/938-load-transform-bcp/src/Main.java @@ -14,6 +14,7 @@ * limitations under the License. */ +import static art.Redefinition.*; import java.lang.reflect.*; import java.util.Base64; @@ -114,11 +115,4 @@ class Main { e.printStackTrace(); } } - - private static native void setPopRetransformations(boolean should_pop); - // Transforms the class - private static native void enableCommonRetransformation(boolean enable); - private static native void addCommonTransformationResult(String target_name, - byte[] class_bytes, - byte[] dex_bytes); } diff --git a/test/938-load-transform-bcp/src/art/Redefinition.java b/test/938-load-transform-bcp/src/art/Redefinition.java new file mode 100644 index 0000000000..0350ab42ad --- /dev/null +++ b/test/938-load-transform-bcp/src/art/Redefinition.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.util.ArrayList; +// Common Redefinition functions. Placed here for use by CTS +public class Redefinition { + // Bind native functions. + static { + Main.bindAgentJNIForClass(Redefinition.class); + } + + public static final class CommonClassDefinition { + public final Class<?> target; + public final byte[] class_file_bytes; + public final byte[] dex_file_bytes; + + public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { + this.target = target; + this.class_file_bytes = class_file_bytes; + this.dex_file_bytes = dex_file_bytes; + } + } + + // A set of possible test configurations. Test should set this if they need to. + // This must be kept in sync with the defines in ti-agent/common_helper.cc + public static enum Config { + COMMON_REDEFINE(0), + COMMON_RETRANSFORM(1), + COMMON_TRANSFORM(2); + + private final int val; + private Config(int val) { + this.val = val; + } + } + + public static void setTestConfiguration(Config type) { + nativeSetTestConfiguration(type.val); + } + + private static native void nativeSetTestConfiguration(int type); + + // Transforms the class + public static native void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile); + + public static void doMultiClassRedefinition(CommonClassDefinition... defs) { + ArrayList<Class<?>> classes = new ArrayList<>(); + ArrayList<byte[]> class_files = new ArrayList<>(); + ArrayList<byte[]> dex_files = new ArrayList<>(); + + for (CommonClassDefinition d : defs) { + classes.add(d.target); + class_files.add(d.class_file_bytes); + dex_files.add(d.dex_file_bytes); + } + doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), + class_files.toArray(new byte[0][]), + dex_files.toArray(new byte[0][])); + } + + public static void addMultiTransformationResults(CommonClassDefinition... defs) { + for (CommonClassDefinition d : defs) { + addCommonTransformationResult(d.target.getCanonicalName(), + d.class_file_bytes, + d.dex_file_bytes); + } + } + + public static native void doCommonMultiClassRedefinition(Class<?>[] targets, + byte[][] classfiles, + byte[][] dexfiles); + public static native void doCommonClassRetransformation(Class<?>... target); + public static native void setPopRetransformations(boolean pop); + public static native void popTransformationFor(String name); + public static native void enableCommonRetransformation(boolean enable); + public static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); +} diff --git a/test/939-hello-transformation-bcp/src/Main.java b/test/939-hello-transformation-bcp/src/Main.java index 0e1f845ab9..7bda667357 100644 --- a/test/939-hello-transformation-bcp/src/Main.java +++ b/test/939-hello-transformation-bcp/src/Main.java @@ -14,6 +14,7 @@ * limitations under the License. */ +import static art.Redefinition.doCommonClassRedefinition; import java.util.Base64; import java.util.OptionalLong; public class Main { @@ -110,7 +111,6 @@ public class Main { "AABHBgAABCAAAAIAAACVBgAAACAAAAEAAACtBgAAABAAAAEAAAD4BgAA"); public static void main(String[] args) { - art.Main.bindAgentJNIForClass(Main.class); // OptionalLong is a class that is unlikely to be used by the time this test starts and is not // likely to be changed in any meaningful way in the future. OptionalLong ol = OptionalLong.of(0xDEADBEEF); @@ -119,9 +119,4 @@ public class Main { doCommonClassRedefinition(OptionalLong.class, CLASS_BYTES, DEX_BYTES); System.out.println("ol.toString() -> '" + ol.toString() + "'"); } - - // Transforms the class - private static native void doCommonClassRedefinition(Class<?> target, - byte[] class_file, - byte[] dex_file); } diff --git a/test/939-hello-transformation-bcp/src/art/Redefinition.java b/test/939-hello-transformation-bcp/src/art/Redefinition.java new file mode 100644 index 0000000000..0350ab42ad --- /dev/null +++ b/test/939-hello-transformation-bcp/src/art/Redefinition.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.util.ArrayList; +// Common Redefinition functions. Placed here for use by CTS +public class Redefinition { + // Bind native functions. + static { + Main.bindAgentJNIForClass(Redefinition.class); + } + + public static final class CommonClassDefinition { + public final Class<?> target; + public final byte[] class_file_bytes; + public final byte[] dex_file_bytes; + + public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { + this.target = target; + this.class_file_bytes = class_file_bytes; + this.dex_file_bytes = dex_file_bytes; + } + } + + // A set of possible test configurations. Test should set this if they need to. + // This must be kept in sync with the defines in ti-agent/common_helper.cc + public static enum Config { + COMMON_REDEFINE(0), + COMMON_RETRANSFORM(1), + COMMON_TRANSFORM(2); + + private final int val; + private Config(int val) { + this.val = val; + } + } + + public static void setTestConfiguration(Config type) { + nativeSetTestConfiguration(type.val); + } + + private static native void nativeSetTestConfiguration(int type); + + // Transforms the class + public static native void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile); + + public static void doMultiClassRedefinition(CommonClassDefinition... defs) { + ArrayList<Class<?>> classes = new ArrayList<>(); + ArrayList<byte[]> class_files = new ArrayList<>(); + ArrayList<byte[]> dex_files = new ArrayList<>(); + + for (CommonClassDefinition d : defs) { + classes.add(d.target); + class_files.add(d.class_file_bytes); + dex_files.add(d.dex_file_bytes); + } + doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), + class_files.toArray(new byte[0][]), + dex_files.toArray(new byte[0][])); + } + + public static void addMultiTransformationResults(CommonClassDefinition... defs) { + for (CommonClassDefinition d : defs) { + addCommonTransformationResult(d.target.getCanonicalName(), + d.class_file_bytes, + d.dex_file_bytes); + } + } + + public static native void doCommonMultiClassRedefinition(Class<?>[] targets, + byte[][] classfiles, + byte[][] dexfiles); + public static native void doCommonClassRetransformation(Class<?>... target); + public static native void setPopRetransformations(boolean pop); + public static native void popTransformationFor(String name); + public static native void enableCommonRetransformation(boolean enable); + public static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); +} diff --git a/test/940-recursive-obsolete/src/Main.java b/test/940-recursive-obsolete/src/Main.java index 724f82de27..0b0211c2c3 100644 --- a/test/940-recursive-obsolete/src/Main.java +++ b/test/940-recursive-obsolete/src/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,77 +14,8 @@ * limitations under the License. */ -import java.util.Base64; - public class Main { - - // class Transform { - // public void sayHi(int recur, Runnable r) { - // System.out.println("Hello" + recur + " - transformed"); - // if (recur == 1) { - // r.run(); - // sayHi(recur - 1, r); - // } else if (recur != 0) { - // sayHi(recur - 1, r); - // } - // System.out.println("Goodbye" + recur + " - transformed"); - // } - // } - private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( - "yv66vgAAADQANwoADwAZCQAaABsHABwKAAMAGQgAHQoAAwAeCgADAB8IACAKAAMAIQoAIgAjCwAk" + - "ACUKAA4AJggAJwcAKAcAKQEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUB" + - "AAVzYXlIaQEAGChJTGphdmEvbGFuZy9SdW5uYWJsZTspVgEADVN0YWNrTWFwVGFibGUBAApTb3Vy" + - "Y2VGaWxlAQAOVHJhbnNmb3JtLmphdmEMABAAEQcAKgwAKwAsAQAXamF2YS9sYW5nL1N0cmluZ0J1" + - "aWxkZXIBAAVIZWxsbwwALQAuDAAtAC8BAA4gLSB0cmFuc2Zvcm1lZAwAMAAxBwAyDAAzADQHADUM" + - "ADYAEQwAFAAVAQAHR29vZGJ5ZQEACVRyYW5zZm9ybQEAEGphdmEvbGFuZy9PYmplY3QBABBqYXZh" + - "L2xhbmcvU3lzdGVtAQADb3V0AQAVTGphdmEvaW8vUHJpbnRTdHJlYW07AQAGYXBwZW5kAQAtKExq" + - "YXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1N0cmluZ0J1aWxkZXI7AQAcKEkpTGphdmEvbGFu" + - "Zy9TdHJpbmdCdWlsZGVyOwEACHRvU3RyaW5nAQAUKClMamF2YS9sYW5nL1N0cmluZzsBABNqYXZh" + - "L2lvL1ByaW50U3RyZWFtAQAHcHJpbnRsbgEAFShMamF2YS9sYW5nL1N0cmluZzspVgEAEmphdmEv" + - "bGFuZy9SdW5uYWJsZQEAA3J1bgAgAA4ADwAAAAAAAgAAABAAEQABABIAAAAdAAEAAQAAAAUqtwAB" + - "sQAAAAEAEwAAAAYAAQAAAAEAAQAUABUAAQASAAAAnQADAAMAAABfsgACuwADWbcABBIFtgAGG7YA" + - "BxIItgAGtgAJtgAKGwSgABQsuQALAQAqGwRkLLYADKcADxuZAAsqGwRkLLYADLIAArsAA1m3AAQS" + - "DbYABhu2AAcSCLYABrYACbYACrEAAAACABMAAAAiAAgAAAADAB4ABAAjAAUAKQAGADQABwA4AAgA" + - "QAAKAF4ACwAWAAAABAACNAsAAQAXAAAAAgAY"); - private static final byte[] DEX_BYTES = Base64.getDecoder().decode( - "ZGV4CjAzNQA3pkIgnymz2/eri+mp2dyZo3jolQmaRPKEBAAAcAAAAHhWNBIAAAAAAAAAAOQDAAAa" + - "AAAAcAAAAAkAAADYAAAABgAAAPwAAAABAAAARAEAAAkAAABMAQAAAQAAAJQBAADQAgAAtAEAAJwC" + - "AACsAgAAtAIAAL0CAADEAgAAxwIAAMoCAADOAgAA0gIAAN8CAAD2AgAACgMAACADAAA0AwAATwMA" + - "AGMDAABzAwAAdgMAAHsDAAB/AwAAhwMAAJsDAACgAwAAqQMAAK4DAAC1AwAABAAAAAgAAAAJAAAA" + - "CgAAAAsAAAAMAAAADQAAAA4AAAAQAAAABQAAAAUAAAAAAAAABgAAAAYAAACEAgAABwAAAAYAAACM" + - "AgAAEAAAAAgAAAAAAAAAEQAAAAgAAACUAgAAEgAAAAgAAACMAgAABwACABUAAAABAAMAAQAAAAEA" + - "BAAYAAAAAgAFABYAAAADAAMAAQAAAAQAAwAXAAAABgADAAEAAAAGAAEAEwAAAAYAAgATAAAABgAA" + - "ABkAAAABAAAAAAAAAAMAAAAAAAAADwAAAAAAAADWAwAAAAAAAAEAAQABAAAAvwMAAAQAAABwEAMA" + - "AAAOAAYAAwADAAAAxAMAAFQAAABiAAAAIgEGAHAQBQABABsCAwAAAG4gBwAhAAwBbiAGAEEADAEb" + - "AgAAAABuIAcAIQAMAW4QCAABAAwBbiACABAAEhAzBCsAchAEAAUA2AAE/24wAQADBWIAAAAiAQYA" + - "cBAFAAEAGwICAAAAbiAHACEADAFuIAYAQQAMARsCAAAAAG4gBwAhAAwBbhAIAAEADAFuIAIAEAAO" + - "ADgE3//YAAT/bjABAAMFKNgBAAAAAAAAAAEAAAAFAAAAAgAAAAAABAAOIC0gdHJhbnNmb3JtZWQA" + - "Bjxpbml0PgAHR29vZGJ5ZQAFSGVsbG8AAUkAAUwAAkxJAAJMTAALTFRyYW5zZm9ybTsAFUxqYXZh" + - "L2lvL1ByaW50U3RyZWFtOwASTGphdmEvbGFuZy9PYmplY3Q7ABRMamF2YS9sYW5nL1J1bm5hYmxl" + - "OwASTGphdmEvbGFuZy9TdHJpbmc7ABlMamF2YS9sYW5nL1N0cmluZ0J1aWxkZXI7ABJMamF2YS9s" + - "YW5nL1N5c3RlbTsADlRyYW5zZm9ybS5qYXZhAAFWAANWSUwAAlZMAAZhcHBlbmQAEmVtaXR0ZXI6" + - "IGphY2stNC4yNAADb3V0AAdwcmludGxuAANydW4ABXNheUhpAAh0b1N0cmluZwABAAcOAAMCAAAH" + - "DgEgDzw8XQEgDxktAAAAAQEAgIAEtAMBAcwDDQAAAAAAAAABAAAAAAAAAAEAAAAaAAAAcAAAAAIA" + - "AAAJAAAA2AAAAAMAAAAGAAAA/AAAAAQAAAABAAAARAEAAAUAAAAJAAAATAEAAAYAAAABAAAAlAEA" + - "AAEgAAACAAAAtAEAAAEQAAADAAAAhAIAAAIgAAAaAAAAnAIAAAMgAAACAAAAvwMAAAAgAAABAAAA" + - "1gMAAAAQAAABAAAA5AMAAA=="); - - public static void main(String[] args) { - art.Main.bindAgentJNIForClass(Main.class); - doTest(new Transform()); + public static void main(String[] args) throws Exception { + art.Test940.run(); } - - public static void doTest(Transform t) { - t.sayHi(2, () -> { System.out.println("Not doing anything here"); }); - t.sayHi(2, () -> { - System.out.println("transforming calling function"); - doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES); - }); - t.sayHi(2, () -> { System.out.println("Not doing anything here"); }); - } - - // Transforms the class - private static native void doCommonClassRedefinition(Class<?> target, - byte[] classfile, - byte[] dexfile); } diff --git a/test/940-recursive-obsolete/src/Transform.java b/test/940-recursive-obsolete/src/Transform.java deleted file mode 100644 index 97522cddf6..0000000000 --- a/test/940-recursive-obsolete/src/Transform.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * 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. - */ - -class Transform { - public void sayHi(int recur, Runnable r) { - System.out.println("hello" + recur); - if (recur == 1) { - r.run(); - sayHi(recur - 1, r); - } else if (recur != 0) { - sayHi(recur - 1, r); - } - System.out.println("goodbye" + recur); - } -} diff --git a/test/940-recursive-obsolete/src/art/Redefinition.java b/test/940-recursive-obsolete/src/art/Redefinition.java new file mode 100644 index 0000000000..0350ab42ad --- /dev/null +++ b/test/940-recursive-obsolete/src/art/Redefinition.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.util.ArrayList; +// Common Redefinition functions. Placed here for use by CTS +public class Redefinition { + // Bind native functions. + static { + Main.bindAgentJNIForClass(Redefinition.class); + } + + public static final class CommonClassDefinition { + public final Class<?> target; + public final byte[] class_file_bytes; + public final byte[] dex_file_bytes; + + public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { + this.target = target; + this.class_file_bytes = class_file_bytes; + this.dex_file_bytes = dex_file_bytes; + } + } + + // A set of possible test configurations. Test should set this if they need to. + // This must be kept in sync with the defines in ti-agent/common_helper.cc + public static enum Config { + COMMON_REDEFINE(0), + COMMON_RETRANSFORM(1), + COMMON_TRANSFORM(2); + + private final int val; + private Config(int val) { + this.val = val; + } + } + + public static void setTestConfiguration(Config type) { + nativeSetTestConfiguration(type.val); + } + + private static native void nativeSetTestConfiguration(int type); + + // Transforms the class + public static native void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile); + + public static void doMultiClassRedefinition(CommonClassDefinition... defs) { + ArrayList<Class<?>> classes = new ArrayList<>(); + ArrayList<byte[]> class_files = new ArrayList<>(); + ArrayList<byte[]> dex_files = new ArrayList<>(); + + for (CommonClassDefinition d : defs) { + classes.add(d.target); + class_files.add(d.class_file_bytes); + dex_files.add(d.dex_file_bytes); + } + doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), + class_files.toArray(new byte[0][]), + dex_files.toArray(new byte[0][])); + } + + public static void addMultiTransformationResults(CommonClassDefinition... defs) { + for (CommonClassDefinition d : defs) { + addCommonTransformationResult(d.target.getCanonicalName(), + d.class_file_bytes, + d.dex_file_bytes); + } + } + + public static native void doCommonMultiClassRedefinition(Class<?>[] targets, + byte[][] classfiles, + byte[][] dexfiles); + public static native void doCommonClassRetransformation(Class<?>... target); + public static native void setPopRetransformations(boolean pop); + public static native void popTransformationFor(String name); + public static native void enableCommonRetransformation(boolean enable); + public static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); +} diff --git a/test/940-recursive-obsolete/src/art/Test940.java b/test/940-recursive-obsolete/src/art/Test940.java new file mode 100644 index 0000000000..d67d7726da --- /dev/null +++ b/test/940-recursive-obsolete/src/art/Test940.java @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * 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 art; + +import java.util.Base64; + +public class Test940 { + + static class Transform { + public void sayHi(int recur, Runnable r) { + System.out.println("hello" + recur); + if (recur == 1) { + r.run(); + sayHi(recur - 1, r); + } else if (recur != 0) { + sayHi(recur - 1, r); + } + System.out.println("goodbye" + recur); + } + } + + + // static class Transform { + // public void sayHi(int recur, Runnable r) { + // System.out.println("Hello" + recur + " - transformed"); + // if (recur == 1) { + // r.run(); + // sayHi(recur - 1, r); + // } else if (recur != 0) { + // sayHi(recur - 1, r); + // } + // System.out.println("Goodbye" + recur + " - transformed"); + // } + // } + private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( + "yv66vgAAADQAOwoADwAZCQAaABsHABwKAAMAGQgAHQoAAwAeCgADAB8IACAKAAMAIQoAIgAjCwAk" + + "ACUKAA4AJggAJwcAKQcALAEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUB" + + "AAVzYXlIaQEAGChJTGphdmEvbGFuZy9SdW5uYWJsZTspVgEADVN0YWNrTWFwVGFibGUBAApTb3Vy" + + "Y2VGaWxlAQAMVGVzdDk0MC5qYXZhDAAQABEHAC0MAC4ALwEAF2phdmEvbGFuZy9TdHJpbmdCdWls" + + "ZGVyAQAFSGVsbG8MADAAMQwAMAAyAQAOIC0gdHJhbnNmb3JtZWQMADMANAcANQwANgA3BwA4DAA5" + + "ABEMABQAFQEAB0dvb2RieWUHADoBABVhcnQvVGVzdDk0MCRUcmFuc2Zvcm0BAAlUcmFuc2Zvcm0B" + + "AAxJbm5lckNsYXNzZXMBABBqYXZhL2xhbmcvT2JqZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEAA291" + + "dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEABmFwcGVuZAEALShMamF2YS9sYW5nL1N0cmluZzsp" + + "TGphdmEvbGFuZy9TdHJpbmdCdWlsZGVyOwEAHChJKUxqYXZhL2xhbmcvU3RyaW5nQnVpbGRlcjsB" + + "AAh0b1N0cmluZwEAFCgpTGphdmEvbGFuZy9TdHJpbmc7AQATamF2YS9pby9QcmludFN0cmVhbQEA" + + "B3ByaW50bG4BABUoTGphdmEvbGFuZy9TdHJpbmc7KVYBABJqYXZhL2xhbmcvUnVubmFibGUBAANy" + + "dW4BAAthcnQvVGVzdDk0MAAgAA4ADwAAAAAAAgAAABAAEQABABIAAAAdAAEAAQAAAAUqtwABsQAA" + + "AAEAEwAAAAYAAQAAAAUAAQAUABUAAQASAAAAnQADAAMAAABfsgACuwADWbcABBIFtgAGG7YABxII" + + "tgAGtgAJtgAKGwSgABQsuQALAQAqGwRkLLYADKcADxuZAAsqGwRkLLYADLIAArsAA1m3AAQSDbYA" + + "Bhu2AAcSCLYABrYACbYACrEAAAACABMAAAAiAAgAAAAHAB4ACAAjAAkAKQAKADQACwA4AAwAQAAO" + + "AF4ADwAWAAAABAACNAsAAgAXAAAAAgAYACsAAAAKAAEADgAoACoACA=="); + private static final byte[] DEX_BYTES = Base64.getDecoder().decode( + "ZGV4CjAzNQDQv3jgAAAAAAAAAAAAAAAAAAAAAAAAAAB8BQAAcAAAAHhWNBIAAAAAAAAAALgEAAAg" + + "AAAAcAAAAAwAAADwAAAABgAAACABAAABAAAAaAEAAAkAAABwAQAAAQAAALgBAACkAwAA2AEAANgB" + + "AADoAQAA8AEAAPkBAAAAAgAAAwIAAAYCAAAKAgAADgIAACcCAAA2AgAAWgIAAHoCAACRAgAApQIA" + + "ALsCAADPAgAA6gIAAP4CAAAMAwAAFwMAABoDAAAfAwAAIwMAADADAAA4AwAAPgMAAEMDAABMAwAA" + + "UQMAAFgDAABiAwAABAAAAAgAAAAJAAAACgAAAAsAAAAMAAAADQAAAA4AAAAPAAAAEAAAABEAAAAU" + + "AAAABQAAAAgAAAAAAAAABgAAAAkAAAB8AwAABwAAAAkAAAB0AwAAFAAAAAsAAAAAAAAAFQAAAAsA" + + "AABsAwAAFgAAAAsAAAB0AwAACgAFABoAAAABAAMAAQAAAAEABAAdAAAABQAFABsAAAAGAAMAAQAA" + + "AAcAAwAcAAAACQADAAEAAAAJAAEAGAAAAAkAAgAYAAAACQAAAB4AAAABAAAAAAAAAAYAAAAAAAAA" + + "EgAAAKgEAAB8BAAAAAAAAA4gLSB0cmFuc2Zvcm1lZAAGPGluaXQ+AAdHb29kYnllAAVIZWxsbwAB" + + "SQABTAACTEkAAkxMABdMYXJ0L1Rlc3Q5NDAkVHJhbnNmb3JtOwANTGFydC9UZXN0OTQwOwAiTGRh" + + "bHZpay9hbm5vdGF0aW9uL0VuY2xvc2luZ0NsYXNzOwAeTGRhbHZpay9hbm5vdGF0aW9uL0lubmVy" + + "Q2xhc3M7ABVMamF2YS9pby9QcmludFN0cmVhbTsAEkxqYXZhL2xhbmcvT2JqZWN0OwAUTGphdmEv" + + "bGFuZy9SdW5uYWJsZTsAEkxqYXZhL2xhbmcvU3RyaW5nOwAZTGphdmEvbGFuZy9TdHJpbmdCdWls" + + "ZGVyOwASTGphdmEvbGFuZy9TeXN0ZW07AAxUZXN0OTQwLmphdmEACVRyYW5zZm9ybQABVgADVklM" + + "AAJWTAALYWNjZXNzRmxhZ3MABmFwcGVuZAAEbmFtZQADb3V0AAdwcmludGxuAANydW4ABXNheUhp" + + "AAh0b1N0cmluZwAFdmFsdWUAAAAAAgAAAAAABwABAAAACAAAAAEAAAAAAAAABQAHDgAHAgAABw4B" + + "IA8BAw8BAw8BBRIBIA8BAQoBAg8AAAAAAQABAAEAAACEAwAABAAAAHAQAwAAAA4ABgADAAMAAACJ" + + "AwAAVQAAAGIAAAAiAQkAcBAFAAEAGwIDAAAAbiAHACEADAFuIAYAQQAMARsCAAAAAG4gBwAhAAwB" + + "bhAIAAEADAFuIAIAEAASEDMEKwByEAQABQDYAAT/bjABAAMFYgAAACIBCQBwEAUAAQAbAgIAAABu" + + "IAcAIQAMAW4gBgBBAAwBGwIAAAAAbiAHACEADAFuEAgAAQAMAW4gAgAQAA4AOATf/9gABP9uMAEA" + + "AwUpANj/AAAAAAEBAICABKgHAQHABwAAAgMBHxgCAgQCFwQIGRcTAAIAAACMBAAAkgQAAJwEAAAA" + + "AAAAAAAAAAAAAAAQAAAAAAAAAAEAAAAAAAAAAQAAACAAAABwAAAAAgAAAAwAAADwAAAAAwAAAAYA" + + "AAAgAQAABAAAAAEAAABoAQAABQAAAAkAAABwAQAABgAAAAEAAAC4AQAAAiAAACAAAADYAQAAARAA" + + "AAMAAABsAwAAAyAAAAIAAACEAwAAASAAAAIAAACoAwAAACAAAAEAAAB8BAAABCAAAAIAAACMBAAA" + + "AxAAAAEAAACcBAAABiAAAAEAAACoBAAAABAAAAEAAAC4BAAA"); + + public static void run() { + Redefinition.setTestConfiguration(Redefinition.Config.COMMON_REDEFINE); + doTest(new Transform()); + } + + public static void doTest(Transform t) { + t.sayHi(2, () -> { System.out.println("Not doing anything here"); }); + t.sayHi(2, () -> { + System.out.println("transforming calling function"); + Redefinition.doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES); + }); + t.sayHi(2, () -> { System.out.println("Not doing anything here"); }); + } +} diff --git a/test/941-recurive-obsolete-jit/src/Main.java b/test/941-recurive-obsolete-jit/src/Main.java index d88bb9b722..1c391a4db5 100644 --- a/test/941-recurive-obsolete-jit/src/Main.java +++ b/test/941-recurive-obsolete-jit/src/Main.java @@ -14,6 +14,8 @@ * limitations under the License. */ +import static art.Redefinition.doCommonClassRedefinition; + import java.util.Base64; import java.util.function.Consumer; import java.lang.reflect.Method; @@ -148,9 +150,4 @@ public class Main { private static native boolean isInterpretedFunction(Method m, boolean require_deoptimizable); private static native void ensureJitCompiled(Class c, String name); - - // Transforms the class - private static native void doCommonClassRedefinition(Class<?> target, - byte[] classfile, - byte[] dexfile); } diff --git a/test/941-recurive-obsolete-jit/src/art/Redefinition.java b/test/941-recurive-obsolete-jit/src/art/Redefinition.java new file mode 100644 index 0000000000..0350ab42ad --- /dev/null +++ b/test/941-recurive-obsolete-jit/src/art/Redefinition.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.util.ArrayList; +// Common Redefinition functions. Placed here for use by CTS +public class Redefinition { + // Bind native functions. + static { + Main.bindAgentJNIForClass(Redefinition.class); + } + + public static final class CommonClassDefinition { + public final Class<?> target; + public final byte[] class_file_bytes; + public final byte[] dex_file_bytes; + + public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { + this.target = target; + this.class_file_bytes = class_file_bytes; + this.dex_file_bytes = dex_file_bytes; + } + } + + // A set of possible test configurations. Test should set this if they need to. + // This must be kept in sync with the defines in ti-agent/common_helper.cc + public static enum Config { + COMMON_REDEFINE(0), + COMMON_RETRANSFORM(1), + COMMON_TRANSFORM(2); + + private final int val; + private Config(int val) { + this.val = val; + } + } + + public static void setTestConfiguration(Config type) { + nativeSetTestConfiguration(type.val); + } + + private static native void nativeSetTestConfiguration(int type); + + // Transforms the class + public static native void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile); + + public static void doMultiClassRedefinition(CommonClassDefinition... defs) { + ArrayList<Class<?>> classes = new ArrayList<>(); + ArrayList<byte[]> class_files = new ArrayList<>(); + ArrayList<byte[]> dex_files = new ArrayList<>(); + + for (CommonClassDefinition d : defs) { + classes.add(d.target); + class_files.add(d.class_file_bytes); + dex_files.add(d.dex_file_bytes); + } + doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), + class_files.toArray(new byte[0][]), + dex_files.toArray(new byte[0][])); + } + + public static void addMultiTransformationResults(CommonClassDefinition... defs) { + for (CommonClassDefinition d : defs) { + addCommonTransformationResult(d.target.getCanonicalName(), + d.class_file_bytes, + d.dex_file_bytes); + } + } + + public static native void doCommonMultiClassRedefinition(Class<?>[] targets, + byte[][] classfiles, + byte[][] dexfiles); + public static native void doCommonClassRetransformation(Class<?>... target); + public static native void setPopRetransformations(boolean pop); + public static native void popTransformationFor(String name); + public static native void enableCommonRetransformation(boolean enable); + public static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); +} diff --git a/test/942-private-recursive/src/Main.java b/test/942-private-recursive/src/Main.java index cac75c02f8..8a1f7c6e04 100644 --- a/test/942-private-recursive/src/Main.java +++ b/test/942-private-recursive/src/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,82 +14,8 @@ * limitations under the License. */ -import java.util.Base64; - public class Main { - - // class Transform { - // public void sayHi(int recur, Runnable r) { - // privateSayHi(recur, r); - // } - // private void privateSayHi(int recur, Runnable r) { - // System.out.println("Hello" + recur + " - transformed"); - // if (recur == 1) { - // r.run(); - // privateSayHi(recur - 1, r); - // } else if (recur != 0) { - // privateSayHi(recur - 1, r); - // } - // System.out.println("Goodbye" + recur + " - transformed"); - // } - // } - private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( - "yv66vgAAADQAOAoADwAaCgAOABsJABwAHQcAHgoABAAaCAAfCgAEACAKAAQAIQgAIgoABAAjCgAk" + - "ACULACYAJwgAKAcAKQcAKgEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUB" + - "AAVzYXlIaQEAGChJTGphdmEvbGFuZy9SdW5uYWJsZTspVgEADHByaXZhdGVTYXlIaQEADVN0YWNr" + - "TWFwVGFibGUBAApTb3VyY2VGaWxlAQAOVHJhbnNmb3JtLmphdmEMABAAEQwAFgAVBwArDAAsAC0B" + - "ABdqYXZhL2xhbmcvU3RyaW5nQnVpbGRlcgEABUhlbGxvDAAuAC8MAC4AMAEADiAtIHRyYW5zZm9y" + - "bWVkDAAxADIHADMMADQANQcANgwANwARAQAHR29vZGJ5ZQEACVRyYW5zZm9ybQEAEGphdmEvbGFu" + - "Zy9PYmplY3QBABBqYXZhL2xhbmcvU3lzdGVtAQADb3V0AQAVTGphdmEvaW8vUHJpbnRTdHJlYW07" + - "AQAGYXBwZW5kAQAtKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1N0cmluZ0J1aWxkZXI7" + - "AQAcKEkpTGphdmEvbGFuZy9TdHJpbmdCdWlsZGVyOwEACHRvU3RyaW5nAQAUKClMamF2YS9sYW5n" + - "L1N0cmluZzsBABNqYXZhL2lvL1ByaW50U3RyZWFtAQAHcHJpbnRsbgEAFShMamF2YS9sYW5nL1N0" + - "cmluZzspVgEAEmphdmEvbGFuZy9SdW5uYWJsZQEAA3J1bgAgAA4ADwAAAAAAAwAAABAAEQABABIA" + - "AAAdAAEAAQAAAAUqtwABsQAAAAEAEwAAAAYAAQAAAAEAAQAUABUAAQASAAAAIwADAAMAAAAHKhss" + - "twACsQAAAAEAEwAAAAoAAgAAAAMABgAEAAIAFgAVAAEAEgAAAJ0AAwADAAAAX7IAA7sABFm3AAUS" + - "BrYABxu2AAgSCbYAB7YACrYACxsEoAAULLkADAEAKhsEZCy3AAKnAA8bmQALKhsEZCy3AAKyAAO7" + - "AARZtwAFEg22AAcbtgAIEgm2AAe2AAq2AAuxAAAAAgATAAAAIgAIAAAABgAeAAcAIwAIACkACQA0" + - "AAoAOAALAEAADQBeAA4AFwAAAAQAAjQLAAEAGAAAAAIAGQ=="); - private static final byte[] DEX_BYTES = Base64.getDecoder().decode( - "ZGV4CjAzNQBQqwVIiZvIuS8j1HDurKbXZEV62Mnug5PEBAAAcAAAAHhWNBIAAAAAAAAAACQEAAAb" + - "AAAAcAAAAAkAAADcAAAABgAAAAABAAABAAAASAEAAAoAAABQAQAAAQAAAKABAAAEAwAAwAEAAMAC" + - "AADQAgAA2AIAAOECAADoAgAA6wIAAO4CAADyAgAA9gIAAAMDAAAaAwAALgMAAEQDAABYAwAAcwMA" + - "AIcDAACXAwAAmgMAAJ8DAACjAwAAqwMAAL8DAADEAwAAzQMAANsDAADgAwAA5wMAAAQAAAAIAAAA" + - "CQAAAAoAAAALAAAADAAAAA0AAAAOAAAAEAAAAAUAAAAFAAAAAAAAAAYAAAAGAAAAqAIAAAcAAAAG" + - "AAAAsAIAABAAAAAIAAAAAAAAABEAAAAIAAAAuAIAABIAAAAIAAAAsAIAAAcAAgAVAAAAAQADAAEA" + - "AAABAAQAFwAAAAEABAAZAAAAAgAFABYAAAADAAMAAQAAAAQAAwAYAAAABgADAAEAAAAGAAEAEwAA" + - "AAYAAgATAAAABgAAABoAAAABAAAAAAAAAAMAAAAAAAAADwAAAAAAAAAQBAAAAAAAAAEAAQABAAAA" + - "8QMAAAQAAABwEAQAAAAOAAYAAwADAAAA9gMAAFQAAABiAAAAIgEGAHAQBgABABsCAwAAAG4gCAAh" + - "AAwBbiAHAEEADAEbAgAAAABuIAgAIQAMAW4QCQABAAwBbiADABAAEhAzBCsAchAFAAUA2AAE/3Aw" + - "AQADBWIAAAAiAQYAcBAGAAEAGwICAAAAbiAIACEADAFuIAcAQQAMARsCAAAAAG4gCAAhAAwBbhAJ" + - "AAEADAFuIAMAEAAOADgE3//YAAT/cDABAAMFKNgDAAMAAwAAAAgEAAAEAAAAcDABABACDgABAAAA" + - "AAAAAAEAAAAFAAAAAgAAAAAABAAOIC0gdHJhbnNmb3JtZWQABjxpbml0PgAHR29vZGJ5ZQAFSGVs" + - "bG8AAUkAAUwAAkxJAAJMTAALTFRyYW5zZm9ybTsAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwASTGph" + - "dmEvbGFuZy9PYmplY3Q7ABRMamF2YS9sYW5nL1J1bm5hYmxlOwASTGphdmEvbGFuZy9TdHJpbmc7" + - "ABlMamF2YS9sYW5nL1N0cmluZ0J1aWxkZXI7ABJMamF2YS9sYW5nL1N5c3RlbTsADlRyYW5zZm9y" + - "bS5qYXZhAAFWAANWSUwAAlZMAAZhcHBlbmQAEmVtaXR0ZXI6IGphY2stNC4yNAADb3V0AAdwcmlu" + - "dGxuAAxwcml2YXRlU2F5SGkAA3J1bgAFc2F5SGkACHRvU3RyaW5nAAEABw4ABgIAAAcOASAPPDxd" + - "ASAPGS0AAwIAAAcOPAAAAAIBAICABMADAQLYAwIBkAUAAA0AAAAAAAAAAQAAAAAAAAABAAAAGwAA" + - "AHAAAAACAAAACQAAANwAAAADAAAABgAAAAABAAAEAAAAAQAAAEgBAAAFAAAACgAAAFABAAAGAAAA" + - "AQAAAKABAAABIAAAAwAAAMABAAABEAAAAwAAAKgCAAACIAAAGwAAAMACAAADIAAAAwAAAPEDAAAA" + - "IAAAAQAAABAEAAAAEAAAAQAAACQEAAA="); - - public static void main(String[] args) { - art.Main.bindAgentJNIForClass(Main.class); - doTest(new Transform()); + public static void main(String[] args) throws Exception { + art.Test942.run(); } - - public static void doTest(Transform t) { - t.sayHi(2, () -> { System.out.println("Not doing anything here"); }); - t.sayHi(2, () -> { - System.out.println("transforming calling function"); - doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES); - }); - t.sayHi(2, () -> { System.out.println("Not doing anything here"); }); - } - - // Transforms the class - private static native void doCommonClassRedefinition(Class<?> target, - byte[] classfile, - byte[] dexfile); } diff --git a/test/942-private-recursive/src/art/Redefinition.java b/test/942-private-recursive/src/art/Redefinition.java new file mode 100644 index 0000000000..0350ab42ad --- /dev/null +++ b/test/942-private-recursive/src/art/Redefinition.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.util.ArrayList; +// Common Redefinition functions. Placed here for use by CTS +public class Redefinition { + // Bind native functions. + static { + Main.bindAgentJNIForClass(Redefinition.class); + } + + public static final class CommonClassDefinition { + public final Class<?> target; + public final byte[] class_file_bytes; + public final byte[] dex_file_bytes; + + public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { + this.target = target; + this.class_file_bytes = class_file_bytes; + this.dex_file_bytes = dex_file_bytes; + } + } + + // A set of possible test configurations. Test should set this if they need to. + // This must be kept in sync with the defines in ti-agent/common_helper.cc + public static enum Config { + COMMON_REDEFINE(0), + COMMON_RETRANSFORM(1), + COMMON_TRANSFORM(2); + + private final int val; + private Config(int val) { + this.val = val; + } + } + + public static void setTestConfiguration(Config type) { + nativeSetTestConfiguration(type.val); + } + + private static native void nativeSetTestConfiguration(int type); + + // Transforms the class + public static native void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile); + + public static void doMultiClassRedefinition(CommonClassDefinition... defs) { + ArrayList<Class<?>> classes = new ArrayList<>(); + ArrayList<byte[]> class_files = new ArrayList<>(); + ArrayList<byte[]> dex_files = new ArrayList<>(); + + for (CommonClassDefinition d : defs) { + classes.add(d.target); + class_files.add(d.class_file_bytes); + dex_files.add(d.dex_file_bytes); + } + doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), + class_files.toArray(new byte[0][]), + dex_files.toArray(new byte[0][])); + } + + public static void addMultiTransformationResults(CommonClassDefinition... defs) { + for (CommonClassDefinition d : defs) { + addCommonTransformationResult(d.target.getCanonicalName(), + d.class_file_bytes, + d.dex_file_bytes); + } + } + + public static native void doCommonMultiClassRedefinition(Class<?>[] targets, + byte[][] classfiles, + byte[][] dexfiles); + public static native void doCommonClassRetransformation(Class<?>... target); + public static native void setPopRetransformations(boolean pop); + public static native void popTransformationFor(String name); + public static native void enableCommonRetransformation(boolean enable); + public static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); +} diff --git a/test/942-private-recursive/src/art/Test942.java b/test/942-private-recursive/src/art/Test942.java new file mode 100644 index 0000000000..cccc2fd9e0 --- /dev/null +++ b/test/942-private-recursive/src/art/Test942.java @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * 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 art; + +import java.util.Base64; + +public class Test942 { + + static class Transform { + private void privateSayHi(int recur, Runnable r) { + System.out.println("hello" + recur); + if (recur == 1) { + r.run(); + privateSayHi(recur - 1, r); + } else if (recur != 0) { + privateSayHi(recur - 1, r); + } + System.out.println("goodbye" + recur); + } + + public void sayHi(int recur, Runnable r) { + privateSayHi(recur, r); + } + } + + + // static class Transform { + // public void sayHi(int recur, Runnable r) { + // privateSayHi(recur, r); + // } + // private void privateSayHi(int recur, Runnable r) { + // System.out.println("Hello" + recur + " - transformed"); + // if (recur == 1) { + // r.run(); + // privateSayHi(recur - 1, r); + // } else if (recur != 0) { + // privateSayHi(recur - 1, r); + // } + // System.out.println("Goodbye" + recur + " - transformed"); + // } + // } + private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( + "yv66vgAAADQAPAoADwAaCgAOABsJABwAHQcAHgoABAAaCAAfCgAEACAKAAQAIQgAIgoABAAjCgAk" + + "ACULACYAJwgAKAcAKgcALQEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUB" + + "AAVzYXlIaQEAGChJTGphdmEvbGFuZy9SdW5uYWJsZTspVgEADHByaXZhdGVTYXlIaQEADVN0YWNr" + + "TWFwVGFibGUBAApTb3VyY2VGaWxlAQAMVGVzdDk0Mi5qYXZhDAAQABEMABYAFQcALgwALwAwAQAX" + + "amF2YS9sYW5nL1N0cmluZ0J1aWxkZXIBAAVIZWxsbwwAMQAyDAAxADMBAA4gLSB0cmFuc2Zvcm1l" + + "ZAwANAA1BwA2DAA3ADgHADkMADoAEQEAB0dvb2RieWUHADsBABVhcnQvVGVzdDk0MiRUcmFuc2Zv" + + "cm0BAAlUcmFuc2Zvcm0BAAxJbm5lckNsYXNzZXMBABBqYXZhL2xhbmcvT2JqZWN0AQAQamF2YS9s" + + "YW5nL1N5c3RlbQEAA291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEABmFwcGVuZAEALShMamF2" + + "YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmdCdWlsZGVyOwEAHChJKUxqYXZhL2xhbmcv" + + "U3RyaW5nQnVpbGRlcjsBAAh0b1N0cmluZwEAFCgpTGphdmEvbGFuZy9TdHJpbmc7AQATamF2YS9p" + + "by9QcmludFN0cmVhbQEAB3ByaW50bG4BABUoTGphdmEvbGFuZy9TdHJpbmc7KVYBABJqYXZhL2xh" + + "bmcvUnVubmFibGUBAANydW4BAAthcnQvVGVzdDk0MgAgAA4ADwAAAAAAAwAAABAAEQABABIAAAAd" + + "AAEAAQAAAAUqtwABsQAAAAEAEwAAAAYAAQAAAAUAAQAUABUAAQASAAAAIwADAAMAAAAHKhsstwAC" + + "sQAAAAEAEwAAAAoAAgAAAAcABgAIAAIAFgAVAAEAEgAAAJ0AAwADAAAAX7IAA7sABFm3AAUSBrYA" + + "Bxu2AAgSCbYAB7YACrYACxsEoAAULLkADAEAKhsEZCy3AAKnAA8bmQALKhsEZCy3AAKyAAO7AARZ" + + "twAFEg22AAcbtgAIEgm2AAe2AAq2AAuxAAAAAgATAAAAIgAIAAAACgAeAAsAIwAMACkADQA0AA4A" + + "OAAPAEAAEQBeABIAFwAAAAQAAjQLAAIAGAAAAAIAGQAsAAAACgABAA4AKQArAAg="); + private static final byte[] DEX_BYTES = Base64.getDecoder().decode( + "ZGV4CjAzNQDiy6hGAAAAAAAAAAAAAAAAAAAAAAAAAAC4BQAAcAAAAHhWNBIAAAAAAAAAAPQEAAAh" + + "AAAAcAAAAAwAAAD0AAAABgAAACQBAAABAAAAbAEAAAoAAAB0AQAAAQAAAMQBAADUAwAA5AEAAOQB" + + "AAD0AQAA/AEAAAUCAAAMAgAADwIAABICAAAWAgAAGgIAADMCAABCAgAAZgIAAIYCAACdAgAAsQIA" + + "AMcCAADbAgAA9gIAAAoDAAAYAwAAIwMAACYDAAArAwAALwMAADwDAABEAwAASgMAAE8DAABYAwAA" + + "ZgMAAGsDAAByAwAAfAMAAAQAAAAIAAAACQAAAAoAAAALAAAADAAAAA0AAAAOAAAADwAAABAAAAAR" + + "AAAAFAAAAAUAAAAIAAAAAAAAAAYAAAAJAAAAlAMAAAcAAAAJAAAAjAMAABQAAAALAAAAAAAAABUA" + + "AAALAAAAhAMAABYAAAALAAAAjAMAAAoABQAaAAAAAQADAAEAAAABAAQAHAAAAAEABAAeAAAABQAF" + + "ABsAAAAGAAMAAQAAAAcAAwAdAAAACQADAAEAAAAJAAEAGAAAAAkAAgAYAAAACQAAAB8AAAABAAAA" + + "AAAAAAYAAAAAAAAAEgAAAOQEAAC0BAAAAAAAAA4gLSB0cmFuc2Zvcm1lZAAGPGluaXQ+AAdHb29k" + + "YnllAAVIZWxsbwABSQABTAACTEkAAkxMABdMYXJ0L1Rlc3Q5NDIkVHJhbnNmb3JtOwANTGFydC9U" + + "ZXN0OTQyOwAiTGRhbHZpay9hbm5vdGF0aW9uL0VuY2xvc2luZ0NsYXNzOwAeTGRhbHZpay9hbm5v" + + "dGF0aW9uL0lubmVyQ2xhc3M7ABVMamF2YS9pby9QcmludFN0cmVhbTsAEkxqYXZhL2xhbmcvT2Jq" + + "ZWN0OwAUTGphdmEvbGFuZy9SdW5uYWJsZTsAEkxqYXZhL2xhbmcvU3RyaW5nOwAZTGphdmEvbGFu" + + "Zy9TdHJpbmdCdWlsZGVyOwASTGphdmEvbGFuZy9TeXN0ZW07AAxUZXN0OTQyLmphdmEACVRyYW5z" + + "Zm9ybQABVgADVklMAAJWTAALYWNjZXNzRmxhZ3MABmFwcGVuZAAEbmFtZQADb3V0AAdwcmludGxu" + + "AAxwcml2YXRlU2F5SGkAA3J1bgAFc2F5SGkACHRvU3RyaW5nAAV2YWx1ZQAAAgAAAAAABwABAAAA" + + "CAAAAAEAAAAAAAAABQAHDgAKAgAABw4BIA8BAw8BAw8BBRIBIA8BAQoBAg8ABwIAAAcOAQMPAAAB" + + "AAEAAQAAAJwDAAAEAAAAcBAEAAAADgAGAAMAAwAAAKEDAABVAAAAYgAAACIBCQBwEAYAAQAbAgMA" + + "AABuIAgAIQAMAW4gBwBBAAwBGwIAAAAAbiAIACEADAFuEAkAAQAMAW4gAwAQABIQMwQrAHIQBQAF" + + "ANgABP9wMAEAAwViAAAAIgEJAHAQBgABABsCAgAAAG4gCAAhAAwBbiAHAEEADAEbAgAAAABuIAgA" + + "IQAMAW4QCQABAAwBbiADABAADgA4BN//2AAE/3AwAQADBSkA2P8AAAMAAwADAAAAvQMAAAQAAABw" + + "MAEAEAIOAAAAAgEAgIAEyAcBAuAHAgGcCQAAAgMBIBgCAgQCFwQIGRcTAAIAAADIBAAAzgQAANgE" + + "AAAAAAAAAAAAAAAAAAAQAAAAAAAAAAEAAAAAAAAAAQAAACEAAABwAAAAAgAAAAwAAAD0AAAAAwAA" + + "AAYAAAAkAQAABAAAAAEAAABsAQAABQAAAAoAAAB0AQAABgAAAAEAAADEAQAAAiAAACEAAADkAQAA" + + "ARAAAAMAAACEAwAAAyAAAAMAAACcAwAAASAAAAMAAADIAwAAACAAAAEAAAC0BAAABCAAAAIAAADI" + + "BAAAAxAAAAEAAADYBAAABiAAAAEAAADkBAAAABAAAAEAAAD0BAAA"); + + public static void run() { + Redefinition.setTestConfiguration(Redefinition.Config.COMMON_REDEFINE); + doTest(new Transform()); + } + + public static void doTest(Transform t) { + t.sayHi(2, () -> { System.out.println("Not doing anything here"); }); + t.sayHi(2, () -> { + System.out.println("transforming calling function"); + Redefinition.doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES); + }); + t.sayHi(2, () -> { System.out.println("Not doing anything here"); }); + } +} diff --git a/test/943-private-recursive-jit/src/Main.java b/test/943-private-recursive-jit/src/Main.java index f380c062d1..01760ad0c1 100644 --- a/test/943-private-recursive-jit/src/Main.java +++ b/test/943-private-recursive-jit/src/Main.java @@ -14,6 +14,8 @@ * limitations under the License. */ +import static art.Redefinition.doCommonClassRedefinition; + import java.util.Base64; import java.util.function.Consumer; import java.lang.reflect.Method; @@ -164,9 +166,4 @@ public class Main { private static native boolean isInterpretedFunction(Method m, boolean require_deoptimizable); private static native void ensureJitCompiled(Class c, String name); - - // Transforms the class - private static native void doCommonClassRedefinition(Class<?> target, - byte[] classfile, - byte[] dexfile); } diff --git a/test/943-private-recursive-jit/src/art/Redefinition.java b/test/943-private-recursive-jit/src/art/Redefinition.java new file mode 100644 index 0000000000..0350ab42ad --- /dev/null +++ b/test/943-private-recursive-jit/src/art/Redefinition.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.util.ArrayList; +// Common Redefinition functions. Placed here for use by CTS +public class Redefinition { + // Bind native functions. + static { + Main.bindAgentJNIForClass(Redefinition.class); + } + + public static final class CommonClassDefinition { + public final Class<?> target; + public final byte[] class_file_bytes; + public final byte[] dex_file_bytes; + + public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { + this.target = target; + this.class_file_bytes = class_file_bytes; + this.dex_file_bytes = dex_file_bytes; + } + } + + // A set of possible test configurations. Test should set this if they need to. + // This must be kept in sync with the defines in ti-agent/common_helper.cc + public static enum Config { + COMMON_REDEFINE(0), + COMMON_RETRANSFORM(1), + COMMON_TRANSFORM(2); + + private final int val; + private Config(int val) { + this.val = val; + } + } + + public static void setTestConfiguration(Config type) { + nativeSetTestConfiguration(type.val); + } + + private static native void nativeSetTestConfiguration(int type); + + // Transforms the class + public static native void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile); + + public static void doMultiClassRedefinition(CommonClassDefinition... defs) { + ArrayList<Class<?>> classes = new ArrayList<>(); + ArrayList<byte[]> class_files = new ArrayList<>(); + ArrayList<byte[]> dex_files = new ArrayList<>(); + + for (CommonClassDefinition d : defs) { + classes.add(d.target); + class_files.add(d.class_file_bytes); + dex_files.add(d.dex_file_bytes); + } + doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), + class_files.toArray(new byte[0][]), + dex_files.toArray(new byte[0][])); + } + + public static void addMultiTransformationResults(CommonClassDefinition... defs) { + for (CommonClassDefinition d : defs) { + addCommonTransformationResult(d.target.getCanonicalName(), + d.class_file_bytes, + d.dex_file_bytes); + } + } + + public static native void doCommonMultiClassRedefinition(Class<?>[] targets, + byte[][] classfiles, + byte[][] dexfiles); + public static native void doCommonClassRetransformation(Class<?>... target); + public static native void setPopRetransformations(boolean pop); + public static native void popTransformationFor(String name); + public static native void enableCommonRetransformation(boolean enable); + public static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); +} diff --git a/test/944-transform-classloaders/classloader.cc b/test/944-transform-classloaders/classloader.cc deleted file mode 100644 index 698e023771..0000000000 --- a/test/944-transform-classloaders/classloader.cc +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * 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. - */ - -#include "android-base/macros.h" -#include "jni.h" -#include "jvmti.h" -#include "mirror/class-inl.h" -#include "scoped_local_ref.h" - -// Test infrastructure -#include "test_env.h" - -namespace art { -namespace Test944TransformClassloaders { - -extern "C" JNIEXPORT jlong JNICALL Java_Main_getDexFilePointer(JNIEnv* env, jclass, jclass klass) { - if (Runtime::Current() == nullptr) { - env->ThrowNew(env->FindClass("java/lang/Exception"), - "We do not seem to be running in ART! Unable to get dex file."); - return 0; - } - ScopedObjectAccess soa(env); - // This sequence of casts must be the same as those done in - // runtime/native/dalvik_system_DexFile.cc in order to ensure that we get the same results. - return static_cast<jlong>(reinterpret_cast<uintptr_t>( - &soa.Decode<mirror::Class>(klass)->GetDexFile())); -} - -} // namespace Test944TransformClassloaders -} // namespace art diff --git a/test/944-transform-classloaders/src/CommonClassDefinition.java b/test/944-transform-classloaders/src/CommonClassDefinition.java deleted file mode 100644 index 62602a02e9..0000000000 --- a/test/944-transform-classloaders/src/CommonClassDefinition.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * 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. - */ - -class CommonClassDefinition { - public final Class<?> target; - public final byte[] class_file_bytes; - public final byte[] dex_file_bytes; - - CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { - this.target = target; - this.class_file_bytes = class_file_bytes; - this.dex_file_bytes = dex_file_bytes; - } -} diff --git a/test/944-transform-classloaders/src/Main.java b/test/944-transform-classloaders/src/Main.java index b558660cfd..3d76d237ea 100644 --- a/test/944-transform-classloaders/src/Main.java +++ b/test/944-transform-classloaders/src/Main.java @@ -14,254 +14,8 @@ * limitations under the License. */ -import java.util.Arrays; -import java.util.ArrayList; -import java.util.Base64; -import java.lang.reflect.*; public class Main { - - /** - * base64 encoded class/dex file for - * class Transform { - * public void sayHi() { - * System.out.println("Goodbye"); - * } - * } - */ - private static CommonClassDefinition TRANSFORM_DEFINITION = new CommonClassDefinition( - Transform.class, - Base64.getDecoder().decode( - "yv66vgAAADQAHAoABgAOCQAPABAIABEKABIAEwcAFAcAFQEABjxpbml0PgEAAygpVgEABENvZGUB" + - "AA9MaW5lTnVtYmVyVGFibGUBAAVzYXlIaQEAClNvdXJjZUZpbGUBAA5UcmFuc2Zvcm0uamF2YQwA" + - "BwAIBwAWDAAXABgBAAdHb29kYnllBwAZDAAaABsBAAlUcmFuc2Zvcm0BABBqYXZhL2xhbmcvT2Jq" + - "ZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2ph" + - "dmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWACAABQAG" + - "AAAAAAACAAAABwAIAAEACQAAAB0AAQABAAAABSq3AAGxAAAAAQAKAAAABgABAAAAEQABAAsACAAB" + - "AAkAAAAlAAIAAQAAAAmyAAISA7YABLEAAAABAAoAAAAKAAIAAAATAAgAFAABAAwAAAACAA0="), - Base64.getDecoder().decode( - "ZGV4CjAzNQCLXSBQ5FiS3f16krSYZFF8xYZtFVp0GRXMAgAAcAAAAHhWNBIAAAAAAAAAACwCAAAO" + - "AAAAcAAAAAYAAACoAAAAAgAAAMAAAAABAAAA2AAAAAQAAADgAAAAAQAAAAABAACsAQAAIAEAAGIB" + - "AABqAQAAcwEAAIABAACXAQAAqwEAAL8BAADTAQAA4wEAAOYBAADqAQAA/gEAAAMCAAAMAgAAAgAA" + - "AAMAAAAEAAAABQAAAAYAAAAIAAAACAAAAAUAAAAAAAAACQAAAAUAAABcAQAABAABAAsAAAAAAAAA" + - "AAAAAAAAAAANAAAAAQABAAwAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAHAAAAAAAAAB4CAAAA" + - "AAAAAQABAAEAAAATAgAABAAAAHAQAwAAAA4AAwABAAIAAAAYAgAACQAAAGIAAAAbAQEAAABuIAIA" + - "EAAOAAAAAQAAAAMABjxpbml0PgAHR29vZGJ5ZQALTFRyYW5zZm9ybTsAFUxqYXZhL2lvL1ByaW50" + - "U3RyZWFtOwASTGphdmEvbGFuZy9PYmplY3Q7ABJMamF2YS9sYW5nL1N0cmluZzsAEkxqYXZhL2xh" + - "bmcvU3lzdGVtOwAOVHJhbnNmb3JtLmphdmEAAVYAAlZMABJlbWl0dGVyOiBqYWNrLTMuMzYAA291" + - "dAAHcHJpbnRsbgAFc2F5SGkAEQAHDgATAAcOhQAAAAEBAICABKACAQG4Ag0AAAAAAAAAAQAAAAAA" + - "AAABAAAADgAAAHAAAAACAAAABgAAAKgAAAADAAAAAgAAAMAAAAAEAAAAAQAAANgAAAAFAAAABAAA" + - "AOAAAAAGAAAAAQAAAAABAAABIAAAAgAAACABAAABEAAAAQAAAFwBAAACIAAADgAAAGIBAAADIAAA" + - "AgAAABMCAAAAIAAAAQAAAB4CAAAAEAAAAQAAACwCAAA=")); - - /** - * base64 encoded class/dex file for - * class Transform2 { - * public void sayHi() { - * System.out.println("Goodbye2"); - * } - * } - */ - private static CommonClassDefinition TRANSFORM2_DEFINITION = new CommonClassDefinition( - Transform2.class, - Base64.getDecoder().decode( - "yv66vgAAADQAHAoABgAOCQAPABAIABEKABIAEwcAFAcAFQEABjxpbml0PgEAAygpVgEABENvZGUB" + - "AA9MaW5lTnVtYmVyVGFibGUBAAVzYXlIaQEAClNvdXJjZUZpbGUBAA9UcmFuc2Zvcm0yLmphdmEM" + - "AAcACAcAFgwAFwAYAQAIR29vZGJ5ZTIHABkMABoAGwEAClRyYW5zZm9ybTIBABBqYXZhL2xhbmcv" + - "T2JqZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEA" + - "E2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWACAA" + - "BQAGAAAAAAACAAAABwAIAAEACQAAAB0AAQABAAAABSq3AAGxAAAAAQAKAAAABgABAAAAAQABAAsA" + - "CAABAAkAAAAlAAIAAQAAAAmyAAISA7YABLEAAAABAAoAAAAKAAIAAAADAAgABAABAAwAAAACAA0="), - Base64.getDecoder().decode( - "ZGV4CjAzNQABX6vL8OT7aGLjbzFBEfCM9Aaz+zzGzVnQAgAAcAAAAHhWNBIAAAAAAAAAADACAAAO" + - "AAAAcAAAAAYAAACoAAAAAgAAAMAAAAABAAAA2AAAAAQAAADgAAAAAQAAAAABAACwAQAAIAEAAGIB" + - "AABqAQAAdAEAAIIBAACZAQAArQEAAMEBAADVAQAA5gEAAOkBAADtAQAAAQIAAAYCAAAPAgAAAgAA" + - "AAMAAAAEAAAABQAAAAYAAAAIAAAACAAAAAUAAAAAAAAACQAAAAUAAABcAQAABAABAAsAAAAAAAAA" + - "AAAAAAAAAAANAAAAAQABAAwAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAHAAAAAAAAACECAAAA" + - "AAAAAQABAAEAAAAWAgAABAAAAHAQAwAAAA4AAwABAAIAAAAbAgAACQAAAGIAAAAbAQEAAABuIAIA" + - "EAAOAAAAAQAAAAMABjxpbml0PgAIR29vZGJ5ZTIADExUcmFuc2Zvcm0yOwAVTGphdmEvaW8vUHJp" + - "bnRTdHJlYW07ABJMamF2YS9sYW5nL09iamVjdDsAEkxqYXZhL2xhbmcvU3RyaW5nOwASTGphdmEv" + - "bGFuZy9TeXN0ZW07AA9UcmFuc2Zvcm0yLmphdmEAAVYAAlZMABJlbWl0dGVyOiBqYWNrLTQuMjQA" + - "A291dAAHcHJpbnRsbgAFc2F5SGkAAQAHDgADAAcOhwAAAAEBAICABKACAQG4AgANAAAAAAAAAAEA" + - "AAAAAAAAAQAAAA4AAABwAAAAAgAAAAYAAACoAAAAAwAAAAIAAADAAAAABAAAAAEAAADYAAAABQAA" + - "AAQAAADgAAAABgAAAAEAAAAAAQAAASAAAAIAAAAgAQAAARAAAAEAAABcAQAAAiAAAA4AAABiAQAA" + - "AyAAAAIAAAAWAgAAACAAAAEAAAAhAgAAABAAAAEAAAAwAgAA")); - public static void main(String[] args) throws Exception { - doTest(); - System.out.println("Passed"); - } - - private static void checkIsInstance(Class<?> klass, Object o) throws Exception { - if (!klass.isInstance(o)) { - throw new Exception(klass + " is not the class of " + o); - } - } - - private static boolean arrayContains(long[] arr, long value) { - if (arr == null) { - return false; - } - for (int i = 0; i < arr.length; i++) { - if (arr[i] == value) { - return true; - } - } - return false; + art.Test944.run(); } - - /** - * Checks that we can find the dex-file for the given class in its classloader. - * - * Throws if it fails. - */ - private static void checkDexFileInClassLoader(Class<?> klass) throws Exception { - // If all the android BCP classes were availible when compiling this test and access checks - // weren't a thing this function would be written as follows: - // - // long dexFilePtr = getDexFilePointer(klass); - // dalvik.system.BaseDexClassLoader loader = - // (dalvik.system.BaseDexClassLoader)klass.getClassLoader(); - // dalvik.system.DexPathList pathListValue = loader.pathList; - // dalvik.system.DexPathList.Element[] elementArrayValue = pathListValue.dexElements; - // int array_length = elementArrayValue.length; - // for (int i = 0; i < array_length; i++) { - // dalvik.system.DexPathList.Element curElement = elementArrayValue[i]; - // dalvik.system.DexFile curDexFile = curElement.dexFile; - // if (curDexFile == null) { - // continue; - // } - // long[] curCookie = (long[])curDexFile.mCookie; - // long[] curInternalCookie = (long[])curDexFile.mInternalCookie; - // if (arrayContains(curCookie, dexFilePtr) || arrayContains(curInternalCookie, dexFilePtr)) { - // return; - // } - // } - // throw new Exception( - // "Unable to find dex file pointer " + dexFilePtr + " in class loader for " + klass); - - // Get all the fields and classes we need by reflection. - Class<?> baseDexClassLoaderClass = Class.forName("dalvik.system.BaseDexClassLoader"); - Field pathListField = baseDexClassLoaderClass.getDeclaredField("pathList"); - - Class<?> dexPathListClass = Class.forName("dalvik.system.DexPathList"); - Field elementArrayField = dexPathListClass.getDeclaredField("dexElements"); - - Class<?> dexPathListElementClass = Class.forName("dalvik.system.DexPathList$Element"); - Field dexFileField = dexPathListElementClass.getDeclaredField("dexFile"); - - Class<?> dexFileClass = Class.forName("dalvik.system.DexFile"); - Field dexFileCookieField = dexFileClass.getDeclaredField("mCookie"); - Field dexFileInternalCookieField = dexFileClass.getDeclaredField("mInternalCookie"); - - // Make all the fields accessible - AccessibleObject.setAccessible(new AccessibleObject[] { pathListField, - elementArrayField, - dexFileField, - dexFileCookieField, - dexFileInternalCookieField }, true); - - long dexFilePtr = getDexFilePointer(klass); - - ClassLoader loader = klass.getClassLoader(); - checkIsInstance(baseDexClassLoaderClass, loader); - // DexPathList pathListValue = ((BaseDexClassLoader) loader).pathList; - Object pathListValue = pathListField.get(loader); - - checkIsInstance(dexPathListClass, pathListValue); - - // DexPathList.Element[] elementArrayValue = pathListValue.dexElements; - Object elementArrayValue = elementArrayField.get(pathListValue); - if (!elementArrayValue.getClass().isArray() || - elementArrayValue.getClass().getComponentType() != dexPathListElementClass) { - throw new Exception("elementArrayValue is not an " + dexPathListElementClass + " array!"); - } - // int array_length = elementArrayValue.length; - int array_length = Array.getLength(elementArrayValue); - for (int i = 0; i < array_length; i++) { - // DexPathList.Element curElement = elementArrayValue[i]; - Object curElement = Array.get(elementArrayValue, i); - checkIsInstance(dexPathListElementClass, curElement); - - // DexFile curDexFile = curElement.dexFile; - Object curDexFile = dexFileField.get(curElement); - if (curDexFile == null) { - continue; - } - checkIsInstance(dexFileClass, curDexFile); - - // long[] curCookie = (long[])curDexFile.mCookie; - long[] curCookie = (long[])dexFileCookieField.get(curDexFile); - // long[] curInternalCookie = (long[])curDexFile.mInternalCookie; - long[] curInternalCookie = (long[])dexFileInternalCookieField.get(curDexFile); - - if (arrayContains(curCookie, dexFilePtr) || arrayContains(curInternalCookie, dexFilePtr)) { - return; - } - } - throw new Exception( - "Unable to find dex file pointer " + dexFilePtr + " in class loader for " + klass); - } - - private static void doTest() throws Exception { - art.Main.bindAgentJNIForClass(Main.class); - - Transform t = new Transform(); - Transform2 t2 = new Transform2(); - - long initial_t1_dex = getDexFilePointer(Transform.class); - long initial_t2_dex = getDexFilePointer(Transform2.class); - if (initial_t2_dex != initial_t1_dex) { - throw new Exception("The classes " + Transform.class + " and " + Transform2.class + " " + - "have different initial dex files!"); - } - checkDexFileInClassLoader(Transform.class); - checkDexFileInClassLoader(Transform2.class); - - // Make sure they are loaded - t.sayHi(); - t2.sayHi(); - // Redefine both of the classes. - doMultiClassRedefinition(TRANSFORM_DEFINITION, TRANSFORM2_DEFINITION); - // Make sure we actually transformed them! - t.sayHi(); - t2.sayHi(); - - long final_t1_dex = getDexFilePointer(Transform.class); - long final_t2_dex = getDexFilePointer(Transform2.class); - if (final_t2_dex == final_t1_dex) { - throw new Exception("The classes " + Transform.class + " and " + Transform2.class + " " + - "have the same initial dex files!"); - } else if (final_t1_dex == initial_t1_dex) { - throw new Exception("The class " + Transform.class + " did not get a new dex file!"); - } else if (final_t2_dex == initial_t2_dex) { - throw new Exception("The class " + Transform2.class + " did not get a new dex file!"); - } - // Check to make sure the new dex files are in the class loader. - checkDexFileInClassLoader(Transform.class); - checkDexFileInClassLoader(Transform2.class); - } - - private static void doMultiClassRedefinition(CommonClassDefinition... defs) { - ArrayList<Class<?>> classes = new ArrayList<>(); - ArrayList<byte[]> class_files = new ArrayList<>(); - ArrayList<byte[]> dex_files = new ArrayList<>(); - - for (CommonClassDefinition d : defs) { - classes.add(d.target); - class_files.add(d.class_file_bytes); - dex_files.add(d.dex_file_bytes); - } - doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), - class_files.toArray(new byte[0][]), - dex_files.toArray(new byte[0][])); - } - - // Gets the 'long' (really a native pointer) that is stored in the ClassLoader representing the - // DexFile a class is loaded from. This is converted from the DexFile* in the same way it is done - // in runtime/native/dalvik_system_DexFile.cc - private static native long getDexFilePointer(Class<?> target); - // Transforms the classes - private static native void doCommonMultiClassRedefinition(Class<?>[] targets, - byte[][] classfiles, - byte[][] dexfiles); } diff --git a/test/944-transform-classloaders/src/Transform.java b/test/944-transform-classloaders/src/Transform.java deleted file mode 100644 index 8e8af355da..0000000000 --- a/test/944-transform-classloaders/src/Transform.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * 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. - */ - -class Transform { - public void sayHi() { - // Use lower 'h' to make sure the string will have a different string id - // than the transformation (the transformation code is the same except - // the actual printed String, which was making the test inacurately passing - // in JIT mode when loading the string from the dex cache, as the string ids - // of the two different strings were the same). - // We know the string ids will be different because lexicographically: - // "Goodbye" < "LTransform;" < "hello". - System.out.println("hello"); - } -} diff --git a/test/944-transform-classloaders/src/Transform2.java b/test/944-transform-classloaders/src/Transform2.java deleted file mode 100644 index eb22842184..0000000000 --- a/test/944-transform-classloaders/src/Transform2.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * 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. - */ - -class Transform2 { - public void sayHi() { - System.out.println("hello2"); - } -} diff --git a/test/944-transform-classloaders/src/art/Redefinition.java b/test/944-transform-classloaders/src/art/Redefinition.java new file mode 100644 index 0000000000..0350ab42ad --- /dev/null +++ b/test/944-transform-classloaders/src/art/Redefinition.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.util.ArrayList; +// Common Redefinition functions. Placed here for use by CTS +public class Redefinition { + // Bind native functions. + static { + Main.bindAgentJNIForClass(Redefinition.class); + } + + public static final class CommonClassDefinition { + public final Class<?> target; + public final byte[] class_file_bytes; + public final byte[] dex_file_bytes; + + public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { + this.target = target; + this.class_file_bytes = class_file_bytes; + this.dex_file_bytes = dex_file_bytes; + } + } + + // A set of possible test configurations. Test should set this if they need to. + // This must be kept in sync with the defines in ti-agent/common_helper.cc + public static enum Config { + COMMON_REDEFINE(0), + COMMON_RETRANSFORM(1), + COMMON_TRANSFORM(2); + + private final int val; + private Config(int val) { + this.val = val; + } + } + + public static void setTestConfiguration(Config type) { + nativeSetTestConfiguration(type.val); + } + + private static native void nativeSetTestConfiguration(int type); + + // Transforms the class + public static native void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile); + + public static void doMultiClassRedefinition(CommonClassDefinition... defs) { + ArrayList<Class<?>> classes = new ArrayList<>(); + ArrayList<byte[]> class_files = new ArrayList<>(); + ArrayList<byte[]> dex_files = new ArrayList<>(); + + for (CommonClassDefinition d : defs) { + classes.add(d.target); + class_files.add(d.class_file_bytes); + dex_files.add(d.dex_file_bytes); + } + doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), + class_files.toArray(new byte[0][]), + dex_files.toArray(new byte[0][])); + } + + public static void addMultiTransformationResults(CommonClassDefinition... defs) { + for (CommonClassDefinition d : defs) { + addCommonTransformationResult(d.target.getCanonicalName(), + d.class_file_bytes, + d.dex_file_bytes); + } + } + + public static native void doCommonMultiClassRedefinition(Class<?>[] targets, + byte[][] classfiles, + byte[][] dexfiles); + public static native void doCommonClassRetransformation(Class<?>... target); + public static native void setPopRetransformations(boolean pop); + public static native void popTransformationFor(String name); + public static native void enableCommonRetransformation(boolean enable); + public static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); +} diff --git a/test/944-transform-classloaders/src/art/Test944.java b/test/944-transform-classloaders/src/art/Test944.java new file mode 100644 index 0000000000..fe1c024ec4 --- /dev/null +++ b/test/944-transform-classloaders/src/art/Test944.java @@ -0,0 +1,297 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import static art.Redefinition.CommonClassDefinition; + +import java.util.Arrays; +import java.util.ArrayList; +import java.util.Base64; +import java.lang.reflect.*; +public class Test944 { + + static class Transform { + public void sayHi() { + System.out.println("hello"); + } + } + + static class Transform2 { + public void sayHi() { + System.out.println("hello2"); + } + } + + /** + * base64 encoded class/dex file for + * static class Transform { + * public void sayHi() { + * System.out.println("Goodbye"); + * } + * } + */ + private static CommonClassDefinition TRANSFORM_DEFINITION = new CommonClassDefinition( + Transform.class, + Base64.getDecoder().decode( + "yv66vgAAADQAIAoABgAOCQAPABAIABEKABIAEwcAFQcAGAEABjxpbml0PgEAAygpVgEABENvZGUB" + + "AA9MaW5lTnVtYmVyVGFibGUBAAVzYXlIaQEAClNvdXJjZUZpbGUBAAxUZXN0OTQ0LmphdmEMAAcA" + + "CAcAGQwAGgAbAQAHR29vZGJ5ZQcAHAwAHQAeBwAfAQAVYXJ0L1Rlc3Q5NDQkVHJhbnNmb3JtAQAJ" + + "VHJhbnNmb3JtAQAMSW5uZXJDbGFzc2VzAQAQamF2YS9sYW5nL09iamVjdAEAEGphdmEvbGFuZy9T" + + "eXN0ZW0BAANvdXQBABVMamF2YS9pby9QcmludFN0cmVhbTsBABNqYXZhL2lvL1ByaW50U3RyZWFt" + + "AQAHcHJpbnRsbgEAFShMamF2YS9sYW5nL1N0cmluZzspVgEAC2FydC9UZXN0OTQ0ACAABQAGAAAA" + + "AAACAAAABwAIAAEACQAAAB0AAQABAAAABSq3AAGxAAAAAQAKAAAABgABAAAACgABAAsACAABAAkA" + + "AAAlAAIAAQAAAAmyAAISA7YABLEAAAABAAoAAAAKAAIAAAAMAAgADQACAAwAAAACAA0AFwAAAAoA" + + "AQAFABQAFgAI"), + Base64.getDecoder().decode( + "ZGV4CjAzNQCFgsuWAAAAAAAAAAAAAAAAAAAAAAAAAAC4AwAAcAAAAHhWNBIAAAAAAAAAAPQCAAAU" + + "AAAAcAAAAAkAAADAAAAAAgAAAOQAAAABAAAA/AAAAAQAAAAEAQAAAQAAACQBAAB0AgAARAEAAEQB" + + "AABMAQAAVQEAAG4BAAB9AQAAoQEAAMEBAADYAQAA7AEAAAACAAAUAgAAIgIAAC0CAAAwAgAANAIA" + + "AEECAABHAgAATAIAAFUCAABcAgAAAgAAAAMAAAAEAAAABQAAAAYAAAAHAAAACAAAAAkAAAAMAAAA" + + "DAAAAAgAAAAAAAAADQAAAAgAAABkAgAABwAEABAAAAAAAAAAAAAAAAAAAAASAAAABAABABEAAAAF" + + "AAAAAAAAAAAAAAAAAAAABQAAAAAAAAAKAAAA5AIAALgCAAAAAAAABjxpbml0PgAHR29vZGJ5ZQAX" + + "TGFydC9UZXN0OTQ0JFRyYW5zZm9ybTsADUxhcnQvVGVzdDk0NDsAIkxkYWx2aWsvYW5ub3RhdGlv" + + "bi9FbmNsb3NpbmdDbGFzczsAHkxkYWx2aWsvYW5ub3RhdGlvbi9Jbm5lckNsYXNzOwAVTGphdmEv" + + "aW8vUHJpbnRTdHJlYW07ABJMamF2YS9sYW5nL09iamVjdDsAEkxqYXZhL2xhbmcvU3RyaW5nOwAS" + + "TGphdmEvbGFuZy9TeXN0ZW07AAxUZXN0OTQ0LmphdmEACVRyYW5zZm9ybQABVgACVkwAC2FjY2Vz" + + "c0ZsYWdzAARuYW1lAANvdXQAB3ByaW50bG4ABXNheUhpAAV2YWx1ZQAAAQAAAAYAAAAKAAcOAAwA" + + "Bw4BCA8AAAAAAQABAAEAAABsAgAABAAAAHAQAwAAAA4AAwABAAIAAABxAgAACQAAAGIAAAAbAQEA" + + "AABuIAIAEAAOAAAAAAABAQCAgAT8BAEBlAUAAAICARMYAQIDAg4ECA8XCwACAAAAyAIAAM4CAADY" + + "AgAAAAAAAAAAAAAAAAAAEAAAAAAAAAABAAAAAAAAAAEAAAAUAAAAcAAAAAIAAAAJAAAAwAAAAAMA" + + "AAACAAAA5AAAAAQAAAABAAAA/AAAAAUAAAAEAAAABAEAAAYAAAABAAAAJAEAAAIgAAAUAAAARAEA" + + "AAEQAAABAAAAZAIAAAMgAAACAAAAbAIAAAEgAAACAAAAfAIAAAAgAAABAAAAuAIAAAQgAAACAAAA" + + "yAIAAAMQAAABAAAA2AIAAAYgAAABAAAA5AIAAAAQAAABAAAA9AIAAA==")); + + /** + * base64 encoded class/dex file for + * static class Transform2 { + * public void sayHi() { + * System.out.println("Goodbye2"); + * } + * } + */ + private static CommonClassDefinition TRANSFORM2_DEFINITION = new CommonClassDefinition( + Transform2.class, + Base64.getDecoder().decode( + "yv66vgAAADQAIAoABgAOCQAPABAIABEKABIAEwcAFQcAGAEABjxpbml0PgEAAygpVgEABENvZGUB" + + "AA9MaW5lTnVtYmVyVGFibGUBAAVzYXlIaQEAClNvdXJjZUZpbGUBAAxUZXN0OTQ0LmphdmEMAAcA" + + "CAcAGQwAGgAbAQAIR29vZGJ5ZTIHABwMAB0AHgcAHwEAFmFydC9UZXN0OTQ0JFRyYW5zZm9ybTIB" + + "AApUcmFuc2Zvcm0yAQAMSW5uZXJDbGFzc2VzAQAQamF2YS9sYW5nL09iamVjdAEAEGphdmEvbGFu" + + "Zy9TeXN0ZW0BAANvdXQBABVMamF2YS9pby9QcmludFN0cmVhbTsBABNqYXZhL2lvL1ByaW50U3Ry" + + "ZWFtAQAHcHJpbnRsbgEAFShMamF2YS9sYW5nL1N0cmluZzspVgEAC2FydC9UZXN0OTQ0ACAABQAG" + + "AAAAAAACAAAABwAIAAEACQAAAB0AAQABAAAABSq3AAGxAAAAAQAKAAAABgABAAAABQABAAsACAAB" + + "AAkAAAAlAAIAAQAAAAmyAAISA7YABLEAAAABAAoAAAAKAAIAAAAHAAgACAACAAwAAAACAA0AFwAA" + + "AAoAAQAFABQAFgAI"), + Base64.getDecoder().decode( + "ZGV4CjAzNQAUg8BCAAAAAAAAAAAAAAAAAAAAAAAAAAC8AwAAcAAAAHhWNBIAAAAAAAAAAPgCAAAU" + + "AAAAcAAAAAkAAADAAAAAAgAAAOQAAAABAAAA/AAAAAQAAAAEAQAAAQAAACQBAAB4AgAARAEAAEQB" + + "AABMAQAAVgEAAHABAAB/AQAAowEAAMMBAADaAQAA7gEAAAICAAAWAgAAJAIAADACAAAzAgAANwIA" + + "AEQCAABKAgAATwIAAFgCAABfAgAAAgAAAAMAAAAEAAAABQAAAAYAAAAHAAAACAAAAAkAAAAMAAAA" + + "DAAAAAgAAAAAAAAADQAAAAgAAABoAgAABwAEABAAAAAAAAAAAAAAAAAAAAASAAAABAABABEAAAAF" + + "AAAAAAAAAAAAAAAAAAAABQAAAAAAAAAKAAAA6AIAALwCAAAAAAAABjxpbml0PgAIR29vZGJ5ZTIA" + + "GExhcnQvVGVzdDk0NCRUcmFuc2Zvcm0yOwANTGFydC9UZXN0OTQ0OwAiTGRhbHZpay9hbm5vdGF0" + + "aW9uL0VuY2xvc2luZ0NsYXNzOwAeTGRhbHZpay9hbm5vdGF0aW9uL0lubmVyQ2xhc3M7ABVMamF2" + + "YS9pby9QcmludFN0cmVhbTsAEkxqYXZhL2xhbmcvT2JqZWN0OwASTGphdmEvbGFuZy9TdHJpbmc7" + + "ABJMamF2YS9sYW5nL1N5c3RlbTsADFRlc3Q5NDQuamF2YQAKVHJhbnNmb3JtMgABVgACVkwAC2Fj" + + "Y2Vzc0ZsYWdzAARuYW1lAANvdXQAB3ByaW50bG4ABXNheUhpAAV2YWx1ZQAAAAEAAAAGAAAABQAH" + + "DgAHAAcOAQgPAAAAAAEAAQABAAAAcAIAAAQAAABwEAMAAAAOAAMAAQACAAAAdQIAAAkAAABiAAAA" + + "GwEBAAAAbiACABAADgAAAAAAAQEAgIAEgAUBAZgFAAACAgETGAECAwIOBAgPFwsAAgAAAMwCAADS" + + "AgAA3AIAAAAAAAAAAAAAAAAAABAAAAAAAAAAAQAAAAAAAAABAAAAFAAAAHAAAAACAAAACQAAAMAA" + + "AAADAAAAAgAAAOQAAAAEAAAAAQAAAPwAAAAFAAAABAAAAAQBAAAGAAAAAQAAACQBAAACIAAAFAAA" + + "AEQBAAABEAAAAQAAAGgCAAADIAAAAgAAAHACAAABIAAAAgAAAIACAAAAIAAAAQAAALwCAAAEIAAA" + + "AgAAAMwCAAADEAAAAQAAANwCAAAGIAAAAQAAAOgCAAAAEAAAAQAAAPgCAAA=")); + + public static void run() throws Exception { + Redefinition.setTestConfiguration(Redefinition.Config.COMMON_REDEFINE); + doTest(); + System.out.println("Passed"); + } + + private static void checkIsInstance(Class<?> klass, Object o) throws Exception { + if (!klass.isInstance(o)) { + throw new Exception(klass + " is not the class of " + o); + } + } + + private static boolean arrayContains(long[] arr, long value) { + if (arr == null) { + return false; + } + for (int i = 0; i < arr.length; i++) { + if (arr[i] == value) { + return true; + } + } + return false; + } + + /** + * Checks that we can find the dex-file for the given class in its classloader. + * + * Throws if it fails. + */ + private static void checkDexFileInClassLoader(Class<?> klass) throws Exception { + // If all the android BCP classes were availible when compiling this test and access checks + // weren't a thing this function would be written as follows: + // + // long dexFilePtr = getDexFilePointer(klass); + // dalvik.system.BaseDexClassLoader loader = + // (dalvik.system.BaseDexClassLoader)klass.getClassLoader(); + // dalvik.system.DexPathList pathListValue = loader.pathList; + // dalvik.system.DexPathList.Element[] elementArrayValue = pathListValue.dexElements; + // int array_length = elementArrayValue.length; + // for (int i = 0; i < array_length; i++) { + // dalvik.system.DexPathList.Element curElement = elementArrayValue[i]; + // dalvik.system.DexFile curDexFile = curElement.dexFile; + // if (curDexFile == null) { + // continue; + // } + // long[] curCookie = (long[])curDexFile.mCookie; + // long[] curInternalCookie = (long[])curDexFile.mInternalCookie; + // if (arrayContains(curCookie, dexFilePtr) || arrayContains(curInternalCookie, dexFilePtr)) { + // return; + // } + // } + // throw new Exception( + // "Unable to find dex file pointer " + dexFilePtr + " in class loader for " + klass); + + // Get all the fields and classes we need by reflection. + Class<?> baseDexClassLoaderClass = Class.forName("dalvik.system.BaseDexClassLoader"); + Field pathListField = baseDexClassLoaderClass.getDeclaredField("pathList"); + + Class<?> dexPathListClass = Class.forName("dalvik.system.DexPathList"); + Field elementArrayField = dexPathListClass.getDeclaredField("dexElements"); + + Class<?> dexPathListElementClass = Class.forName("dalvik.system.DexPathList$Element"); + Field dexFileField = dexPathListElementClass.getDeclaredField("dexFile"); + + Class<?> dexFileClass = Class.forName("dalvik.system.DexFile"); + Field dexFileCookieField = dexFileClass.getDeclaredField("mCookie"); + Field dexFileInternalCookieField = dexFileClass.getDeclaredField("mInternalCookie"); + + // Make all the fields accessible + AccessibleObject.setAccessible(new AccessibleObject[] { pathListField, + elementArrayField, + dexFileField, + dexFileCookieField, + dexFileInternalCookieField }, true); + + long dexFilePtr = getDexFilePointer(klass); + + ClassLoader loader = klass.getClassLoader(); + checkIsInstance(baseDexClassLoaderClass, loader); + // DexPathList pathListValue = ((BaseDexClassLoader) loader).pathList; + Object pathListValue = pathListField.get(loader); + + checkIsInstance(dexPathListClass, pathListValue); + + // DexPathList.Element[] elementArrayValue = pathListValue.dexElements; + Object elementArrayValue = elementArrayField.get(pathListValue); + if (!elementArrayValue.getClass().isArray() || + elementArrayValue.getClass().getComponentType() != dexPathListElementClass) { + throw new Exception("elementArrayValue is not an " + dexPathListElementClass + " array!"); + } + // int array_length = elementArrayValue.length; + int array_length = Array.getLength(elementArrayValue); + for (int i = 0; i < array_length; i++) { + // DexPathList.Element curElement = elementArrayValue[i]; + Object curElement = Array.get(elementArrayValue, i); + checkIsInstance(dexPathListElementClass, curElement); + + // DexFile curDexFile = curElement.dexFile; + Object curDexFile = dexFileField.get(curElement); + if (curDexFile == null) { + continue; + } + checkIsInstance(dexFileClass, curDexFile); + + // long[] curCookie = (long[])curDexFile.mCookie; + long[] curCookie = (long[])dexFileCookieField.get(curDexFile); + // long[] curInternalCookie = (long[])curDexFile.mInternalCookie; + long[] curInternalCookie = (long[])dexFileInternalCookieField.get(curDexFile); + + if (arrayContains(curCookie, dexFilePtr) || arrayContains(curInternalCookie, dexFilePtr)) { + return; + } + } + throw new Exception( + "Unable to find dex file pointer " + dexFilePtr + " in class loader for " + klass); + } + + private static void doTest() throws Exception { + Transform t = new Transform(); + Transform2 t2 = new Transform2(); + + long initial_t1_dex = getDexFilePointer(Transform.class); + long initial_t2_dex = getDexFilePointer(Transform2.class); + if (initial_t2_dex != initial_t1_dex) { + throw new Exception("The classes " + Transform.class + " and " + Transform2.class + " " + + "have different initial dex files!"); + } + checkDexFileInClassLoader(Transform.class); + checkDexFileInClassLoader(Transform2.class); + + // Make sure they are loaded + t.sayHi(); + t2.sayHi(); + // Redefine both of the classes. + Redefinition.doMultiClassRedefinition(TRANSFORM_DEFINITION, TRANSFORM2_DEFINITION); + // Make sure we actually transformed them! + t.sayHi(); + t2.sayHi(); + + long final_t1_dex = getDexFilePointer(Transform.class); + long final_t2_dex = getDexFilePointer(Transform2.class); + if (final_t2_dex == final_t1_dex) { + throw new Exception("The classes " + Transform.class + " and " + Transform2.class + " " + + "have the same initial dex files!"); + } else if (final_t1_dex == initial_t1_dex) { + throw new Exception("The class " + Transform.class + " did not get a new dex file!"); + } else if (final_t2_dex == initial_t2_dex) { + throw new Exception("The class " + Transform2.class + " did not get a new dex file!"); + } + // Check to make sure the new dex files are in the class loader. + checkDexFileInClassLoader(Transform.class); + checkDexFileInClassLoader(Transform2.class); + } + + // Gets the 'long' (really a native pointer) that is stored in the ClassLoader representing the + // DexFile a class is loaded from. This is plucked out of the internal DexCache object associated + // with the class. + private static long getDexFilePointer(Class<?> target) throws Exception { + // If all the android BCP classes were available when compiling this test and access checks + // weren't a thing this function would be written as follows: + // + // java.lang.DexCache dexCacheObject = target.dexCache; + // if (dexCacheObject == null) { + // return 0; + // } + // return dexCacheObject.dexFile; + Field dexCacheField = Class.class.getDeclaredField("dexCache"); + + Class<?> dexCacheClass = Class.forName("java.lang.DexCache"); + Field dexFileField = dexCacheClass.getDeclaredField("dexFile"); + + AccessibleObject.setAccessible(new AccessibleObject[] { dexCacheField, dexFileField }, true); + + Object dexCacheObject = dexCacheField.get(target); + if (dexCacheObject == null) { + return 0; + } + checkIsInstance(dexCacheClass, dexCacheObject); + return dexFileField.getLong(dexCacheObject); + } +} diff --git a/test/945-obsolete-native/obsolete_native.cc b/test/945-obsolete-native/obsolete_native.cc index ee653a4a12..e3090f5906 100644 --- a/test/945-obsolete-native/obsolete_native.cc +++ b/test/945-obsolete-native/obsolete_native.cc @@ -19,31 +19,20 @@ #include <stdio.h> #include "android-base/stringprintf.h" - -#include "android-base/stringprintf.h" -#include "base/logging.h" -#include "base/macros.h" #include "jni.h" #include "jvmti.h" -#include "scoped_local_ref.h" // Test infrastructure #include "jni_binder.h" #include "test_env.h" +#include "scoped_local_ref.h" namespace art { namespace Test945ObsoleteNative { -extern "C" JNIEXPORT void JNICALL Java_Main_bindTest945ObsoleteNative( - JNIEnv* env, jclass klass ATTRIBUTE_UNUSED) { - BindFunctions(jvmti_env, env, "Transform"); -} - -extern "C" JNIEXPORT void JNICALL Java_Transform_doExecute(JNIEnv* env, - jclass klass ATTRIBUTE_UNUSED, - jobject runnable) { +extern "C" JNIEXPORT void JNICALL Java_art_Test945_00024Transform_doExecute( + JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jobject runnable) { jclass runnable_klass = env->FindClass("java/lang/Runnable"); - DCHECK(runnable_klass != nullptr); jmethodID run_method = env->GetMethodID(runnable_klass, "run", "()V"); env->CallVoidMethod(runnable, run_method); } diff --git a/test/945-obsolete-native/src/Main.java b/test/945-obsolete-native/src/Main.java index a7901cd2bb..c94bc2206c 100644 --- a/test/945-obsolete-native/src/Main.java +++ b/test/945-obsolete-native/src/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,65 +14,8 @@ * limitations under the License. */ -import java.util.Base64; - public class Main { - // class Transform { - // public void sayHi(Runnable r) { - // System.out.println("Hello - Transformed"); - // doExecute(r); - // System.out.println("Goodbye - Transformed"); - // } - // - // private static native void doExecute(Runnable r); - // } - private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( - "yv66vgAAADQAIgoACAASCQATABQIABUKABYAFwoABwAYCAAZBwAaBwAbAQAGPGluaXQ+AQADKClW" + - "AQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEABXNheUhpAQAXKExqYXZhL2xhbmcvUnVubmFibGU7" + - "KVYBAAlkb0V4ZWN1dGUBAApTb3VyY2VGaWxlAQAOVHJhbnNmb3JtLmphdmEMAAkACgcAHAwAHQAe" + - "AQATSGVsbG8gLSBUcmFuc2Zvcm1lZAcAHwwAIAAhDAAPAA4BABVHb29kYnllIC0gVHJhbnNmb3Jt" + - "ZWQBAAlUcmFuc2Zvcm0BABBqYXZhL2xhbmcvT2JqZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEAA291" + - "dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxu" + - "AQAVKExqYXZhL2xhbmcvU3RyaW5nOylWACAABwAIAAAAAAADAAAACQAKAAEACwAAAB0AAQABAAAA" + - "BSq3AAGxAAAAAQAMAAAABgABAAAAEQABAA0ADgABAAsAAAA5AAIAAgAAABWyAAISA7YABCu4AAWy" + - "AAISBrYABLEAAAABAAwAAAASAAQAAAATAAgAFAAMABUAFAAWAQoADwAOAAAAAQAQAAAAAgAR"); - private static final byte[] DEX_BYTES = Base64.getDecoder().decode( - "ZGV4CjAzNQB1fZcJR/opPuXacK8mIla5shH0LSg72qJYAwAAcAAAAHhWNBIAAAAAAAAAALgCAAAR" + - "AAAAcAAAAAcAAAC0AAAAAwAAANAAAAABAAAA9AAAAAUAAAD8AAAAAQAAACQBAAAUAgAARAEAAKIB" + - "AACqAQAAwQEAANYBAADjAQAA+gEAAA4CAAAkAgAAOAIAAEwCAABcAgAAXwIAAGMCAABuAgAAggIA" + - "AIcCAACQAgAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAACgAAAAoAAAAGAAAAAAAAAAsAAAAGAAAA" + - "lAEAAAsAAAAGAAAAnAEAAAUAAQAOAAAAAAAAAAAAAAAAAAEADAAAAAAAAQAQAAAAAQACAA8AAAAC" + - "AAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAJAAAAAAAAAKUCAAAAAAAAAQABAAEAAACXAgAABAAAAHAQ" + - "BAAAAA4ABAACAAIAAACcAgAAFAAAAGIAAAAbAQIAAABuIAMAEABxEAEAAwBiAAAAGwEBAAAAbiAD" + - "ABAADgABAAAAAwAAAAEAAAAEAAY8aW5pdD4AFUdvb2RieWUgLSBUcmFuc2Zvcm1lZAATSGVsbG8g" + - "LSBUcmFuc2Zvcm1lZAALTFRyYW5zZm9ybTsAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwASTGphdmEv" + - "bGFuZy9PYmplY3Q7ABRMamF2YS9sYW5nL1J1bm5hYmxlOwASTGphdmEvbGFuZy9TdHJpbmc7ABJM" + - "amF2YS9sYW5nL1N5c3RlbTsADlRyYW5zZm9ybS5qYXZhAAFWAAJWTAAJZG9FeGVjdXRlABJlbWl0" + - "dGVyOiBqYWNrLTQuMjUAA291dAAHcHJpbnRsbgAFc2F5SGkAEQAHDgATAQAHDoc8hwAAAAIBAICA" + - "BMQCAYoCAAIB3AIADQAAAAAAAAABAAAAAAAAAAEAAAARAAAAcAAAAAIAAAAHAAAAtAAAAAMAAAAD" + - "AAAA0AAAAAQAAAABAAAA9AAAAAUAAAAFAAAA/AAAAAYAAAABAAAAJAEAAAEgAAACAAAARAEAAAEQ" + - "AAACAAAAlAEAAAIgAAARAAAAogEAAAMgAAACAAAAlwIAAAAgAAABAAAApQIAAAAQAAABAAAAuAIA" + - "AA=="); - - public static void main(String[] args) { - art.Main.bindAgentJNIForClass(Main.class); - bindTest945ObsoleteNative(); - doTest(new Transform()); - } - - public static void doTest(Transform t) { - t.sayHi(() -> { System.out.println("Not doing anything here"); }); - t.sayHi(() -> { - System.out.println("transforming calling function"); - doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES); - }); - t.sayHi(() -> { System.out.println("Not doing anything here"); }); + public static void main(String[] args) throws Exception { + art.Test945.run(); } - - // Transforms the class - private static native void doCommonClassRedefinition(Class<?> target, - byte[] classfile, - byte[] dexfile); - - private static native void bindTest945ObsoleteNative(); } diff --git a/test/945-obsolete-native/src/Transform.java b/test/945-obsolete-native/src/Transform.java deleted file mode 100644 index 2b7cc1b3a1..0000000000 --- a/test/945-obsolete-native/src/Transform.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * 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. - */ - -class Transform { - public void sayHi(Runnable r) { - System.out.println("hello"); - doExecute(r); - System.out.println("goodbye"); - } - - private static native void doExecute(Runnable r); -} diff --git a/test/945-obsolete-native/src/art/Redefinition.java b/test/945-obsolete-native/src/art/Redefinition.java new file mode 100644 index 0000000000..0350ab42ad --- /dev/null +++ b/test/945-obsolete-native/src/art/Redefinition.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.util.ArrayList; +// Common Redefinition functions. Placed here for use by CTS +public class Redefinition { + // Bind native functions. + static { + Main.bindAgentJNIForClass(Redefinition.class); + } + + public static final class CommonClassDefinition { + public final Class<?> target; + public final byte[] class_file_bytes; + public final byte[] dex_file_bytes; + + public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { + this.target = target; + this.class_file_bytes = class_file_bytes; + this.dex_file_bytes = dex_file_bytes; + } + } + + // A set of possible test configurations. Test should set this if they need to. + // This must be kept in sync with the defines in ti-agent/common_helper.cc + public static enum Config { + COMMON_REDEFINE(0), + COMMON_RETRANSFORM(1), + COMMON_TRANSFORM(2); + + private final int val; + private Config(int val) { + this.val = val; + } + } + + public static void setTestConfiguration(Config type) { + nativeSetTestConfiguration(type.val); + } + + private static native void nativeSetTestConfiguration(int type); + + // Transforms the class + public static native void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile); + + public static void doMultiClassRedefinition(CommonClassDefinition... defs) { + ArrayList<Class<?>> classes = new ArrayList<>(); + ArrayList<byte[]> class_files = new ArrayList<>(); + ArrayList<byte[]> dex_files = new ArrayList<>(); + + for (CommonClassDefinition d : defs) { + classes.add(d.target); + class_files.add(d.class_file_bytes); + dex_files.add(d.dex_file_bytes); + } + doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), + class_files.toArray(new byte[0][]), + dex_files.toArray(new byte[0][])); + } + + public static void addMultiTransformationResults(CommonClassDefinition... defs) { + for (CommonClassDefinition d : defs) { + addCommonTransformationResult(d.target.getCanonicalName(), + d.class_file_bytes, + d.dex_file_bytes); + } + } + + public static native void doCommonMultiClassRedefinition(Class<?>[] targets, + byte[][] classfiles, + byte[][] dexfiles); + public static native void doCommonClassRetransformation(Class<?>... target); + public static native void setPopRetransformations(boolean pop); + public static native void popTransformationFor(String name); + public static native void enableCommonRetransformation(boolean enable); + public static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); +} diff --git a/test/945-obsolete-native/src/art/Test945.java b/test/945-obsolete-native/src/art/Test945.java new file mode 100644 index 0000000000..6cf31f6d05 --- /dev/null +++ b/test/945-obsolete-native/src/art/Test945.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * 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 art; + +import java.util.Base64; + +public class Test945 { + + static class Transform { + static { + art.Main.bindAgentJNIForClass(Transform.class); + } + + public void sayHi(Runnable r) { + System.out.println("hello"); + doExecute(r); + System.out.println("goodbye"); + } + + private static native void doExecute(Runnable r); + } + + // static class Transform { + // static { } + // public void sayHi(Runnable r) { + // System.out.println("Hello - Transformed"); + // doExecute(r); + // System.out.println("Goodbye - Transformed"); + // } + // + // private static native void doExecute(Runnable r); + // } + private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( + "yv66vgAAADQAJwoACAATCQAUABUIABYKABcAGAoABwAZCAAaBwAcBwAfAQAGPGluaXQ+AQADKClW" + + "AQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEABXNheUhpAQAXKExqYXZhL2xhbmcvUnVubmFibGU7" + + "KVYBAAlkb0V4ZWN1dGUBAAg8Y2xpbml0PgEAClNvdXJjZUZpbGUBAAxUZXN0OTQ1LmphdmEMAAkA" + + "CgcAIAwAIQAiAQATSGVsbG8gLSBUcmFuc2Zvcm1lZAcAIwwAJAAlDAAPAA4BABVHb29kYnllIC0g" + + "VHJhbnNmb3JtZWQHACYBABVhcnQvVGVzdDk0NSRUcmFuc2Zvcm0BAAlUcmFuc2Zvcm0BAAxJbm5l" + + "ckNsYXNzZXMBABBqYXZhL2xhbmcvT2JqZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxq" + + "YXZhL2lvL1ByaW50U3RyZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExq" + + "YXZhL2xhbmcvU3RyaW5nOylWAQALYXJ0L1Rlc3Q5NDUAIAAHAAgAAAAAAAQAAAAJAAoAAQALAAAA" + + "HQABAAEAAAAFKrcAAbEAAAABAAwAAAAGAAEAAAAFAAEADQAOAAEACwAAADkAAgACAAAAFbIAAhID" + + "tgAEK7gABbIAAhIGtgAEsQAAAAEADAAAABIABAAAAAgACAAJAAwACgAUAAsBCgAPAA4AAAAIABAA" + + "CgABAAsAAAAZAAAAAAAAAAGxAAAAAQAMAAAABgABAAAABgACABEAAAACABIAHgAAAAoAAQAHABsA" + + "HQAI"); + private static final byte[] DEX_BYTES = Base64.getDecoder().decode( + "ZGV4CjAzNQAFqcJFAAAAAAAAAAAAAAAAAAAAAAAAAAB8BAAAcAAAAHhWNBIAAAAAAAAAALgDAAAY" + + "AAAAcAAAAAoAAADQAAAAAwAAAPgAAAABAAAAHAEAAAYAAAAkAQAAAQAAAFQBAAAIAwAAdAEAAHQB" + + "AAB+AQAAhgEAAJ0BAACyAQAAywEAANoBAAD+AQAAHgIAADUCAABJAgAAXwIAAHMCAACHAgAAlQIA" + + "AKACAACjAgAApwIAALQCAAC/AgAAxQIAAMoCAADTAgAA2gIAAAQAAAAFAAAABgAAAAcAAAAIAAAA" + + "CQAAAAoAAAALAAAADAAAAA8AAAAPAAAACQAAAAAAAAAQAAAACQAAAOQCAAAQAAAACQAAAOwCAAAI" + + "AAQAFAAAAAAAAAAAAAAAAAAAAAEAAAAAAAEAEgAAAAAAAQAWAAAABAACABUAAAAFAAAAAQAAAAAA" + + "AAAAAAAABQAAAAAAAAANAAAAqAMAAHQDAAAAAAAACDxjbGluaXQ+AAY8aW5pdD4AFUdvb2RieWUg" + + "LSBUcmFuc2Zvcm1lZAATSGVsbG8gLSBUcmFuc2Zvcm1lZAAXTGFydC9UZXN0OTQ1JFRyYW5zZm9y" + + "bTsADUxhcnQvVGVzdDk0NTsAIkxkYWx2aWsvYW5ub3RhdGlvbi9FbmNsb3NpbmdDbGFzczsAHkxk" + + "YWx2aWsvYW5ub3RhdGlvbi9Jbm5lckNsYXNzOwAVTGphdmEvaW8vUHJpbnRTdHJlYW07ABJMamF2" + + "YS9sYW5nL09iamVjdDsAFExqYXZhL2xhbmcvUnVubmFibGU7ABJMamF2YS9sYW5nL1N0cmluZzsA" + + "EkxqYXZhL2xhbmcvU3lzdGVtOwAMVGVzdDk0NS5qYXZhAAlUcmFuc2Zvcm0AAVYAAlZMAAthY2Nl" + + "c3NGbGFncwAJZG9FeGVjdXRlAARuYW1lAANvdXQAB3ByaW50bG4ABXNheUhpAAV2YWx1ZQAAAAAB" + + "AAAABgAAAAEAAAAHAAAABQAHDgAFAAcOAAgBAAcOAQgPAQMPAQgPAAAAAAAAAAAAAAAA9AIAAAEA" + + "AAAOAAAAAQABAAEAAAD5AgAABAAAAHAQBQAAAA4ABAACAAIAAAD+AgAAFAAAAGIAAAAbAQMAAABu" + + "IAQAEABxEAIAAwBiAAAAGwECAAAAbiAEABAADgAAAAMBAIiABJAGAYCABKQGAYoCAAMBvAYCAgEX" + + "GAECAwIRBAgTFw4AAgAAAIwDAACSAwAAnAMAAAAAAAAAAAAAAAAAABAAAAAAAAAAAQAAAAAAAAAB" + + "AAAAGAAAAHAAAAACAAAACgAAANAAAAADAAAAAwAAAPgAAAAEAAAAAQAAABwBAAAFAAAABgAAACQB" + + "AAAGAAAAAQAAAFQBAAACIAAAGAAAAHQBAAABEAAAAgAAAOQCAAADIAAAAwAAAPQCAAABIAAAAwAA" + + "ABADAAAAIAAAAQAAAHQDAAAEIAAAAgAAAIwDAAADEAAAAQAAAJwDAAAGIAAAAQAAAKgDAAAAEAAA" + + "AQAAALgDAAA="); + + public static void run() { + Redefinition.setTestConfiguration(Redefinition.Config.COMMON_REDEFINE); + doTest(new Transform()); + } + + public static void doTest(Transform t) { + t.sayHi(() -> { System.out.println("Not doing anything here"); }); + t.sayHi(() -> { + System.out.println("transforming calling function"); + Redefinition.doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES); + }); + t.sayHi(() -> { System.out.println("Not doing anything here"); }); + } +} diff --git a/test/946-obsolete-throw/expected.txt b/test/946-obsolete-throw/expected.txt index 71d5182100..edf796eb96 100644 --- a/test/946-obsolete-throw/expected.txt +++ b/test/946-obsolete-throw/expected.txt @@ -5,10 +5,11 @@ hello transforming calling function Received error : java.lang.Error: Throwing exception into an obsolete method! java.lang.Error: Throwing exception into an obsolete method! - at Main$DoRedefinitionClass.run(Main.java:65) - at Transform.sayHi(Transform.java:27) - at Main.doTest(Main.java:72) - at Main.main(Main.java:57) + at art.Test946$DoRedefinitionClass.run(Test946.java:81) + at art.Test946$Transform.sayHi(Test946.java:26) + at art.Test946.doTest(Test946.java:88) + at art.Test946.run(Test946.java:73) + at Main.main(Main.java:19) Hello - Transformed Not doing anything here Goodbye - Transformed diff --git a/test/946-obsolete-throw/src/Main.java b/test/946-obsolete-throw/src/Main.java index 077ad72acd..0b1f78dc4a 100644 --- a/test/946-obsolete-throw/src/Main.java +++ b/test/946-obsolete-throw/src/Main.java @@ -14,71 +14,8 @@ * limitations under the License. */ -import java.util.Base64; - public class Main { - // class Transform { - // public void sayHi(Runnable r) { - // System.out.println("Hello - Transformed"); - // r.run(); - // System.out.println("Goodbye - Transformed"); - // } - // } - private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( - "yv66vgAAADQAJAoACAARCQASABMIABQKABUAFgsAFwAYCAAZBwAaBwAbAQAGPGluaXQ+AQADKClW" + - "AQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEABXNheUhpAQAXKExqYXZhL2xhbmcvUnVubmFibGU7" + - "KVYBAApTb3VyY2VGaWxlAQAOVHJhbnNmb3JtLmphdmEMAAkACgcAHAwAHQAeAQATSGVsbG8gLSBU" + - "cmFuc2Zvcm1lZAcAHwwAIAAhBwAiDAAjAAoBABVHb29kYnllIC0gVHJhbnNmb3JtZWQBAAlUcmFu" + - "c2Zvcm0BABBqYXZhL2xhbmcvT2JqZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZh" + - "L2lvL1ByaW50U3RyZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZh" + - "L2xhbmcvU3RyaW5nOylWAQASamF2YS9sYW5nL1J1bm5hYmxlAQADcnVuACAABwAIAAAAAAACAAAA" + - "CQAKAAEACwAAAB0AAQABAAAABSq3AAGxAAAAAQAMAAAABgABAAAAAQABAA0ADgABAAsAAAA7AAIA" + - "AgAAABeyAAISA7YABCu5AAUBALIAAhIGtgAEsQAAAAEADAAAABIABAAAAAMACAAEAA4ABQAWAAYA" + - "AQAPAAAAAgAQ"); - private static final byte[] DEX_BYTES = Base64.getDecoder().decode( - "ZGV4CjAzNQAYeAMMXgYWxoeSHAS9EWKCCtVRSAGpqZVQAwAAcAAAAHhWNBIAAAAAAAAAALACAAAR" + - "AAAAcAAAAAcAAAC0AAAAAwAAANAAAAABAAAA9AAAAAUAAAD8AAAAAQAAACQBAAAMAgAARAEAAKIB" + - "AACqAQAAwQEAANYBAADjAQAA+gEAAA4CAAAkAgAAOAIAAEwCAABcAgAAXwIAAGMCAAB3AgAAfAIA" + - "AIUCAACKAgAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAACgAAAAoAAAAGAAAAAAAAAAsAAAAGAAAA" + - "lAEAAAsAAAAGAAAAnAEAAAUAAQANAAAAAAAAAAAAAAAAAAEAEAAAAAEAAgAOAAAAAgAAAAAAAAAD" + - "AAAADwAAAAAAAAAAAAAAAgAAAAAAAAAJAAAAAAAAAJ8CAAAAAAAAAQABAAEAAACRAgAABAAAAHAQ" + - "AwAAAA4ABAACAAIAAACWAgAAFAAAAGIAAAAbAQIAAABuIAIAEAByEAQAAwBiAAAAGwEBAAAAbiAC" + - "ABAADgABAAAAAwAAAAEAAAAEAAY8aW5pdD4AFUdvb2RieWUgLSBUcmFuc2Zvcm1lZAATSGVsbG8g" + - "LSBUcmFuc2Zvcm1lZAALTFRyYW5zZm9ybTsAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwASTGphdmEv" + - "bGFuZy9PYmplY3Q7ABRMamF2YS9sYW5nL1J1bm5hYmxlOwASTGphdmEvbGFuZy9TdHJpbmc7ABJM" + - "amF2YS9sYW5nL1N5c3RlbTsADlRyYW5zZm9ybS5qYXZhAAFWAAJWTAASZW1pdHRlcjogamFjay00" + - "LjEzAANvdXQAB3ByaW50bG4AA3J1bgAFc2F5SGkAAQAHDgADAQAHDoc8hwAAAAEBAICABMQCAQHc" + - "AgAAAA0AAAAAAAAAAQAAAAAAAAABAAAAEQAAAHAAAAACAAAABwAAALQAAAADAAAAAwAAANAAAAAE" + - "AAAAAQAAAPQAAAAFAAAABQAAAPwAAAAGAAAAAQAAACQBAAABIAAAAgAAAEQBAAABEAAAAgAAAJQB" + - "AAACIAAAEQAAAKIBAAADIAAAAgAAAJECAAAAIAAAAQAAAJ8CAAAAEAAAAQAAALACAAA="); - - public static void main(String[] args) { - art.Main.bindAgentJNIForClass(Main.class); - doTest(new Transform()); - } - - static class DoRedefinitionClass implements Runnable { - @Override - public void run() { - System.out.println("transforming calling function"); - doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES); - throw new Error("Throwing exception into an obsolete method!"); - } + public static void main(String[] args) throws Exception { + art.Test946.run(); } - - public static void doTest(Transform t) { - t.sayHi(() -> { System.out.println("Not doing anything here"); }); - try { - t.sayHi(new DoRedefinitionClass()); - } catch (Throwable e) { - System.out.println("Received error : " + e); - e.printStackTrace(System.out); - } - t.sayHi(() -> { System.out.println("Not doing anything here"); }); - } - - // Transforms the class - private static native void doCommonClassRedefinition(Class<?> target, - byte[] classfile, - byte[] dexfile); } diff --git a/test/946-obsolete-throw/src/Transform.java b/test/946-obsolete-throw/src/Transform.java deleted file mode 100644 index 4f43086d32..0000000000 --- a/test/946-obsolete-throw/src/Transform.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * 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. - */ - -class Transform { - public void sayHi(Runnable r) { - // Use lower 'h' to make sure the string will have a different string id - // than the transformation (the transformation code is the same except - // the actual printed String, which was making the test inacurately passing - // in JIT mode when loading the string from the dex cache, as the string ids - // of the two different strings were the same). - // We know the string ids will be different because lexicographically: - // "Hello" < "LTransform;" < "hello". - System.out.println("hello"); - r.run(); - System.out.println("goodbye"); - } -} diff --git a/test/946-obsolete-throw/src/art/Redefinition.java b/test/946-obsolete-throw/src/art/Redefinition.java new file mode 100644 index 0000000000..0350ab42ad --- /dev/null +++ b/test/946-obsolete-throw/src/art/Redefinition.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.util.ArrayList; +// Common Redefinition functions. Placed here for use by CTS +public class Redefinition { + // Bind native functions. + static { + Main.bindAgentJNIForClass(Redefinition.class); + } + + public static final class CommonClassDefinition { + public final Class<?> target; + public final byte[] class_file_bytes; + public final byte[] dex_file_bytes; + + public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { + this.target = target; + this.class_file_bytes = class_file_bytes; + this.dex_file_bytes = dex_file_bytes; + } + } + + // A set of possible test configurations. Test should set this if they need to. + // This must be kept in sync with the defines in ti-agent/common_helper.cc + public static enum Config { + COMMON_REDEFINE(0), + COMMON_RETRANSFORM(1), + COMMON_TRANSFORM(2); + + private final int val; + private Config(int val) { + this.val = val; + } + } + + public static void setTestConfiguration(Config type) { + nativeSetTestConfiguration(type.val); + } + + private static native void nativeSetTestConfiguration(int type); + + // Transforms the class + public static native void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile); + + public static void doMultiClassRedefinition(CommonClassDefinition... defs) { + ArrayList<Class<?>> classes = new ArrayList<>(); + ArrayList<byte[]> class_files = new ArrayList<>(); + ArrayList<byte[]> dex_files = new ArrayList<>(); + + for (CommonClassDefinition d : defs) { + classes.add(d.target); + class_files.add(d.class_file_bytes); + dex_files.add(d.dex_file_bytes); + } + doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), + class_files.toArray(new byte[0][]), + dex_files.toArray(new byte[0][])); + } + + public static void addMultiTransformationResults(CommonClassDefinition... defs) { + for (CommonClassDefinition d : defs) { + addCommonTransformationResult(d.target.getCanonicalName(), + d.class_file_bytes, + d.dex_file_bytes); + } + } + + public static native void doCommonMultiClassRedefinition(Class<?>[] targets, + byte[][] classfiles, + byte[][] dexfiles); + public static native void doCommonClassRetransformation(Class<?>... target); + public static native void setPopRetransformations(boolean pop); + public static native void popTransformationFor(String name); + public static native void enableCommonRetransformation(boolean enable); + public static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); +} diff --git a/test/946-obsolete-throw/src/art/Test946.java b/test/946-obsolete-throw/src/art/Test946.java new file mode 100644 index 0000000000..9f0e57c333 --- /dev/null +++ b/test/946-obsolete-throw/src/art/Test946.java @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.util.Base64; + +public class Test946 { + + static class Transform { + public void sayHi(Runnable r) { + System.out.println("hello"); + r.run(); + System.out.println("goodbye"); + } + } + + // static class Transform { + // public void sayHi(Runnable r) { + // System.out.println("Hello - Transformed"); + // r.run(); + // System.out.println("Goodbye - Transformed"); + // } + // } + private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( + "yv66vgAAADQAKAoACAARCQASABMIABQKABUAFgsAFwAYCAAZBwAbBwAeAQAGPGluaXQ+AQADKClW" + + "AQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEABXNheUhpAQAXKExqYXZhL2xhbmcvUnVubmFibGU7" + + "KVYBAApTb3VyY2VGaWxlAQAMVGVzdDk0Ni5qYXZhDAAJAAoHAB8MACAAIQEAE0hlbGxvIC0gVHJh" + + "bnNmb3JtZWQHACIMACMAJAcAJQwAJgAKAQAVR29vZGJ5ZSAtIFRyYW5zZm9ybWVkBwAnAQAVYXJ0" + + "L1Rlc3Q5NDYkVHJhbnNmb3JtAQAJVHJhbnNmb3JtAQAMSW5uZXJDbGFzc2VzAQAQamF2YS9sYW5n" + + "L09iamVjdAEAEGphdmEvbGFuZy9TeXN0ZW0BAANvdXQBABVMamF2YS9pby9QcmludFN0cmVhbTsB" + + "ABNqYXZhL2lvL1ByaW50U3RyZWFtAQAHcHJpbnRsbgEAFShMamF2YS9sYW5nL1N0cmluZzspVgEA" + + "EmphdmEvbGFuZy9SdW5uYWJsZQEAA3J1bgEAC2FydC9UZXN0OTQ2ACAABwAIAAAAAAACAAAACQAK" + + "AAEACwAAAB0AAQABAAAABSq3AAGxAAAAAQAMAAAABgABAAAABQABAA0ADgABAAsAAAA7AAIAAgAA" + + "ABeyAAISA7YABCu5AAUBALIAAhIGtgAEsQAAAAEADAAAABIABAAAAAcACAAIAA4ACQAWAAoAAgAP" + + "AAAAAgAQAB0AAAAKAAEABwAaABwACA=="); + private static final byte[] DEX_BYTES = Base64.getDecoder().decode( + "ZGV4CjAzNQB0mzt6AAAAAAAAAAAAAAAAAAAAAAAAAAA8BAAAcAAAAHhWNBIAAAAAAAAAAHgDAAAX" + + "AAAAcAAAAAoAAADMAAAAAwAAAPQAAAABAAAAGAEAAAUAAAAgAQAAAQAAAEgBAADUAgAAaAEAAGgB" + + "AABwAQAAhwEAAJwBAAC1AQAAxAEAAOgBAAAIAgAAHwIAADMCAABJAgAAXQIAAHECAAB/AgAAigIA" + + "AI0CAACRAgAAngIAAKQCAACpAgAAsgIAALcCAAC+AgAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAA" + + "CQAAAAoAAAALAAAADgAAAA4AAAAJAAAAAAAAAA8AAAAJAAAAyAIAAA8AAAAJAAAA0AIAAAgABAAS" + + "AAAAAAAAAAAAAAAAAAEAFQAAAAQAAgATAAAABQAAAAAAAAAGAAAAFAAAAAAAAAAAAAAABQAAAAAA" + + "AAAMAAAAaAMAADwDAAAAAAAABjxpbml0PgAVR29vZGJ5ZSAtIFRyYW5zZm9ybWVkABNIZWxsbyAt" + + "IFRyYW5zZm9ybWVkABdMYXJ0L1Rlc3Q5NDYkVHJhbnNmb3JtOwANTGFydC9UZXN0OTQ2OwAiTGRh" + + "bHZpay9hbm5vdGF0aW9uL0VuY2xvc2luZ0NsYXNzOwAeTGRhbHZpay9hbm5vdGF0aW9uL0lubmVy" + + "Q2xhc3M7ABVMamF2YS9pby9QcmludFN0cmVhbTsAEkxqYXZhL2xhbmcvT2JqZWN0OwAUTGphdmEv" + + "bGFuZy9SdW5uYWJsZTsAEkxqYXZhL2xhbmcvU3RyaW5nOwASTGphdmEvbGFuZy9TeXN0ZW07AAxU" + + "ZXN0OTQ2LmphdmEACVRyYW5zZm9ybQABVgACVkwAC2FjY2Vzc0ZsYWdzAARuYW1lAANvdXQAB3By" + + "aW50bG4AA3J1bgAFc2F5SGkABXZhbHVlAAAAAAEAAAAGAAAAAQAAAAcAAAAFAAcOAAcBAAcOAQgP" + + "AQMPAQgPAAEAAQABAAAA2AIAAAQAAABwEAMAAAAOAAQAAgACAAAA3QIAABQAAABiAAAAGwECAAAA" + + "biACABAAchAEAAMAYgAAABsBAQAAAG4gAgAQAA4AAAABAQCAgATsBQEBhAYAAAICARYYAQIDAhAE" + + "CBEXDQACAAAATAMAAFIDAABcAwAAAAAAAAAAAAAAAAAAEAAAAAAAAAABAAAAAAAAAAEAAAAXAAAA" + + "cAAAAAIAAAAKAAAAzAAAAAMAAAADAAAA9AAAAAQAAAABAAAAGAEAAAUAAAAFAAAAIAEAAAYAAAAB" + + "AAAASAEAAAIgAAAXAAAAaAEAAAEQAAACAAAAyAIAAAMgAAACAAAA2AIAAAEgAAACAAAA7AIAAAAg" + + "AAABAAAAPAMAAAQgAAACAAAATAMAAAMQAAABAAAAXAMAAAYgAAABAAAAaAMAAAAQAAABAAAAeAMA" + + "AA=="); + + public static void run() { + doTest(new Transform()); + } + + static class DoRedefinitionClass implements Runnable { + @Override + public void run() { + System.out.println("transforming calling function"); + Redefinition.doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES); + throw new Error("Throwing exception into an obsolete method!"); + } + } + + public static void doTest(Transform t) { + t.sayHi(() -> { System.out.println("Not doing anything here"); }); + try { + t.sayHi(new DoRedefinitionClass()); + } catch (Throwable e) { + System.out.println("Received error : " + e); + e.printStackTrace(System.out); + } + t.sayHi(() -> { System.out.println("Not doing anything here"); }); + } +} diff --git a/test/947-reflect-method/src/Main.java b/test/947-reflect-method/src/Main.java index da746ac4db..bc3f4b2cf4 100644 --- a/test/947-reflect-method/src/Main.java +++ b/test/947-reflect-method/src/Main.java @@ -14,60 +14,8 @@ * limitations under the License. */ -import java.util.Base64; -import java.lang.reflect.Method; - public class Main { - - /** - * base64 encoded class/dex file for - * class Transform { - * public void sayHi() { - * System.out.println("Goodbye"); - * } - * } - */ - private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( - "yv66vgAAADQAHAoABgAOCQAPABAIABEKABIAEwcAFAcAFQEABjxpbml0PgEAAygpVgEABENvZGUB" + - "AA9MaW5lTnVtYmVyVGFibGUBAAVzYXlIaQEAClNvdXJjZUZpbGUBAA5UcmFuc2Zvcm0uamF2YQwA" + - "BwAIBwAWDAAXABgBAAdHb29kYnllBwAZDAAaABsBAAlUcmFuc2Zvcm0BABBqYXZhL2xhbmcvT2Jq" + - "ZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2ph" + - "dmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWACAABQAG" + - "AAAAAAACAAAABwAIAAEACQAAAB0AAQABAAAABSq3AAGxAAAAAQAKAAAABgABAAAAEQABAAsACAAB" + - "AAkAAAAlAAIAAQAAAAmyAAISA7YABLEAAAABAAoAAAAKAAIAAAATAAgAFAABAAwAAAACAA0="); - private static final byte[] DEX_BYTES = Base64.getDecoder().decode( - "ZGV4CjAzNQCLXSBQ5FiS3f16krSYZFF8xYZtFVp0GRXMAgAAcAAAAHhWNBIAAAAAAAAAACwCAAAO" + - "AAAAcAAAAAYAAACoAAAAAgAAAMAAAAABAAAA2AAAAAQAAADgAAAAAQAAAAABAACsAQAAIAEAAGIB" + - "AABqAQAAcwEAAIABAACXAQAAqwEAAL8BAADTAQAA4wEAAOYBAADqAQAA/gEAAAMCAAAMAgAAAgAA" + - "AAMAAAAEAAAABQAAAAYAAAAIAAAACAAAAAUAAAAAAAAACQAAAAUAAABcAQAABAABAAsAAAAAAAAA" + - "AAAAAAAAAAANAAAAAQABAAwAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAHAAAAAAAAAB4CAAAA" + - "AAAAAQABAAEAAAATAgAABAAAAHAQAwAAAA4AAwABAAIAAAAYAgAACQAAAGIAAAAbAQEAAABuIAIA" + - "EAAOAAAAAQAAAAMABjxpbml0PgAHR29vZGJ5ZQALTFRyYW5zZm9ybTsAFUxqYXZhL2lvL1ByaW50" + - "U3RyZWFtOwASTGphdmEvbGFuZy9PYmplY3Q7ABJMamF2YS9sYW5nL1N0cmluZzsAEkxqYXZhL2xh" + - "bmcvU3lzdGVtOwAOVHJhbnNmb3JtLmphdmEAAVYAAlZMABJlbWl0dGVyOiBqYWNrLTMuMzYAA291" + - "dAAHcHJpbnRsbgAFc2F5SGkAEQAHDgATAAcOhQAAAAEBAICABKACAQG4Ag0AAAAAAAAAAQAAAAAA" + - "AAABAAAADgAAAHAAAAACAAAABgAAAKgAAAADAAAAAgAAAMAAAAAEAAAAAQAAANgAAAAFAAAABAAA" + - "AOAAAAAGAAAAAQAAAAABAAABIAAAAgAAACABAAABEAAAAQAAAFwBAAACIAAADgAAAGIBAAADIAAA" + - "AgAAABMCAAAAIAAAAQAAAB4CAAAAEAAAAQAAACwCAAA="); - - public static void main(String[] args) { - art.Main.bindAgentJNIForClass(Main.class); - doTest(new Transform()); + public static void main(String[] args) throws Exception { + art.Test947.run(); } - - public static void doTest(Transform t) { - try { - Method say_hi_method = t.getClass().getDeclaredMethod("sayHi"); - say_hi_method.invoke(t); - doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES); - say_hi_method.invoke(t); - } catch (Exception e) { - e.printStackTrace(); - } - } - - // Transforms the class - private static native void doCommonClassRedefinition(Class<?> target, - byte[] class_file, - byte[] dex_file); } diff --git a/test/947-reflect-method/src/Transform.java b/test/947-reflect-method/src/Transform.java deleted file mode 100644 index b8fe34aef3..0000000000 --- a/test/947-reflect-method/src/Transform.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * 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. - */ - -class Transform { - public void sayHi() { - // Use lower 'h' to make sure the string will have a different string id - // than the transformation (the transformation code is the same except - // the actual printed String, which was making the test inacurately passing - // in JIT mode when loading the string from the dex cache, as the string ids - // of the two different strings were the same). - // We know the string ids will be different because lexicographically: - // "Goodbye" < "LTransform;" < "hello". - System.out.println("hello"); - } -} diff --git a/test/947-reflect-method/src/art/Redefinition.java b/test/947-reflect-method/src/art/Redefinition.java new file mode 100644 index 0000000000..0350ab42ad --- /dev/null +++ b/test/947-reflect-method/src/art/Redefinition.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.util.ArrayList; +// Common Redefinition functions. Placed here for use by CTS +public class Redefinition { + // Bind native functions. + static { + Main.bindAgentJNIForClass(Redefinition.class); + } + + public static final class CommonClassDefinition { + public final Class<?> target; + public final byte[] class_file_bytes; + public final byte[] dex_file_bytes; + + public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { + this.target = target; + this.class_file_bytes = class_file_bytes; + this.dex_file_bytes = dex_file_bytes; + } + } + + // A set of possible test configurations. Test should set this if they need to. + // This must be kept in sync with the defines in ti-agent/common_helper.cc + public static enum Config { + COMMON_REDEFINE(0), + COMMON_RETRANSFORM(1), + COMMON_TRANSFORM(2); + + private final int val; + private Config(int val) { + this.val = val; + } + } + + public static void setTestConfiguration(Config type) { + nativeSetTestConfiguration(type.val); + } + + private static native void nativeSetTestConfiguration(int type); + + // Transforms the class + public static native void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile); + + public static void doMultiClassRedefinition(CommonClassDefinition... defs) { + ArrayList<Class<?>> classes = new ArrayList<>(); + ArrayList<byte[]> class_files = new ArrayList<>(); + ArrayList<byte[]> dex_files = new ArrayList<>(); + + for (CommonClassDefinition d : defs) { + classes.add(d.target); + class_files.add(d.class_file_bytes); + dex_files.add(d.dex_file_bytes); + } + doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), + class_files.toArray(new byte[0][]), + dex_files.toArray(new byte[0][])); + } + + public static void addMultiTransformationResults(CommonClassDefinition... defs) { + for (CommonClassDefinition d : defs) { + addCommonTransformationResult(d.target.getCanonicalName(), + d.class_file_bytes, + d.dex_file_bytes); + } + } + + public static native void doCommonMultiClassRedefinition(Class<?>[] targets, + byte[][] classfiles, + byte[][] dexfiles); + public static native void doCommonClassRetransformation(Class<?>... target); + public static native void setPopRetransformations(boolean pop); + public static native void popTransformationFor(String name); + public static native void enableCommonRetransformation(boolean enable); + public static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); +} diff --git a/test/947-reflect-method/src/art/Test947.java b/test/947-reflect-method/src/art/Test947.java new file mode 100644 index 0000000000..8cb515e492 --- /dev/null +++ b/test/947-reflect-method/src/art/Test947.java @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.util.Base64; +import java.lang.reflect.Method; + +public class Test947 { + + static class Transform { + public void sayHi() { + System.out.println("hello"); + } + } + + + /** + * base64 encoded class/dex file for + * static class Transform { + * public void sayHi() { + * System.out.println("Goodbye"); + * } + * } + */ + private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( + "yv66vgAAADQAIAoABgAOCQAPABAIABEKABIAEwcAFQcAGAEABjxpbml0PgEAAygpVgEABENvZGUB" + + "AA9MaW5lTnVtYmVyVGFibGUBAAVzYXlIaQEAClNvdXJjZUZpbGUBAAxUZXN0OTQ3LmphdmEMAAcA" + + "CAcAGQwAGgAbAQAHR29vZGJ5ZQcAHAwAHQAeBwAfAQAVYXJ0L1Rlc3Q5NDckVHJhbnNmb3JtAQAJ" + + "VHJhbnNmb3JtAQAMSW5uZXJDbGFzc2VzAQAQamF2YS9sYW5nL09iamVjdAEAEGphdmEvbGFuZy9T" + + "eXN0ZW0BAANvdXQBABVMamF2YS9pby9QcmludFN0cmVhbTsBABNqYXZhL2lvL1ByaW50U3RyZWFt" + + "AQAHcHJpbnRsbgEAFShMamF2YS9sYW5nL1N0cmluZzspVgEAC2FydC9UZXN0OTQ3ACAABQAGAAAA" + + "AAACAAAABwAIAAEACQAAAB0AAQABAAAABSq3AAGxAAAAAQAKAAAABgABAAAABQABAAsACAABAAkA" + + "AAAlAAIAAQAAAAmyAAISA7YABLEAAAABAAoAAAAKAAIAAAAHAAgACAACAAwAAAACAA0AFwAAAAoA" + + "AQAFABQAFgAI"); + private static final byte[] DEX_BYTES = Base64.getDecoder().decode( + "ZGV4CjAzNQCEgoKcAAAAAAAAAAAAAAAAAAAAAAAAAAC4AwAAcAAAAHhWNBIAAAAAAAAAAPQCAAAU" + + "AAAAcAAAAAkAAADAAAAAAgAAAOQAAAABAAAA/AAAAAQAAAAEAQAAAQAAACQBAAB0AgAARAEAAEQB" + + "AABMAQAAVQEAAG4BAAB9AQAAoQEAAMEBAADYAQAA7AEAAAACAAAUAgAAIgIAAC0CAAAwAgAANAIA" + + "AEECAABHAgAATAIAAFUCAABcAgAAAgAAAAMAAAAEAAAABQAAAAYAAAAHAAAACAAAAAkAAAAMAAAA" + + "DAAAAAgAAAAAAAAADQAAAAgAAABkAgAABwAEABAAAAAAAAAAAAAAAAAAAAASAAAABAABABEAAAAF" + + "AAAAAAAAAAAAAAAAAAAABQAAAAAAAAAKAAAA5AIAALgCAAAAAAAABjxpbml0PgAHR29vZGJ5ZQAX" + + "TGFydC9UZXN0OTQ3JFRyYW5zZm9ybTsADUxhcnQvVGVzdDk0NzsAIkxkYWx2aWsvYW5ub3RhdGlv" + + "bi9FbmNsb3NpbmdDbGFzczsAHkxkYWx2aWsvYW5ub3RhdGlvbi9Jbm5lckNsYXNzOwAVTGphdmEv" + + "aW8vUHJpbnRTdHJlYW07ABJMamF2YS9sYW5nL09iamVjdDsAEkxqYXZhL2xhbmcvU3RyaW5nOwAS" + + "TGphdmEvbGFuZy9TeXN0ZW07AAxUZXN0OTQ3LmphdmEACVRyYW5zZm9ybQABVgACVkwAC2FjY2Vz" + + "c0ZsYWdzAARuYW1lAANvdXQAB3ByaW50bG4ABXNheUhpAAV2YWx1ZQAAAQAAAAYAAAAFAAcOAAcA" + + "Bw4BCA8AAAAAAQABAAEAAABsAgAABAAAAHAQAwAAAA4AAwABAAIAAABxAgAACQAAAGIAAAAbAQEA" + + "AABuIAIAEAAOAAAAAAABAQCAgAT8BAEBlAUAAAICARMYAQIDAg4ECA8XCwACAAAAyAIAAM4CAADY" + + "AgAAAAAAAAAAAAAAAAAAEAAAAAAAAAABAAAAAAAAAAEAAAAUAAAAcAAAAAIAAAAJAAAAwAAAAAMA" + + "AAACAAAA5AAAAAQAAAABAAAA/AAAAAUAAAAEAAAABAEAAAYAAAABAAAAJAEAAAIgAAAUAAAARAEA" + + "AAEQAAABAAAAZAIAAAMgAAACAAAAbAIAAAEgAAACAAAAfAIAAAAgAAABAAAAuAIAAAQgAAACAAAA" + + "yAIAAAMQAAABAAAA2AIAAAYgAAABAAAA5AIAAAAQAAABAAAA9AIAAA=="); + + public static void run() { + doTest(new Transform()); + } + + public static void doTest(Transform t) { + try { + Method say_hi_method = t.getClass().getDeclaredMethod("sayHi"); + say_hi_method.invoke(t); + Redefinition.doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES); + say_hi_method.invoke(t); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/test/948-change-annotations/src/Main.java b/test/948-change-annotations/src/Main.java index a290396ebf..5d3406dacc 100644 --- a/test/948-change-annotations/src/Main.java +++ b/test/948-change-annotations/src/Main.java @@ -14,6 +14,7 @@ * limitations under the License. */ +import art.Redefinition; import java.util.Arrays; import java.util.Base64; import java.util.Comparator; @@ -85,7 +86,9 @@ public class Main { } // Transforms the class - public static native void doCommonClassRedefinition(Class<?> target, - byte[] class_file, - byte[] dex_file); + public static void doCommonClassRedefinition(Class<?> target, + byte[] class_file, + byte[] dex_file) { + Redefinition.doCommonClassRedefinition(target, class_file, dex_file); + } } diff --git a/test/948-change-annotations/src/art/Redefinition.java b/test/948-change-annotations/src/art/Redefinition.java new file mode 100644 index 0000000000..0350ab42ad --- /dev/null +++ b/test/948-change-annotations/src/art/Redefinition.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.util.ArrayList; +// Common Redefinition functions. Placed here for use by CTS +public class Redefinition { + // Bind native functions. + static { + Main.bindAgentJNIForClass(Redefinition.class); + } + + public static final class CommonClassDefinition { + public final Class<?> target; + public final byte[] class_file_bytes; + public final byte[] dex_file_bytes; + + public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { + this.target = target; + this.class_file_bytes = class_file_bytes; + this.dex_file_bytes = dex_file_bytes; + } + } + + // A set of possible test configurations. Test should set this if they need to. + // This must be kept in sync with the defines in ti-agent/common_helper.cc + public static enum Config { + COMMON_REDEFINE(0), + COMMON_RETRANSFORM(1), + COMMON_TRANSFORM(2); + + private final int val; + private Config(int val) { + this.val = val; + } + } + + public static void setTestConfiguration(Config type) { + nativeSetTestConfiguration(type.val); + } + + private static native void nativeSetTestConfiguration(int type); + + // Transforms the class + public static native void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile); + + public static void doMultiClassRedefinition(CommonClassDefinition... defs) { + ArrayList<Class<?>> classes = new ArrayList<>(); + ArrayList<byte[]> class_files = new ArrayList<>(); + ArrayList<byte[]> dex_files = new ArrayList<>(); + + for (CommonClassDefinition d : defs) { + classes.add(d.target); + class_files.add(d.class_file_bytes); + dex_files.add(d.dex_file_bytes); + } + doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), + class_files.toArray(new byte[0][]), + dex_files.toArray(new byte[0][])); + } + + public static void addMultiTransformationResults(CommonClassDefinition... defs) { + for (CommonClassDefinition d : defs) { + addCommonTransformationResult(d.target.getCanonicalName(), + d.class_file_bytes, + d.dex_file_bytes); + } + } + + public static native void doCommonMultiClassRedefinition(Class<?>[] targets, + byte[][] classfiles, + byte[][] dexfiles); + public static native void doCommonClassRetransformation(Class<?>... target); + public static native void setPopRetransformations(boolean pop); + public static native void popTransformationFor(String name); + public static native void enableCommonRetransformation(boolean enable); + public static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); +} diff --git a/test/949-in-memory-transform/src/Main.java b/test/949-in-memory-transform/src/Main.java index 1a6b224a37..b49a93f67b 100644 --- a/test/949-in-memory-transform/src/Main.java +++ b/test/949-in-memory-transform/src/Main.java @@ -14,112 +14,8 @@ * limitations under the License. */ -import java.util.Base64; -import java.lang.reflect.*; -import java.nio.ByteBuffer; - public class Main { - /** - * base64 encoded class/dex file for - * public class Transform { - * public void sayHi() { - * System.out.println("hello"); - * } - * } - */ - private static final byte[] INITIAL_CLASS_BYTES = Base64.getDecoder().decode( - "yv66vgAAADQAHAoABgAOCQAPABAIABEKABIAEwcAFAcAFQEABjxpbml0PgEAAygpVgEABENvZGUB" + - "AA9MaW5lTnVtYmVyVGFibGUBAAVzYXlIaQEAClNvdXJjZUZpbGUBAA5UcmFuc2Zvcm0uamF2YQwA" + - "BwAIBwAWDAAXABgBAAVoZWxsbwcAGQwAGgAbAQAJVHJhbnNmb3JtAQAQamF2YS9sYW5nL09iamVj" + - "dAEAEGphdmEvbGFuZy9TeXN0ZW0BAANvdXQBABVMamF2YS9pby9QcmludFN0cmVhbTsBABNqYXZh" + - "L2lvL1ByaW50U3RyZWFtAQAHcHJpbnRsbgEAFShMamF2YS9sYW5nL1N0cmluZzspVgAhAAUABgAA" + - "AAAAAgABAAcACAABAAkAAAAdAAEAAQAAAAUqtwABsQAAAAEACgAAAAYAAQAAABEAAQALAAgAAQAJ" + - "AAAAJQACAAEAAAAJsgACEgO2AASxAAAAAQAKAAAACgACAAAAGgAIABsAAQAMAAAAAgAN"); - private static final byte[] INITIAL_DEX_BYTES = Base64.getDecoder().decode( - "ZGV4CjAzNQAJX3mZphwHJCT1qdTz/GS+jXOR+O/9e3fMAgAAcAAAAHhWNBIAAAAAAAAAACwCAAAO" + - "AAAAcAAAAAYAAACoAAAAAgAAAMAAAAABAAAA2AAAAAQAAADgAAAAAQAAAAABAACsAQAAIAEAAGIB" + - "AABqAQAAdwEAAI4BAACiAQAAtgEAAMoBAADaAQAA3QEAAOEBAAD1AQAA/AEAAAECAAAKAgAAAQAA" + - "AAIAAAADAAAABAAAAAUAAAAHAAAABwAAAAUAAAAAAAAACAAAAAUAAABcAQAABAABAAsAAAAAAAAA" + - "AAAAAAAAAAANAAAAAQABAAwAAAACAAAAAAAAAAAAAAABAAAAAgAAAAAAAAAGAAAAAAAAABwCAAAA" + - "AAAAAQABAAEAAAARAgAABAAAAHAQAwAAAA4AAwABAAIAAAAWAgAACQAAAGIAAAAbAQoAAABuIAIA" + - "EAAOAAAAAQAAAAMABjxpbml0PgALTFRyYW5zZm9ybTsAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwAS" + - "TGphdmEvbGFuZy9PYmplY3Q7ABJMamF2YS9sYW5nL1N0cmluZzsAEkxqYXZhL2xhbmcvU3lzdGVt" + - "OwAOVHJhbnNmb3JtLmphdmEAAVYAAlZMABJlbWl0dGVyOiBqYWNrLTQuMjUABWhlbGxvAANvdXQA" + - "B3ByaW50bG4ABXNheUhpABEABw4AGgAHDocAAAABAQCBgASgAgEBuAIAAA0AAAAAAAAAAQAAAAAA" + - "AAABAAAADgAAAHAAAAACAAAABgAAAKgAAAADAAAAAgAAAMAAAAAEAAAAAQAAANgAAAAFAAAABAAA" + - "AOAAAAAGAAAAAQAAAAABAAABIAAAAgAAACABAAABEAAAAQAAAFwBAAACIAAADgAAAGIBAAADIAAA" + - "AgAAABECAAAAIAAAAQAAABwCAAAAEAAAAQAAACwCAAA="); - - - /** - * base64 encoded class/dex file for - * public class Transform { - * public void sayHi() { - * System.out.println("Goodbye"); - * } - * } - */ - private static final byte[] TRANSFORMED_CLASS_BYTES = Base64.getDecoder().decode( - "yv66vgAAADQAHAoABgAOCQAPABAIABEKABIAEwcAFAcAFQEABjxpbml0PgEAAygpVgEABENvZGUB" + - "AA9MaW5lTnVtYmVyVGFibGUBAAVzYXlIaQEAClNvdXJjZUZpbGUBAA5UcmFuc2Zvcm0uamF2YQwA" + - "BwAIBwAWDAAXABgBAAdHb29kYnllBwAZDAAaABsBAAlUcmFuc2Zvcm0BABBqYXZhL2xhbmcvT2Jq" + - "ZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2ph" + - "dmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWACEABQAG" + - "AAAAAAACAAEABwAIAAEACQAAAB0AAQABAAAABSq3AAGxAAAAAQAKAAAABgABAAAAEQABAAsACAAB" + - "AAkAAAAlAAIAAQAAAAmyAAISA7YABLEAAAABAAoAAAAKAAIAAAAaAAgAGwABAAwAAAACAA0="); - private static final byte[] TRANSFORMED_DEX_BYTES = Base64.getDecoder().decode( - "ZGV4CjAzNQAPXh6T3l1FObhHsKf1U2vi+0GmAvElxBLMAgAAcAAAAHhWNBIAAAAAAAAAACwCAAAO" + - "AAAAcAAAAAYAAACoAAAAAgAAAMAAAAABAAAA2AAAAAQAAADgAAAAAQAAAAABAACsAQAAIAEAAGIB" + - "AABqAQAAcwEAAIABAACXAQAAqwEAAL8BAADTAQAA4wEAAOYBAADqAQAA/gEAAAMCAAAMAgAAAgAA" + - "AAMAAAAEAAAABQAAAAYAAAAIAAAACAAAAAUAAAAAAAAACQAAAAUAAABcAQAABAABAAsAAAAAAAAA" + - "AAAAAAAAAAANAAAAAQABAAwAAAACAAAAAAAAAAAAAAABAAAAAgAAAAAAAAAHAAAAAAAAAB4CAAAA" + - "AAAAAQABAAEAAAATAgAABAAAAHAQAwAAAA4AAwABAAIAAAAYAgAACQAAAGIAAAAbAQEAAABuIAIA" + - "EAAOAAAAAQAAAAMABjxpbml0PgAHR29vZGJ5ZQALTFRyYW5zZm9ybTsAFUxqYXZhL2lvL1ByaW50" + - "U3RyZWFtOwASTGphdmEvbGFuZy9PYmplY3Q7ABJMamF2YS9sYW5nL1N0cmluZzsAEkxqYXZhL2xh" + - "bmcvU3lzdGVtOwAOVHJhbnNmb3JtLmphdmEAAVYAAlZMABJlbWl0dGVyOiBqYWNrLTQuMjUAA291" + - "dAAHcHJpbnRsbgAFc2F5SGkAEQAHDgAaAAcOhwAAAAEBAIGABKACAQG4Ag0AAAAAAAAAAQAAAAAA" + - "AAABAAAADgAAAHAAAAACAAAABgAAAKgAAAADAAAAAgAAAMAAAAAEAAAAAQAAANgAAAAFAAAABAAA" + - "AOAAAAAGAAAAAQAAAAABAAABIAAAAgAAACABAAABEAAAAQAAAFwBAAACIAAADgAAAGIBAAADIAAA" + - "AgAAABMCAAAAIAAAAQAAAB4CAAAAEAAAAQAAACwCAAA="); - public static void main(String[] args) throws Exception { - art.Main.bindAgentJNIForClass(Main.class); - ClassLoader loader; - try { - // Art uses this classloader to do in-memory dex files. There is no support for defineClass - loader = (ClassLoader)Class.forName("dalvik.system.InMemoryDexClassLoader") - .getConstructor(ByteBuffer.class, ClassLoader.class) - .newInstance(ByteBuffer.wrap(INITIAL_DEX_BYTES), - ClassLoader.getSystemClassLoader()); - } catch (ClassNotFoundException e) { - // Seem to be on RI. Just make a new ClassLoader that calls defineClass. - loader = new ClassLoader() { - public Class<?> findClass(String name) throws ClassNotFoundException { - if (name.equals("Transform")) { - return defineClass(name, INITIAL_CLASS_BYTES, 0, INITIAL_CLASS_BYTES.length); - } else { - throw new ClassNotFoundException("Couldn't find class: " + name); - } - } - }; - } - doTest(loader); + art.Test949.run(); } - - public static void doTest(ClassLoader loader) throws Exception { - // Get the class - Class<?> transform_class = loader.loadClass("Transform"); - Method say_hi_method = transform_class.getMethod("sayHi"); - Object t = transform_class.newInstance(); - - // Run the actual test. - say_hi_method.invoke(t); - doCommonClassRedefinition(transform_class, TRANSFORMED_CLASS_BYTES, TRANSFORMED_DEX_BYTES); - say_hi_method.invoke(t); - } - - // Transforms the class - private static native void doCommonClassRedefinition(Class<?> target, - byte[] class_file, - byte[] dex_file); } diff --git a/test/949-in-memory-transform/src/art/Redefinition.java b/test/949-in-memory-transform/src/art/Redefinition.java new file mode 100644 index 0000000000..0350ab42ad --- /dev/null +++ b/test/949-in-memory-transform/src/art/Redefinition.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.util.ArrayList; +// Common Redefinition functions. Placed here for use by CTS +public class Redefinition { + // Bind native functions. + static { + Main.bindAgentJNIForClass(Redefinition.class); + } + + public static final class CommonClassDefinition { + public final Class<?> target; + public final byte[] class_file_bytes; + public final byte[] dex_file_bytes; + + public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { + this.target = target; + this.class_file_bytes = class_file_bytes; + this.dex_file_bytes = dex_file_bytes; + } + } + + // A set of possible test configurations. Test should set this if they need to. + // This must be kept in sync with the defines in ti-agent/common_helper.cc + public static enum Config { + COMMON_REDEFINE(0), + COMMON_RETRANSFORM(1), + COMMON_TRANSFORM(2); + + private final int val; + private Config(int val) { + this.val = val; + } + } + + public static void setTestConfiguration(Config type) { + nativeSetTestConfiguration(type.val); + } + + private static native void nativeSetTestConfiguration(int type); + + // Transforms the class + public static native void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile); + + public static void doMultiClassRedefinition(CommonClassDefinition... defs) { + ArrayList<Class<?>> classes = new ArrayList<>(); + ArrayList<byte[]> class_files = new ArrayList<>(); + ArrayList<byte[]> dex_files = new ArrayList<>(); + + for (CommonClassDefinition d : defs) { + classes.add(d.target); + class_files.add(d.class_file_bytes); + dex_files.add(d.dex_file_bytes); + } + doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), + class_files.toArray(new byte[0][]), + dex_files.toArray(new byte[0][])); + } + + public static void addMultiTransformationResults(CommonClassDefinition... defs) { + for (CommonClassDefinition d : defs) { + addCommonTransformationResult(d.target.getCanonicalName(), + d.class_file_bytes, + d.dex_file_bytes); + } + } + + public static native void doCommonMultiClassRedefinition(Class<?>[] targets, + byte[][] classfiles, + byte[][] dexfiles); + public static native void doCommonClassRetransformation(Class<?>... target); + public static native void setPopRetransformations(boolean pop); + public static native void popTransformationFor(String name); + public static native void enableCommonRetransformation(boolean enable); + public static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); +} diff --git a/test/949-in-memory-transform/src/art/Test949.java b/test/949-in-memory-transform/src/art/Test949.java new file mode 100644 index 0000000000..cd733b9f2d --- /dev/null +++ b/test/949-in-memory-transform/src/art/Test949.java @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import static art.Redefinition.doCommonClassRedefinition; + +import java.util.Base64; +import java.lang.reflect.*; +import java.nio.ByteBuffer; + +public class Test949 { + /** + * base64 encoded class/dex file for + * public class Transform { + * public void sayHi() { + * System.out.println("hello"); + * } + * } + */ + private static final byte[] INITIAL_CLASS_BYTES = Base64.getDecoder().decode( + "yv66vgAAADQAHAoABgAOCQAPABAIABEKABIAEwcAFAcAFQEABjxpbml0PgEAAygpVgEABENvZGUB" + + "AA9MaW5lTnVtYmVyVGFibGUBAAVzYXlIaQEAClNvdXJjZUZpbGUBAA5UcmFuc2Zvcm0uamF2YQwA" + + "BwAIBwAWDAAXABgBAAVoZWxsbwcAGQwAGgAbAQAJVHJhbnNmb3JtAQAQamF2YS9sYW5nL09iamVj" + + "dAEAEGphdmEvbGFuZy9TeXN0ZW0BAANvdXQBABVMamF2YS9pby9QcmludFN0cmVhbTsBABNqYXZh" + + "L2lvL1ByaW50U3RyZWFtAQAHcHJpbnRsbgEAFShMamF2YS9sYW5nL1N0cmluZzspVgAhAAUABgAA" + + "AAAAAgABAAcACAABAAkAAAAdAAEAAQAAAAUqtwABsQAAAAEACgAAAAYAAQAAABEAAQALAAgAAQAJ" + + "AAAAJQACAAEAAAAJsgACEgO2AASxAAAAAQAKAAAACgACAAAAGgAIABsAAQAMAAAAAgAN"); + private static final byte[] INITIAL_DEX_BYTES = Base64.getDecoder().decode( + "ZGV4CjAzNQAJX3mZphwHJCT1qdTz/GS+jXOR+O/9e3fMAgAAcAAAAHhWNBIAAAAAAAAAACwCAAAO" + + "AAAAcAAAAAYAAACoAAAAAgAAAMAAAAABAAAA2AAAAAQAAADgAAAAAQAAAAABAACsAQAAIAEAAGIB" + + "AABqAQAAdwEAAI4BAACiAQAAtgEAAMoBAADaAQAA3QEAAOEBAAD1AQAA/AEAAAECAAAKAgAAAQAA" + + "AAIAAAADAAAABAAAAAUAAAAHAAAABwAAAAUAAAAAAAAACAAAAAUAAABcAQAABAABAAsAAAAAAAAA" + + "AAAAAAAAAAANAAAAAQABAAwAAAACAAAAAAAAAAAAAAABAAAAAgAAAAAAAAAGAAAAAAAAABwCAAAA" + + "AAAAAQABAAEAAAARAgAABAAAAHAQAwAAAA4AAwABAAIAAAAWAgAACQAAAGIAAAAbAQoAAABuIAIA" + + "EAAOAAAAAQAAAAMABjxpbml0PgALTFRyYW5zZm9ybTsAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwAS" + + "TGphdmEvbGFuZy9PYmplY3Q7ABJMamF2YS9sYW5nL1N0cmluZzsAEkxqYXZhL2xhbmcvU3lzdGVt" + + "OwAOVHJhbnNmb3JtLmphdmEAAVYAAlZMABJlbWl0dGVyOiBqYWNrLTQuMjUABWhlbGxvAANvdXQA" + + "B3ByaW50bG4ABXNheUhpABEABw4AGgAHDocAAAABAQCBgASgAgEBuAIAAA0AAAAAAAAAAQAAAAAA" + + "AAABAAAADgAAAHAAAAACAAAABgAAAKgAAAADAAAAAgAAAMAAAAAEAAAAAQAAANgAAAAFAAAABAAA" + + "AOAAAAAGAAAAAQAAAAABAAABIAAAAgAAACABAAABEAAAAQAAAFwBAAACIAAADgAAAGIBAAADIAAA" + + "AgAAABECAAAAIAAAAQAAABwCAAAAEAAAAQAAACwCAAA="); + + + /** + * base64 encoded class/dex file for + * public class Transform { + * public void sayHi() { + * System.out.println("Goodbye"); + * } + * } + */ + private static final byte[] TRANSFORMED_CLASS_BYTES = Base64.getDecoder().decode( + "yv66vgAAADQAHAoABgAOCQAPABAIABEKABIAEwcAFAcAFQEABjxpbml0PgEAAygpVgEABENvZGUB" + + "AA9MaW5lTnVtYmVyVGFibGUBAAVzYXlIaQEAClNvdXJjZUZpbGUBAA5UcmFuc2Zvcm0uamF2YQwA" + + "BwAIBwAWDAAXABgBAAdHb29kYnllBwAZDAAaABsBAAlUcmFuc2Zvcm0BABBqYXZhL2xhbmcvT2Jq" + + "ZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2ph" + + "dmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWACEABQAG" + + "AAAAAAACAAEABwAIAAEACQAAAB0AAQABAAAABSq3AAGxAAAAAQAKAAAABgABAAAAEQABAAsACAAB" + + "AAkAAAAlAAIAAQAAAAmyAAISA7YABLEAAAABAAoAAAAKAAIAAAAaAAgAGwABAAwAAAACAA0="); + private static final byte[] TRANSFORMED_DEX_BYTES = Base64.getDecoder().decode( + "ZGV4CjAzNQAPXh6T3l1FObhHsKf1U2vi+0GmAvElxBLMAgAAcAAAAHhWNBIAAAAAAAAAACwCAAAO" + + "AAAAcAAAAAYAAACoAAAAAgAAAMAAAAABAAAA2AAAAAQAAADgAAAAAQAAAAABAACsAQAAIAEAAGIB" + + "AABqAQAAcwEAAIABAACXAQAAqwEAAL8BAADTAQAA4wEAAOYBAADqAQAA/gEAAAMCAAAMAgAAAgAA" + + "AAMAAAAEAAAABQAAAAYAAAAIAAAACAAAAAUAAAAAAAAACQAAAAUAAABcAQAABAABAAsAAAAAAAAA" + + "AAAAAAAAAAANAAAAAQABAAwAAAACAAAAAAAAAAAAAAABAAAAAgAAAAAAAAAHAAAAAAAAAB4CAAAA" + + "AAAAAQABAAEAAAATAgAABAAAAHAQAwAAAA4AAwABAAIAAAAYAgAACQAAAGIAAAAbAQEAAABuIAIA" + + "EAAOAAAAAQAAAAMABjxpbml0PgAHR29vZGJ5ZQALTFRyYW5zZm9ybTsAFUxqYXZhL2lvL1ByaW50" + + "U3RyZWFtOwASTGphdmEvbGFuZy9PYmplY3Q7ABJMamF2YS9sYW5nL1N0cmluZzsAEkxqYXZhL2xh" + + "bmcvU3lzdGVtOwAOVHJhbnNmb3JtLmphdmEAAVYAAlZMABJlbWl0dGVyOiBqYWNrLTQuMjUAA291" + + "dAAHcHJpbnRsbgAFc2F5SGkAEQAHDgAaAAcOhwAAAAEBAIGABKACAQG4Ag0AAAAAAAAAAQAAAAAA" + + "AAABAAAADgAAAHAAAAACAAAABgAAAKgAAAADAAAAAgAAAMAAAAAEAAAAAQAAANgAAAAFAAAABAAA" + + "AOAAAAAGAAAAAQAAAAABAAABIAAAAgAAACABAAABEAAAAQAAAFwBAAACIAAADgAAAGIBAAADIAAA" + + "AgAAABMCAAAAIAAAAQAAAB4CAAAAEAAAAQAAACwCAAA="); + + public static void run() throws Exception { + ClassLoader loader; + try { + // Art uses this classloader to do in-memory dex files. There is no support for defineClass + loader = (ClassLoader)Class.forName("dalvik.system.InMemoryDexClassLoader") + .getConstructor(ByteBuffer.class, ClassLoader.class) + .newInstance(ByteBuffer.wrap(INITIAL_DEX_BYTES), + ClassLoader.getSystemClassLoader()); + } catch (ClassNotFoundException e) { + // Seem to be on RI. Just make a new ClassLoader that calls defineClass. + loader = new ClassLoader() { + public Class<?> findClass(String name) throws ClassNotFoundException { + if (name.equals("Transform")) { + return defineClass(name, INITIAL_CLASS_BYTES, 0, INITIAL_CLASS_BYTES.length); + } else { + throw new ClassNotFoundException("Couldn't find class: " + name); + } + } + }; + } + doTest(loader); + } + + public static void doTest(ClassLoader loader) throws Exception { + // Get the class + Class<?> transform_class = loader.loadClass("Transform"); + Method say_hi_method = transform_class.getMethod("sayHi"); + Object t = transform_class.newInstance(); + + // Run the actual test. + say_hi_method.invoke(t); + doCommonClassRedefinition(transform_class, TRANSFORMED_CLASS_BYTES, TRANSFORMED_DEX_BYTES); + say_hi_method.invoke(t); + } +} diff --git a/test/950-redefine-intrinsic/src/Main.java b/test/950-redefine-intrinsic/src/Main.java index 2578d6e278..369a8f417e 100644 --- a/test/950-redefine-intrinsic/src/Main.java +++ b/test/950-redefine-intrinsic/src/Main.java @@ -14,6 +14,7 @@ * limitations under the License. */ +import static art.Redefinition.doCommonClassRedefinition; import java.util.Base64; import java.util.Random; import java.util.function.*; @@ -464,9 +465,4 @@ public class Main { } System.out.println("Finished!"); } - - // Transforms the class - private static native void doCommonClassRedefinition(Class<?> target, - byte[] class_file, - byte[] dex_file); } diff --git a/test/950-redefine-intrinsic/src/art/Redefinition.java b/test/950-redefine-intrinsic/src/art/Redefinition.java new file mode 100644 index 0000000000..0350ab42ad --- /dev/null +++ b/test/950-redefine-intrinsic/src/art/Redefinition.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.util.ArrayList; +// Common Redefinition functions. Placed here for use by CTS +public class Redefinition { + // Bind native functions. + static { + Main.bindAgentJNIForClass(Redefinition.class); + } + + public static final class CommonClassDefinition { + public final Class<?> target; + public final byte[] class_file_bytes; + public final byte[] dex_file_bytes; + + public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { + this.target = target; + this.class_file_bytes = class_file_bytes; + this.dex_file_bytes = dex_file_bytes; + } + } + + // A set of possible test configurations. Test should set this if they need to. + // This must be kept in sync with the defines in ti-agent/common_helper.cc + public static enum Config { + COMMON_REDEFINE(0), + COMMON_RETRANSFORM(1), + COMMON_TRANSFORM(2); + + private final int val; + private Config(int val) { + this.val = val; + } + } + + public static void setTestConfiguration(Config type) { + nativeSetTestConfiguration(type.val); + } + + private static native void nativeSetTestConfiguration(int type); + + // Transforms the class + public static native void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile); + + public static void doMultiClassRedefinition(CommonClassDefinition... defs) { + ArrayList<Class<?>> classes = new ArrayList<>(); + ArrayList<byte[]> class_files = new ArrayList<>(); + ArrayList<byte[]> dex_files = new ArrayList<>(); + + for (CommonClassDefinition d : defs) { + classes.add(d.target); + class_files.add(d.class_file_bytes); + dex_files.add(d.dex_file_bytes); + } + doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), + class_files.toArray(new byte[0][]), + dex_files.toArray(new byte[0][])); + } + + public static void addMultiTransformationResults(CommonClassDefinition... defs) { + for (CommonClassDefinition d : defs) { + addCommonTransformationResult(d.target.getCanonicalName(), + d.class_file_bytes, + d.dex_file_bytes); + } + } + + public static native void doCommonMultiClassRedefinition(Class<?>[] targets, + byte[][] classfiles, + byte[][] dexfiles); + public static native void doCommonClassRetransformation(Class<?>... target); + public static native void setPopRetransformations(boolean pop); + public static native void popTransformationFor(String name); + public static native void enableCommonRetransformation(boolean enable); + public static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); +} diff --git a/test/951-threaded-obsolete/src/Main.java b/test/951-threaded-obsolete/src/Main.java index a82090e736..d245aa9ec8 100644 --- a/test/951-threaded-obsolete/src/Main.java +++ b/test/951-threaded-obsolete/src/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,84 +14,8 @@ * limitations under the License. */ -import java.util.Base64; -import java.util.concurrent.Semaphore; - public class Main { - // class Transform { - // public void sayHi(Runnable r) { - // System.out.println("Hello - Transformed"); - // r.run(); - // System.out.println("Goodbye - Transformed"); - // } - // } - private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( - "yv66vgAAADQAJAoACAARCQASABMIABQKABUAFgsAFwAYCAAZBwAaBwAbAQAGPGluaXQ+AQADKClW" + - "AQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEABXNheUhpAQAXKExqYXZhL2xhbmcvUnVubmFibGU7" + - "KVYBAApTb3VyY2VGaWxlAQAOVHJhbnNmb3JtLmphdmEMAAkACgcAHAwAHQAeAQATSGVsbG8gLSBU" + - "cmFuc2Zvcm1lZAcAHwwAIAAhBwAiDAAjAAoBABVHb29kYnllIC0gVHJhbnNmb3JtZWQBAAlUcmFu" + - "c2Zvcm0BABBqYXZhL2xhbmcvT2JqZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZh" + - "L2lvL1ByaW50U3RyZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZh" + - "L2xhbmcvU3RyaW5nOylWAQASamF2YS9sYW5nL1J1bm5hYmxlAQADcnVuACAABwAIAAAAAAACAAAA" + - "CQAKAAEACwAAAB0AAQABAAAABSq3AAGxAAAAAQAMAAAABgABAAAAAQABAA0ADgABAAsAAAA7AAIA" + - "AgAAABeyAAISA7YABCu5AAUBALIAAhIGtgAEsQAAAAEADAAAABIABAAAAAMACAAEAA4ABQAWAAYA" + - "AQAPAAAAAgAQ"); - private static final byte[] DEX_BYTES = Base64.getDecoder().decode( - "ZGV4CjAzNQAYeAMMXgYWxoeSHAS9EWKCCtVRSAGpqZVQAwAAcAAAAHhWNBIAAAAAAAAAALACAAAR" + - "AAAAcAAAAAcAAAC0AAAAAwAAANAAAAABAAAA9AAAAAUAAAD8AAAAAQAAACQBAAAMAgAARAEAAKIB" + - "AACqAQAAwQEAANYBAADjAQAA+gEAAA4CAAAkAgAAOAIAAEwCAABcAgAAXwIAAGMCAAB3AgAAfAIA" + - "AIUCAACKAgAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAACgAAAAoAAAAGAAAAAAAAAAsAAAAGAAAA" + - "lAEAAAsAAAAGAAAAnAEAAAUAAQANAAAAAAAAAAAAAAAAAAEAEAAAAAEAAgAOAAAAAgAAAAAAAAAD" + - "AAAADwAAAAAAAAAAAAAAAgAAAAAAAAAJAAAAAAAAAJ8CAAAAAAAAAQABAAEAAACRAgAABAAAAHAQ" + - "AwAAAA4ABAACAAIAAACWAgAAFAAAAGIAAAAbAQIAAABuIAIAEAByEAQAAwBiAAAAGwEBAAAAbiAC" + - "ABAADgABAAAAAwAAAAEAAAAEAAY8aW5pdD4AFUdvb2RieWUgLSBUcmFuc2Zvcm1lZAATSGVsbG8g" + - "LSBUcmFuc2Zvcm1lZAALTFRyYW5zZm9ybTsAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwASTGphdmEv" + - "bGFuZy9PYmplY3Q7ABRMamF2YS9sYW5nL1J1bm5hYmxlOwASTGphdmEvbGFuZy9TdHJpbmc7ABJM" + - "amF2YS9sYW5nL1N5c3RlbTsADlRyYW5zZm9ybS5qYXZhAAFWAAJWTAASZW1pdHRlcjogamFjay00" + - "LjEzAANvdXQAB3ByaW50bG4AA3J1bgAFc2F5SGkAAQAHDgADAQAHDoc8hwAAAAEBAICABMQCAQHc" + - "AgAAAA0AAAAAAAAAAQAAAAAAAAABAAAAEQAAAHAAAAACAAAABwAAALQAAAADAAAAAwAAANAAAAAE" + - "AAAAAQAAAPQAAAAFAAAABQAAAPwAAAAGAAAAAQAAACQBAAABIAAAAgAAAEQBAAABEAAAAgAAAJQB" + - "AAACIAAAEQAAAKIBAAADIAAAAgAAAJECAAAAIAAAAQAAAJ8CAAAAEAAAAQAAALACAAA="); - - public static void main(String[] args) { - art.Main.bindAgentJNIForClass(Main.class); - // Semaphores to let each thread know where the other is. We could use barriers but semaphores - // mean we don't need to have the worker thread be waiting around. - final Semaphore sem_redefine_start = new Semaphore(0); - final Semaphore sem_redefine_end = new Semaphore(0); - // Create a thread to do the actual redefinition. We will just communicate through an - // atomic-integer. - new Thread(() -> { - try { - // Wait for the other thread to ask for redefinition. - sem_redefine_start.acquire(); - // Do the redefinition. - doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES); - // Allow the other thread to wake up if it is waiting. - sem_redefine_end.release(); - } catch (InterruptedException e) { - throw new Error("unable to do redefinition", e); - } - }).start(); - - Transform t = new Transform(); - t.sayHi(() -> { System.out.println("Not doing anything here"); }); - t.sayHi(() -> { - try { - System.out.println("transforming calling function"); - // Wake up the waiting thread. - sem_redefine_start.release(); - // Wait for the other thread to finish with redefinition. - sem_redefine_end.acquire(); - } catch (InterruptedException e) { - throw new Error("unable to do redefinition", e); - } - }); - t.sayHi(() -> { System.out.println("Not doing anything here"); }); + public static void main(String[] args) throws Exception { + art.Test951.run(); } - - // Transforms the class - private static native void doCommonClassRedefinition(Class<?> target, - byte[] classfile, - byte[] dexfile); } diff --git a/test/951-threaded-obsolete/src/Transform.java b/test/951-threaded-obsolete/src/Transform.java deleted file mode 100644 index 8cda6cdf53..0000000000 --- a/test/951-threaded-obsolete/src/Transform.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * 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. - */ - -class Transform { - public void sayHi(Runnable r) { - // Use lower 'h' to make sure the string will have a different string id - // than the transformation (the transformation code is the same except - // the actual printed String, which was making the test inacurately passing - // in JIT mode when loading the string from the dex cache, as the string ids - // of the two different strings were the same). - // We know the string ids will be different because lexicographically: - // "Hello" < "LTransform;" < "hello". - System.out.println("hello"); - r.run(); - System.out.println("goodbye"); - } -} diff --git a/test/951-threaded-obsolete/src/art/Redefinition.java b/test/951-threaded-obsolete/src/art/Redefinition.java new file mode 100644 index 0000000000..0350ab42ad --- /dev/null +++ b/test/951-threaded-obsolete/src/art/Redefinition.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.util.ArrayList; +// Common Redefinition functions. Placed here for use by CTS +public class Redefinition { + // Bind native functions. + static { + Main.bindAgentJNIForClass(Redefinition.class); + } + + public static final class CommonClassDefinition { + public final Class<?> target; + public final byte[] class_file_bytes; + public final byte[] dex_file_bytes; + + public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { + this.target = target; + this.class_file_bytes = class_file_bytes; + this.dex_file_bytes = dex_file_bytes; + } + } + + // A set of possible test configurations. Test should set this if they need to. + // This must be kept in sync with the defines in ti-agent/common_helper.cc + public static enum Config { + COMMON_REDEFINE(0), + COMMON_RETRANSFORM(1), + COMMON_TRANSFORM(2); + + private final int val; + private Config(int val) { + this.val = val; + } + } + + public static void setTestConfiguration(Config type) { + nativeSetTestConfiguration(type.val); + } + + private static native void nativeSetTestConfiguration(int type); + + // Transforms the class + public static native void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile); + + public static void doMultiClassRedefinition(CommonClassDefinition... defs) { + ArrayList<Class<?>> classes = new ArrayList<>(); + ArrayList<byte[]> class_files = new ArrayList<>(); + ArrayList<byte[]> dex_files = new ArrayList<>(); + + for (CommonClassDefinition d : defs) { + classes.add(d.target); + class_files.add(d.class_file_bytes); + dex_files.add(d.dex_file_bytes); + } + doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), + class_files.toArray(new byte[0][]), + dex_files.toArray(new byte[0][])); + } + + public static void addMultiTransformationResults(CommonClassDefinition... defs) { + for (CommonClassDefinition d : defs) { + addCommonTransformationResult(d.target.getCanonicalName(), + d.class_file_bytes, + d.dex_file_bytes); + } + } + + public static native void doCommonMultiClassRedefinition(Class<?>[] targets, + byte[][] classfiles, + byte[][] dexfiles); + public static native void doCommonClassRetransformation(Class<?>... target); + public static native void setPopRetransformations(boolean pop); + public static native void popTransformationFor(String name); + public static native void enableCommonRetransformation(boolean enable); + public static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); +} diff --git a/test/951-threaded-obsolete/src/art/Test951.java b/test/951-threaded-obsolete/src/art/Test951.java new file mode 100644 index 0000000000..3628f4f9db --- /dev/null +++ b/test/951-threaded-obsolete/src/art/Test951.java @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * 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 art; + +import java.util.Base64; +import java.util.concurrent.Semaphore; + +public class Test951 { + + static class Transform { + public void sayHi(Runnable r) { + System.out.println("hello"); + r.run(); + System.out.println("goodbye"); + } + } + + // static class Transform { + // public void sayHi(Runnable r) { + // System.out.println("Hello - Transformed"); + // r.run(); + // System.out.println("Goodbye - Transformed"); + // } + // } + private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( + "yv66vgAAADQAKAoACAARCQASABMIABQKABUAFgsAFwAYCAAZBwAbBwAeAQAGPGluaXQ+AQADKClW" + + "AQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEABXNheUhpAQAXKExqYXZhL2xhbmcvUnVubmFibGU7" + + "KVYBAApTb3VyY2VGaWxlAQAMVGVzdDk1MS5qYXZhDAAJAAoHAB8MACAAIQEAE0hlbGxvIC0gVHJh" + + "bnNmb3JtZWQHACIMACMAJAcAJQwAJgAKAQAVR29vZGJ5ZSAtIFRyYW5zZm9ybWVkBwAnAQAVYXJ0" + + "L1Rlc3Q5NTEkVHJhbnNmb3JtAQAJVHJhbnNmb3JtAQAMSW5uZXJDbGFzc2VzAQAQamF2YS9sYW5n" + + "L09iamVjdAEAEGphdmEvbGFuZy9TeXN0ZW0BAANvdXQBABVMamF2YS9pby9QcmludFN0cmVhbTsB" + + "ABNqYXZhL2lvL1ByaW50U3RyZWFtAQAHcHJpbnRsbgEAFShMamF2YS9sYW5nL1N0cmluZzspVgEA" + + "EmphdmEvbGFuZy9SdW5uYWJsZQEAA3J1bgEAC2FydC9UZXN0OTUxACAABwAIAAAAAAACAAAACQAK" + + "AAEACwAAAB0AAQABAAAABSq3AAGxAAAAAQAMAAAABgABAAAABQABAA0ADgABAAsAAAA7AAIAAgAA" + + "ABeyAAISA7YABCu5AAUBALIAAhIGtgAEsQAAAAEADAAAABIABAAAAAcACAAIAA4ACQAWAAoAAgAP" + + "AAAAAgAQAB0AAAAKAAEABwAaABwACA=="); + private static final byte[] DEX_BYTES = Base64.getDecoder().decode( + "ZGV4CjAzNQBom/JeAAAAAAAAAAAAAAAAAAAAAAAAAAA8BAAAcAAAAHhWNBIAAAAAAAAAAHgDAAAX" + + "AAAAcAAAAAoAAADMAAAAAwAAAPQAAAABAAAAGAEAAAUAAAAgAQAAAQAAAEgBAADUAgAAaAEAAGgB" + + "AABwAQAAhwEAAJwBAAC1AQAAxAEAAOgBAAAIAgAAHwIAADMCAABJAgAAXQIAAHECAAB/AgAAigIA" + + "AI0CAACRAgAAngIAAKQCAACpAgAAsgIAALcCAAC+AgAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAA" + + "CQAAAAoAAAALAAAADgAAAA4AAAAJAAAAAAAAAA8AAAAJAAAAyAIAAA8AAAAJAAAA0AIAAAgABAAS" + + "AAAAAAAAAAAAAAAAAAEAFQAAAAQAAgATAAAABQAAAAAAAAAGAAAAFAAAAAAAAAAAAAAABQAAAAAA" + + "AAAMAAAAaAMAADwDAAAAAAAABjxpbml0PgAVR29vZGJ5ZSAtIFRyYW5zZm9ybWVkABNIZWxsbyAt" + + "IFRyYW5zZm9ybWVkABdMYXJ0L1Rlc3Q5NTEkVHJhbnNmb3JtOwANTGFydC9UZXN0OTUxOwAiTGRh" + + "bHZpay9hbm5vdGF0aW9uL0VuY2xvc2luZ0NsYXNzOwAeTGRhbHZpay9hbm5vdGF0aW9uL0lubmVy" + + "Q2xhc3M7ABVMamF2YS9pby9QcmludFN0cmVhbTsAEkxqYXZhL2xhbmcvT2JqZWN0OwAUTGphdmEv" + + "bGFuZy9SdW5uYWJsZTsAEkxqYXZhL2xhbmcvU3RyaW5nOwASTGphdmEvbGFuZy9TeXN0ZW07AAxU" + + "ZXN0OTUxLmphdmEACVRyYW5zZm9ybQABVgACVkwAC2FjY2Vzc0ZsYWdzAARuYW1lAANvdXQAB3By" + + "aW50bG4AA3J1bgAFc2F5SGkABXZhbHVlAAAAAAEAAAAGAAAAAQAAAAcAAAAFAAcOAAcBAAcOAQgP" + + "AQMPAQgPAAEAAQABAAAA2AIAAAQAAABwEAMAAAAOAAQAAgACAAAA3QIAABQAAABiAAAAGwECAAAA" + + "biACABAAchAEAAMAYgAAABsBAQAAAG4gAgAQAA4AAAABAQCAgATsBQEBhAYAAAICARYYAQIDAhAE" + + "CBEXDQACAAAATAMAAFIDAABcAwAAAAAAAAAAAAAAAAAAEAAAAAAAAAABAAAAAAAAAAEAAAAXAAAA" + + "cAAAAAIAAAAKAAAAzAAAAAMAAAADAAAA9AAAAAQAAAABAAAAGAEAAAUAAAAFAAAAIAEAAAYAAAAB" + + "AAAASAEAAAIgAAAXAAAAaAEAAAEQAAACAAAAyAIAAAMgAAACAAAA2AIAAAEgAAACAAAA7AIAAAAg" + + "AAABAAAAPAMAAAQgAAACAAAATAMAAAMQAAABAAAAXAMAAAYgAAABAAAAaAMAAAAQAAABAAAAeAMA" + + "AA=="); + + public static void run() { + // Semaphores to let each thread know where the other is. We could use barriers but semaphores + // mean we don't need to have the worker thread be waiting around. + final Semaphore sem_redefine_start = new Semaphore(0); + final Semaphore sem_redefine_end = new Semaphore(0); + // Create a thread to do the actual redefinition. We will just communicate through an + // atomic-integer. + new Thread(() -> { + try { + // Wait for the other thread to ask for redefinition. + sem_redefine_start.acquire(); + // Do the redefinition. + Redefinition.doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES); + // Allow the other thread to wake up if it is waiting. + sem_redefine_end.release(); + } catch (InterruptedException e) { + throw new Error("unable to do redefinition", e); + } + }).start(); + + Transform t = new Transform(); + t.sayHi(() -> { System.out.println("Not doing anything here"); }); + t.sayHi(() -> { + try { + System.out.println("transforming calling function"); + // Wake up the waiting thread. + sem_redefine_start.release(); + // Wait for the other thread to finish with redefinition. + sem_redefine_end.acquire(); + } catch (InterruptedException e) { + throw new Error("unable to do redefinition", e); + } + }); + t.sayHi(() -> { System.out.println("Not doing anything here"); }); + } +} diff --git a/test/980-redefine-object/check b/test/980-redefine-object/check index 987066fe15..07b21b3176 100755 --- a/test/980-redefine-object/check +++ b/test/980-redefine-object/check @@ -17,4 +17,4 @@ # The number of paused background threads (and therefore InterruptedExceptions) # can change so we will just delete their lines from the log. -sed "/Object allocated of type 'Ljava\/lang\/InterruptedException;'/d" "$2" | diff --strip-trailing-cr -q "$1" - >/dev/null +sed "/Object allocated of type 'java\.lang\.InterruptedException'/d" "$2" | diff --strip-trailing-cr -q "$1" - >/dev/null diff --git a/test/980-redefine-object/expected.txt b/test/980-redefine-object/expected.txt index 6e9bce027a..4c294bc870 100644 --- a/test/980-redefine-object/expected.txt +++ b/test/980-redefine-object/expected.txt @@ -2,51 +2,31 @@ Allocating an j.l.Object before redefining Object class Allocating a Transform before redefining Object class Redefining the Object class to add a hook into the <init> method -Object allocated of type 'Ljava/lang/StringBuilder;' -Object allocated of type 'Ljava/nio/HeapCharBuffer;' Allocating an j.l.Object after redefining Object class -Object allocated of type 'Ljava/lang/Object;' -Object allocated of type 'Ljava/lang/StringBuilder;' -Object allocated of type 'Ljava/nio/HeapCharBuffer;' +Object allocated of type 'java.lang.Object' Allocating a Transform after redefining Object class -Object allocated of type 'LTransform;' -Object allocated of type 'Ljava/lang/StringBuilder;' -Object allocated of type 'Ljava/nio/HeapCharBuffer;' +Object allocated of type 'Transform' Allocating an int[] after redefining Object class -Object allocated of type 'Ljava/lang/StringBuilder;' -Object allocated of type 'Ljava/nio/HeapCharBuffer;' Allocating an array list -Object allocated of type 'Ljava/util/ArrayList;' -Object allocated of type 'Ljava/lang/StringBuilder;' -Object allocated of type 'Ljava/nio/HeapCharBuffer;' +Object allocated of type 'java.util.ArrayList' Adding a bunch of stuff to the array list -Object allocated of type 'Ljava/lang/Object;' -Object allocated of type 'Ljava/lang/Object;' -Object allocated of type 'LTransform;' -Object allocated of type 'Ljava/lang/StringBuilder;' -Object allocated of type 'Ljava/nio/HeapCharBuffer;' +Object allocated of type 'java.lang.Object' +Object allocated of type 'java.lang.Object' +Object allocated of type 'Transform' Allocating a linked list -Object allocated of type 'Ljava/util/LinkedList;' -Object allocated of type 'Ljava/lang/StringBuilder;' -Object allocated of type 'Ljava/nio/HeapCharBuffer;' +Object allocated of type 'java.util.LinkedList' Adding a bunch of stuff to the linked list -Object allocated of type 'Ljava/lang/Object;' -Object allocated of type 'Ljava/util/LinkedList$Node;' -Object allocated of type 'Ljava/lang/Object;' -Object allocated of type 'Ljava/util/LinkedList$Node;' -Object allocated of type 'Ljava/util/LinkedList$Node;' -Object allocated of type 'Ljava/util/LinkedList$Node;' -Object allocated of type 'Ljava/util/LinkedList$Node;' -Object allocated of type 'Ljava/util/LinkedList$Node;' -Object allocated of type 'LTransform;' -Object allocated of type 'Ljava/util/LinkedList$Node;' -Object allocated of type 'Ljava/lang/StringBuilder;' -Object allocated of type 'Ljava/nio/HeapCharBuffer;' +Object allocated of type 'java.lang.Object' +Object allocated of type 'java.util.LinkedList$Node' +Object allocated of type 'java.lang.Object' +Object allocated of type 'java.util.LinkedList$Node' +Object allocated of type 'java.util.LinkedList$Node' +Object allocated of type 'java.util.LinkedList$Node' +Object allocated of type 'java.util.LinkedList$Node' +Object allocated of type 'java.util.LinkedList$Node' +Object allocated of type 'Transform' +Object allocated of type 'java.util.LinkedList$Node' Throwing from down 4 stack frames -Object allocated of type 'Ljava/lang/Exception;' -Object allocated of type 'Ljava/lang/StringBuilder;' -Object allocated of type 'Ljava/nio/HeapCharBuffer;' +Object allocated of type 'java.lang.Exception' Exception caught. -Object allocated of type 'Ljava/lang/StringBuilder;' -Object allocated of type 'Ljava/nio/HeapCharBuffer;' Finishing test! diff --git a/test/980-redefine-object/redefine_object.cc b/test/980-redefine-object/redefine_object.cc deleted file mode 100644 index 1faf1a16a7..0000000000 --- a/test/980-redefine-object/redefine_object.cc +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * 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. - */ - -#include <inttypes.h> -#include <iostream> - -#include "android-base/stringprintf.h" -#include "base/logging.h" -#include "base/macros.h" -#include "jni.h" -#include "jvmti.h" -#include "scoped_utf_chars.h" - -// Test infrastructure -#include "jni_binder.h" -#include "jvmti_helper.h" -#include "test_env.h" - -namespace art { -namespace Test980RedefineObjects { - -extern "C" JNIEXPORT void JNICALL Java_Main_bindFunctionsForClass( - JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jclass target) { - BindFunctionsOnClass(jvmti_env, env, target); -} - -extern "C" JNIEXPORT void JNICALL Java_art_test_TestWatcher_NotifyConstructed( - JNIEnv* env, jclass TestWatcherClass ATTRIBUTE_UNUSED, jobject constructed) { - char* sig = nullptr; - char* generic_sig = nullptr; - if (JvmtiErrorToException(env, - jvmti_env, - jvmti_env->GetClassSignature(env->GetObjectClass(constructed), - &sig, - &generic_sig))) { - // Exception. - return; - } - std::cout << "Object allocated of type '" << sig << "'" << std::endl; - jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(sig)); - jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(generic_sig)); -} - -} // namespace Test980RedefineObjects -} // namespace art diff --git a/test/980-redefine-object/src-ex/TestWatcher.java b/test/980-redefine-object/src-ex/TestWatcher.java index d15e68871c..c38e07bfe9 100644 --- a/test/980-redefine-object/src-ex/TestWatcher.java +++ b/test/980-redefine-object/src-ex/TestWatcher.java @@ -16,10 +16,60 @@ package art.test; +import java.util.concurrent.locks.ReentrantLock; + public class TestWatcher { - // NB This function is native since it is called in the Object.<init> method and so cannot cause - // any java allocations at all. The normal System.out.print* functions will cause allocations to - // occur so we cannot use them. This means the easiest way to report the object as being created - // is to go into native code and do it there. - public static native void NotifyConstructed(Object o); + // Lock to synchronize access to the static state of this class. + private static final ReentrantLock lock = new ReentrantLock(); + private static volatile boolean criticalFailure = false; + private static boolean reportingEnabled = true; + private static boolean doingReport = false; + + private static void MonitorEnter() { + lock.lock(); + } + + private static void MonitorExit() { + // Need to do this manually since we need to notify critical failure but would deadlock if + // waited for the unlock. + if (!lock.isHeldByCurrentThread()) { + NotifyCriticalFailure(); + throw new IllegalMonitorStateException("Locking error!"); + } else { + lock.unlock(); + } + } + + // Stops reporting. Must be paired with an EnableReporting call. + public static void DisableReporting() { + MonitorEnter(); + reportingEnabled = false; + } + + // Stops reporting. Must be paired with a DisableReporting call. + public static void EnableReporting() { + reportingEnabled = true; + MonitorExit(); + } + + public static void NotifyCriticalFailure() { + criticalFailure = true; + } + + public static void NotifyConstructed(Object o) { + if (criticalFailure) { + // Something went very wrong. We are probably trying to report it so don't get in the way. + return; + } + MonitorEnter(); + // We could enter an infinite loop if println allocates (which it does) so we disable + // reporting while we are doing a report. Since we are synchronized we won't miss any + // allocations. + if (reportingEnabled && !doingReport) { + doingReport = true; + System.out.println("Object allocated of type '" + o.getClass().getName() + "'"); + doingReport = false; + } + MonitorExit(); + } } diff --git a/test/980-redefine-object/src/Main.java b/test/980-redefine-object/src/Main.java index a50215e1ad..63c0cab95e 100644 --- a/test/980-redefine-object/src/Main.java +++ b/test/980-redefine-object/src/Main.java @@ -14,6 +14,9 @@ * limitations under the License. */ +import static art.Redefinition.doCommonClassRedefinition; + +import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Base64; import java.util.LinkedList; @@ -287,6 +290,31 @@ public class Main { private static final String LISTENER_LOCATION = System.getenv("DEX_LOCATION") + "/980-redefine-object-ex.jar"; + private static Method doEnableReporting; + private static Method doDisableReporting; + + private static void DisableReporting() { + if (doDisableReporting == null) { + return; + } + try { + doDisableReporting.invoke(null); + } catch (Exception e) { + throw new Error("Unable to disable reporting!"); + } + } + + private static void EnableReporting() { + if (doEnableReporting == null) { + return; + } + try { + doEnableReporting.invoke(null); + } catch (Exception e) { + throw new Error("Unable to enable reporting!"); + } + } + public static void main(String[] args) { art.Main.bindAgentJNIForClass(Main.class); doTest(); @@ -298,8 +326,8 @@ public class Main { addToBootClassLoader(LISTENER_LOCATION); // Load TestWatcher from the bootclassloader and make sure it is initialized. Class<?> testwatcher_class = Class.forName("art.test.TestWatcher", true, null); - // Bind the native functions of testwatcher_class. - bindFunctionsForClass(testwatcher_class); + doEnableReporting = testwatcher_class.getDeclaredMethod("EnableReporting"); + doDisableReporting = testwatcher_class.getDeclaredMethod("DisableReporting"); } catch (Exception e) { throw new Error("Exception while making testwatcher", e); } @@ -308,9 +336,9 @@ public class Main { // NB This function will cause 2 objects of type "Ljava/nio/HeapCharBuffer;" and // "Ljava/nio/HeapCharBuffer;" to be allocated each time it is called. private static void safePrintln(Object o) { - System.out.flush(); - System.out.print("\t" + o + "\n"); - System.out.flush(); + DisableReporting(); + System.out.println("\t" + o); + EnableReporting(); } private static void throwFrom(int depth) throws Exception { @@ -381,11 +409,4 @@ public class Main { } private static native void addToBootClassLoader(String s); - - private static native void bindFunctionsForClass(Class<?> target); - - // Transforms the class - private static native void doCommonClassRedefinition(Class<?> target, - byte[] class_file, - byte[] dex_file); } diff --git a/test/980-redefine-object/src/art/Redefinition.java b/test/980-redefine-object/src/art/Redefinition.java new file mode 100644 index 0000000000..0350ab42ad --- /dev/null +++ b/test/980-redefine-object/src/art/Redefinition.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.util.ArrayList; +// Common Redefinition functions. Placed here for use by CTS +public class Redefinition { + // Bind native functions. + static { + Main.bindAgentJNIForClass(Redefinition.class); + } + + public static final class CommonClassDefinition { + public final Class<?> target; + public final byte[] class_file_bytes; + public final byte[] dex_file_bytes; + + public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { + this.target = target; + this.class_file_bytes = class_file_bytes; + this.dex_file_bytes = dex_file_bytes; + } + } + + // A set of possible test configurations. Test should set this if they need to. + // This must be kept in sync with the defines in ti-agent/common_helper.cc + public static enum Config { + COMMON_REDEFINE(0), + COMMON_RETRANSFORM(1), + COMMON_TRANSFORM(2); + + private final int val; + private Config(int val) { + this.val = val; + } + } + + public static void setTestConfiguration(Config type) { + nativeSetTestConfiguration(type.val); + } + + private static native void nativeSetTestConfiguration(int type); + + // Transforms the class + public static native void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile); + + public static void doMultiClassRedefinition(CommonClassDefinition... defs) { + ArrayList<Class<?>> classes = new ArrayList<>(); + ArrayList<byte[]> class_files = new ArrayList<>(); + ArrayList<byte[]> dex_files = new ArrayList<>(); + + for (CommonClassDefinition d : defs) { + classes.add(d.target); + class_files.add(d.class_file_bytes); + dex_files.add(d.dex_file_bytes); + } + doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), + class_files.toArray(new byte[0][]), + dex_files.toArray(new byte[0][])); + } + + public static void addMultiTransformationResults(CommonClassDefinition... defs) { + for (CommonClassDefinition d : defs) { + addCommonTransformationResult(d.target.getCanonicalName(), + d.class_file_bytes, + d.dex_file_bytes); + } + } + + public static native void doCommonMultiClassRedefinition(Class<?>[] targets, + byte[][] classfiles, + byte[][] dexfiles); + public static native void doCommonClassRetransformation(Class<?>... target); + public static native void setPopRetransformations(boolean pop); + public static native void popTransformationFor(String name); + public static native void enableCommonRetransformation(boolean enable); + public static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); +} diff --git a/test/981-dedup-original-dex/src/Main.java b/test/981-dedup-original-dex/src/Main.java index 288f7ce4e0..f90c15ce8a 100644 --- a/test/981-dedup-original-dex/src/Main.java +++ b/test/981-dedup-original-dex/src/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,190 +14,8 @@ * limitations under the License. */ -import java.lang.reflect.Field; -import java.util.Base64; -import java.nio.ByteBuffer; - -import dalvik.system.ClassExt; -import dalvik.system.InMemoryDexClassLoader; - public class Main { - - /** - * base64 encoded class/dex file for - * class Transform { - * public void sayHi() { - * System.out.println("Goodbye"); - * } - * } - */ - private static final byte[] DEX_BYTES_1 = Base64.getDecoder().decode( - "ZGV4CjAzNQCLXSBQ5FiS3f16krSYZFF8xYZtFVp0GRXMAgAAcAAAAHhWNBIAAAAAAAAAACwCAAAO" + - "AAAAcAAAAAYAAACoAAAAAgAAAMAAAAABAAAA2AAAAAQAAADgAAAAAQAAAAABAACsAQAAIAEAAGIB" + - "AABqAQAAcwEAAIABAACXAQAAqwEAAL8BAADTAQAA4wEAAOYBAADqAQAA/gEAAAMCAAAMAgAAAgAA" + - "AAMAAAAEAAAABQAAAAYAAAAIAAAACAAAAAUAAAAAAAAACQAAAAUAAABcAQAABAABAAsAAAAAAAAA" + - "AAAAAAAAAAANAAAAAQABAAwAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAHAAAAAAAAAB4CAAAA" + - "AAAAAQABAAEAAAATAgAABAAAAHAQAwAAAA4AAwABAAIAAAAYAgAACQAAAGIAAAAbAQEAAABuIAIA" + - "EAAOAAAAAQAAAAMABjxpbml0PgAHR29vZGJ5ZQALTFRyYW5zZm9ybTsAFUxqYXZhL2lvL1ByaW50" + - "U3RyZWFtOwASTGphdmEvbGFuZy9PYmplY3Q7ABJMamF2YS9sYW5nL1N0cmluZzsAEkxqYXZhL2xh" + - "bmcvU3lzdGVtOwAOVHJhbnNmb3JtLmphdmEAAVYAAlZMABJlbWl0dGVyOiBqYWNrLTMuMzYAA291" + - "dAAHcHJpbnRsbgAFc2F5SGkAEQAHDgATAAcOhQAAAAEBAICABKACAQG4Ag0AAAAAAAAAAQAAAAAA" + - "AAABAAAADgAAAHAAAAACAAAABgAAAKgAAAADAAAAAgAAAMAAAAAEAAAAAQAAANgAAAAFAAAABAAA" + - "AOAAAAAGAAAAAQAAAAABAAABIAAAAgAAACABAAABEAAAAQAAAFwBAAACIAAADgAAAGIBAAADIAAA" + - "AgAAABMCAAAAIAAAAQAAAB4CAAAAEAAAAQAAACwCAAA="); - - /** - * base64 encoded class/dex file for - * class Transform2 { - * public void sayHi() { - * System.out.println("Goodbye2"); - * } - * } - */ - private static final byte[] DEX_BYTES_2 = Base64.getDecoder().decode( - "ZGV4CjAzNQAjXDED2iflQ3NXbPtBRVjQVMqoDU9nDz/QAgAAcAAAAHhWNBIAAAAAAAAAADACAAAO" + - "AAAAcAAAAAYAAACoAAAAAgAAAMAAAAABAAAA2AAAAAQAAADgAAAAAQAAAAABAACwAQAAIAEAAGIB" + - "AABqAQAAdAEAAIIBAACZAQAArQEAAMEBAADVAQAA5gEAAOkBAADtAQAAAQIAAAYCAAAPAgAAAgAA" + - "AAMAAAAEAAAABQAAAAYAAAAIAAAACAAAAAUAAAAAAAAACQAAAAUAAABcAQAABAABAAsAAAAAAAAA" + - "AAAAAAAAAAANAAAAAQABAAwAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAHAAAAAAAAACECAAAA" + - "AAAAAQABAAEAAAAWAgAABAAAAHAQAwAAAA4AAwABAAIAAAAbAgAACQAAAGIAAAAbAQEAAABuIAIA" + - "EAAOAAAAAQAAAAMABjxpbml0PgAIR29vZGJ5ZTIADExUcmFuc2Zvcm0yOwAVTGphdmEvaW8vUHJp" + - "bnRTdHJlYW07ABJMamF2YS9sYW5nL09iamVjdDsAEkxqYXZhL2xhbmcvU3RyaW5nOwASTGphdmEv" + - "bGFuZy9TeXN0ZW07AA9UcmFuc2Zvcm0yLmphdmEAAVYAAlZMABJlbWl0dGVyOiBqYWNrLTQuMzAA" + - "A291dAAHcHJpbnRsbgAFc2F5SGkAAQAHDgADAAcOhwAAAAEBAICABKACAQG4AgANAAAAAAAAAAEA" + - "AAAAAAAAAQAAAA4AAABwAAAAAgAAAAYAAACoAAAAAwAAAAIAAADAAAAABAAAAAEAAADYAAAABQAA" + - "AAQAAADgAAAABgAAAAEAAAAAAQAAASAAAAIAAAAgAQAAARAAAAEAAABcAQAAAiAAAA4AAABiAQAA" + - "AyAAAAIAAAAWAgAAACAAAAEAAAAhAgAAABAAAAEAAAAwAgAA"); - - - /** - * base64 encoded class/dex file for - * class Transform3 { - * public void sayHi() { - * System.out.println("hello3"); - * } - * } - */ - private static final byte[] DEX_BYTES_3_INITIAL = Base64.getDecoder().decode( - "ZGV4CjAzNQC2W2fBsAeLNAwWYlG8FVigzfsV7nBWITzQAgAAcAAAAHhWNBIAAAAAAAAAADACAAAO" + - "AAAAcAAAAAYAAACoAAAAAgAAAMAAAAABAAAA2AAAAAQAAADgAAAAAQAAAAABAACwAQAAIAEAAGIB" + - "AABqAQAAeAEAAI8BAACjAQAAtwEAAMsBAADcAQAA3wEAAOMBAAD3AQAA/wEAAAQCAAANAgAAAQAA" + - "AAIAAAADAAAABAAAAAUAAAAHAAAABwAAAAUAAAAAAAAACAAAAAUAAABcAQAABAABAAsAAAAAAAAA" + - "AAAAAAAAAAANAAAAAQABAAwAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAGAAAAAAAAAB8CAAAA" + - "AAAAAQABAAEAAAAUAgAABAAAAHAQAwAAAA4AAwABAAIAAAAZAgAACQAAAGIAAAAbAQoAAABuIAIA" + - "EAAOAAAAAQAAAAMABjxpbml0PgAMTFRyYW5zZm9ybTM7ABVMamF2YS9pby9QcmludFN0cmVhbTsA" + - "EkxqYXZhL2xhbmcvT2JqZWN0OwASTGphdmEvbGFuZy9TdHJpbmc7ABJMamF2YS9sYW5nL1N5c3Rl" + - "bTsAD1RyYW5zZm9ybTMuamF2YQABVgACVkwAEmVtaXR0ZXI6IGphY2stNC4zMAAGaGVsbG8zAANv" + - "dXQAB3ByaW50bG4ABXNheUhpAAIABw4ABAAHDocAAAABAQCAgASgAgEBuAIAAAANAAAAAAAAAAEA" + - "AAAAAAAAAQAAAA4AAABwAAAAAgAAAAYAAACoAAAAAwAAAAIAAADAAAAABAAAAAEAAADYAAAABQAA" + - "AAQAAADgAAAABgAAAAEAAAAAAQAAASAAAAIAAAAgAQAAARAAAAEAAABcAQAAAiAAAA4AAABiAQAA" + - "AyAAAAIAAAAUAgAAACAAAAEAAAAfAgAAABAAAAEAAAAwAgAA"); - - /** - * base64 encoded class/dex file for - * class Transform3 { - * public void sayHi() { - * System.out.println("Goodbye3"); - * } - * } - */ - private static final byte[] DEX_BYTES_3_FINAL = Base64.getDecoder().decode( - "ZGV4CjAzNQBAXE5GthgMydaFBuinf+ZBfXcBYIw2UlXQAgAAcAAAAHhWNBIAAAAAAAAAADACAAAO" + - "AAAAcAAAAAYAAACoAAAAAgAAAMAAAAABAAAA2AAAAAQAAADgAAAAAQAAAAABAACwAQAAIAEAAGIB" + - "AABqAQAAdAEAAIIBAACZAQAArQEAAMEBAADVAQAA5gEAAOkBAADtAQAAAQIAAAYCAAAPAgAAAgAA" + - "AAMAAAAEAAAABQAAAAYAAAAIAAAACAAAAAUAAAAAAAAACQAAAAUAAABcAQAABAABAAsAAAAAAAAA" + - "AAAAAAAAAAANAAAAAQABAAwAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAHAAAAAAAAACECAAAA" + - "AAAAAQABAAEAAAAWAgAABAAAAHAQAwAAAA4AAwABAAIAAAAbAgAACQAAAGIAAAAbAQEAAABuIAIA" + - "EAAOAAAAAQAAAAMABjxpbml0PgAIR29vZGJ5ZTMADExUcmFuc2Zvcm0zOwAVTGphdmEvaW8vUHJp" + - "bnRTdHJlYW07ABJMamF2YS9sYW5nL09iamVjdDsAEkxqYXZhL2xhbmcvU3RyaW5nOwASTGphdmEv" + - "bGFuZy9TeXN0ZW07AA9UcmFuc2Zvcm0zLmphdmEAAVYAAlZMABJlbWl0dGVyOiBqYWNrLTQuMzAA" + - "A291dAAHcHJpbnRsbgAFc2F5SGkAAgAHDgAEAAcOhwAAAAEBAICABKACAQG4AgANAAAAAAAAAAEA" + - "AAAAAAAAAQAAAA4AAABwAAAAAgAAAAYAAACoAAAAAwAAAAIAAADAAAAABAAAAAEAAADYAAAABQAA" + - "AAQAAADgAAAABgAAAAEAAAAAAQAAASAAAAIAAAAgAQAAARAAAAEAAABcAQAAAiAAAA4AAABiAQAA" + - "AyAAAAIAAAAWAgAAACAAAAEAAAAhAgAAABAAAAEAAAAwAgAA"); - - public static void main(String[] args) { - art.Main.bindAgentJNIForClass(Main.class); - try { - doTest(); - } catch (Exception e) { - e.printStackTrace(); - } - } - - private static void assertSame(Object a, Object b) throws Exception { - if (a != b) { - throw new AssertionError("'" + (a != null ? a.toString() : "null") + "' is not the same as " + - "'" + (b != null ? b.toString() : "null") + "'"); - } - } - - private static Object getObjectField(Object o, String name) throws Exception { - return getObjectField(o, o.getClass(), name); - } - - private static Object getObjectField(Object o, Class<?> type, String name) throws Exception { - Field f = type.getDeclaredField(name); - f.setAccessible(true); - return f.get(o); - } - - private static Object getOriginalDexFile(Class<?> k) throws Exception { - ClassExt ext_data_object = (ClassExt) getObjectField(k, "extData"); - if (ext_data_object == null) { - return null; - } - - return getObjectField(ext_data_object, "originalDexFile"); + public static void main(String[] args) throws Exception { + art.Test981.run(); } - - public static void doTest() throws Exception { - // Make sure both of these are loaded prior to transformations being added so they have the same - // original dex files. - Transform t1 = new Transform(); - Transform2 t2 = new Transform2(); - - assertSame(null, getOriginalDexFile(t1.getClass())); - assertSame(null, getOriginalDexFile(t2.getClass())); - assertSame(null, getOriginalDexFile(Main.class)); - - addCommonTransformationResult("Transform", new byte[0], DEX_BYTES_1); - addCommonTransformationResult("Transform2", new byte[0], DEX_BYTES_2); - enableCommonRetransformation(true); - doCommonClassRetransformation(Transform.class, Transform2.class); - - assertSame(getOriginalDexFile(t1.getClass()), getOriginalDexFile(t2.getClass())); - assertSame(null, getOriginalDexFile(Main.class)); - // Make sure that the original dex file is a DexCache object. - assertSame(getOriginalDexFile(t1.getClass()).getClass(), Class.forName("java.lang.DexCache")); - - // Check that we end up with a byte[] if we do a direct RedefineClasses - enableCommonRetransformation(false); - doCommonClassRedefinition(Transform.class, new byte[0], DEX_BYTES_1); - assertSame((new byte[0]).getClass(), getOriginalDexFile(t1.getClass()).getClass()); - - // Check we don't have anything if we don't have any originalDexFile if the onload - // transformation doesn't do anything. - enableCommonRetransformation(true); - Class<?> transform3Class = new InMemoryDexClassLoader( - ByteBuffer.wrap(DEX_BYTES_3_INITIAL), Main.class.getClassLoader()).loadClass("Transform3"); - assertSame(null, getOriginalDexFile(transform3Class)); - - // Check that we end up with a java.lang.Long pointer if we do an 'on-load' redefinition. - addCommonTransformationResult("Transform3", new byte[0], DEX_BYTES_3_FINAL); - enableCommonRetransformation(true); - Class<?> transform3ClassTransformed = new InMemoryDexClassLoader( - ByteBuffer.wrap(DEX_BYTES_3_INITIAL), Main.class.getClassLoader()).loadClass("Transform3"); - assertSame(Long.class, getOriginalDexFile(transform3ClassTransformed).getClass()); - } - - // Transforms the class - private static native void doCommonClassRetransformation(Class<?>... target); - private static native void doCommonClassRedefinition(Class<?> target, - byte[] class_file, - byte[] dex_file); - private static native void enableCommonRetransformation(boolean enable); - private static native void addCommonTransformationResult(String target_name, - byte[] class_bytes, - byte[] dex_bytes); } diff --git a/test/981-dedup-original-dex/src/Transform.java b/test/981-dedup-original-dex/src/Transform.java deleted file mode 100644 index 3c97907ddc..0000000000 --- a/test/981-dedup-original-dex/src/Transform.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * 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. - */ - -class Transform { - public void sayHi() { - System.out.println("hello"); - } -} diff --git a/test/981-dedup-original-dex/src/Transform2.java b/test/981-dedup-original-dex/src/Transform2.java deleted file mode 100644 index eb22842184..0000000000 --- a/test/981-dedup-original-dex/src/Transform2.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * 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. - */ - -class Transform2 { - public void sayHi() { - System.out.println("hello2"); - } -} diff --git a/test/981-dedup-original-dex/src/art/Redefinition.java b/test/981-dedup-original-dex/src/art/Redefinition.java new file mode 100644 index 0000000000..0350ab42ad --- /dev/null +++ b/test/981-dedup-original-dex/src/art/Redefinition.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.util.ArrayList; +// Common Redefinition functions. Placed here for use by CTS +public class Redefinition { + // Bind native functions. + static { + Main.bindAgentJNIForClass(Redefinition.class); + } + + public static final class CommonClassDefinition { + public final Class<?> target; + public final byte[] class_file_bytes; + public final byte[] dex_file_bytes; + + public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { + this.target = target; + this.class_file_bytes = class_file_bytes; + this.dex_file_bytes = dex_file_bytes; + } + } + + // A set of possible test configurations. Test should set this if they need to. + // This must be kept in sync with the defines in ti-agent/common_helper.cc + public static enum Config { + COMMON_REDEFINE(0), + COMMON_RETRANSFORM(1), + COMMON_TRANSFORM(2); + + private final int val; + private Config(int val) { + this.val = val; + } + } + + public static void setTestConfiguration(Config type) { + nativeSetTestConfiguration(type.val); + } + + private static native void nativeSetTestConfiguration(int type); + + // Transforms the class + public static native void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile); + + public static void doMultiClassRedefinition(CommonClassDefinition... defs) { + ArrayList<Class<?>> classes = new ArrayList<>(); + ArrayList<byte[]> class_files = new ArrayList<>(); + ArrayList<byte[]> dex_files = new ArrayList<>(); + + for (CommonClassDefinition d : defs) { + classes.add(d.target); + class_files.add(d.class_file_bytes); + dex_files.add(d.dex_file_bytes); + } + doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), + class_files.toArray(new byte[0][]), + dex_files.toArray(new byte[0][])); + } + + public static void addMultiTransformationResults(CommonClassDefinition... defs) { + for (CommonClassDefinition d : defs) { + addCommonTransformationResult(d.target.getCanonicalName(), + d.class_file_bytes, + d.dex_file_bytes); + } + } + + public static native void doCommonMultiClassRedefinition(Class<?>[] targets, + byte[][] classfiles, + byte[][] dexfiles); + public static native void doCommonClassRetransformation(Class<?>... target); + public static native void setPopRetransformations(boolean pop); + public static native void popTransformationFor(String name); + public static native void enableCommonRetransformation(boolean enable); + public static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); +} diff --git a/test/981-dedup-original-dex/src/art/Test981.java b/test/981-dedup-original-dex/src/art/Test981.java new file mode 100644 index 0000000000..3a97268ef9 --- /dev/null +++ b/test/981-dedup-original-dex/src/art/Test981.java @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * 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 art; + +import java.lang.reflect.Field; +import java.util.Base64; +import java.nio.ByteBuffer; + +import dalvik.system.ClassExt; +import dalvik.system.InMemoryDexClassLoader; + +public class Test981 { + + static class Transform { + public void sayHi() { + System.out.println("hello"); + } + } + + static class Transform2 { + public void sayHi() { + System.out.println("hello2"); + } + } + + /** + * base64 encoded class/dex file for + * static class Transform { + * public void sayHi() { + * System.out.println("Goodbye"); + * } + * } + */ + private static final byte[] DEX_BYTES_1 = Base64.getDecoder().decode( + "ZGV4CjAzNQB+giqQAAAAAAAAAAAAAAAAAAAAAAAAAAC4AwAAcAAAAHhWNBIAAAAAAAAAAPQCAAAU" + + "AAAAcAAAAAkAAADAAAAAAgAAAOQAAAABAAAA/AAAAAQAAAAEAQAAAQAAACQBAAB0AgAARAEAAEQB" + + "AABMAQAAVQEAAG4BAAB9AQAAoQEAAMEBAADYAQAA7AEAAAACAAAUAgAAIgIAAC0CAAAwAgAANAIA" + + "AEECAABHAgAATAIAAFUCAABcAgAAAgAAAAMAAAAEAAAABQAAAAYAAAAHAAAACAAAAAkAAAAMAAAA" + + "DAAAAAgAAAAAAAAADQAAAAgAAABkAgAABwAEABAAAAAAAAAAAAAAAAAAAAASAAAABAABABEAAAAF" + + "AAAAAAAAAAAAAAAAAAAABQAAAAAAAAAKAAAA5AIAALgCAAAAAAAABjxpbml0PgAHR29vZGJ5ZQAX" + + "TGFydC9UZXN0OTgxJFRyYW5zZm9ybTsADUxhcnQvVGVzdDk4MTsAIkxkYWx2aWsvYW5ub3RhdGlv" + + "bi9FbmNsb3NpbmdDbGFzczsAHkxkYWx2aWsvYW5ub3RhdGlvbi9Jbm5lckNsYXNzOwAVTGphdmEv" + + "aW8vUHJpbnRTdHJlYW07ABJMamF2YS9sYW5nL09iamVjdDsAEkxqYXZhL2xhbmcvU3RyaW5nOwAS" + + "TGphdmEvbGFuZy9TeXN0ZW07AAxUZXN0OTgxLmphdmEACVRyYW5zZm9ybQABVgACVkwAC2FjY2Vz" + + "c0ZsYWdzAARuYW1lAANvdXQAB3ByaW50bG4ABXNheUhpAAV2YWx1ZQAAAQAAAAYAAAAFAAcOAAcA" + + "Bw4BCA8AAAAAAQABAAEAAABsAgAABAAAAHAQAwAAAA4AAwABAAIAAABxAgAACQAAAGIAAAAbAQEA" + + "AABuIAIAEAAOAAAAAAABAQCAgAT8BAEBlAUAAAICARMYAQIDAg4ECA8XCwACAAAAyAIAAM4CAADY" + + "AgAAAAAAAAAAAAAAAAAAEAAAAAAAAAABAAAAAAAAAAEAAAAUAAAAcAAAAAIAAAAJAAAAwAAAAAMA" + + "AAACAAAA5AAAAAQAAAABAAAA/AAAAAUAAAAEAAAABAEAAAYAAAABAAAAJAEAAAIgAAAUAAAARAEA" + + "AAEQAAABAAAAZAIAAAMgAAACAAAAbAIAAAEgAAACAAAAfAIAAAAgAAABAAAAuAIAAAQgAAACAAAA" + + "yAIAAAMQAAABAAAA2AIAAAYgAAABAAAA5AIAAAAQAAABAAAA9AIAAA=="); + + /** + * base64 encoded class/dex file for + * static class Transform2 { + * public void sayHi() { + * System.out.println("Goodbye2"); + * } + * } + */ + private static final byte[] DEX_BYTES_2 = Base64.getDecoder().decode( + "ZGV4CjAzNQAhg+RVAAAAAAAAAAAAAAAAAAAAAAAAAAC8AwAAcAAAAHhWNBIAAAAAAAAAAPgCAAAU" + + "AAAAcAAAAAkAAADAAAAAAgAAAOQAAAABAAAA/AAAAAQAAAAEAQAAAQAAACQBAAB4AgAARAEAAEQB" + + "AABMAQAAVgEAAHABAAB/AQAAowEAAMMBAADaAQAA7gEAAAICAAAWAgAAJAIAADACAAAzAgAANwIA" + + "AEQCAABKAgAATwIAAFgCAABfAgAAAgAAAAMAAAAEAAAABQAAAAYAAAAHAAAACAAAAAkAAAAMAAAA" + + "DAAAAAgAAAAAAAAADQAAAAgAAABoAgAABwAEABAAAAAAAAAAAAAAAAAAAAASAAAABAABABEAAAAF" + + "AAAAAAAAAAAAAAAAAAAABQAAAAAAAAAKAAAA6AIAALwCAAAAAAAABjxpbml0PgAIR29vZGJ5ZTIA" + + "GExhcnQvVGVzdDk4MSRUcmFuc2Zvcm0yOwANTGFydC9UZXN0OTgxOwAiTGRhbHZpay9hbm5vdGF0" + + "aW9uL0VuY2xvc2luZ0NsYXNzOwAeTGRhbHZpay9hbm5vdGF0aW9uL0lubmVyQ2xhc3M7ABVMamF2" + + "YS9pby9QcmludFN0cmVhbTsAEkxqYXZhL2xhbmcvT2JqZWN0OwASTGphdmEvbGFuZy9TdHJpbmc7" + + "ABJMamF2YS9sYW5nL1N5c3RlbTsADFRlc3Q5ODEuamF2YQAKVHJhbnNmb3JtMgABVgACVkwAC2Fj" + + "Y2Vzc0ZsYWdzAARuYW1lAANvdXQAB3ByaW50bG4ABXNheUhpAAV2YWx1ZQAAAAEAAAAGAAAACgAH" + + "DgAMAAcOAQgPAAAAAAEAAQABAAAAcAIAAAQAAABwEAMAAAAOAAMAAQACAAAAdQIAAAkAAABiAAAA" + + "GwEBAAAAbiACABAADgAAAAAAAQEAgIAEgAUBAZgFAAACAgETGAECAwIOBAgPFwsAAgAAAMwCAADS" + + "AgAA3AIAAAAAAAAAAAAAAAAAABAAAAAAAAAAAQAAAAAAAAABAAAAFAAAAHAAAAACAAAACQAAAMAA" + + "AAADAAAAAgAAAOQAAAAEAAAAAQAAAPwAAAAFAAAABAAAAAQBAAAGAAAAAQAAACQBAAACIAAAFAAA" + + "AEQBAAABEAAAAQAAAGgCAAADIAAAAgAAAHACAAABIAAAAgAAAIACAAAAIAAAAQAAALwCAAAEIAAA" + + "AgAAAMwCAAADEAAAAQAAANwCAAAGIAAAAQAAAOgCAAAAEAAAAQAAAPgCAAA="); + + /** + * base64 encoded class/dex file for + * class Transform3 { + * public void sayHi() { + * System.out.println("hello3"); + * } + * } + */ + private static final byte[] DEX_BYTES_3_INITIAL = Base64.getDecoder().decode( + "ZGV4CjAzNQC2W2fBsAeLNAwWYlG8FVigzfsV7nBWITzQAgAAcAAAAHhWNBIAAAAAAAAAADACAAAO" + + "AAAAcAAAAAYAAACoAAAAAgAAAMAAAAABAAAA2AAAAAQAAADgAAAAAQAAAAABAACwAQAAIAEAAGIB" + + "AABqAQAAeAEAAI8BAACjAQAAtwEAAMsBAADcAQAA3wEAAOMBAAD3AQAA/wEAAAQCAAANAgAAAQAA" + + "AAIAAAADAAAABAAAAAUAAAAHAAAABwAAAAUAAAAAAAAACAAAAAUAAABcAQAABAABAAsAAAAAAAAA" + + "AAAAAAAAAAANAAAAAQABAAwAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAGAAAAAAAAAB8CAAAA" + + "AAAAAQABAAEAAAAUAgAABAAAAHAQAwAAAA4AAwABAAIAAAAZAgAACQAAAGIAAAAbAQoAAABuIAIA" + + "EAAOAAAAAQAAAAMABjxpbml0PgAMTFRyYW5zZm9ybTM7ABVMamF2YS9pby9QcmludFN0cmVhbTsA" + + "EkxqYXZhL2xhbmcvT2JqZWN0OwASTGphdmEvbGFuZy9TdHJpbmc7ABJMamF2YS9sYW5nL1N5c3Rl" + + "bTsAD1RyYW5zZm9ybTMuamF2YQABVgACVkwAEmVtaXR0ZXI6IGphY2stNC4zMAAGaGVsbG8zAANv" + + "dXQAB3ByaW50bG4ABXNheUhpAAIABw4ABAAHDocAAAABAQCAgASgAgEBuAIAAAANAAAAAAAAAAEA" + + "AAAAAAAAAQAAAA4AAABwAAAAAgAAAAYAAACoAAAAAwAAAAIAAADAAAAABAAAAAEAAADYAAAABQAA" + + "AAQAAADgAAAABgAAAAEAAAAAAQAAASAAAAIAAAAgAQAAARAAAAEAAABcAQAAAiAAAA4AAABiAQAA" + + "AyAAAAIAAAAUAgAAACAAAAEAAAAfAgAAABAAAAEAAAAwAgAA"); + + /** + * base64 encoded class/dex file for + * class Transform3 { + * public void sayHi() { + * System.out.println("Goodbye3"); + * } + * } + */ + private static final byte[] DEX_BYTES_3_FINAL = Base64.getDecoder().decode( + "ZGV4CjAzNQBAXE5GthgMydaFBuinf+ZBfXcBYIw2UlXQAgAAcAAAAHhWNBIAAAAAAAAAADACAAAO" + + "AAAAcAAAAAYAAACoAAAAAgAAAMAAAAABAAAA2AAAAAQAAADgAAAAAQAAAAABAACwAQAAIAEAAGIB" + + "AABqAQAAdAEAAIIBAACZAQAArQEAAMEBAADVAQAA5gEAAOkBAADtAQAAAQIAAAYCAAAPAgAAAgAA" + + "AAMAAAAEAAAABQAAAAYAAAAIAAAACAAAAAUAAAAAAAAACQAAAAUAAABcAQAABAABAAsAAAAAAAAA" + + "AAAAAAAAAAANAAAAAQABAAwAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAHAAAAAAAAACECAAAA" + + "AAAAAQABAAEAAAAWAgAABAAAAHAQAwAAAA4AAwABAAIAAAAbAgAACQAAAGIAAAAbAQEAAABuIAIA" + + "EAAOAAAAAQAAAAMABjxpbml0PgAIR29vZGJ5ZTMADExUcmFuc2Zvcm0zOwAVTGphdmEvaW8vUHJp" + + "bnRTdHJlYW07ABJMamF2YS9sYW5nL09iamVjdDsAEkxqYXZhL2xhbmcvU3RyaW5nOwASTGphdmEv" + + "bGFuZy9TeXN0ZW07AA9UcmFuc2Zvcm0zLmphdmEAAVYAAlZMABJlbWl0dGVyOiBqYWNrLTQuMzAA" + + "A291dAAHcHJpbnRsbgAFc2F5SGkAAgAHDgAEAAcOhwAAAAEBAICABKACAQG4AgANAAAAAAAAAAEA" + + "AAAAAAAAAQAAAA4AAABwAAAAAgAAAAYAAACoAAAAAwAAAAIAAADAAAAABAAAAAEAAADYAAAABQAA" + + "AAQAAADgAAAABgAAAAEAAAAAAQAAASAAAAIAAAAgAQAAARAAAAEAAABcAQAAAiAAAA4AAABiAQAA" + + "AyAAAAIAAAAWAgAAACAAAAEAAAAhAgAAABAAAAEAAAAwAgAA"); + + public static void run() throws Exception { + Redefinition.setTestConfiguration(Redefinition.Config.COMMON_RETRANSFORM); + doTest(); + } + + private static void assertSame(Object a, Object b) throws Exception { + if (a != b) { + throw new AssertionError("'" + (a != null ? a.toString() : "null") + "' is not the same as " + + "'" + (b != null ? b.toString() : "null") + "'"); + } + } + + private static Object getObjectField(Object o, String name) throws Exception { + return getObjectField(o, o.getClass(), name); + } + + private static Object getObjectField(Object o, Class<?> type, String name) throws Exception { + Field f = type.getDeclaredField(name); + f.setAccessible(true); + return f.get(o); + } + + private static Object getOriginalDexFile(Class<?> k) throws Exception { + ClassExt ext_data_object = (ClassExt) getObjectField(k, "extData"); + if (ext_data_object == null) { + return null; + } + + return getObjectField(ext_data_object, "originalDexFile"); + } + + public static void doTest() throws Exception { + // Make sure both of these are loaded prior to transformations being added so they have the same + // original dex files. + Transform t1 = new Transform(); + Transform2 t2 = new Transform2(); + + assertSame(null, getOriginalDexFile(t1.getClass())); + assertSame(null, getOriginalDexFile(t2.getClass())); + assertSame(null, getOriginalDexFile(Test981.class)); + + Redefinition.addCommonTransformationResult("art/Test981$Transform", new byte[0], DEX_BYTES_1); + Redefinition.addCommonTransformationResult("art/Test981$Transform2", new byte[0], DEX_BYTES_2); + Redefinition.enableCommonRetransformation(true); + Redefinition.doCommonClassRetransformation(Transform.class, Transform2.class); + + assertSame(getOriginalDexFile(t1.getClass()), getOriginalDexFile(t2.getClass())); + assertSame(null, getOriginalDexFile(Test981.class)); + // Make sure that the original dex file is a DexCache object. + assertSame(getOriginalDexFile(t1.getClass()).getClass(), Class.forName("java.lang.DexCache")); + + // Check that we end up with a byte[] if we do a direct RedefineClasses + Redefinition.enableCommonRetransformation(false); + Redefinition.doCommonClassRedefinition(Transform.class, new byte[0], DEX_BYTES_1); + assertSame((new byte[0]).getClass(), getOriginalDexFile(t1.getClass()).getClass()); + + // Check we don't have anything if we don't have any originalDexFile if the onload + // transformation doesn't do anything. + Redefinition.enableCommonRetransformation(true); + Class<?> transform3Class = new InMemoryDexClassLoader( + ByteBuffer.wrap(DEX_BYTES_3_INITIAL), Test981.class.getClassLoader()).loadClass("Transform3"); + assertSame(null, getOriginalDexFile(transform3Class)); + + // Check that we end up with a java.lang.Long pointer if we do an 'on-load' redefinition. + Redefinition.addCommonTransformationResult("Transform3", new byte[0], DEX_BYTES_3_FINAL); + Redefinition.enableCommonRetransformation(true); + Class<?> transform3ClassTransformed = new InMemoryDexClassLoader( + ByteBuffer.wrap(DEX_BYTES_3_INITIAL), Test981.class.getClassLoader()).loadClass("Transform3"); + assertSame(Long.class, getOriginalDexFile(transform3ClassTransformed).getClass()); + } +} diff --git a/test/982-ok-no-retransform/src/Main.java b/test/982-ok-no-retransform/src/Main.java index 33e50d77ba..bd73e81da6 100644 --- a/test/982-ok-no-retransform/src/Main.java +++ b/test/982-ok-no-retransform/src/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,22 +14,8 @@ * limitations under the License. */ -import java.util.Base64; public class Main { - - public static void main(String[] args) { - art.Main.bindAgentJNIForClass(Main.class); - doTest(new Transform()); - } - - public static void doTest(Transform t) { - t.sayHi(); - enableCommonRetransformation(true); - doCommonClassRetransformation(Transform.class); - t.sayHi(); + public static void main(String[] args) throws Exception { + art.Test982.run(); } - - // Transforms the class - private static native void doCommonClassRetransformation(Class<?>... target); - private static native void enableCommonRetransformation(boolean enable); } diff --git a/test/982-ok-no-retransform/src/Transform.java b/test/982-ok-no-retransform/src/Transform.java deleted file mode 100644 index 8e8af355da..0000000000 --- a/test/982-ok-no-retransform/src/Transform.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * 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. - */ - -class Transform { - public void sayHi() { - // Use lower 'h' to make sure the string will have a different string id - // than the transformation (the transformation code is the same except - // the actual printed String, which was making the test inacurately passing - // in JIT mode when loading the string from the dex cache, as the string ids - // of the two different strings were the same). - // We know the string ids will be different because lexicographically: - // "Goodbye" < "LTransform;" < "hello". - System.out.println("hello"); - } -} diff --git a/test/982-ok-no-retransform/src/art/Redefinition.java b/test/982-ok-no-retransform/src/art/Redefinition.java new file mode 100644 index 0000000000..0350ab42ad --- /dev/null +++ b/test/982-ok-no-retransform/src/art/Redefinition.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.util.ArrayList; +// Common Redefinition functions. Placed here for use by CTS +public class Redefinition { + // Bind native functions. + static { + Main.bindAgentJNIForClass(Redefinition.class); + } + + public static final class CommonClassDefinition { + public final Class<?> target; + public final byte[] class_file_bytes; + public final byte[] dex_file_bytes; + + public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { + this.target = target; + this.class_file_bytes = class_file_bytes; + this.dex_file_bytes = dex_file_bytes; + } + } + + // A set of possible test configurations. Test should set this if they need to. + // This must be kept in sync with the defines in ti-agent/common_helper.cc + public static enum Config { + COMMON_REDEFINE(0), + COMMON_RETRANSFORM(1), + COMMON_TRANSFORM(2); + + private final int val; + private Config(int val) { + this.val = val; + } + } + + public static void setTestConfiguration(Config type) { + nativeSetTestConfiguration(type.val); + } + + private static native void nativeSetTestConfiguration(int type); + + // Transforms the class + public static native void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile); + + public static void doMultiClassRedefinition(CommonClassDefinition... defs) { + ArrayList<Class<?>> classes = new ArrayList<>(); + ArrayList<byte[]> class_files = new ArrayList<>(); + ArrayList<byte[]> dex_files = new ArrayList<>(); + + for (CommonClassDefinition d : defs) { + classes.add(d.target); + class_files.add(d.class_file_bytes); + dex_files.add(d.dex_file_bytes); + } + doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), + class_files.toArray(new byte[0][]), + dex_files.toArray(new byte[0][])); + } + + public static void addMultiTransformationResults(CommonClassDefinition... defs) { + for (CommonClassDefinition d : defs) { + addCommonTransformationResult(d.target.getCanonicalName(), + d.class_file_bytes, + d.dex_file_bytes); + } + } + + public static native void doCommonMultiClassRedefinition(Class<?>[] targets, + byte[][] classfiles, + byte[][] dexfiles); + public static native void doCommonClassRetransformation(Class<?>... target); + public static native void setPopRetransformations(boolean pop); + public static native void popTransformationFor(String name); + public static native void enableCommonRetransformation(boolean enable); + public static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); +} diff --git a/test/942-private-recursive/src/Transform.java b/test/982-ok-no-retransform/src/art/Test982.java index 7714326066..080d47facc 100644 --- a/test/942-private-recursive/src/Transform.java +++ b/test/982-ok-no-retransform/src/art/Test982.java @@ -14,19 +14,26 @@ * limitations under the License. */ -class Transform { - private void privateSayHi(int recur, Runnable r) { - System.out.println("hello" + recur); - if (recur == 1) { - r.run(); - privateSayHi(recur - 1, r); - } else if (recur != 0) { - privateSayHi(recur - 1, r); +package art; + +import java.util.Base64; +public class Test982 { + + static class Transform { + public void sayHi() { + System.out.println("hello"); } - System.out.println("goodbye" + recur); } - public void sayHi(int recur, Runnable r) { - privateSayHi(recur, r); + public static void run() { + Redefinition.setTestConfiguration(Redefinition.Config.COMMON_RETRANSFORM); + doTest(new Transform()); + } + + public static void doTest(Transform t) { + t.sayHi(); + Redefinition.enableCommonRetransformation(true); + Redefinition.doCommonClassRetransformation(Transform.class); + t.sayHi(); } } diff --git a/test/983-source-transform-verify/expected.txt b/test/983-source-transform-verify/expected.txt index 0a94212ad2..abcdf3a868 100644 --- a/test/983-source-transform-verify/expected.txt +++ b/test/983-source-transform-verify/expected.txt @@ -1,2 +1,2 @@ -Dex file hook for Transform +Dex file hook for art/Test983$Transform Dex file hook for java/lang/Object diff --git a/test/983-source-transform-verify/src/Main.java b/test/983-source-transform-verify/src/Main.java index ad081a2006..e1d20f6678 100644 --- a/test/983-source-transform-verify/src/Main.java +++ b/test/983-source-transform-verify/src/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,23 +14,8 @@ * limitations under the License. */ -import java.util.Base64; public class Main { - - public static void main(String[] args) { - art.Main.bindAgentJNIForClass(Main.class); - doTest(); - } - - public static void doTest() { - Transform abc = new Transform(); - enableCommonRetransformation(true); - doCommonClassRetransformation(Transform.class); - doCommonClassRetransformation(Object.class); - enableCommonRetransformation(false); + public static void main(String[] args) throws Exception { + art.Test983.run(); } - - // Transforms the class - private static native void doCommonClassRetransformation(Class<?>... target); - private static native void enableCommonRetransformation(boolean enable); } diff --git a/test/983-source-transform-verify/src/Transform.java b/test/983-source-transform-verify/src/Transform.java deleted file mode 100644 index 8e8af355da..0000000000 --- a/test/983-source-transform-verify/src/Transform.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * 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. - */ - -class Transform { - public void sayHi() { - // Use lower 'h' to make sure the string will have a different string id - // than the transformation (the transformation code is the same except - // the actual printed String, which was making the test inacurately passing - // in JIT mode when loading the string from the dex cache, as the string ids - // of the two different strings were the same). - // We know the string ids will be different because lexicographically: - // "Goodbye" < "LTransform;" < "hello". - System.out.println("hello"); - } -} diff --git a/test/983-source-transform-verify/src/art/Redefinition.java b/test/983-source-transform-verify/src/art/Redefinition.java new file mode 100644 index 0000000000..0350ab42ad --- /dev/null +++ b/test/983-source-transform-verify/src/art/Redefinition.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.util.ArrayList; +// Common Redefinition functions. Placed here for use by CTS +public class Redefinition { + // Bind native functions. + static { + Main.bindAgentJNIForClass(Redefinition.class); + } + + public static final class CommonClassDefinition { + public final Class<?> target; + public final byte[] class_file_bytes; + public final byte[] dex_file_bytes; + + public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { + this.target = target; + this.class_file_bytes = class_file_bytes; + this.dex_file_bytes = dex_file_bytes; + } + } + + // A set of possible test configurations. Test should set this if they need to. + // This must be kept in sync with the defines in ti-agent/common_helper.cc + public static enum Config { + COMMON_REDEFINE(0), + COMMON_RETRANSFORM(1), + COMMON_TRANSFORM(2); + + private final int val; + private Config(int val) { + this.val = val; + } + } + + public static void setTestConfiguration(Config type) { + nativeSetTestConfiguration(type.val); + } + + private static native void nativeSetTestConfiguration(int type); + + // Transforms the class + public static native void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile); + + public static void doMultiClassRedefinition(CommonClassDefinition... defs) { + ArrayList<Class<?>> classes = new ArrayList<>(); + ArrayList<byte[]> class_files = new ArrayList<>(); + ArrayList<byte[]> dex_files = new ArrayList<>(); + + for (CommonClassDefinition d : defs) { + classes.add(d.target); + class_files.add(d.class_file_bytes); + dex_files.add(d.dex_file_bytes); + } + doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), + class_files.toArray(new byte[0][]), + dex_files.toArray(new byte[0][])); + } + + public static void addMultiTransformationResults(CommonClassDefinition... defs) { + for (CommonClassDefinition d : defs) { + addCommonTransformationResult(d.target.getCanonicalName(), + d.class_file_bytes, + d.dex_file_bytes); + } + } + + public static native void doCommonMultiClassRedefinition(Class<?>[] targets, + byte[][] classfiles, + byte[][] dexfiles); + public static native void doCommonClassRetransformation(Class<?>... target); + public static native void setPopRetransformations(boolean pop); + public static native void popTransformationFor(String name); + public static native void enableCommonRetransformation(boolean enable); + public static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); +} diff --git a/test/915-obsolete-2/src/Transform.java b/test/983-source-transform-verify/src/art/Test983.java index e914e29479..b81e7f4df3 100644 --- a/test/915-obsolete-2/src/Transform.java +++ b/test/983-source-transform-verify/src/art/Test983.java @@ -14,22 +14,25 @@ * limitations under the License. */ -class Transform { - private void Start() { - System.out.println("hello - private"); +package art; + +import java.util.Base64; +public class Test983 { + static class Transform { + public void sayHi() { + System.out.println("hello"); + } } - private void Finish() { - System.out.println("goodbye - private"); + public static void run() { + doTest(); } - public void sayHi(Runnable r) { - System.out.println("Pre Start private method call"); - Start(); - System.out.println("Post Start private method call"); - r.run(); - System.out.println("Pre Finish private method call"); - Finish(); - System.out.println("Post Finish private method call"); + public static void doTest() { + Transform abc = new Transform(); + Redefinition.enableCommonRetransformation(true); + Redefinition.doCommonClassRetransformation(Transform.class); + Redefinition.doCommonClassRetransformation(Object.class); + Redefinition.enableCommonRetransformation(false); } } diff --git a/test/984-obsolete-invoke/obsolete_invoke.cc b/test/984-obsolete-invoke/obsolete_invoke.cc index 27e36ba509..ab2499aa62 100644 --- a/test/984-obsolete-invoke/obsolete_invoke.cc +++ b/test/984-obsolete-invoke/obsolete_invoke.cc @@ -17,20 +17,20 @@ #include "android-base/macros.h" #include "jni.h" #include "jvmti.h" -#include "mirror/class-inl.h" -#include "scoped_local_ref.h" // Test infrastructure #include "test_env.h" #include "jvmti_helper.h" +#include "scoped_local_ref.h" namespace art { namespace Test984ObsoleteInvoke { static constexpr size_t kNumFrames = 30; -extern "C" JNIEXPORT jobject JNICALL Java_Main_getFirstObsoleteMethod984(JNIEnv* env, jclass) { +extern "C" JNIEXPORT jobject JNICALL Java_art_Test984_getFirstObsoleteMethod984(JNIEnv* env, + jclass) { jthread cur; jint frame_count; jvmtiFrameInfo frames[kNumFrames]; diff --git a/test/984-obsolete-invoke/src/Main.java b/test/984-obsolete-invoke/src/Main.java index 418d64d906..04a368dcd4 100644 --- a/test/984-obsolete-invoke/src/Main.java +++ b/test/984-obsolete-invoke/src/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,96 +14,8 @@ * limitations under the License. */ -import java.lang.reflect.Method; -import java.util.Base64; - public class Main { - // class Transform { - // public static void sayHi(Runnable r) { - // System.out.println("Hello - Transformed"); - // r.run(); - // System.out.println("Goodbye - Transformed"); - // } - // } - private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( - "yv66vgAAADQAJAoACAARCQASABMIABQKABUAFgsAFwAYCAAZBwAaBwAbAQAGPGluaXQ+AQADKClW" + - "AQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEABXNheUhpAQAXKExqYXZhL2xhbmcvUnVubmFibGU7" + - "KVYBAApTb3VyY2VGaWxlAQAOVHJhbnNmb3JtLmphdmEMAAkACgcAHAwAHQAeAQATSGVsbG8gLSBU" + - "cmFuc2Zvcm1lZAcAHwwAIAAhBwAiDAAjAAoBABVHb29kYnllIC0gVHJhbnNmb3JtZWQBAAlUcmFu" + - "c2Zvcm0BABBqYXZhL2xhbmcvT2JqZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZh" + - "L2lvL1ByaW50U3RyZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZh" + - "L2xhbmcvU3RyaW5nOylWAQASamF2YS9sYW5nL1J1bm5hYmxlAQADcnVuACAABwAIAAAAAAACAAAA" + - "CQAKAAEACwAAAB0AAQABAAAABSq3AAGxAAAAAQAMAAAABgABAAAAAQAJAA0ADgABAAsAAAA7AAIA" + - "AQAAABeyAAISA7YABCq5AAUBALIAAhIGtgAEsQAAAAEADAAAABIABAAAAAMACAAEAA4ABQAWAAYA" + - "AQAPAAAAAgAQ"); - private static final byte[] DEX_BYTES = Base64.getDecoder().decode( - "ZGV4CjAzNQCMekj2NPwzrEp/v+2yzzSg8xZvBtU1bC1QAwAAcAAAAHhWNBIAAAAAAAAAALACAAAR" + - "AAAAcAAAAAcAAAC0AAAAAwAAANAAAAABAAAA9AAAAAUAAAD8AAAAAQAAACQBAAAMAgAARAEAAKIB" + - "AACqAQAAwQEAANYBAADjAQAA+gEAAA4CAAAkAgAAOAIAAEwCAABcAgAAXwIAAGMCAAB3AgAAfAIA" + - "AIUCAACKAgAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAACgAAAAoAAAAGAAAAAAAAAAsAAAAGAAAA" + - "lAEAAAsAAAAGAAAAnAEAAAUAAQANAAAAAAAAAAAAAAAAAAEAEAAAAAEAAgAOAAAAAgAAAAAAAAAD" + - "AAAADwAAAAAAAAAAAAAAAgAAAAAAAAAJAAAAAAAAAJ8CAAAAAAAAAQABAAEAAACRAgAABAAAAHAQ" + - "AwAAAA4AAwABAAIAAACWAgAAFAAAAGIAAAAbAQIAAABuIAIAEAByEAQAAgBiAAAAGwEBAAAAbiAC" + - "ABAADgABAAAAAwAAAAEAAAAEAAY8aW5pdD4AFUdvb2RieWUgLSBUcmFuc2Zvcm1lZAATSGVsbG8g" + - "LSBUcmFuc2Zvcm1lZAALTFRyYW5zZm9ybTsAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwASTGphdmEv" + - "bGFuZy9PYmplY3Q7ABRMamF2YS9sYW5nL1J1bm5hYmxlOwASTGphdmEvbGFuZy9TdHJpbmc7ABJM" + - "amF2YS9sYW5nL1N5c3RlbTsADlRyYW5zZm9ybS5qYXZhAAFWAAJWTAASZW1pdHRlcjogamFjay00" + - "LjMxAANvdXQAB3ByaW50bG4AA3J1bgAFc2F5SGkAAQAHDgADAQAHDoc8hwAAAAIAAICABMQCAQnc" + - "AgAAAA0AAAAAAAAAAQAAAAAAAAABAAAAEQAAAHAAAAACAAAABwAAALQAAAADAAAAAwAAANAAAAAE" + - "AAAAAQAAAPQAAAAFAAAABQAAAPwAAAAGAAAAAQAAACQBAAABIAAAAgAAAEQBAAABEAAAAgAAAJQB" + - "AAACIAAAEQAAAKIBAAADIAAAAgAAAJECAAAAIAAAAQAAAJ8CAAAAEAAAAQAAALACAAA="); - - public static void main(String[] args) { - art.Main.bindAgentJNIForClass(Main.class); - doTest(); + public static void main(String[] args) throws Exception { + art.Test984.run(); } - - // The Method that holds an obsolete method pointer. We will fill it in by getting a jmethodID - // from a stack with an obsolete method in it. There should be no other ways to obtain an obsolete - // jmethodID in ART without unsafe casts. - public static Method obsolete_method = null; - - public static void doTest() { - // Capture the obsolete method. - // - // NB The obsolete method must be direct so that we will not look in the receiver type to get - // the actual method. - Transform.sayHi(() -> { - System.out.println("transforming calling function"); - doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES); - System.out.println("Retrieving obsolete method from current stack"); - // This should get the obsolete sayHi method (as the only obsolete method on the current - // threads stack). - Main.obsolete_method = getFirstObsoleteMethod984(); - }); - - // Prove we did actually redefine something. - System.out.println("Invoking redefined version of method."); - Transform.sayHi(() -> { System.out.println("Not doing anything here"); }); - - System.out.println("invoking obsolete method"); - try { - obsolete_method.invoke(null, (Runnable)() -> { - throw new Error("Unexpected code running from invoke of obsolete method!"); - }); - throw new Error("Running obsolete method did not throw exception"); - } catch (Throwable e) { - if (e instanceof InternalError || e.getCause() instanceof InternalError) { - System.out.println("Caught expected error from attempting to invoke an obsolete method."); - } else { - System.out.println("Unexpected error type for calling obsolete method! Expected either " - + "an InternalError or something that is caused by an InternalError."); - throw new Error("Unexpected error caught: ", e); - } - } - } - - // Transforms the class - private static native void doCommonClassRedefinition(Class<?> target, - byte[] classfile, - byte[] dexfile); - - // Gets the first obsolete method on the current threads stack (NB only looks through the first 30 - // stack frames). - private static native Method getFirstObsoleteMethod984(); } diff --git a/test/984-obsolete-invoke/src/Transform.java b/test/984-obsolete-invoke/src/Transform.java deleted file mode 100644 index 536de84c46..0000000000 --- a/test/984-obsolete-invoke/src/Transform.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * 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. - */ - -class Transform { - // This method must be 'static' so that when we try to invoke it through a j.l.r.Method we will - // simply use the jmethodID directly and not do any lookup in any receiver object. - public static void sayHi(Runnable r) { - System.out.println("hello"); - r.run(); - System.out.println("goodbye"); - } -} diff --git a/test/984-obsolete-invoke/src/art/Redefinition.java b/test/984-obsolete-invoke/src/art/Redefinition.java new file mode 100644 index 0000000000..0350ab42ad --- /dev/null +++ b/test/984-obsolete-invoke/src/art/Redefinition.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.util.ArrayList; +// Common Redefinition functions. Placed here for use by CTS +public class Redefinition { + // Bind native functions. + static { + Main.bindAgentJNIForClass(Redefinition.class); + } + + public static final class CommonClassDefinition { + public final Class<?> target; + public final byte[] class_file_bytes; + public final byte[] dex_file_bytes; + + public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { + this.target = target; + this.class_file_bytes = class_file_bytes; + this.dex_file_bytes = dex_file_bytes; + } + } + + // A set of possible test configurations. Test should set this if they need to. + // This must be kept in sync with the defines in ti-agent/common_helper.cc + public static enum Config { + COMMON_REDEFINE(0), + COMMON_RETRANSFORM(1), + COMMON_TRANSFORM(2); + + private final int val; + private Config(int val) { + this.val = val; + } + } + + public static void setTestConfiguration(Config type) { + nativeSetTestConfiguration(type.val); + } + + private static native void nativeSetTestConfiguration(int type); + + // Transforms the class + public static native void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile); + + public static void doMultiClassRedefinition(CommonClassDefinition... defs) { + ArrayList<Class<?>> classes = new ArrayList<>(); + ArrayList<byte[]> class_files = new ArrayList<>(); + ArrayList<byte[]> dex_files = new ArrayList<>(); + + for (CommonClassDefinition d : defs) { + classes.add(d.target); + class_files.add(d.class_file_bytes); + dex_files.add(d.dex_file_bytes); + } + doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), + class_files.toArray(new byte[0][]), + dex_files.toArray(new byte[0][])); + } + + public static void addMultiTransformationResults(CommonClassDefinition... defs) { + for (CommonClassDefinition d : defs) { + addCommonTransformationResult(d.target.getCanonicalName(), + d.class_file_bytes, + d.dex_file_bytes); + } + } + + public static native void doCommonMultiClassRedefinition(Class<?>[] targets, + byte[][] classfiles, + byte[][] dexfiles); + public static native void doCommonClassRetransformation(Class<?>... target); + public static native void setPopRetransformations(boolean pop); + public static native void popTransformationFor(String name); + public static native void enableCommonRetransformation(boolean enable); + public static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); +} diff --git a/test/984-obsolete-invoke/src/art/Test984.java b/test/984-obsolete-invoke/src/art/Test984.java new file mode 100644 index 0000000000..3fe66f68bf --- /dev/null +++ b/test/984-obsolete-invoke/src/art/Test984.java @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * 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 art; + +import java.lang.reflect.Method; +import java.util.Base64; + +public class Test984 { + + static class Transform { + // This method must be 'static' so that when we try to invoke it through a j.l.r.Method we will + // simply use the jmethodID directly and not do any lookup in any receiver object. + public static void sayHi(Runnable r) { + System.out.println("hello"); + r.run(); + System.out.println("goodbye"); + } + } + // static class Transform { + // public static void sayHi(Runnable r) { + // System.out.println("Hello - Transformed"); + // r.run(); + // System.out.println("Goodbye - Transformed"); + // } + // } + private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( + "yv66vgAAADQAKAoACAARCQASABMIABQKABUAFgsAFwAYCAAZBwAbBwAeAQAGPGluaXQ+AQADKClW" + + "AQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEABXNheUhpAQAXKExqYXZhL2xhbmcvUnVubmFibGU7" + + "KVYBAApTb3VyY2VGaWxlAQAMVGVzdDk4NC5qYXZhDAAJAAoHAB8MACAAIQEAE0hlbGxvIC0gVHJh" + + "bnNmb3JtZWQHACIMACMAJAcAJQwAJgAKAQAVR29vZGJ5ZSAtIFRyYW5zZm9ybWVkBwAnAQAVYXJ0" + + "L1Rlc3Q5ODQkVHJhbnNmb3JtAQAJVHJhbnNmb3JtAQAMSW5uZXJDbGFzc2VzAQAQamF2YS9sYW5n" + + "L09iamVjdAEAEGphdmEvbGFuZy9TeXN0ZW0BAANvdXQBABVMamF2YS9pby9QcmludFN0cmVhbTsB" + + "ABNqYXZhL2lvL1ByaW50U3RyZWFtAQAHcHJpbnRsbgEAFShMamF2YS9sYW5nL1N0cmluZzspVgEA" + + "EmphdmEvbGFuZy9SdW5uYWJsZQEAA3J1bgEAC2FydC9UZXN0OTg0ACAABwAIAAAAAAACAAAACQAK" + + "AAEACwAAAB0AAQABAAAABSq3AAGxAAAAAQAMAAAABgABAAAABQAJAA0ADgABAAsAAAA7AAIAAQAA" + + "ABeyAAISA7YABCq5AAUBALIAAhIGtgAEsQAAAAEADAAAABIABAAAAAcACAAIAA4ACQAWAAoAAgAP" + + "AAAAAgAQAB0AAAAKAAEABwAaABwACA=="); + private static final byte[] DEX_BYTES = Base64.getDecoder().decode( + "ZGV4CjAzNQB/mxSMAAAAAAAAAAAAAAAAAAAAAAAAAAA8BAAAcAAAAHhWNBIAAAAAAAAAAHgDAAAX" + + "AAAAcAAAAAoAAADMAAAAAwAAAPQAAAABAAAAGAEAAAUAAAAgAQAAAQAAAEgBAADUAgAAaAEAAGgB" + + "AABwAQAAhwEAAJwBAAC1AQAAxAEAAOgBAAAIAgAAHwIAADMCAABJAgAAXQIAAHECAAB/AgAAigIA" + + "AI0CAACRAgAAngIAAKQCAACpAgAAsgIAALcCAAC+AgAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAA" + + "CQAAAAoAAAALAAAADgAAAA4AAAAJAAAAAAAAAA8AAAAJAAAAyAIAAA8AAAAJAAAA0AIAAAgABAAS" + + "AAAAAAAAAAAAAAAAAAEAFQAAAAQAAgATAAAABQAAAAAAAAAGAAAAFAAAAAAAAAAAAAAABQAAAAAA" + + "AAAMAAAAaAMAADwDAAAAAAAABjxpbml0PgAVR29vZGJ5ZSAtIFRyYW5zZm9ybWVkABNIZWxsbyAt" + + "IFRyYW5zZm9ybWVkABdMYXJ0L1Rlc3Q5ODQkVHJhbnNmb3JtOwANTGFydC9UZXN0OTg0OwAiTGRh" + + "bHZpay9hbm5vdGF0aW9uL0VuY2xvc2luZ0NsYXNzOwAeTGRhbHZpay9hbm5vdGF0aW9uL0lubmVy" + + "Q2xhc3M7ABVMamF2YS9pby9QcmludFN0cmVhbTsAEkxqYXZhL2xhbmcvT2JqZWN0OwAUTGphdmEv" + + "bGFuZy9SdW5uYWJsZTsAEkxqYXZhL2xhbmcvU3RyaW5nOwASTGphdmEvbGFuZy9TeXN0ZW07AAxU" + + "ZXN0OTg0LmphdmEACVRyYW5zZm9ybQABVgACVkwAC2FjY2Vzc0ZsYWdzAARuYW1lAANvdXQAB3By" + + "aW50bG4AA3J1bgAFc2F5SGkABXZhbHVlAAAAAAEAAAAGAAAAAQAAAAcAAAAFAAcOAAcBAAcOAQgP" + + "AQMPAQgPAAEAAQABAAAA2AIAAAQAAABwEAMAAAAOAAMAAQACAAAA3QIAABQAAABiAAAAGwECAAAA" + + "biACABAAchAEAAIAYgAAABsBAQAAAG4gAgAQAA4AAAACAACAgATsBQEJhAYAAAICARYYAQIDAhAE" + + "CBEXDQACAAAATAMAAFIDAABcAwAAAAAAAAAAAAAAAAAAEAAAAAAAAAABAAAAAAAAAAEAAAAXAAAA" + + "cAAAAAIAAAAKAAAAzAAAAAMAAAADAAAA9AAAAAQAAAABAAAAGAEAAAUAAAAFAAAAIAEAAAYAAAAB" + + "AAAASAEAAAIgAAAXAAAAaAEAAAEQAAACAAAAyAIAAAMgAAACAAAA2AIAAAEgAAACAAAA7AIAAAAg" + + "AAABAAAAPAMAAAQgAAACAAAATAMAAAMQAAABAAAAXAMAAAYgAAABAAAAaAMAAAAQAAABAAAAeAMA" + + "AA=="); + + public static void run() { + art.Main.bindAgentJNIForClass(Test984.class); + doTest(); + } + + // The Method that holds an obsolete method pointer. We will fill it in by getting a jmethodID + // from a stack with an obsolete method in it. There should be no other ways to obtain an obsolete + // jmethodID in ART without unsafe casts. + public static Method obsolete_method = null; + + public static void doTest() { + // Capture the obsolete method. + // + // NB The obsolete method must be direct so that we will not look in the receiver type to get + // the actual method. + Transform.sayHi(() -> { + System.out.println("transforming calling function"); + Redefinition.doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES); + System.out.println("Retrieving obsolete method from current stack"); + // This should get the obsolete sayHi method (as the only obsolete method on the current + // threads stack). + Test984.obsolete_method = getFirstObsoleteMethod984(); + }); + + // Prove we did actually redefine something. + System.out.println("Invoking redefined version of method."); + Transform.sayHi(() -> { System.out.println("Not doing anything here"); }); + + System.out.println("invoking obsolete method"); + try { + obsolete_method.invoke(null, (Runnable)() -> { + throw new Error("Unexpected code running from invoke of obsolete method!"); + }); + throw new Error("Running obsolete method did not throw exception"); + } catch (Throwable e) { + if (e instanceof InternalError || e.getCause() instanceof InternalError) { + System.out.println("Caught expected error from attempting to invoke an obsolete method."); + } else { + System.out.println("Unexpected error type for calling obsolete method! Expected either " + + "an InternalError or something that is caused by an InternalError."); + throw new Error("Unexpected error caught: ", e); + } + } + } + + // Gets the first obsolete method on the current threads stack (NB only looks through the first 30 + // stack frames). + private static native Method getFirstObsoleteMethod984(); +} diff --git a/test/Android.bp b/test/Android.bp index 8059a2f204..c5d96da20c 100644 --- a/test/Android.bp +++ b/test/Android.bp @@ -250,6 +250,7 @@ art_cc_defaults { "ti-agent/jni_binder.cc", "ti-agent/jvmti_helper.cc", "ti-agent/test_env.cc", + "ti-agent/common_helper.cc", // This is the list of non-special OnLoad things and excludes BCI and anything that depends // on ART internals. "903-hello-tagging/tagging.cc", @@ -260,6 +261,7 @@ art_cc_defaults { "908-gc-start-finish/gc_callbacks.cc", "910-methods/methods.cc", "911-get-stack-trace/stack_trace.cc", + "913-heaps/heaps.cc", "918-fields/fields.cc", "920-objects/objects.cc", "922-properties/properties.cc", @@ -271,6 +273,8 @@ art_cc_defaults { "929-search/search.cc", "931-agent-thread/agent_thread.cc", "933-misc-events/misc_events.cc", + "945-obsolete-native/obsolete_native.cc", + "984-obsolete-invoke/obsolete_invoke.cc", ], shared_libs: [ "libbase", @@ -286,20 +290,14 @@ art_cc_defaults { // This is to get the IsInterpreted native method. "common/stack_inspect.cc", "common/runtime_state.cc", + "ti-agent/common_load.cc", // This includes the remaining test functions. We should try to refactor things to // make this list smaller. - "ti-agent/common_helper.cc", - "ti-agent/common_load.cc", "901-hello-ti-agent/basics.cc", "909-attach-agent/attach.cc", "912-classes/classes.cc", - "913-heaps/heaps.cc", "936-search-onload/search_onload.cc", - "944-transform-classloaders/classloader.cc", - "945-obsolete-native/obsolete_native.cc", - "980-redefine-object/redefine_object.cc", "983-source-transform-verify/source_transform.cc", - "984-obsolete-invoke/obsolete_invoke.cc", ], } diff --git a/test/Android.run-test-jvmti-java-library.mk b/test/Android.run-test-jvmti-java-library.mk index b6da92b942..dcb238cd9f 100644 --- a/test/Android.run-test-jvmti-java-library.mk +++ b/test/Android.run-test-jvmti-java-library.mk @@ -18,13 +18,17 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) -# Main shim classes. We use one that exposes the tagging common functionality. -LOCAL_MAIN_SHIM := 903-hello-tagging/src/art/Main.java -LOCAL_SRC_FILES := $(LOCAL_MAIN_SHIM) +# shim classes. We use one that exposes the common functionality. +LOCAL_SHIM_CLASSES := \ + 902-hello-transformation/src/art/Redefinition.java \ + 903-hello-tagging/src/art/Main.java \ + +LOCAL_SRC_FILES := $(LOCAL_SHIM_CLASSES) # Actual test classes. LOCAL_SRC_FILES += \ 901-hello-ti-agent/src/art/Test901.java \ + 902-hello-transformation/src/art/Test902.java \ 903-hello-tagging/src/art/Test903.java \ 904-object-allocation/src/art/Test904.java \ 905-object-free/src/art/Test905.java \ @@ -42,19 +46,36 @@ LOCAL_SRC_FILES += \ 911-get-stack-trace/src/art/SameThread.java \ 911-get-stack-trace/src/art/ThreadListTraces.java \ 913-heaps/src/art/Test913.java \ + 914-hello-obsolescence/src/art/Test914.java \ + 915-obsolete-2/src/art/Test915.java \ + 917-fields-transformation/src/art/Test917.java \ 918-fields/src/art/Test918.java \ + 919-obsolete-fields/src/art/Test919.java \ 920-objects/src/art/Test920.java \ 922-properties/src/art/Test922.java \ 923-monitors/src/art/Test923.java \ 924-threads/src/art/Test924.java \ 925-threadgroups/src/art/Test925.java \ + 926-multi-obsolescence/src/art/Test926.java \ 927-timers/src/art/Test927.java \ 928-jni-table/src/art/Test928.java \ + 930-hello-retransform/src/art/Test930.java \ 931-agent-thread/src/art/Test931.java \ + 932-transform-saves/src/art/Test932.java \ 933-misc-events/src/art/Test933.java \ + 940-recursive-obsolete/src/art/Test940.java \ + 942-private-recursive/src/art/Test942.java \ + 944-transform-classloaders/src/art/Test944.java \ + 945-obsolete-native/src/art/Test945.java \ + 947-reflect-method/src/art/Test947.java \ + 951-threaded-obsolete/src/art/Test951.java \ + 981-dedup-original-dex/src/art/Test981.java \ + 982-ok-no-retransform/src/art/Test982.java \ + 984-obsolete-invoke/src/art/Test984.java \ JVMTI_RUN_TEST_GENERATED_NUMBERS := \ 901 \ + 902 \ 903 \ 904 \ 905 \ @@ -64,16 +85,32 @@ JVMTI_RUN_TEST_GENERATED_NUMBERS := \ 910 \ 911 \ 913 \ + 914 \ + 915 \ + 917 \ 918 \ + 919 \ 920 \ 922 \ 923 \ 924 \ 925 \ + 926 \ 927 \ 928 \ + 930 \ 931 \ + 932 \ 933 \ + 940 \ + 942 \ + 944 \ + 945 \ + 947 \ + 951 \ + 981 \ + 982 \ + 984 \ # Try to enforce that the directories correspond to the Java files we pull in. JVMTI_RUN_TEST_DIR_CHECK := $(sort $(foreach DIR,$(JVMTI_RUN_TEST_GENERATED_NUMBERS), \ diff --git a/test/etc/default-build b/test/etc/default-build index d74b24d985..744c38bb6d 100755 --- a/test/etc/default-build +++ b/test/etc/default-build @@ -91,7 +91,7 @@ JAVAC_EXPERIMENTAL_ARGS["default-methods"]="-source 1.8 -target 1.8" JAVAC_EXPERIMENTAL_ARGS["lambdas"]="-source 1.8 -target 1.8" JAVAC_EXPERIMENTAL_ARGS["method-handles"]="-source 1.8 -target 1.8" # We need to leave javac at default 1.7 so that dx will continue to work -JAVAC_EXPERIMENTAL_ARGS[${DEFAULT_EXPERIMENT}]="-source 1.7 -target 1.7" +JAVAC_EXPERIMENTAL_ARGS[${DEFAULT_EXPERIMENT}]="-source 1.8 -target 1.8" JAVAC_EXPERIMENTAL_ARGS["agents"]="-source 1.8 -target 1.8" while true; do diff --git a/test/knownfailures.json b/test/knownfailures.json index 54786bb772..29c1e8bfd0 100644 --- a/test/knownfailures.json +++ b/test/knownfailures.json @@ -601,20 +601,20 @@ }, { "tests": [ - "008-exceptions", "031-class-attributes", - "034-call-null", - "038-inner-null", - "054-uncaught", - "122-npe", - "439-npe", - "911-get-stack-trace", - "946-obsolete-throw" + "911-get-stack-trace" ], "description": [ "Tests that use annotations and debug data that is not kept around by dexter." ], - "bug": "b/37240685 & b/37239009", + "bug": "b/37239009", "variant": "jvmti-stress" + }, + { + "tests": "160-read-barrier-stress", + "description": ["Disable 160-read-barrier-stress temporarily until we find ", + "a fix to avoid the OOME with Jack. Note that it cannot be compiled ", + "by javac either ('error: code too large')"], + "bug": "http://b/37335480" } ] diff --git a/test/ti-agent/common_helper.cc b/test/ti-agent/common_helper.cc index ab5dbcc0db..bfd4d254f4 100644 --- a/test/ti-agent/common_helper.cc +++ b/test/ti-agent/common_helper.cc @@ -17,18 +17,15 @@ #include "common_helper.h" #include <dlfcn.h> +#include <map> #include <stdio.h> #include <sstream> #include <deque> +#include <vector> #include "android-base/stringprintf.h" -#include "art_method.h" #include "jni.h" -#include "jni_internal.h" #include "jvmti.h" -#include "scoped_thread_state_change-inl.h" -#include "stack.h" -#include "utils.h" #include "jni_binder.h" #include "jvmti_helper.h" @@ -37,6 +34,10 @@ namespace art { +static void SetupCommonRetransform(); +static void SetupCommonRedefine(); +static void SetupCommonTransform(); + template <bool is_redefine> static void throwCommonRedefinitionError(jvmtiEnv* jvmti, JNIEnv* env, @@ -108,18 +109,15 @@ static void DoClassRedefine(jvmtiEnv* jvmti_env, // Magic JNI export that classes can use for redefining classes. // To use classes should declare this as a native function with signature (Ljava/lang/Class;[B[B)V -extern "C" JNIEXPORT void JNICALL Java_Main_doCommonClassRedefinition(JNIEnv* env, - jclass, - jclass target, - jbyteArray class_file_bytes, - jbyteArray dex_file_bytes) { +extern "C" JNIEXPORT void JNICALL Java_art_Redefinition_doCommonClassRedefinition( + JNIEnv* env, jclass, jclass target, jbyteArray class_file_bytes, jbyteArray dex_file_bytes) { DoClassRedefine(jvmti_env, env, target, class_file_bytes, dex_file_bytes); } // Magic JNI export that classes can use for redefining classes. // To use classes should declare this as a native function with signature // ([Ljava/lang/Class;[[B[[B)V -extern "C" JNIEXPORT void JNICALL Java_Main_doCommonMultiClassRedefinition( +extern "C" JNIEXPORT void JNICALL Java_art_Redefinition_doCommonMultiClassRedefinition( JNIEnv* env, jclass, jobjectArray targets, @@ -155,11 +153,7 @@ jint OnLoad(JavaVM* vm, printf("Unable to get jvmti env!\n"); return 1; } - jvmtiCapabilities caps; - jvmti_env->GetPotentialCapabilities(&caps); - caps.can_retransform_classes = 0; - caps.can_retransform_any_class = 0; - jvmti_env->AddCapabilities(&caps); + SetupCommonRedefine(); return 0; } @@ -183,11 +177,8 @@ struct CommonTransformationResult { std::map<std::string, std::deque<CommonTransformationResult>> gTransformations; bool gPopTransformations = true; -extern "C" JNIEXPORT void JNICALL Java_Main_addCommonTransformationResult(JNIEnv* env, - jclass, - jstring class_name, - jbyteArray class_array, - jbyteArray dex_array) { +extern "C" JNIEXPORT void JNICALL Java_art_Redefinition_addCommonTransformationResult( + JNIEnv* env, jclass, jstring class_name, jbyteArray class_array, jbyteArray dex_array) { const char* name_chrs = env->GetStringUTFChars(class_name, nullptr); std::string name_str(name_chrs); env->ReleaseStringUTFChars(class_name, name_chrs); @@ -244,15 +235,15 @@ void JNICALL CommonClassFileLoadHookRetransformable(jvmtiEnv* jvmti_env, } } -extern "C" JNIEXPORT void Java_Main_setPopRetransformations(JNIEnv*, - jclass, - jboolean enable) { +extern "C" JNIEXPORT void Java_art_Redefinition_setPopRetransformations(JNIEnv*, + jclass, + jboolean enable) { gPopTransformations = enable; } -extern "C" JNIEXPORT void Java_Main_popTransformationFor(JNIEnv* env, - jclass, - jstring class_name) { +extern "C" JNIEXPORT void Java_art_Redefinition_popTransformationFor(JNIEnv* env, + jclass, + jstring class_name) { const char* name_chrs = env->GetStringUTFChars(class_name, nullptr); std::string name_str(name_chrs); env->ReleaseStringUTFChars(class_name, name_chrs); @@ -267,9 +258,9 @@ extern "C" JNIEXPORT void Java_Main_popTransformationFor(JNIEnv* env, } } -extern "C" JNIEXPORT void Java_Main_enableCommonRetransformation(JNIEnv* env, - jclass, - jboolean enable) { +extern "C" JNIEXPORT void Java_art_Redefinition_enableCommonRetransformation(JNIEnv* env, + jclass, + jboolean enable) { jvmtiError res = jvmti_env->SetEventNotificationMode(enable ? JVMTI_ENABLE : JVMTI_DISABLE, JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, nullptr); @@ -298,9 +289,8 @@ static void DoClassRetransformation(jvmtiEnv* jvmti_env, JNIEnv* env, jobjectArr } } -extern "C" JNIEXPORT void JNICALL Java_Main_doCommonClassRetransformation(JNIEnv* env, - jclass, - jobjectArray targets) { +extern "C" JNIEXPORT void JNICALL Java_art_Redefinition_doCommonClassRetransformation( + JNIEnv* env, jclass, jobjectArray targets) { jvmtiCapabilities caps; jvmtiError caps_err = jvmti_env->GetCapabilities(&caps); if (caps_err != JVMTI_ERROR_NONE) { @@ -338,14 +328,7 @@ jint OnLoad(JavaVM* vm, printf("Unable to get jvmti env!\n"); return 1; } - SetAllCapabilities(jvmti_env); - jvmtiEventCallbacks cb; - memset(&cb, 0, sizeof(cb)); - cb.ClassFileLoadHook = CommonClassFileLoadHookRetransformable; - if (jvmti_env->SetEventCallbacks(&cb, sizeof(cb)) != JVMTI_ERROR_NONE) { - printf("Unable to set class file load hook cb!\n"); - return 1; - } + SetupCommonRetransform(); return 0; } @@ -353,8 +336,6 @@ jint OnLoad(JavaVM* vm, namespace common_transform { -using art::common_retransform::CommonClassFileLoadHookRetransformable; - // Get all capabilities except those related to retransformation. jint OnLoad(JavaVM* vm, char* options ATTRIBUTE_UNUSED, @@ -363,6 +344,35 @@ jint OnLoad(JavaVM* vm, printf("Unable to get jvmti env!\n"); return 1; } + SetupCommonTransform(); + return 0; +} + +} // namespace common_transform + +#define CONFIGURATION_COMMON_REDEFINE 0 +#define CONFIGURATION_COMMON_RETRANSFORM 1 +#define CONFIGURATION_COMMON_TRANSFORM 2 + +static void SetupCommonRedefine() { + jvmtiCapabilities caps; + jvmti_env->GetPotentialCapabilities(&caps); + caps.can_retransform_classes = 0; + caps.can_retransform_any_class = 0; + jvmti_env->AddCapabilities(&caps); +} + +static void SetupCommonRetransform() { + SetAllCapabilities(jvmti_env); + jvmtiEventCallbacks cb; + memset(&cb, 0, sizeof(cb)); + cb.ClassFileLoadHook = common_retransform::CommonClassFileLoadHookRetransformable; + jvmtiError res = jvmti_env->SetEventCallbacks(&cb, sizeof(cb)); + CHECK_EQ(res, JVMTI_ERROR_NONE); + common_retransform::gTransformations.clear(); +} + +static void SetupCommonTransform() { // Don't set the retransform caps jvmtiCapabilities caps; jvmti_env->GetPotentialCapabilities(&caps); @@ -373,14 +383,31 @@ jint OnLoad(JavaVM* vm, // Use the same callback as the retransform test. jvmtiEventCallbacks cb; memset(&cb, 0, sizeof(cb)); - cb.ClassFileLoadHook = CommonClassFileLoadHookRetransformable; - if (jvmti_env->SetEventCallbacks(&cb, sizeof(cb)) != JVMTI_ERROR_NONE) { - printf("Unable to set class file load hook cb!\n"); - return 1; - } - return 0; + cb.ClassFileLoadHook = common_retransform::CommonClassFileLoadHookRetransformable; + jvmtiError res = jvmti_env->SetEventCallbacks(&cb, sizeof(cb)); + CHECK_EQ(res, JVMTI_ERROR_NONE); + common_retransform::gTransformations.clear(); } -} // namespace common_transform - +extern "C" JNIEXPORT void JNICALL Java_art_Redefinition_nativeSetTestConfiguration(JNIEnv*, + jclass, + jint type) { + switch (type) { + case CONFIGURATION_COMMON_REDEFINE: { + SetupCommonRedefine(); + return; + } + case CONFIGURATION_COMMON_RETRANSFORM: { + SetupCommonRetransform(); + return; + } + case CONFIGURATION_COMMON_TRANSFORM: { + SetupCommonTransform(); + return; + } + default: { + LOG(FATAL) << "Unknown test configuration: " << type; + } + } +} } // namespace art diff --git a/test/ti-agent/common_load.cc b/test/ti-agent/common_load.cc index 9e7b75daf2..3455409b2d 100644 --- a/test/ti-agent/common_load.cc +++ b/test/ti-agent/common_load.cc @@ -60,31 +60,17 @@ static jint MinimalOnLoad(JavaVM* vm, // MinimalOnLoad. static AgentLib agents[] = { { "901-hello-ti-agent", Test901HelloTi::OnLoad, nullptr }, - { "902-hello-transformation", common_redefine::OnLoad, nullptr }, { "909-attach-agent", nullptr, Test909AttachAgent::OnAttach }, - { "914-hello-obsolescence", common_redefine::OnLoad, nullptr }, - { "915-obsolete-2", common_redefine::OnLoad, nullptr }, { "916-obsolete-jit", common_redefine::OnLoad, nullptr }, - { "917-fields-transformation", common_redefine::OnLoad, nullptr }, - { "919-obsolete-fields", common_redefine::OnLoad, nullptr }, { "921-hello-failure", common_retransform::OnLoad, nullptr }, - { "926-multi-obsolescence", common_redefine::OnLoad, nullptr }, - { "930-hello-retransform", common_retransform::OnLoad, nullptr }, - { "932-transform-saves", common_retransform::OnLoad, nullptr }, { "934-load-transform", common_retransform::OnLoad, nullptr }, { "935-non-retransformable", common_transform::OnLoad, nullptr }, { "936-search-onload", Test936SearchOnload::OnLoad, nullptr }, { "937-hello-retransform-package", common_retransform::OnLoad, nullptr }, { "938-load-transform-bcp", common_retransform::OnLoad, nullptr }, { "939-hello-transformation-bcp", common_redefine::OnLoad, nullptr }, - { "940-recursive-obsolete", common_redefine::OnLoad, nullptr }, { "941-recursive-obsolete-jit", common_redefine::OnLoad, nullptr }, - { "942-private-recursive", common_redefine::OnLoad, nullptr }, { "943-private-recursive-jit", common_redefine::OnLoad, nullptr }, - { "944-transform-classloaders", common_redefine::OnLoad, nullptr }, - { "945-obsolete-native", common_redefine::OnLoad, nullptr }, - { "981-dedup-original-dex", common_retransform::OnLoad, nullptr }, - { "982-ok-no-retransform", common_retransform::OnLoad, nullptr }, { "983-source-transform-verify", Test983SourceTransformVerify::OnLoad, nullptr }, }; |