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() + ", " + sayHiJapanese() + " from " + Thread.currentThread().getName(); 54 * } 55 * public String sayHiEnglish() { 56 * return greetingEnglish; 57 * } 58 * public String sayHiDanish() { 59 * return greetingDanish; 60 * } 61 * public String sayHiJapanese() { 62 * return greetingJapanese; 63 * } 64 * public String sayHiFrench() { 65 * return greetingFrench; 66 * } 67 * } 68 */ 69 private static final byte[] DEX_BYTES = Base64.getDecoder().decode( 70 "ZGV4CjAzNQCsHrUqkb8cYgT2oYN7HlVbeOxJT/kONRvgBgAAcAAAAHhWNBIAAAAAAAAAABwGAAAl" + 71 "AAAAcAAAAAkAAAAEAQAABAAAACgBAAAEAAAAWAEAAAwAAAB4AQAAAQAAANgBAADoBAAA+AEAAEoD" + 72 "AABSAwAAVgMAAF4DAABwAwAAfAMAAIkDAACMAwAAkAMAAKoDAAC6AwAA3gMAAP4DAAASBAAAJgQA" + 73 "AEEEAABVBAAAZAQAAG8EAAByBAAAfwQAAIcEAACWBAAAnwQAAK8EAADABAAA0AQAAOIEAADoBAAA" + 74 "7wQAAPwEAAAKBQAAFwUAACYFAAAwBQAANwUAAK8FAAAIAAAACQAAAAoAAAALAAAADAAAAA0AAAAO" + 75 "AAAADwAAABIAAAAGAAAABQAAAAAAAAAHAAAABgAAAEQDAAAGAAAABwAAAAAAAAASAAAACAAAAAAA" + 76 "AAAAAAUAFwAAAAAABQAYAAAAAAAFABkAAAAAAAUAGgAAAAAAAwACAAAAAAAAABwAAAAAAAAAHQAA" + 77 "AAAAAAAeAAAAAAAAAB8AAAAAAAAAIAAAAAQAAwACAAAABgADAAIAAAAGAAEAFAAAAAYAAAAhAAAA" + 78 "BwACABUAAAAHAAAAFgAAAAAAAAARAAAABAAAAAAAAAAQAAAADAYAANUFAAAAAAAABwABAAIAAAAt" + 79 "AwAAQQAAAG4QAwAGAAwAbhAEAAYADAFuEAIABgAMAm4QBQAGAAwDcQAKAAAADARuEAsABAAMBCIF" + 80 "BgBwEAcABQBuIAgABQAaAAEAbiAIAAUAbiAIABUAbiAIAAUAbiAIACUAbiAIAAUAbiAIADUAGgAA" + 81 "AG4gCAAFAG4gCABFAG4QCQAFAAwAEQAAAAIAAQAAAAAAMQMAAAMAAABUEAAAEQAAAAIAAQAAAAAA" + 82 "NQMAAAMAAABUEAEAEQAAAAIAAQAAAAAAOQMAAAMAAABUEAIAEQAAAAIAAQAAAAAAPQMAAAMAAABU" + 83 "EAMAEQAAAAIAAQABAAAAJAMAABQAAABwEAYAAQAaAAUAWxABABoAAwBbEAIAGgAEAFsQAAAaACQA" + 84 "WxADAA4ACQAOPEtLS0sAEAAOABYADgATAA4AHAAOABkADgAAAAABAAAABQAGIGZyb20gAAIsIAAG" + 85 "PGluaXQ+ABBCb25qb3VyIGxlIE1vbmRlAApIZWogVmVyZGVuAAtIZWxsbyBXb3JsZAABTAACTEwA" + 86 "GExhcnQvVGVzdDE5OTUkVHJhbnNmb3JtOwAOTGFydC9UZXN0MTk5NTsAIkxkYWx2aWsvYW5ub3Rh" + 87 "dGlvbi9FbmNsb3NpbmdDbGFzczsAHkxkYWx2aWsvYW5ub3RhdGlvbi9Jbm5lckNsYXNzOwASTGph" + 88 "dmEvbGFuZy9PYmplY3Q7ABJMamF2YS9sYW5nL1N0cmluZzsAGUxqYXZhL2xhbmcvU3RyaW5nQnVp" + 89 "bGRlcjsAEkxqYXZhL2xhbmcvVGhyZWFkOwANVGVzdDE5OTUuamF2YQAJVHJhbnNmb3JtAAFWAAth" + 90 "Y2Nlc3NGbGFncwAGYXBwZW5kAA1jdXJyZW50VGhyZWFkAAdnZXROYW1lAA5ncmVldGluZ0Rhbmlz" + 91 "aAAPZ3JlZXRpbmdFbmdsaXNoAA5ncmVldGluZ0ZyZW5jaAAQZ3JlZXRpbmdKYXBhbmVzZQAEbmFt" + 92 "ZQAFc2F5SGkAC3NheUhpRGFuaXNoAAxzYXlIaUVuZ2xpc2gAC3NheUhpRnJlbmNoAA1zYXlIaUph" + 93 "cGFuZXNlAAh0b1N0cmluZwAFdmFsdWUAdn5+RDh7ImNvbXBpbGF0aW9uLW1vZGUiOiJkZWJ1ZyIs" + 94 "Im1pbi1hcGkiOjEsInNoYS0xIjoiNjBkYTRkNjdiMzgxYzQyNDY3NzU3YzQ5ZmI2ZTU1NzU2ZDg4" + 95 "YTJmMyIsInZlcnNpb24iOiIxLjcuMTItZGV2In0AB+OBk+OCk+OBq+OBoeOBr+S4lueVjAACAgEi" + 96 "GAECAwITBBkbFxEABAEFAAEBAQEBAQEAgYAE7AUBAfgDAQGMBQEBpAUBAbwFAQHUBQAAAAAAAgAA" + 97 "AMYFAADMBQAAAAYAAAAAAAAAAAAAAAAAABAAAAAAAAAAAQAAAAAAAAABAAAAJQAAAHAAAAACAAAA" + 98 "CQAAAAQBAAADAAAABAAAACgBAAAEAAAABAAAAFgBAAAFAAAADAAAAHgBAAAGAAAAAQAAANgBAAAB" + 99 "IAAABgAAAPgBAAADIAAABgAAACQDAAABEAAAAQAAAEQDAAACIAAAJQAAAEoDAAAEIAAAAgAAAMYF" + 100 "AAAAIAAAAQAAANUFAAADEAAAAgAAAPwFAAAGIAAAAQAAAAwGAAAAEAAAAQAAABwGAAA="); 101 102 run()103 public static void run() throws Exception { 104 Redefinition.setTestConfiguration(Redefinition.Config.COMMON_REDEFINE); 105 doTest(); 106 } 107 108 public static final class MyThread extends Thread { MyThread(CountDownLatch delay, int id)109 public MyThread(CountDownLatch delay, int id) { 110 super("Thread: " + id); 111 this.thr_id = id; 112 this.results = new ArrayList<>(TASK_COUNT_LIMIT); 113 this.finish = false; 114 this.delay = delay; 115 } 116 run()117 public void run() { 118 delay.countDown(); 119 while (!finish && results.size() < TASK_COUNT_LIMIT) { 120 Transform t = new Transform(); 121 results.add(t.sayHi()); 122 } 123 } 124 finish()125 public void finish() throws Exception { 126 finish = true; 127 this.join(); 128 } 129 Check()130 public void Check() throws Exception { 131 for (String s : results) { 132 if (!s.equals("Hello from " + getName()) && 133 !s.equals("Hello, null, null, null from " + getName()) && 134 !s.equals("Hello World, Bonjour le Monde, Hej Verden, こんにちは世界 from " + getName())) { 135 System.out.println("FAIL " + thr_id + ": Unexpected result: " + s); 136 } 137 } 138 } 139 140 public ArrayList<String> results; 141 public volatile boolean finish; 142 public int thr_id; 143 public CountDownLatch delay; 144 } 145 startThreads(int num_threads)146 public static MyThread[] startThreads(int num_threads) throws Exception { 147 CountDownLatch cdl = new CountDownLatch(num_threads); 148 MyThread[] res = new MyThread[num_threads]; 149 for (int i = 0; i < num_threads; i++) { 150 res[i] = new MyThread(cdl, i); 151 res[i].start(); 152 } 153 cdl.await(); 154 return res; 155 } finishThreads(MyThread[] thrs)156 public static void finishThreads(MyThread[] thrs) throws Exception { 157 for (MyThread t : thrs) { 158 t.finish(); 159 } 160 for (MyThread t : thrs) { 161 t.Check(); 162 } 163 } 164 doTest()165 public static void doTest() throws Exception { 166 MyThread[] threads = startThreads(NUM_THREADS); 167 Redefinition.doCommonStructuralClassRedefinition(Transform.class, DEX_BYTES); 168 finishThreads(threads); 169 } 170 } 171