1 /*
2  * Copyright (C) 2016 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 
17 package art;
18 
19 import java.lang.reflect.Field;
20 import java.util.ArrayList;
21 import java.util.Base64;
22 import java.util.concurrent.CountDownLatch;
23 public class Test1995 {
24     private static final int NUM_THREADS = 20;
25     // Don't perform more than this many repeats per thread to prevent OOMEs
26     private static final int TASK_COUNT_LIMIT = 1000;
27 
28     public static final class Transform {
29         public String greetingEnglish;
Transform()30         public Transform() {
31             this.greetingEnglish = "Hello";
32         }
sayHi()33         public String sayHi() {
34             return greetingEnglish + " from " + Thread.currentThread().getName();
35         }
36     }
37 
38     /**
39      * base64 encoded class/dex file for
40      * public static final class Transform {
41      *     public String greetingEnglish;
42      *     public String greetingFrench;
43      *     public String greetingDanish;
44      *     public String greetingJapanese;
45      *
46      *     public Transform() {
47      *         this.greetingEnglish = "Hello World";
48      *         this.greetingFrench = "Bonjour le Monde";
49      *         this.greetingDanish = "Hej Verden";
50      *         this.greetingJapanese = "こんにちは世界";
51      *     }
52      *     public String sayHi() {
53      *         return sayHiEnglish() + ", " + sayHiFrench() + ", " + sayHiDanish() + ", " +
54      *                 sayHiJapanese() + " from " + Thread.currentThread().getName();
55      *     }
56      *     public String sayHiEnglish() {
57      *         return greetingEnglish;
58      *     }
59      *     public String sayHiDanish() {
60      *         return greetingDanish;
61      *     }
62      *     public String sayHiJapanese() {
63      *         return greetingJapanese;
64      *     }
65      *     public String sayHiFrench() {
66      *         return greetingFrench;
67      *     }
68      * }
69      */
70     private static final byte[] DEX_BYTES = Base64.getDecoder().decode(
71             "ZGV4CjAzNQCsHrUqkb8cYgT2oYN7HlVbeOxJT/kONRvgBgAAcAAAAHhWNBIAAAAAAAAAABwGAAAl" +
72             "AAAAcAAAAAkAAAAEAQAABAAAACgBAAAEAAAAWAEAAAwAAAB4AQAAAQAAANgBAADoBAAA+AEAAEoD" +
73             "AABSAwAAVgMAAF4DAABwAwAAfAMAAIkDAACMAwAAkAMAAKoDAAC6AwAA3gMAAP4DAAASBAAAJgQA" +
74             "AEEEAABVBAAAZAQAAG8EAAByBAAAfwQAAIcEAACWBAAAnwQAAK8EAADABAAA0AQAAOIEAADoBAAA" +
75             "7wQAAPwEAAAKBQAAFwUAACYFAAAwBQAANwUAAK8FAAAIAAAACQAAAAoAAAALAAAADAAAAA0AAAAO" +
76             "AAAADwAAABIAAAAGAAAABQAAAAAAAAAHAAAABgAAAEQDAAAGAAAABwAAAAAAAAASAAAACAAAAAAA" +
77             "AAAAAAUAFwAAAAAABQAYAAAAAAAFABkAAAAAAAUAGgAAAAAAAwACAAAAAAAAABwAAAAAAAAAHQAA" +
78             "AAAAAAAeAAAAAAAAAB8AAAAAAAAAIAAAAAQAAwACAAAABgADAAIAAAAGAAEAFAAAAAYAAAAhAAAA" +
79             "BwACABUAAAAHAAAAFgAAAAAAAAARAAAABAAAAAAAAAAQAAAADAYAANUFAAAAAAAABwABAAIAAAAt" +
80             "AwAAQQAAAG4QAwAGAAwAbhAEAAYADAFuEAIABgAMAm4QBQAGAAwDcQAKAAAADARuEAsABAAMBCIF" +
81             "BgBwEAcABQBuIAgABQAaAAEAbiAIAAUAbiAIABUAbiAIAAUAbiAIACUAbiAIAAUAbiAIADUAGgAA" +
82             "AG4gCAAFAG4gCABFAG4QCQAFAAwAEQAAAAIAAQAAAAAAMQMAAAMAAABUEAAAEQAAAAIAAQAAAAAA" +
83             "NQMAAAMAAABUEAEAEQAAAAIAAQAAAAAAOQMAAAMAAABUEAIAEQAAAAIAAQAAAAAAPQMAAAMAAABU" +
84             "EAMAEQAAAAIAAQABAAAAJAMAABQAAABwEAYAAQAaAAUAWxABABoAAwBbEAIAGgAEAFsQAAAaACQA" +
85             "WxADAA4ACQAOPEtLS0sAEAAOABYADgATAA4AHAAOABkADgAAAAABAAAABQAGIGZyb20gAAIsIAAG" +
86             "PGluaXQ+ABBCb25qb3VyIGxlIE1vbmRlAApIZWogVmVyZGVuAAtIZWxsbyBXb3JsZAABTAACTEwA" +
87             "GExhcnQvVGVzdDE5OTUkVHJhbnNmb3JtOwAOTGFydC9UZXN0MTk5NTsAIkxkYWx2aWsvYW5ub3Rh" +
88             "dGlvbi9FbmNsb3NpbmdDbGFzczsAHkxkYWx2aWsvYW5ub3RhdGlvbi9Jbm5lckNsYXNzOwASTGph" +
89             "dmEvbGFuZy9PYmplY3Q7ABJMamF2YS9sYW5nL1N0cmluZzsAGUxqYXZhL2xhbmcvU3RyaW5nQnVp" +
90             "bGRlcjsAEkxqYXZhL2xhbmcvVGhyZWFkOwANVGVzdDE5OTUuamF2YQAJVHJhbnNmb3JtAAFWAAth" +
91             "Y2Nlc3NGbGFncwAGYXBwZW5kAA1jdXJyZW50VGhyZWFkAAdnZXROYW1lAA5ncmVldGluZ0Rhbmlz" +
92             "aAAPZ3JlZXRpbmdFbmdsaXNoAA5ncmVldGluZ0ZyZW5jaAAQZ3JlZXRpbmdKYXBhbmVzZQAEbmFt" +
93             "ZQAFc2F5SGkAC3NheUhpRGFuaXNoAAxzYXlIaUVuZ2xpc2gAC3NheUhpRnJlbmNoAA1zYXlIaUph" +
94             "cGFuZXNlAAh0b1N0cmluZwAFdmFsdWUAdn5+RDh7ImNvbXBpbGF0aW9uLW1vZGUiOiJkZWJ1ZyIs" +
95             "Im1pbi1hcGkiOjEsInNoYS0xIjoiNjBkYTRkNjdiMzgxYzQyNDY3NzU3YzQ5ZmI2ZTU1NzU2ZDg4" +
96             "YTJmMyIsInZlcnNpb24iOiIxLjcuMTItZGV2In0AB+OBk+OCk+OBq+OBoeOBr+S4lueVjAACAgEi" +
97             "GAECAwITBBkbFxEABAEFAAEBAQEBAQEAgYAE7AUBAfgDAQGMBQEBpAUBAbwFAQHUBQAAAAAAAgAA" +
98             "AMYFAADMBQAAAAYAAAAAAAAAAAAAAAAAABAAAAAAAAAAAQAAAAAAAAABAAAAJQAAAHAAAAACAAAA" +
99             "CQAAAAQBAAADAAAABAAAACgBAAAEAAAABAAAAFgBAAAFAAAADAAAAHgBAAAGAAAAAQAAANgBAAAB" +
100             "IAAABgAAAPgBAAADIAAABgAAACQDAAABEAAAAQAAAEQDAAACIAAAJQAAAEoDAAAEIAAAAgAAAMYF" +
101             "AAAAIAAAAQAAANUFAAADEAAAAgAAAPwFAAAGIAAAAQAAAAwGAAAAEAAAAQAAABwGAAA=");
102 
103 
run()104     public static void run() throws Exception {
105         Redefinition.setTestConfiguration(Redefinition.Config.COMMON_REDEFINE);
106         doTest();
107     }
108 
109     public static final class MyThread extends Thread {
MyThread(CountDownLatch delay, int id)110         public MyThread(CountDownLatch delay, int id) {
111             super("Thread: " + id);
112             this.thr_id = id;
113             this.results = new ArrayList<>(TASK_COUNT_LIMIT);
114             this.finish = false;
115             this.delay = delay;
116         }
117 
run()118         public void run() {
119             delay.countDown();
120             while (!finish && results.size() < TASK_COUNT_LIMIT) {
121                 Transform t = new Transform();
122                 results.add(t.sayHi());
123             }
124         }
125 
finish()126         public void finish() throws Exception {
127             finish = true;
128             this.join();
129         }
130 
Check()131         public void Check() throws Exception {
132             for (String s : results) {
133                 if (!s.equals("Hello from " + getName()) &&
134                         !s.equals("Hello, null, null, null from " + getName()) &&
135                         !s.equals(
136                                 "Hello World, Bonjour le Monde, Hej Verden, こんにちは世界 from " +
137                                 getName())) {
138                     System.out.println("FAIL " + thr_id + ": Unexpected result: " + s);
139                 }
140             }
141         }
142 
143         public ArrayList<String> results;
144         public volatile boolean finish;
145         public int thr_id;
146         public CountDownLatch delay;
147     }
148 
startThreads(int num_threads)149     public static MyThread[] startThreads(int num_threads) throws Exception {
150         CountDownLatch cdl = new CountDownLatch(num_threads);
151         MyThread[] res = new MyThread[num_threads];
152         for (int i = 0; i < num_threads; i++) {
153             res[i] = new MyThread(cdl, i);
154             res[i].start();
155         }
156         cdl.await();
157         return res;
158     }
finishThreads(MyThread[] thrs)159     public static void finishThreads(MyThread[] thrs) throws Exception {
160         for (MyThread t : thrs) {
161             t.finish();
162         }
163         for (MyThread t : thrs) {
164             t.Check();
165         }
166     }
167 
doTest()168     public static void doTest() throws Exception {
169         MyThread[] threads = startThreads(NUM_THREADS);
170         Redefinition.doCommonStructuralClassRedefinition(Transform.class, DEX_BYTES);
171         finishThreads(threads);
172     }
173 }
174