1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5  * in compliance with the License. You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software distributed under the License
10  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11  * or implied. See the License for the specific language governing permissions and limitations under
12  * the License.
13  */
14 package android.jvmti.cts;
15 
16 import static org.junit.Assert.assertEquals;
17 import static org.junit.Assert.assertArrayEquals;
18 import static org.junit.Assert.assertTrue;
19 
20 import dalvik.system.InMemoryDexClassLoader;
21 
22 import java.lang.ref.WeakReference;
23 import java.nio.ByteBuffer;
24 import java.util.Arrays;
25 import java.util.ArrayList;
26 import java.util.Base64;
27 import java.util.Collections;
28 import java.util.LinkedList;
29 import java.util.List;
30 
31 import org.junit.Assert;
32 import org.junit.After;
33 import org.junit.Before;
34 import org.junit.BeforeClass;
35 import org.junit.Test;
36 
37 import art.Main;
38 
39 /**
40  * Check redefineClasses-related functionality.
41  */
42 public class JvmtiRedefineClassesTest extends JvmtiTestBase {
43 
44     @Before
setUp()45     public void setUp() throws Exception {
46         // make sure everything is cleared.
47         setTransformationEvent(false);
48         setPopTransformations(true);
49         clearTransformations();
50         // Make sure Transform.class is in the initial state.
51         checkRedefinition(INITIAL_TRANSFORM);
52     }
53 
54     static class RedefineError {
55         public int expectedError;
56         public Class<?> target;
57         public byte[] dexData;
58 
RedefineError(int err, Class<?> target, String base64string)59         public RedefineError(int err, Class<?> target, String base64string) {
60             this(err, target, Base64.getDecoder().decode(base64string));
61         }
62 
RedefineError(int err, Class<?> klass, byte[] dex)63         public RedefineError(int err, Class<?> klass, byte[] dex) {
64             this.expectedError = err;
65             this.target = klass;
66             this.dexData = dex;
67         }
68     }
69 
70     // Just an interface.
71     interface Consumer<T> {
accept(T data)72         public void accept(T data);
73     }
74 
75     static class StringCollector implements Consumer<String> {
76         public ArrayList<String> reports = new ArrayList<>();
77 
accept(String data)78         public void accept(String data) {
79             reports.add(data);
80         }
81     }
82 
83     /**
84      * Try to redefine a class and assert that the redefinition matches whats expected.
85      */
checkRedefinition(RedefineError err)86     private static void checkRedefinition(RedefineError err) {
87         assertEquals(err.expectedError, redefineClass(err.target, err.dexData));
88     }
89 
90     // This is a class that we will transform for tests.
91     // NB This has the actual name Landroid/jvmti/cts/JvmtiRedefineClassesTest$Transform;
92     static class Transform {
93         // NB This field has type Landroid/jvmti/cts/JvmtiRedefineClassesTest$Consumer;
94         private Consumer<String> reporter;
95 
Transform(Consumer<String> reporter)96         public Transform(Consumer<String> reporter) {
97             this.reporter = reporter;
98         }
99 
Start()100         private void Start() {
101             reporter.accept("hello - private");
102         }
103 
Finish()104         private void Finish() {
105             reporter.accept("goodbye - private");
106         }
107 
sayHi(Runnable r)108         public void sayHi(Runnable r) {
109             reporter.accept("Pre Start private method call");
110             Start();
111             reporter.accept("Post Start private method call");
112             r.run();
113             reporter.accept("Pre Finish private method call");
114             Finish();
115             reporter.accept("Post Finish private method call");
116         }
117     }
118 
119     /**
120      * Base64 encoded dex file for the initial version of Transform class.
121      */
122     private static final RedefineError INITIAL_TRANSFORM = new RedefineError(
123             JvmtiErrors.NONE, Transform.class,
124             "ZGV4CjAzNQA+L+iHAAAAAAAAAAAAAAAAAAAAAAAAAACgBgAAcAAAAHhWNBIAAAAAAAAAANwFAAAi" +
125             "AAAAcAAAAAkAAAD4AAAABAAAABwBAAABAAAATAEAAAcAAABUAQAAAQAAAIwBAAD0BAAArAEAAKwB" +
126             "AACvAQAAsgEAALoBAAC+AQAAxAEAAMwBAADrAQAAIQIAAFgCAACQAgAAvgIAAOICAAACAwAAIQMA" +
127             "ADUDAABLAwAAXwMAAIADAACgAwAAwAMAAN8DAADmAwAA8QMAAPQDAAD4AwAAAAQAAA0EAAAgBAAA" +
128             "MQQAADcEAABBBAAARgQAAE0EAAAIAAAACQAAAAoAAAALAAAADAAAAA0AAAAOAAAADwAAABcAAAAX" +
129             "AAAACAAAAAAAAAAYAAAACAAAAFQEAAAYAAAACAAAAFwEAAAYAAAACAAAAGQEAAABAAAAHgAAAAAA" +
130             "AgAZAAAAAQABAAIAAAABAAAABQAAAAEAAAAVAAAAAQADACAAAAAGAAAAAgAAAAcAAAAfAAAAAQAA" +
131             "AAAAAAAGAAAAAAAAAAYAAAC8BQAAWAUAAAAAAAABKAABPAAGPGluaXQ+AAI+OwAEPjspVgAGRmlu" +
132             "aXNoAB1Kdm10aVJlZGVmaW5lQ2xhc3Nlc1Rlc3QuamF2YQA0TGFuZHJvaWQvanZtdGkvY3RzL0p2" +
133             "bXRpUmVkZWZpbmVDbGFzc2VzVGVzdCRDb25zdW1lcgA1TGFuZHJvaWQvanZtdGkvY3RzL0p2bXRp" +
134             "UmVkZWZpbmVDbGFzc2VzVGVzdCRDb25zdW1lcjsANkxhbmRyb2lkL2p2bXRpL2N0cy9Kdm10aVJl" +
135             "ZGVmaW5lQ2xhc3Nlc1Rlc3QkVHJhbnNmb3JtOwAsTGFuZHJvaWQvanZtdGkvY3RzL0p2bXRpUmVk" +
136             "ZWZpbmVDbGFzc2VzVGVzdDsAIkxkYWx2aWsvYW5ub3RhdGlvbi9FbmNsb3NpbmdDbGFzczsAHkxk" +
137             "YWx2aWsvYW5ub3RhdGlvbi9Jbm5lckNsYXNzOwAdTGRhbHZpay9hbm5vdGF0aW9uL1NpZ25hdHVy" +
138             "ZTsAEkxqYXZhL2xhbmcvT2JqZWN0OwAUTGphdmEvbGFuZy9SdW5uYWJsZTsAEkxqYXZhL2xhbmcv" +
139             "U3RyaW5nOwAfUG9zdCBGaW5pc2ggcHJpdmF0ZSBtZXRob2QgY2FsbAAeUG9zdCBTdGFydCBwcml2" +
140             "YXRlIG1ldGhvZCBjYWxsAB5QcmUgRmluaXNoIHByaXZhdGUgbWV0aG9kIGNhbGwAHVByZSBTdGFy" +
141             "dCBwcml2YXRlIG1ldGhvZCBjYWxsAAVTdGFydAAJVHJhbnNmb3JtAAFWAAJWTAAGYWNjZXB0AAth" +
142             "Y2Nlc3NGbGFncwARZ29vZGJ5ZSAtIHByaXZhdGUAD2hlbGxvIC0gcHJpdmF0ZQAEbmFtZQAIcmVw" +
143             "b3J0ZXIAA3J1bgAFc2F5SGkABXZhbHVlAAEAAAAAAAAAAQAAAAYAAAABAAAABwAAAAwBAAcOPC0A" +
144             "FQAHDocAEQAHDocAGQEABw6HPIc8hzyHAAAAAAIAAgABAAAAbAQAAAYAAABwEAUAAABbAQAADgAD" +
145             "AAEAAgAAAHQEAAAJAAAAVCAAABsBGwAAAHIgAAAQAA4AAAADAAEAAgAAAHoEAAAJAAAAVCAAABsB" +
146             "HAAAAHIgAAAQAA4AAAAEAAIAAgAAAIAEAAAqAAAAVCAAABsBFAAAAHIgAAAQAHAQAwACAFQgAAAb" +
147             "ARIAAAByIAAAEAByEAYAAwBUIAAAGwETAAAAciAAABAAcBACAAIAVCAAABsBEQAAAHIgAAAQAA4A" +
148             "AAEDAQACAYGABJAJAQKsCQEC0AkEAfQJAgMBIRgCAgQCGgQIHRcWAgUBIRwEFwcXARcQFwMCBQEh" +
149             "HAUXABcHFwEXEBcEAAAAAgAAAHAFAAB2BQAAAQAAAH8FAAABAAAAjQUAAKAFAAABAAAAAQAAAAAA" +
150             "AAAAAAAArAUAAAEAAAC0BQAAEAAAAAAAAAABAAAAAAAAAAEAAAAiAAAAcAAAAAIAAAAJAAAA+AAA" +
151             "AAMAAAAEAAAAHAEAAAQAAAABAAAATAEAAAUAAAAHAAAAVAEAAAYAAAABAAAAjAEAAAIgAAAiAAAA" +
152             "rAEAAAEQAAADAAAAVAQAAAMgAAAEAAAAbAQAAAEgAAAEAAAAkAQAAAAgAAABAAAAWAUAAAQgAAAE" +
153             "AAAAcAUAAAMQAAADAAAAoAUAAAYgAAABAAAAvAUAAAAQAAABAAAA3AUAAA==");
154 
155     /**
156      * Base64 encoded dex file containing the following inner class.
157      * <code>
158      * // NB This has the actual name Landroid/jvmti/cts/JvmtiRedefineClassesTest$Transform;
159      * static class Transform {
160      *     // NB This field has type Landroid/jvmti/cts/JvmtiRedefineClassesTest$Consumer;
161      *     private Consumer<String> reporter;
162      *     public Transform(Consumer<String> reporter) {
163      *         this.reporter = reporter;
164      *     }
165      *     private void Start() {
166      *         reporter.accept("TRANSFORMED - Hello - private");
167      *     }
168      *     private void Finish() {
169      *         reporter.accept("TRANSFORMED - Goodbye - private");
170      *     }
171      *     public void sayHi(Runnable r) {
172      *         reporter.accept("TRANSFORMED - pre Start private method call");
173      *         Start();
174      *         reporter.accept("TRANSFORMED - post Start private method call");
175      *         r.run();
176      *         reporter.accept("TRANSFORMED - pre Finish private method call");
177      *         Finish();
178      *         reporter.accept("TRANSFORMED - post Finish private method call");
179      *     }
180      * }
181      * </code>
182      */
183     private static final RedefineError GOOD_TRANSFORM = new RedefineError(
184             JvmtiErrors.NONE, Transform.class,
185             "ZGV4CjAzNQBmR3TRAAAAAAAAAAAAAAAAAAAAAAAAAAD0BgAAcAAAAHhWNBIAAAAAAAAAADAGAAAi" +
186             "AAAAcAAAAAkAAAD4AAAABAAAABwBAAABAAAATAEAAAcAAABUAQAAAQAAAIwBAABIBQAArAEAAKwB" +
187             "AACvAQAAsgEAALoBAAC+AQAAxAEAAMwBAADrAQAAIQIAAFgCAACQAgAAvgIAAOICAAACAwAAIQMA" +
188             "ADUDAABLAwAAXwMAAGYDAACHAwAApgMAANUDAAADBAAAMQQAAF4EAABpBAAAbAQAAHAEAAB4BAAA" +
189             "hQQAAIsEAACVBAAAmgQAAKEEAAAIAAAACQAAAAoAAAALAAAADAAAAA0AAAAOAAAADwAAABkAAAAZ" +
190             "AAAACAAAAAAAAAAaAAAACAAAAKgEAAAaAAAACAAAALAEAAAaAAAACAAAALgEAAABAAAAHgAAAAAA" +
191             "AgAbAAAAAQABAAIAAAABAAAABQAAAAEAAAARAAAAAQADACAAAAAGAAAAAgAAAAcAAAAfAAAAAQAA" +
192             "AAAAAAAGAAAAAAAAAAYAAAAQBgAArAUAAAAAAAABKAABPAAGPGluaXQ+AAI+OwAEPjspVgAGRmlu" +
193             "aXNoAB1Kdm10aVJlZGVmaW5lQ2xhc3Nlc1Rlc3QuamF2YQA0TGFuZHJvaWQvanZtdGkvY3RzL0p2" +
194             "bXRpUmVkZWZpbmVDbGFzc2VzVGVzdCRDb25zdW1lcgA1TGFuZHJvaWQvanZtdGkvY3RzL0p2bXRp" +
195             "UmVkZWZpbmVDbGFzc2VzVGVzdCRDb25zdW1lcjsANkxhbmRyb2lkL2p2bXRpL2N0cy9Kdm10aVJl" +
196             "ZGVmaW5lQ2xhc3Nlc1Rlc3QkVHJhbnNmb3JtOwAsTGFuZHJvaWQvanZtdGkvY3RzL0p2bXRpUmVk" +
197             "ZWZpbmVDbGFzc2VzVGVzdDsAIkxkYWx2aWsvYW5ub3RhdGlvbi9FbmNsb3NpbmdDbGFzczsAHkxk" +
198             "YWx2aWsvYW5ub3RhdGlvbi9Jbm5lckNsYXNzOwAdTGRhbHZpay9hbm5vdGF0aW9uL1NpZ25hdHVy" +
199             "ZTsAEkxqYXZhL2xhbmcvT2JqZWN0OwAUTGphdmEvbGFuZy9SdW5uYWJsZTsAEkxqYXZhL2xhbmcv" +
200             "U3RyaW5nOwAFU3RhcnQAH1RSQU5TRk9STUVEIC0gR29vZGJ5ZSAtIHByaXZhdGUAHVRSQU5TRk9S" +
201             "TUVEIC0gSGVsbG8gLSBwcml2YXRlAC1UUkFOU0ZPUk1FRCAtIHBvc3QgRmluaXNoIHByaXZhdGUg" +
202             "bWV0aG9kIGNhbGwALFRSQU5TRk9STUVEIC0gcG9zdCBTdGFydCBwcml2YXRlIG1ldGhvZCBjYWxs" +
203             "ACxUUkFOU0ZPUk1FRCAtIHByZSBGaW5pc2ggcHJpdmF0ZSBtZXRob2QgY2FsbAArVFJBTlNGT1JN" +
204             "RUQgLSBwcmUgU3RhcnQgcHJpdmF0ZSBtZXRob2QgY2FsbAAJVHJhbnNmb3JtAAFWAAJWTAAGYWNj" +
205             "ZXB0AAthY2Nlc3NGbGFncwAEbmFtZQAIcmVwb3J0ZXIAA3J1bgAFc2F5SGkABXZhbHVlAAEAAAAA" +
206             "AAAAAQAAAAYAAAABAAAABwAAAAsBAAcOPC0AFAAHDocAEAAHDocAGAEABw6HPIc8hzyHAAAAAAIA" +
207             "AgABAAAAwAQAAAYAAABwEAUAAABbAQAADgADAAEAAgAAAMgEAAAJAAAAVCAAABsBEgAAAHIgAAAQ" +
208             "AA4AAAADAAEAAgAAAM4EAAAJAAAAVCAAABsBEwAAAHIgAAAQAA4AAAAEAAIAAgAAANQEAAAqAAAA" +
209             "VCAAABsBFwAAAHIgAAAQAHAQAwACAFQgAAAbARUAAAByIAAAEAByEAYAAwBUIAAAGwEWAAAAciAA" +
210             "ABAAcBACAAIAVCAAABsBFAAAAHIgAAAQAA4AAAEDAQACAYGABOQJAQKACgECpAoEAcgKAgMBIRgC" +
211             "AgQCHAQIHRcYAgUBIRwEFwcXARcQFwMCBQEhHAUXABcHFwEXEBcEAAAAAgAAAMQFAADKBQAAAQAA" +
212             "ANMFAAABAAAA4QUAAPQFAAABAAAAAQAAAAAAAAAAAAAAAAYAAAEAAAAIBgAAEAAAAAAAAAABAAAA" +
213             "AAAAAAEAAAAiAAAAcAAAAAIAAAAJAAAA+AAAAAMAAAAEAAAAHAEAAAQAAAABAAAATAEAAAUAAAAH" +
214             "AAAAVAEAAAYAAAABAAAAjAEAAAIgAAAiAAAArAEAAAEQAAADAAAAqAQAAAMgAAAEAAAAwAQAAAEg" +
215             "AAAEAAAA5AQAAAAgAAABAAAArAUAAAQgAAAEAAAAxAUAAAMQAAADAAAA9AUAAAYgAAABAAAAEAYA" +
216             "AAAQAAABAAAAMAYAAA==");
217 
218     /**
219      * Tests that we can redefine Transform class from INITIAL_TRANSFORM to GOOD_TRANSFORM.
220      * <p>
221      * It uses doRedefine to do the transformation.
222      */
checkRedefinedTransform(Runnable doRedefine)223     private void checkRedefinedTransform(Runnable doRedefine) {
224         // The consumer that we use to observe the changes to the Transform class.
225         final StringCollector c = new StringCollector();
226         Transform t = new Transform(c);
227         // Run once without changes.
228         t.sayHi(new Runnable() {
229             public void run() {
230                 c.accept("Initial test run. No changes.");
231             }
232         });
233         // Run once with obsolete methods.
234         t.sayHi(new Runnable() {
235             public void run() {
236                 c.accept("Redefining calling function.");
237                 doRedefine.run();
238             }
239         });
240         // Run once with new definition.
241         t.sayHi(new Runnable() {
242             public void run() {
243                 c.accept("Final test run.");
244             }
245         });
246 
247         String[] output = c.reports.toArray(new String[0]);
248         assertArrayEquals(
249                 new String[]{
250                         // The first call to sayHi
251                         "Pre Start private method call",
252                         "hello - private",
253                         "Post Start private method call",
254                         "Initial test run. No changes.",
255                         "Pre Finish private method call",
256                         "goodbye - private",
257                         "Post Finish private method call",
258 
259                         // The second call to sayHi.
260                         "Pre Start private method call",
261                         "hello - private",
262                         "Post Start private method call",
263                         "Redefining calling function.",
264                         "Pre Finish private method call",
265                         "TRANSFORMED - Goodbye - private",
266                         "Post Finish private method call",
267 
268                         // The final call to sayHi.
269                         "TRANSFORMED - pre Start private method call",
270                         "TRANSFORMED - Hello - private",
271                         "TRANSFORMED - post Start private method call",
272                         "Final test run.",
273                         "TRANSFORMED - pre Finish private method call",
274                         "TRANSFORMED - Goodbye - private",
275                         "TRANSFORMED - post Finish private method call",
276                 }, output);
277     }
278 
279     @Test
testSucessfulRedefine()280     public void testSucessfulRedefine() throws Exception {
281         checkRedefinedTransform(new Runnable() {
282             public void run() {
283                 checkRedefinition(GOOD_TRANSFORM);
284             }
285         });
286     }
287 
288     @Test
testSucessfulRetransform()289     public void testSucessfulRetransform() throws Exception {
290         pushTransformationResult(GOOD_TRANSFORM.target, GOOD_TRANSFORM.dexData);
291         checkRedefinedTransform(new Runnable() {
292             public void run() {
293                 setTransformationEvent(true);
294                 assertEquals(JvmtiErrors.NONE, retransformClass(Transform.class));
295             }
296         });
297     }
298 
299     // This is a class that we will transform for tests.
300     // NB This has the actual name Landroid/jvmti/cts/JvmtiRedefineClassesTest$Transform2;
301     static class Transform2 {
sayHi()302         public void sayHi() {
303             Assert.fail("Should not be called!");
304         }
305     }
306 
307     /**
308      * Test cases for failing redefines.
309      */
310     private static final RedefineError[] FAILING_DEX_FILES = {
311             /**
312              * Base64 for this class.
313              *
314              *  .class Landroid/jvmti/cts/JvmtiRedefineClassesTest$Transform2;
315              *  .super Ljava/lang/Object;
316              *  .source "JvmtiRedefineClassesTest.java"
317              *
318              *  # annotations
319              *  .annotation system Ldalvik/annotation/EnclosingClass;
320              *      value = Landroid/jvmti/cts/JvmtiRedefineClassesTest;
321              *  .end annotation
322              *
323              *  .annotation system Ldalvik/annotation/InnerClass;
324              *      accessFlags = 0x8
325              *      name = "Transform2"
326              *  .end annotation
327              *
328              *  # direct methods
329              *  .method constructor <init>()V
330              *      .registers 1
331              *      .prologue
332              *      .line 33
333              *      invoke-direct {p0}, Ljava/lang/Object;-><init>()V
334              *      return-void
335              *  .end method
336              *
337              *  # virtual methods
338              *  .method public sayHi()V
339              *      .registers 1
340              *      .prologue
341              *      .line 35
342              *      return-object v0
343              *  .end method
344             */
345             new RedefineError(JvmtiErrors.FAILS_VERIFICATION, Transform2.class,
346                     "ZGV4CjAzNQBOhefYdQRcgqmkwhWsSyzb5I3udX0SnJ44AwAAcAAAAHhWNBIAAAAAAAAAAIwCAAAN" +
347                     "AAAAcAAAAAYAAACkAAAAAQAAALwAAAAAAAAAAAAAAAMAAADIAAAAAQAAAOAAAAA4AgAAAAEAAAAB" +
348                     "AAAIAQAAJwEAAGABAACOAQAAsgEAANIBAADmAQAA8gEAAPUBAAACAgAACAIAAA8CAAACAAAAAwAA" +
349                     "AAQAAAAFAAAABgAAAAgAAAAIAAAABQAAAAAAAAAAAAAAAAAAAAAAAAALAAAABAAAAAAAAAAAAAAA" +
350                     "AAAAAAQAAAAAAAAAAQAAADgCAAB+AgAAAAAAAAY8aW5pdD4AHUp2bXRpUmVkZWZpbmVDbGFzc2Vz" +
351                     "VGVzdC5qYXZhADdMYW5kcm9pZC9qdm10aS9jdHMvSnZtdGlSZWRlZmluZUNsYXNzZXNUZXN0JFRy" +
352                     "YW5zZm9ybTI7ACxMYW5kcm9pZC9qdm10aS9jdHMvSnZtdGlSZWRlZmluZUNsYXNzZXNUZXN0OwAi" +
353                     "TGRhbHZpay9hbm5vdGF0aW9uL0VuY2xvc2luZ0NsYXNzOwAeTGRhbHZpay9hbm5vdGF0aW9uL0lu" +
354                     "bmVyQ2xhc3M7ABJMamF2YS9sYW5nL09iamVjdDsAClRyYW5zZm9ybTIAAVYAC2FjY2Vzc0ZsYWdz" +
355                     "AARuYW1lAAVzYXlIaQAFdmFsdWUAAAACAwIJBAgKFwcCAgEMGAEAAAAAAAIAAAAhAgAAGAIAACwC" +
356                     "AAAAAAAAAAAAAAAAAAAhAAcOACMABw4AAAABAAEAAQAAAEgCAAAEAAAAcBACAAAADgACAAEAAAAA" +
357                     "AE0CAAABAAAAEQAAAAEBAICABNQEAQHsBA4AAAAAAAAAAQAAAAAAAAABAAAADQAAAHAAAAACAAAA" +
358                     "BgAAAKQAAAADAAAAAQAAALwAAAAFAAAAAwAAAMgAAAAGAAAAAQAAAOAAAAACIAAADQAAAAABAAAE" +
359                     "IAAAAgAAABgCAAADEAAAAgAAACgCAAAGIAAAAQAAADgCAAADIAAAAgAAAEgCAAABIAAAAgAAAFQC" +
360                     "AAAAIAAAAQAAAH4CAAAAEAAAAQAAAIwCAAA="),
361             /**
362              * Base64 for this class.
363              *
364              *  static class Transform {
365              *    private Consumer<String> reporter;
366              *    public Transform(Consumer<String> reporter) {
367              *      this.reporter = reporter;
368              *    }
369              *    private void Start() { }
370              *    private void Finish() { }
371              *    protected void sayHi(Runnable r) { }
372              *  }
373             */
374             new RedefineError(
375                     JvmtiErrors.UNSUPPORTED_REDEFINITION_METHOD_MODIFIERS_CHANGED, Transform.class,
376                     "ZGV4CjAzNQAf2DrkAAAAAAAAAAAAAAAAAAAAAAAAAAAwBQAAcAAAAHhWNBIAAAAAAAAAAGwEAAAa" +
377                     "AAAAcAAAAAkAAADYAAAAAwAAAPwAAAABAAAAIAEAAAUAAAAoAQAAAQAAAFABAADAAwAAcAEAAHAB" +
378                     "AABzAQAAdgEAAH4BAACCAQAAiAEAAJABAACvAQAA5QEAABwCAABUAgAAggIAAKYCAADGAgAA5QIA" +
379                     "APkCAAAPAwAAIwMAACoDAAA1AwAAOAMAADwDAABJAwAATwMAAFkDAABgAwAACAAAAAkAAAAKAAAA" +
380                     "CwAAAAwAAAANAAAADgAAAA8AAAATAAAAEwAAAAgAAAAAAAAAFAAAAAgAAABoAwAAFAAAAAgAAABw" +
381                     "AwAAAQAAABcAAAABAAEAAgAAAAEAAAAFAAAAAQAAABEAAAABAAIAGAAAAAYAAAACAAAAAQAAAAAA" +
382                     "AAAGAAAAAAAAAAYAAABMBAAA6AMAAAAAAAABKAABPAAGPGluaXQ+AAI+OwAEPjspVgAGRmluaXNo" +
383                     "AB1Kdm10aVJlZGVmaW5lQ2xhc3Nlc1Rlc3QuamF2YQA0TGFuZHJvaWQvanZtdGkvY3RzL0p2bXRp" +
384                     "UmVkZWZpbmVDbGFzc2VzVGVzdCRDb25zdW1lcgA1TGFuZHJvaWQvanZtdGkvY3RzL0p2bXRpUmVk" +
385                     "ZWZpbmVDbGFzc2VzVGVzdCRDb25zdW1lcjsANkxhbmRyb2lkL2p2bXRpL2N0cy9Kdm10aVJlZGVm" +
386                     "aW5lQ2xhc3Nlc1Rlc3QkVHJhbnNmb3JtOwAsTGFuZHJvaWQvanZtdGkvY3RzL0p2bXRpUmVkZWZp" +
387                     "bmVDbGFzc2VzVGVzdDsAIkxkYWx2aWsvYW5ub3RhdGlvbi9FbmNsb3NpbmdDbGFzczsAHkxkYWx2" +
388                     "aWsvYW5ub3RhdGlvbi9Jbm5lckNsYXNzOwAdTGRhbHZpay9hbm5vdGF0aW9uL1NpZ25hdHVyZTsA" +
389                     "EkxqYXZhL2xhbmcvT2JqZWN0OwAUTGphdmEvbGFuZy9SdW5uYWJsZTsAEkxqYXZhL2xhbmcvU3Ry" +
390                     "aW5nOwAFU3RhcnQACVRyYW5zZm9ybQABVgACVkwAC2FjY2Vzc0ZsYWdzAARuYW1lAAhyZXBvcnRl" +
391                     "cgAFc2F5SGkABXZhbHVlAAABAAAAAAAAAAEAAAAHAAAACwEABw48LQARAAcOAA8ABw4AEwEABw4A" +
392                     "AgACAAEAAAB4AwAABgAAAHAQBAAAAFsBAAAOAAEAAQAAAAAAgAMAAAEAAAAOAAAAAQABAAAAAACF" +
393                     "AwAAAQAAAA4AAAACAAIAAAAAAIoDAAABAAAADgAAAAABAwEAAgCBgASQBwECrAcBAsAHAwTUBwID" +
394                     "ARkYAgIEAhUECBYXEgIFARkcBBcHFwEXEBcDAgUBGRwFFwAXBxcBFxAXBAAAAAIAAAAABAAABgQA" +
395                     "AAEAAAAPBAAAAQAAAB0EAAAwBAAAAQAAAAEAAAAAAAAAAAAAADwEAAAAAAAARAQAABAAAAAAAAAA" +
396                     "AQAAAAAAAAABAAAAGgAAAHAAAAACAAAACQAAANgAAAADAAAAAwAAAPwAAAAEAAAAAQAAACABAAAF" +
397                     "AAAABQAAACgBAAAGAAAAAQAAAFABAAACIAAAGgAAAHABAAABEAAAAgAAAGgDAAADIAAABAAAAHgD" +
398                     "AAABIAAABAAAAJADAAAAIAAAAQAAAOgDAAAEIAAABAAAAAAEAAADEAAAAwAAADAEAAAGIAAAAQAA" +
399                     "AEwEAAAAEAAAAQAAAGwEAAA="),
400             /**
401              * Base64 for this class.
402              *
403              *  static final class Transform {
404              *    private Consumer<String> reporter;
405              *    public Transform(Consumer<String> reporter) {
406              *      this.reporter = reporter;
407              *    }
408              *    private void Start() { }
409              *    private void Finish() { }
410              *    public void sayHi(Runnable r) { }
411              *  }
412             */
413             new RedefineError(
414                     JvmtiErrors.UNSUPPORTED_REDEFINITION_CLASS_MODIFIERS_CHANGED, Transform.class,
415                     "ZGV4CjAzNQA82MAwAAAAAAAAAAAAAAAAAAAAAAAAAAAwBQAAcAAAAHhWNBIAAAAAAAAAAGwEAAAa" +
416                     "AAAAcAAAAAkAAADYAAAAAwAAAPwAAAABAAAAIAEAAAUAAAAoAQAAAQAAAFABAADAAwAAcAEAAHAB" +
417                     "AABzAQAAdgEAAH4BAACCAQAAiAEAAJABAACvAQAA5QEAABwCAABUAgAAggIAAKYCAADGAgAA5QIA" +
418                     "APkCAAAPAwAAIwMAACoDAAA1AwAAOAMAADwDAABJAwAATwMAAFkDAABgAwAACAAAAAkAAAAKAAAA" +
419                     "CwAAAAwAAAANAAAADgAAAA8AAAATAAAAEwAAAAgAAAAAAAAAFAAAAAgAAABoAwAAFAAAAAgAAABw" +
420                     "AwAAAQAAABcAAAABAAEAAgAAAAEAAAAFAAAAAQAAABEAAAABAAIAGAAAAAYAAAACAAAAAQAAABAA" +
421                     "AAAGAAAAAAAAAAYAAABMBAAA6AMAAAAAAAABKAABPAAGPGluaXQ+AAI+OwAEPjspVgAGRmluaXNo" +
422                     "AB1Kdm10aVJlZGVmaW5lQ2xhc3Nlc1Rlc3QuamF2YQA0TGFuZHJvaWQvanZtdGkvY3RzL0p2bXRp" +
423                     "UmVkZWZpbmVDbGFzc2VzVGVzdCRDb25zdW1lcgA1TGFuZHJvaWQvanZtdGkvY3RzL0p2bXRpUmVk" +
424                     "ZWZpbmVDbGFzc2VzVGVzdCRDb25zdW1lcjsANkxhbmRyb2lkL2p2bXRpL2N0cy9Kdm10aVJlZGVm" +
425                     "aW5lQ2xhc3Nlc1Rlc3QkVHJhbnNmb3JtOwAsTGFuZHJvaWQvanZtdGkvY3RzL0p2bXRpUmVkZWZp" +
426                     "bmVDbGFzc2VzVGVzdDsAIkxkYWx2aWsvYW5ub3RhdGlvbi9FbmNsb3NpbmdDbGFzczsAHkxkYWx2" +
427                     "aWsvYW5ub3RhdGlvbi9Jbm5lckNsYXNzOwAdTGRhbHZpay9hbm5vdGF0aW9uL1NpZ25hdHVyZTsA" +
428                     "EkxqYXZhL2xhbmcvT2JqZWN0OwAUTGphdmEvbGFuZy9SdW5uYWJsZTsAEkxqYXZhL2xhbmcvU3Ry" +
429                     "aW5nOwAFU3RhcnQACVRyYW5zZm9ybQABVgACVkwAC2FjY2Vzc0ZsYWdzAARuYW1lAAhyZXBvcnRl" +
430                     "cgAFc2F5SGkABXZhbHVlAAABAAAAAAAAAAEAAAAHAAAACwEABw48LQARAAcOAA8ABw4AEwEABw4A" +
431                     "AgACAAEAAAB4AwAABgAAAHAQBAAAAFsBAAAOAAEAAQAAAAAAgAMAAAEAAAAOAAAAAQABAAAAAACF" +
432                     "AwAAAQAAAA4AAAACAAIAAAAAAIoDAAABAAAADgAAAAABAwEAAgCBgASQBwECrAcBAsAHAwHUBwID" +
433                     "ARkYAgIEAhUEGBYXEgIFARkcBBcHFwEXEBcDAgUBGRwFFwAXBxcBFxAXBAAAAAIAAAAABAAABgQA" +
434                     "AAEAAAAPBAAAAQAAAB0EAAAwBAAAAQAAAAEAAAAAAAAAAAAAADwEAAAAAAAARAQAABAAAAAAAAAA" +
435                     "AQAAAAAAAAABAAAAGgAAAHAAAAACAAAACQAAANgAAAADAAAAAwAAAPwAAAAEAAAAAQAAACABAAAF" +
436                     "AAAABQAAACgBAAAGAAAAAQAAAFABAAACIAAAGgAAAHABAAABEAAAAgAAAGgDAAADIAAABAAAAHgD" +
437                     "AAABIAAABAAAAJADAAAAIAAAAQAAAOgDAAAEIAAABAAAAAAEAAADEAAAAwAAADAEAAAGIAAAAQAA" +
438                     "AEwEAAAAEAAAAQAAAGwEAAA="),
439             /**
440              * Base64 for this class.
441              *
442              *  static class Transform {
443              *    private Consumer<String> reporter;
444              *    public Transform(Consumer<String> reporter) {
445              *      this.reporter = reporter;
446              *    }
447              *    private void Finish() { }
448              *    public void sayHi(Runnable r) { }
449              *  }
450             */
451             new RedefineError(
452                     JvmtiErrors.UNSUPPORTED_REDEFINITION_METHOD_DELETED, Transform.class,
453                     "ZGV4CjAzNQBG028hAAAAAAAAAAAAAAAAAAAAAAAAAAAABQAAcAAAAHhWNBIAAAAAAAAAADwEAAAZ" +
454                     "AAAAcAAAAAkAAADUAAAAAwAAAPgAAAABAAAAHAEAAAQAAAAkAQAAAQAAAEQBAACcAwAAZAEAAGQB" +
455                     "AABnAQAAagEAAHIBAAB2AQAAfAEAAJsBAADRAQAACAIAAEACAABuAgAAkgIAALICAADRAgAA5QIA" +
456                     "APsCAAAPAwAAFgMAACEDAAAkAwAAKAMAADUDAAA7AwAARQMAAEwDAAAHAAAACAAAAAkAAAAKAAAA" +
457                     "CwAAAAwAAAANAAAADgAAABIAAAASAAAACAAAAAAAAAATAAAACAAAAFQDAAATAAAACAAAAFwDAAAB" +
458                     "AAAAFgAAAAEAAQACAAAAAQAAABAAAAABAAIAFwAAAAYAAAACAAAAAQAAAAAAAAAGAAAAAAAAAAUA" +
459                     "AAAcBAAAvAMAAAAAAAABKAABPAAGPGluaXQ+AAI+OwAEPjspVgAdSnZtdGlSZWRlZmluZUNsYXNz" +
460                     "ZXNUZXN0LmphdmEANExhbmRyb2lkL2p2bXRpL2N0cy9Kdm10aVJlZGVmaW5lQ2xhc3Nlc1Rlc3Qk" +
461                     "Q29uc3VtZXIANUxhbmRyb2lkL2p2bXRpL2N0cy9Kdm10aVJlZGVmaW5lQ2xhc3Nlc1Rlc3QkQ29u" +
462                     "c3VtZXI7ADZMYW5kcm9pZC9qdm10aS9jdHMvSnZtdGlSZWRlZmluZUNsYXNzZXNUZXN0JFRyYW5z" +
463                     "Zm9ybTsALExhbmRyb2lkL2p2bXRpL2N0cy9Kdm10aVJlZGVmaW5lQ2xhc3Nlc1Rlc3Q7ACJMZGFs" +
464                     "dmlrL2Fubm90YXRpb24vRW5jbG9zaW5nQ2xhc3M7AB5MZGFsdmlrL2Fubm90YXRpb24vSW5uZXJD" +
465                     "bGFzczsAHUxkYWx2aWsvYW5ub3RhdGlvbi9TaWduYXR1cmU7ABJMamF2YS9sYW5nL09iamVjdDsA" +
466                     "FExqYXZhL2xhbmcvUnVubmFibGU7ABJMamF2YS9sYW5nL1N0cmluZzsABVN0YXJ0AAlUcmFuc2Zv" +
467                     "cm0AAVYAAlZMAAthY2Nlc3NGbGFncwAEbmFtZQAIcmVwb3J0ZXIABXNheUhpAAV2YWx1ZQAAAQAA" +
468                     "AAAAAAABAAAABwAAAA0BAAcOAA4ABw4AEAEABw4AAAAAAgACAAEAAABkAwAABgAAAHAQAwAAAFsB" +
469                     "AAAOAAEAAQAAAAAAagMAAAEAAAAOAAAAAgACAAAAAABvAwAAAQAAAA4AAAAAAQIBAAIAgYAE+AYB" +
470                     "ApQHAgGoBwIDARgYAgIEAhQECBUXEQIFARgcBBcGFwEXDxcDAgUBGBwFFwAXBhcBFw8XBAAAAAIA" +
471                     "AADQAwAA1gMAAAEAAADfAwAAAQAAAO0DAAAABAAAAQAAAAEAAAAAAAAAAAAAAAwEAAAAAAAAFAQA" +
472                     "ABAAAAAAAAAAAQAAAAAAAAABAAAAGQAAAHAAAAACAAAACQAAANQAAAADAAAAAwAAAPgAAAAEAAAA" +
473                     "AQAAABwBAAAFAAAABAAAACQBAAAGAAAAAQAAAEQBAAACIAAAGQAAAGQBAAABEAAAAgAAAFQDAAAD" +
474                     "IAAAAwAAAGQDAAABIAAAAwAAAHgDAAAAIAAAAQAAALwDAAAEIAAABAAAANADAAADEAAAAwAAAAAE" +
475                     "AAAGIAAAAQAAABwEAAAAEAAAAQAAADwEAAA="),
476             /**
477              * Base6is class.
478              *
479              *  static class Transform {
480              *    private Consumer<String> reporter;
481              *    public Transform(Consumer<String> reporter) {
482              *      this.reporter = reporter;
483              *    }
484              *    private void Start() { }
485              *    private void Start2() { }
486              *    private void Finish() { }
487              *    public void sayHi(Runnable r) { }
488              *  }
489             */
490             new RedefineError(
491                     JvmtiErrors.UNSUPPORTED_REDEFINITION_METHOD_ADDED, Transform.class,
492                     "ZGV4CjAzNQC43HElAAAAAAAAAAAAAAAAAAAAAAAAAABgBQAAcAAAAHhWNBIAAAAAAAAAAJwEAAAb" +
493                     "AAAAcAAAAAkAAADcAAAAAwAAAAABAAABAAAAJAEAAAYAAAAsAQAAAQAAAFwBAADkAwAAfAEAAHwB" +
494                     "AAB/AQAAggEAAIoBAACOAQAAlAEAAJwBAAC7AQAA8QEAACgCAABgAgAAjgIAALICAADSAgAA8QIA" +
495                     "AAUDAAAbAwAALwMAADYDAAA+AwAASQMAAEwDAABQAwAAXQMAAGMDAABtAwAAdAMAAAgAAAAJAAAA" +
496                     "CgAAAAsAAAAMAAAADQAAAA4AAAAPAAAAFAAAABQAAAAIAAAAAAAAABUAAAAIAAAAfAMAABUAAAAI" +
497                     "AAAAhAMAAAEAAAAYAAAAAQABAAIAAAABAAAABQAAAAEAAAARAAAAAQAAABIAAAABAAIAGQAAAAYA" +
498                     "AAACAAAAAQAAAAAAAAAGAAAAAAAAAAYAAAB8BAAAFAQAAAAAAAABKAABPAAGPGluaXQ+AAI+OwAE" +
499                     "PjspVgAGRmluaXNoAB1Kdm10aVJlZGVmaW5lQ2xhc3Nlc1Rlc3QuamF2YQA0TGFuZHJvaWQvanZt" +
500                     "dGkvY3RzL0p2bXRpUmVkZWZpbmVDbGFzc2VzVGVzdCRDb25zdW1lcgA1TGFuZHJvaWQvanZtdGkv" +
501                     "Y3RzL0p2bXRpUmVkZWZpbmVDbGFzc2VzVGVzdCRDb25zdW1lcjsANkxhbmRyb2lkL2p2bXRpL2N0" +
502                     "cy9Kdm10aVJlZGVmaW5lQ2xhc3Nlc1Rlc3QkVHJhbnNmb3JtOwAsTGFuZHJvaWQvanZtdGkvY3Rz" +
503                     "L0p2bXRpUmVkZWZpbmVDbGFzc2VzVGVzdDsAIkxkYWx2aWsvYW5ub3RhdGlvbi9FbmNsb3NpbmdD" +
504                     "bGFzczsAHkxkYWx2aWsvYW5ub3RhdGlvbi9Jbm5lckNsYXNzOwAdTGRhbHZpay9hbm5vdGF0aW9u" +
505                     "L1NpZ25hdHVyZTsAEkxqYXZhL2xhbmcvT2JqZWN0OwAUTGphdmEvbGFuZy9SdW5uYWJsZTsAEkxq" +
506                     "YXZhL2xhbmcvU3RyaW5nOwAFU3RhcnQABlN0YXJ0MgAJVHJhbnNmb3JtAAFWAAJWTAALYWNjZXNz" +
507                     "RmxhZ3MABG5hbWUACHJlcG9ydGVyAAVzYXlIaQAFdmFsdWUAAAEAAAAAAAAAAQAAAAcAAAANAQAH" +
508                     "DgAQAAcOAA4ABw4ADwAHDgARAQAHDgAAAgACAAEAAACMAwAABgAAAHAQBQAAAFsBAAAOAAEAAQAA" +
509                     "AAAAkgMAAAEAAAAOAAAAAQABAAAAAACXAwAAAQAAAA4AAAABAAEAAAAAAJwDAAABAAAADgAAAAIA" +
510                     "AgAAAAAAoQMAAAEAAAAOAAAAAAEEAQACAIGABKgHAQLEBwEC2AcBAuwHBAGACAIDARoYAgIEAhYE" +
511                     "CBcXEwIFARocBBcHFwEXEBcDAgUBGhwFFwAXBxcBFxAXBAAAAAIAAAAwBAAANgQAAAEAAAA/BAAA" +
512                     "AQAAAE0EAABgBAAAAQAAAAEAAAAAAAAAAAAAAGwEAAAAAAAAdAQAABAAAAAAAAAAAQAAAAAAAAAB" +
513                     "AAAAGwAAAHAAAAACAAAACQAAANwAAAADAAAAAwAAAAABAAAEAAAAAQAAACQBAAAFAAAABgAAACwB" +
514                     "AAAGAAAAAQAAAFwBAAACIAAAGwAAAHwBAAABEAAAAgAAAHwDAAADIAAABQAAAIwDAAABIAAABQAA" +
515                     "AKgDAAAAIAAAAQAAABQEAAAEIAAABAAAADAEAAADEAAAAwAAAGAEAAAGIAAAAQAAAHwEAAAAEAAA" +
516                     "AQAAAJwEAAA="),
517             /**
518              * Base64 for this class.
519              *
520              *  static class Transform {
521              *    public Transform(Consumer<String> reporter) { }
522              *    private void Start() { }
523              *    private void Finish() { }
524              *    public void sayHi(Runnable r) { }
525              *  }
526             */
527             new RedefineError(
528                     JvmtiErrors.UNSUPPORTED_REDEFINITION_SCHEMA_CHANGED, Transform.class,
529                     "ZGV4CjAzNQCn0K9/AAAAAAAAAAAAAAAAAAAAAAAAAADkBAAAcAAAAHhWNBIAAAAAAAAAACwEAAAY" +
530                     "AAAAcAAAAAkAAADQAAAAAwAAAPQAAAAAAAAAAAAAAAUAAAAYAQAAAQAAAEABAACEAwAAYAEAAGAB" +
531                     "AABjAQAAZgEAAG4BAAB0AQAAfAEAAJsBAADRAQAACAIAAEACAABuAgAAkgIAALICAADRAgAA5QIA" +
532                     "APsCAAAPAwAAFgMAACEDAAAkAwAAKAMAADUDAAA7AwAAQgMAAAcAAAAIAAAACQAAAAoAAAALAAAA" +
533                     "DAAAAA0AAAAOAAAAEgAAABIAAAAIAAAAAAAAABMAAAAIAAAATAMAABMAAAAIAAAAVAMAAAEAAQAC" +
534                     "AAAAAQAAAAQAAAABAAAAEAAAAAEAAgAWAAAABgAAAAIAAAABAAAAAAAAAAYAAAAAAAAABQAAABQE" +
535                     "AADIAwAAAAAAAAEoAAE8AAY8aW5pdD4ABD47KVYABkZpbmlzaAAdSnZtdGlSZWRlZmluZUNsYXNz" +
536                     "ZXNUZXN0LmphdmEANExhbmRyb2lkL2p2bXRpL2N0cy9Kdm10aVJlZGVmaW5lQ2xhc3Nlc1Rlc3Qk" +
537                     "Q29uc3VtZXIANUxhbmRyb2lkL2p2bXRpL2N0cy9Kdm10aVJlZGVmaW5lQ2xhc3Nlc1Rlc3QkQ29u" +
538                     "c3VtZXI7ADZMYW5kcm9pZC9qdm10aS9jdHMvSnZtdGlSZWRlZmluZUNsYXNzZXNUZXN0JFRyYW5z" +
539                     "Zm9ybTsALExhbmRyb2lkL2p2bXRpL2N0cy9Kdm10aVJlZGVmaW5lQ2xhc3Nlc1Rlc3Q7ACJMZGFs" +
540                     "dmlrL2Fubm90YXRpb24vRW5jbG9zaW5nQ2xhc3M7AB5MZGFsdmlrL2Fubm90YXRpb24vSW5uZXJD" +
541                     "bGFzczsAHUxkYWx2aWsvYW5ub3RhdGlvbi9TaWduYXR1cmU7ABJMamF2YS9sYW5nL09iamVjdDsA" +
542                     "FExqYXZhL2xhbmcvUnVubmFibGU7ABJMamF2YS9sYW5nL1N0cmluZzsABVN0YXJ0AAlUcmFuc2Zv" +
543                     "cm0AAVYAAlZMAAthY2Nlc3NGbGFncwAEbmFtZQAFc2F5SGkABXZhbHVlAAAAAAEAAAAAAAAAAQAA" +
544                     "AAcAAAAMAQAHDgAOAAcOAA0ABw4ADwEABw4AAAACAAIAAQAAAFwDAAAEAAAAcBAEAAAADgABAAEA" +
545                     "AAAAAGIDAAABAAAADgAAAAEAAQAAAAAAZwMAAAEAAAAOAAAAAgACAAAAAABsAwAAAQAAAA4AAAAA" +
546                     "AAMBAIGABPQGAQKMBwECoAcDAbQHAAACAwEXGAICBAIUBAgVFxECBQEXHAUXABcGFwEXDxcDAAIA" +
547                     "AADgAwAA5gMAAAEAAADvAwAAAAQAAAAAAAABAAAAAAAAAAAAAAAMBAAADwAAAAAAAAABAAAAAAAA" +
548                     "AAEAAAAYAAAAcAAAAAIAAAAJAAAA0AAAAAMAAAADAAAA9AAAAAUAAAAFAAAAGAEAAAYAAAABAAAA" +
549                     "QAEAAAIgAAAYAAAAYAEAAAEQAAACAAAATAMAAAMgAAAEAAAAXAMAAAEgAAAEAAAAdAMAAAAgAAAB" +
550                     "AAAAyAMAAAQgAAADAAAA4AMAAAMQAAACAAAAAAQAAAYgAAABAAAAFAQAAAAQAAABAAAALAQAAA=="),
551             /**
552              * Base64 for this class.
553              *
554              *  static class Transform3 {
555              *      // NB This field has type Landroid/jvmti/cts/JvmtiRedefineClassesTest$Consumer;
556              *      private Consumer<String> reporter;
557              *      public Transform3(Consumer<String> reporter) { this.reporter = reporter; }
558              *      private void Start() { }
559              *      private void Finish() { }
560              *      public void sayHi(Runnable r) { }
561              *  }
562             */
563             new RedefineError(
564                     JvmtiErrors.NAMES_DONT_MATCH, Transform.class,
565                     "ZGV4CjAzNQCc2B3nAAAAAAAAAAAAAAAAAAAAAAAAAAA0BQAAcAAAAHhWNBIAAAAAAAAAAHAEAAAa" +
566                     "AAAAcAAAAAkAAADYAAAAAwAAAPwAAAABAAAAIAEAAAUAAAAoAQAAAQAAAFABAADEAwAAcAEAAHAB" +
567                     "AABzAQAAdgEAAH4BAACCAQAAiAEAAJABAACvAQAA5QEAABwCAABVAgAAgwIAAKcCAADHAgAA5gIA" +
568                     "APoCAAAQAwAAJAMAACsDAAA3AwAAOgMAAD4DAABLAwAAUQMAAFsDAABiAwAACAAAAAkAAAAKAAAA" +
569                     "CwAAAAwAAAANAAAADgAAAA8AAAATAAAAEwAAAAgAAAAAAAAAFAAAAAgAAABsAwAAFAAAAAgAAAB0" +
570                     "AwAAAQAAABcAAAABAAEAAgAAAAEAAAAFAAAAAQAAABEAAAABAAIAGAAAAAYAAAACAAAAAQAAAAAA" +
571                     "AAAGAAAAAAAAAAYAAABQBAAA7AMAAAAAAAABKAABPAAGPGluaXQ+AAI+OwAEPjspVgAGRmluaXNo" +
572                     "AB1Kdm10aVJlZGVmaW5lQ2xhc3Nlc1Rlc3QuamF2YQA0TGFuZHJvaWQvanZtdGkvY3RzL0p2bXRp" +
573                     "UmVkZWZpbmVDbGFzc2VzVGVzdCRDb25zdW1lcgA1TGFuZHJvaWQvanZtdGkvY3RzL0p2bXRpUmVk" +
574                     "ZWZpbmVDbGFzc2VzVGVzdCRDb25zdW1lcjsAN0xhbmRyb2lkL2p2bXRpL2N0cy9Kdm10aVJlZGVm" +
575                     "aW5lQ2xhc3Nlc1Rlc3QkVHJhbnNmb3JtMzsALExhbmRyb2lkL2p2bXRpL2N0cy9Kdm10aVJlZGVm" +
576                     "aW5lQ2xhc3Nlc1Rlc3Q7ACJMZGFsdmlrL2Fubm90YXRpb24vRW5jbG9zaW5nQ2xhc3M7AB5MZGFs" +
577                     "dmlrL2Fubm90YXRpb24vSW5uZXJDbGFzczsAHUxkYWx2aWsvYW5ub3RhdGlvbi9TaWduYXR1cmU7" +
578                     "ABJMamF2YS9sYW5nL09iamVjdDsAFExqYXZhL2xhbmcvUnVubmFibGU7ABJMamF2YS9sYW5nL1N0" +
579                     "cmluZzsABVN0YXJ0AApUcmFuc2Zvcm0zAAFWAAJWTAALYWNjZXNzRmxhZ3MABG5hbWUACHJlcG9y" +
580                     "dGVyAAVzYXlIaQAFdmFsdWUAAAAAAQAAAAAAAAABAAAABwAAAAwBAAcOAA4ABw4ADQAHDgAPAQAH" +
581                     "DgAAAAIAAgABAAAAfAMAAAYAAABwEAQAAABbAQAADgABAAEAAAAAAIIDAAABAAAADgAAAAEAAQAA" +
582                     "AAAAhwMAAAEAAAAOAAAAAgACAAAAAACMAwAAAQAAAA4AAAAAAQMBAAIAgYAElAcBArAHAQLEBwMB" +
583                     "2AcCAwEZGAICBAIVBAgWFxICBQEZHAQXBxcBFxAXAwIFARkcBRcAFwcXARcQFwQAAAACAAAABAQA" +
584                     "AAoEAAABAAAAEwQAAAEAAAAhBAAANAQAAAEAAAABAAAAAAAAAAAAAABABAAAAAAAAEgEAAAQAAAA" +
585                     "AAAAAAEAAAAAAAAAAQAAABoAAABwAAAAAgAAAAkAAADYAAAAAwAAAAMAAAD8AAAABAAAAAEAAAAg" +
586                     "AQAABQAAAAUAAAAoAQAABgAAAAEAAABQAQAAAiAAABoAAABwAQAAARAAAAIAAABsAwAAAyAAAAQA" +
587                     "AAB8AwAAASAAAAQAAACUAwAAACAAAAEAAADsAwAABCAAAAQAAAAEBAAAAxAAAAMAAAA0BAAABiAA" +
588                     "AAEAAABQBAAAABAAAAEAAABwBAAA"),
589             /**
590              * Base64 for this class.
591              *
592              *  static class Transform extends Observable {
593              *      // NB This field has type Landroid/jvmti/cts/JvmtiRedefineClassesTest$Consumer;
594              *      private Consumer<String> reporter;
595              *      public Transform(Consumer<String> reporter) { super(); this.reporter = reporter; }
596              *      private void Start() { }
597              *      private void Finish() { }
598              *      public void sayHi(Runnable r) { }
599              *  }
600             */
601             new RedefineError(
602                     JvmtiErrors.UNSUPPORTED_REDEFINITION_HIERARCHY_CHANGED, Transform.class,
603                     "ZGV4CjAzNQAV2qEZAAAAAAAAAAAAAAAAAAAAAAAAAAA0BQAAcAAAAHhWNBIAAAAAAAAAAHAEAAAa" +
604                     "AAAAcAAAAAkAAADYAAAAAwAAAPwAAAABAAAAIAEAAAUAAAAoAQAAAQAAAFABAADEAwAAcAEAAHAB" +
605                     "AABzAQAAdgEAAH4BAACCAQAAiAEAAJABAACvAQAA5QEAABwCAABUAgAAggIAAKYCAADGAgAA5QIA" +
606                     "APsCAAAPAwAAJwMAAC4DAAA5AwAAPAMAAEADAABNAwAAUwMAAF0DAABkAwAACAAAAAkAAAAKAAAA" +
607                     "CwAAAAwAAAANAAAADgAAABAAAAATAAAAEwAAAAgAAAAAAAAAFAAAAAgAAABsAwAAFAAAAAgAAAB0" +
608                     "AwAAAQAAABcAAAABAAEAAgAAAAEAAAAFAAAAAQAAABEAAAABAAIAGAAAAAcAAAACAAAAAQAAAAAA" +
609                     "AAAHAAAAAAAAAAYAAABQBAAA7AMAAAAAAAABKAABPAAGPGluaXQ+AAI+OwAEPjspVgAGRmluaXNo" +
610                     "AB1Kdm10aVJlZGVmaW5lQ2xhc3Nlc1Rlc3QuamF2YQA0TGFuZHJvaWQvanZtdGkvY3RzL0p2bXRp" +
611                     "UmVkZWZpbmVDbGFzc2VzVGVzdCRDb25zdW1lcgA1TGFuZHJvaWQvanZtdGkvY3RzL0p2bXRpUmVk" +
612                     "ZWZpbmVDbGFzc2VzVGVzdCRDb25zdW1lcjsANkxhbmRyb2lkL2p2bXRpL2N0cy9Kdm10aVJlZGVm" +
613                     "aW5lQ2xhc3Nlc1Rlc3QkVHJhbnNmb3JtOwAsTGFuZHJvaWQvanZtdGkvY3RzL0p2bXRpUmVkZWZp" +
614                     "bmVDbGFzc2VzVGVzdDsAIkxkYWx2aWsvYW5ub3RhdGlvbi9FbmNsb3NpbmdDbGFzczsAHkxkYWx2" +
615                     "aWsvYW5ub3RhdGlvbi9Jbm5lckNsYXNzOwAdTGRhbHZpay9hbm5vdGF0aW9uL1NpZ25hdHVyZTsA" +
616                     "FExqYXZhL2xhbmcvUnVubmFibGU7ABJMamF2YS9sYW5nL1N0cmluZzsAFkxqYXZhL3V0aWwvT2Jz" +
617                     "ZXJ2YWJsZTsABVN0YXJ0AAlUcmFuc2Zvcm0AAVYAAlZMAAthY2Nlc3NGbGFncwAEbmFtZQAIcmVw" +
618                     "b3J0ZXIABXNheUhpAAV2YWx1ZQAAAQAAAAAAAAABAAAABgAAAA0BAAcOAA8ABw4ADgAHDgAQAQAH" +
619                     "DgAAAAIAAgABAAAAfAMAAAYAAABwEAQAAABbAQAADgABAAEAAAAAAIIDAAABAAAADgAAAAEAAQAA" +
620                     "AAAAhwMAAAEAAAAOAAAAAgACAAAAAACMAwAAAQAAAA4AAAAAAQMBAAIAgYAElAcBArAHAQLEBwMB" +
621                     "2AcCAwEZGAICBAIVBAgWFxICBQEZHAQXBxcBFw8XAwIFARkcBRcAFwcXARcPFwQAAAACAAAABAQA" +
622                     "AAoEAAABAAAAEwQAAAEAAAAhBAAANAQAAAEAAAABAAAAAAAAAAAAAABABAAAAAAAAEgEAAAQAAAA" +
623                     "AAAAAAEAAAAAAAAAAQAAABoAAABwAAAAAgAAAAkAAADYAAAAAwAAAAMAAAD8AAAABAAAAAEAAAAg" +
624                     "AQAABQAAAAUAAAAoAQAABgAAAAEAAABQAQAAAiAAABoAAABwAQAAARAAAAIAAABsAwAAAyAAAAQA" +
625                     "AAB8AwAAASAAAAQAAACUAwAAACAAAAEAAADsAwAABCAAAAQAAAAEBAAAAxAAAAMAAAA0BAAABiAA" +
626                     "AAEAAABQBAAAABAAAAEAAABwBAAA"),
627             /**
628              * Array classes are never modifiable.
629              *
630              * The base64 data is just an empty dex file. It has no classes associated with it.
631             */
632             new RedefineError(JvmtiErrors.UNMODIFIABLE_CLASS, Transform[].class,
633                     "ZGV4CjAzNQCRAy8PAAAAAAAAAAAAAAAAAAAAAAAAAACMAAAAcAAAAHhWNBIAAAAAAAAAAHAAAAAA" +
634                     "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcAAAAcAAAAAIA" +
635                     "AAAAAAAAAQAAAAAAAAAAEAAAAQAAAHAAAAA="),
636     };
637 
638     @Test
testRedefineFailures()639     public void testRedefineFailures() throws Exception {
640         // Just check each of the failing tests.
641         for (RedefineError e : FAILING_DEX_FILES) {
642             checkRedefinition(e);
643         }
644     }
645 
checkRetransformation(RedefineError e)646     private void checkRetransformation(RedefineError e) {
647         clearTransformations();
648         pushTransformationResult(e.target, e.dexData);
649         assertEquals(e.expectedError, retransformClass(e.target));
650     }
651 
652     @Test
testRetransformFailures()653     public void testRetransformFailures() throws Exception {
654         setTransformationEvent(true);
655         setPopTransformations(true);
656         for (RedefineError e : FAILING_DEX_FILES) {
657             checkRetransformation(e);
658         }
659     }
660 
661     private static final String ONLOAD_TEST_CLASS_NAME =
662             "android.jvmti.cts.memory_dex.TransformTarget";
663     /**
664      * Base64 encoded version of the following class.
665      * package android.jvmti.cts.memory_dex;
666      * <p>
667      * public class TransformTarget {
668      * public void alpha() { }
669      * public void beta() { }
670      * }
671      */
672     private static final byte[] ONLOAD_INITIAL_CLASS = Base64.getDecoder().decode(
673             "ZGV4CjAzNQAQT37mO0bz7SniP0I8RLnGvVsfM5ybXmdYAgAAcAAAAHhWNBIAAAAAAAAAANABAAAI" +
674             "AAAAcAAAAAMAAACQAAAAAQAAAJwAAAAAAAAAAAAAAAQAAACoAAAAAQAAAMgAAABwAQAA6AAAACgB" +
675             "AAAwAQAAYAEAAHQBAACKAQAAjQEAAJQBAACaAQAAAQAAAAIAAAAEAAAABAAAAAIAAAAAAAAAAAAA" +
676             "AAAAAAAAAAAABQAAAAAAAAAGAAAAAQAAAAAAAAAAAAAAAQAAAAEAAAAAAAAAAwAAAAAAAAC9AQAA" +
677             "AAAAAAEAAQABAAAArgEAAAQAAABwEAMAAAAOAAEAAQAAAAAAswEAAAEAAAAOAAAAAQABAAAAAAC4" +
678             "AQAAAQAAAA4AAAAGPGluaXQ+AC5MYW5kcm9pZC9qdm10aS9jdHMvbWVtb3J5X2RleC9UcmFuc2Zv" +
679             "cm1UYXJnZXQ7ABJMamF2YS9sYW5nL09iamVjdDsAFFRyYW5zZm9ybVRhcmdldC5qYXZhAAFWAAVh" +
680             "bHBoYQAEYmV0YQASZW1pdHRlcjogamFjay00LjI4AAIABw4AAwAHDgAEAAcOAAAAAQIAgYAE6AEB" +
681             "AYACAQGUAgALAAAAAAAAAAEAAAAAAAAAAQAAAAgAAABwAAAAAgAAAAMAAACQAAAAAwAAAAEAAACc" +
682             "AAAABQAAAAQAAACoAAAABgAAAAEAAADIAAAAASAAAAMAAADoAAAAAiAAAAgAAAAoAQAAAyAAAAMA" +
683             "AACuAQAAACAAAAEAAAC9AQAAABAAAAEAAADQAQAA");
684     /**
685      * Base64 encoded version of the following class.
686      * Note that this would be an illegal transformation if the class had been loaded as the first
687      * one.
688      * <p>
689      * package android.jvmti.cts.memory_dex;
690      * <p>
691      * public class TransformTarget {
692      * public void alpha(int abc) {
693      * }
694      * public int beta() {
695      * return 12;
696      * }
697      * public void gamma() {
698      * }
699      * }
700      */
701     private static final byte[] ONLOAD_FINAL_CLASS = Base64.getDecoder().decode(
702             "ZGV4CjAzNQA5VqbusSyl8/G1EXrbm9uRuiHvkP4XixrMAgAAcAAAAHhWNBIAAAAAAAAAADgCAAAL" +
703             "AAAAcAAAAAQAAACcAAAAAwAAAKwAAAAAAAAAAAAAAAUAAADQAAAAAQAAAPgAAAC0AQAAGAEAAHYB" +
704             "AAB+AQAAgQEAALEBAADFAQAA2wEAAN4BAADiAQAA6QEAAO8BAAADAgAAAQAAAAIAAAADAAAABQAA" +
705             "AAEAAAAAAAAAAAAAAAUAAAADAAAAAAAAAAYAAAADAAAAcAEAAAEAAQAAAAAAAQACAAcAAAABAAAA" +
706             "CAAAAAEAAQAKAAAAAgABAAAAAAABAAAAAQAAAAIAAAAAAAAABAAAAAAAAAAfAgAAAAAAAAEAAQAB" +
707             "AAAACgIAAAQAAABwEAQAAAAOAAIAAgAAAAAADwIAAAEAAAAOAAAAAgABAAAAAAAVAgAAAwAAABMA" +
708             "DAAPAAAAAQABAAAAAAAaAgAAAQAAAA4AAAABAAAAAAAGPGluaXQ+AAFJAC5MYW5kcm9pZC9qdm10" +
709             "aS9jdHMvbWVtb3J5X2RleC9UcmFuc2Zvcm1UYXJnZXQ7ABJMamF2YS9sYW5nL09iamVjdDsAFFRy" +
710             "YW5zZm9ybVRhcmdldC5qYXZhAAFWAAJWSQAFYWxwaGEABGJldGEAEmVtaXR0ZXI6IGphY2stNC4y" +
711             "OAAFZ2FtbWEAAgAHDgAEAQAHDgAGAAcOAAkABw4AAAABAwCBgASYAgEBsAIBAcQCAQHcAgAAAAwA" +
712             "AAAAAAAAAQAAAAAAAAABAAAACwAAAHAAAAACAAAABAAAAJwAAAADAAAAAwAAAKwAAAAFAAAABQAA" +
713             "ANAAAAAGAAAAAQAAAPgAAAABIAAABAAAABgBAAABEAAAAQAAAHABAAACIAAACwAAAHYBAAADIAAA" +
714             "BAAAAAoCAAAAIAAAAQAAAB8CAAAAEAAAAQAAADgCAAA=");
715 
716     private static class ExpectedMethod {
717         public final Class<?> returnType;
718         public final String name;
719         public final Class<?>[] params;
720 
ExpectedMethod(Class<?> returnType, String name, Class<?>... params)721         public ExpectedMethod(Class<?> returnType, String name, Class<?>... params) {
722             this.returnType = returnType;
723             this.name = name;
724             this.params = params;
725         }
726 
ensureHasMethod(Class<?> klass)727         public void ensureHasMethod(Class<?> klass) throws Exception {
728             try {
729                 assertEquals(returnType, klass.getDeclaredMethod(name, params).getReturnType());
730             } catch (NoSuchMethodException e) {
731                 Assert.fail("Could not find method: " + klass + ": " + name +
732                         " (params: " + Arrays.toString(params) + "). Reason was " + e);
733             }
734         }
735     }
736 
checkClassHasMethods(Class<?> target, ExpectedMethod[] methods)737     private void checkClassHasMethods(Class<?> target, ExpectedMethod[] methods) throws Exception {
738         for (ExpectedMethod m : methods) {
739             m.ensureHasMethod(target);
740         }
741     }
742 
743     @Test
testCannotRetransformOnLoadTest()744     public void testCannotRetransformOnLoadTest() throws Exception {
745         // Just a sanity check along with below.
746         Class<?> target_class = new InMemoryDexClassLoader(
747                 ByteBuffer.wrap(ONLOAD_INITIAL_CLASS),
748                 getClass().getClassLoader()).loadClass(ONLOAD_TEST_CLASS_NAME);
749         checkClassHasMethods(
750                 target_class,
751                 new ExpectedMethod[]{
752                         new ExpectedMethod(Void.TYPE, "alpha"),
753                         new ExpectedMethod(Void.TYPE, "beta"),
754                 });
755         assertTrue(JvmtiErrors.NONE != redefineClass(target_class, ONLOAD_FINAL_CLASS));
756     }
757 
758     @Test
testRetransformOnLoad()759     public void testRetransformOnLoad() throws Exception {
760         pushTransformationResult(ONLOAD_TEST_CLASS_NAME.replace('.', '/'), ONLOAD_FINAL_CLASS);
761         setTransformationEvent(true);
762         setPopTransformations(false);
763         checkClassHasMethods(
764                 new InMemoryDexClassLoader(ByteBuffer.wrap(ONLOAD_INITIAL_CLASS),
765                         getClass().getClassLoader()).loadClass(ONLOAD_TEST_CLASS_NAME),
766                 new ExpectedMethod[]{
767                         new ExpectedMethod(Void.TYPE, "alpha", int.class),
768                         new ExpectedMethod(int.class, "beta"),
769                         new ExpectedMethod(Void.TYPE, "gamma"),
770                 });
771     }
772 
redefineClass(Class<?> target, byte[] dex)773     private static native int redefineClass(Class<?> target, byte[] dex);
774 
retransformClass(Class<?> target)775     private static native int retransformClass(Class<?> target);
776 
setTransformationEvent(boolean enable)777     private static native void setTransformationEvent(boolean enable);
778 
clearTransformations()779     private static native void clearTransformations();
780 
pushTransformationResult(String target, byte[] dexBytes)781     private static native void pushTransformationResult(String target, byte[] dexBytes);
782 
setPopTransformations(boolean enable)783     private static native void setPopTransformations(boolean enable);
784 
pushTransformationResult(Class<?> target, byte[] dex)785     private static void pushTransformationResult(Class<?> target, byte[] dex) {
786         pushTransformationResult(target.getName().replace('.', '/'), dex);
787     }
788 }
789