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