blob: 23b1656b6594e127a86b738c6be1b40afc8d7ee9 [file] [log] [blame]
Alex Light55eccdf2019-10-07 13:51:13 +00001/*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17import art.Redefinition;
18import java.lang.invoke.*;
19import java.lang.reflect.Field;
20import java.util.Base64;
21import java.util.concurrent.CountDownLatch;
22
23public class Main {
24 public static final class Transform {
25 static {
26 }
27
28 public static Object foo = null;
29 }
30
31 /**
32 * Base64 encoded dex bytes for:
33 *
34 * public static final class Transform {
35 * static {}
36 * public static Object bar = null;
37 * public static Object foo = null;
38 * }
39 */
40 public static final byte[] DEX_BYTES =
41 Base64.getDecoder()
42 .decode(
43 "ZGV4CjAzNQCjkRjcSr1RJO8FnnCjHV/8h6keJP/+P3WQAwAAcAAAAHhWNBIAAAAAAAAAANgCAAAQ"
44 + "AAAAcAAAAAYAAACwAAAAAQAAAMgAAAACAAAA1AAAAAMAAADkAAAAAQAAAPwAAAB0AgAAHAEAAFwB"
45 + "AABmAQAAbgEAAIABAACIAQAArAEAAMwBAADgAQAA6wEAAPYBAAD5AQAABgIAAAsCAAAQAgAAFgIA"
46 + "AB0CAAACAAAAAwAAAAQAAAAFAAAABgAAAAkAAAAJAAAABQAAAAAAAAAAAAQACwAAAAAABAAMAAAA"
47 + "AAAAAAAAAAAAAAAAAQAAAAQAAAABAAAAAAAAABEAAAAEAAAAAAAAAAcAAADIAgAApAIAAAAAAAAB"
48 + "AAAAAAAAAFABAAAGAAAAEgBpAAAAaQABAA4AAQABAAEAAABVAQAABAAAAHAQAgAAAA4ABwAOPAAF"
49 + "AA4AAAAACDxjbGluaXQ+AAY8aW5pdD4AEExNYWluJFRyYW5zZm9ybTsABkxNYWluOwAiTGRhbHZp"
50 + "ay9hbm5vdGF0aW9uL0VuY2xvc2luZ0NsYXNzOwAeTGRhbHZpay9hbm5vdGF0aW9uL0lubmVyQ2xh"
51 + "c3M7ABJMamF2YS9sYW5nL09iamVjdDsACU1haW4uamF2YQAJVHJhbnNmb3JtAAFWAAthY2Nlc3NG"
52 + "bGFncwADYmFyAANmb28ABG5hbWUABXZhbHVlAHZ+fkQ4eyJjb21waWxhdGlvbi1tb2RlIjoiZGVi"
53 + "dWciLCJtaW4tYXBpIjoxLCJzaGEtMSI6IjI4YmNlZjUwYWM4NTk3Y2YyMmU4OTJiMWJjM2EzYjky"
54 + "Yjc0ZTcwZTkiLCJ2ZXJzaW9uIjoiMS42LjMyLWRldiJ9AAICAQ4YAQIDAgoEGQ0XCAIAAgAACQEJ"
55 + "AIiABJwCAYGABLgCAAAAAAIAAACVAgAAmwIAALwCAAAAAAAAAAAAAAAAAAAPAAAAAAAAAAEAAAAA"
56 + "AAAAAQAAABAAAABwAAAAAgAAAAYAAACwAAAAAwAAAAEAAADIAAAABAAAAAIAAADUAAAABQAAAAMA"
57 + "AADkAAAABgAAAAEAAAD8AAAAASAAAAIAAAAcAQAAAyAAAAIAAABQAQAAAiAAABAAAABcAQAABCAA"
58 + "AAIAAACVAgAAACAAAAEAAACkAgAAAxAAAAIAAAC4AgAABiAAAAEAAADIAgAAABAAAAEAAADYAgAA");
59
60 public static void assertEquals(Object a, Object b) {
61 if (a != b) {
62 throw new Error("Expected " + b + ", got " + a);
63 }
64 }
65
66 public static void assertAllEquals(Object[] a, Object b) {
67 boolean failed = false;
68 String msg = "";
69 for (int i = 0; i < a.length; i++) {
70 if (a[i] != b) {
71 failed = true;
72 msg += "Expected " + b + ", got a[" + i + "] (" + a[i] + "), ";
73 }
74 }
75 if (failed) {
76 throw new Error(msg);
77 }
78 }
79
80 public static void main(String[] args) throws Exception, Throwable {
81 System.loadLibrary(args[0]);
82 Field f = Transform.class.getDeclaredField("foo");
83 Transform.foo = "THIS IS A FOO VALUE";
84 assertEquals(f.get(null), Transform.foo);
85 final int num_threads = 10;
86 Object[] results = new Object[num_threads];
87 Thread[] threads = new Thread[num_threads];
88 CountDownLatch start_latch = new CountDownLatch(num_threads);
89 CountDownLatch continue_latch = new CountDownLatch(1);
90 for (int i = 0; i < num_threads; i++) {
91 final int id = i;
92 threads[id] =
93 new Thread(
94 () -> {
95 try {
96 MethodHandle mh =
97 NativeFieldScopeCheck(
98 f,
99 () -> {
100 try {
101 start_latch.countDown();
102 continue_latch.await();
103 } catch (Exception e) {
104 throw new Error("failed!", e);
105 }
106 });
107 results[id] = mh.invokeExact();
108 } catch (Throwable t) {
109 throw new Error("Failed", t);
110 }
111 },
112 "Target thread " + id);
113 threads[id].start();
114 }
115 start_latch.await();
116 Redefinition.doCommonStructuralClassRedefinition(Transform.class, DEX_BYTES);
117 continue_latch.countDown();
118 for (Thread t : threads) {
119 t.join();
120 }
121 assertAllEquals(results, Transform.foo);
122 }
123
124 // Hold the field as a ArtField, run the 'test' function, turn the ArtField into a MethodHandle
125 // directly and return that.
126 public static native MethodHandle NativeFieldScopeCheck(Field in, Runnable test);
127}