blob: dd40eaa6461a5aea12358fdbc8f2f3ed1e7941fe [file] [log] [blame]
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package android.jvmti.cts;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertTrue;
import dalvik.system.InMemoryDexClassLoader;
import java.lang.ref.WeakReference;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import org.junit.Assert;
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import art.Main;
/**
* Check redefineClasses-related functionality.
*/
public class JvmtiRedefineClassesTest extends JvmtiTestBase {
@Before
public void setUp() throws Exception {
Main.bindAgentJNI("android/jvmti/cts/JvmtiRedefineClassesTest",
getClass().getClassLoader());
// make sure everything is cleared.
setTransformationEvent(false);
setPopTransformations(true);
clearTransformations();
// Make sure Transform.class is in the initial state.
checkRedefinition(INITIAL_TRANSFORM);
}
static class RedefineError {
public int expectedError;
public Class<?> target;
public byte[] dexData;
public RedefineError(int err, Class<?> target, String base64string) {
this(err, target, Base64.getDecoder().decode(base64string));
}
public RedefineError(int err, Class<?> klass, byte[] dex) {
this.expectedError = err;
this.target = klass;
this.dexData = dex;
}
}
// Just an interface.
interface Consumer<T> {
public void accept(T data);
}
static class StringCollector implements Consumer<String> {
public ArrayList<String> reports = new ArrayList<>();
public void accept(String data) {
reports.add(data);
}
}
/**
* Try to redefine a class and assert that the redefinition matches whats expected.
*/
private static void checkRedefinition(RedefineError err) {
assertEquals(err.expectedError, redefineClass(err.target, err.dexData));
}
// This is a class that we will transform for tests.
// NB This has the actual name Landroid/jvmti/cts/JvmtiRedefineClassesTest$Transform;
static class Transform {
// NB This field has type Landroid/jvmti/cts/JvmtiRedefineClassesTest$Consumer;
private Consumer<String> reporter;
public Transform(Consumer<String> reporter) {
this.reporter = reporter;
}
private void Start() {
reporter.accept("hello - private");
}
private void Finish() {
reporter.accept("goodbye - private");
}
public void sayHi(Runnable r) {
reporter.accept("Pre Start private method call");
Start();
reporter.accept("Post Start private method call");
r.run();
reporter.accept("Pre Finish private method call");
Finish();
reporter.accept("Post Finish private method call");
}
}
/**
* Base64 encoded dex file for the initial version of Transform class.
*/
private static final RedefineError INITIAL_TRANSFORM = new RedefineError(
JvmtiErrors.NONE, Transform.class,
"ZGV4CjAzNQA+L+iHAAAAAAAAAAAAAAAAAAAAAAAAAACgBgAAcAAAAHhWNBIAAAAAAAAAANwFAAAi" +
"AAAAcAAAAAkAAAD4AAAABAAAABwBAAABAAAATAEAAAcAAABUAQAAAQAAAIwBAAD0BAAArAEAAKwB" +
"AACvAQAAsgEAALoBAAC+AQAAxAEAAMwBAADrAQAAIQIAAFgCAACQAgAAvgIAAOICAAACAwAAIQMA" +
"ADUDAABLAwAAXwMAAIADAACgAwAAwAMAAN8DAADmAwAA8QMAAPQDAAD4AwAAAAQAAA0EAAAgBAAA" +
"MQQAADcEAABBBAAARgQAAE0EAAAIAAAACQAAAAoAAAALAAAADAAAAA0AAAAOAAAADwAAABcAAAAX" +
"AAAACAAAAAAAAAAYAAAACAAAAFQEAAAYAAAACAAAAFwEAAAYAAAACAAAAGQEAAABAAAAHgAAAAAA" +
"AgAZAAAAAQABAAIAAAABAAAABQAAAAEAAAAVAAAAAQADACAAAAAGAAAAAgAAAAcAAAAfAAAAAQAA" +
"AAAAAAAGAAAAAAAAAAYAAAC8BQAAWAUAAAAAAAABKAABPAAGPGluaXQ+AAI+OwAEPjspVgAGRmlu" +
"aXNoAB1Kdm10aVJlZGVmaW5lQ2xhc3Nlc1Rlc3QuamF2YQA0TGFuZHJvaWQvanZtdGkvY3RzL0p2" +
"bXRpUmVkZWZpbmVDbGFzc2VzVGVzdCRDb25zdW1lcgA1TGFuZHJvaWQvanZtdGkvY3RzL0p2bXRp" +
"UmVkZWZpbmVDbGFzc2VzVGVzdCRDb25zdW1lcjsANkxhbmRyb2lkL2p2bXRpL2N0cy9Kdm10aVJl" +
"ZGVmaW5lQ2xhc3Nlc1Rlc3QkVHJhbnNmb3JtOwAsTGFuZHJvaWQvanZtdGkvY3RzL0p2bXRpUmVk" +
"ZWZpbmVDbGFzc2VzVGVzdDsAIkxkYWx2aWsvYW5ub3RhdGlvbi9FbmNsb3NpbmdDbGFzczsAHkxk" +
"YWx2aWsvYW5ub3RhdGlvbi9Jbm5lckNsYXNzOwAdTGRhbHZpay9hbm5vdGF0aW9uL1NpZ25hdHVy" +
"ZTsAEkxqYXZhL2xhbmcvT2JqZWN0OwAUTGphdmEvbGFuZy9SdW5uYWJsZTsAEkxqYXZhL2xhbmcv" +
"U3RyaW5nOwAfUG9zdCBGaW5pc2ggcHJpdmF0ZSBtZXRob2QgY2FsbAAeUG9zdCBTdGFydCBwcml2" +
"YXRlIG1ldGhvZCBjYWxsAB5QcmUgRmluaXNoIHByaXZhdGUgbWV0aG9kIGNhbGwAHVByZSBTdGFy" +
"dCBwcml2YXRlIG1ldGhvZCBjYWxsAAVTdGFydAAJVHJhbnNmb3JtAAFWAAJWTAAGYWNjZXB0AAth" +
"Y2Nlc3NGbGFncwARZ29vZGJ5ZSAtIHByaXZhdGUAD2hlbGxvIC0gcHJpdmF0ZQAEbmFtZQAIcmVw" +
"b3J0ZXIAA3J1bgAFc2F5SGkABXZhbHVlAAEAAAAAAAAAAQAAAAYAAAABAAAABwAAAAwBAAcOPC0A" +
"FQAHDocAEQAHDocAGQEABw6HPIc8hzyHAAAAAAIAAgABAAAAbAQAAAYAAABwEAUAAABbAQAADgAD" +
"AAEAAgAAAHQEAAAJAAAAVCAAABsBGwAAAHIgAAAQAA4AAAADAAEAAgAAAHoEAAAJAAAAVCAAABsB" +
"HAAAAHIgAAAQAA4AAAAEAAIAAgAAAIAEAAAqAAAAVCAAABsBFAAAAHIgAAAQAHAQAwACAFQgAAAb" +
"ARIAAAByIAAAEAByEAYAAwBUIAAAGwETAAAAciAAABAAcBACAAIAVCAAABsBEQAAAHIgAAAQAA4A" +
"AAEDAQACAYGABJAJAQKsCQEC0AkEAfQJAgMBIRgCAgQCGgQIHRcWAgUBIRwEFwcXARcQFwMCBQEh" +
"HAUXABcHFwEXEBcEAAAAAgAAAHAFAAB2BQAAAQAAAH8FAAABAAAAjQUAAKAFAAABAAAAAQAAAAAA" +
"AAAAAAAArAUAAAEAAAC0BQAAEAAAAAAAAAABAAAAAAAAAAEAAAAiAAAAcAAAAAIAAAAJAAAA+AAA" +
"AAMAAAAEAAAAHAEAAAQAAAABAAAATAEAAAUAAAAHAAAAVAEAAAYAAAABAAAAjAEAAAIgAAAiAAAA" +
"rAEAAAEQAAADAAAAVAQAAAMgAAAEAAAAbAQAAAEgAAAEAAAAkAQAAAAgAAABAAAAWAUAAAQgAAAE" +
"AAAAcAUAAAMQAAADAAAAoAUAAAYgAAABAAAAvAUAAAAQAAABAAAA3AUAAA==");
/**
* Base64 encoded dex file containing the following inner class.
* <code>
* // NB This has the actual name Landroid/jvmti/cts/JvmtiRedefineClassesTest$Transform;
* static class Transform {
* // NB This field has type Landroid/jvmti/cts/JvmtiRedefineClassesTest$Consumer;
* private Consumer<String> reporter;
* public Transform(Consumer<String> reporter) {
* this.reporter = reporter;
* }
* private void Start() {
* reporter.accept("TRANSFORMED - Hello - private");
* }
* private void Finish() {
* reporter.accept("TRANSFORMED - Goodbye - private");
* }
* public void sayHi(Runnable r) {
* reporter.accept("TRANSFORMED - pre Start private method call");
* Start();
* reporter.accept("TRANSFORMED - post Start private method call");
* r.run();
* reporter.accept("TRANSFORMED - pre Finish private method call");
* Finish();
* reporter.accept("TRANSFORMED - post Finish private method call");
* }
* }
* </code>
*/
private static final RedefineError GOOD_TRANSFORM = new RedefineError(
JvmtiErrors.NONE, Transform.class,
"ZGV4CjAzNQBmR3TRAAAAAAAAAAAAAAAAAAAAAAAAAAD0BgAAcAAAAHhWNBIAAAAAAAAAADAGAAAi" +
"AAAAcAAAAAkAAAD4AAAABAAAABwBAAABAAAATAEAAAcAAABUAQAAAQAAAIwBAABIBQAArAEAAKwB" +
"AACvAQAAsgEAALoBAAC+AQAAxAEAAMwBAADrAQAAIQIAAFgCAACQAgAAvgIAAOICAAACAwAAIQMA" +
"ADUDAABLAwAAXwMAAGYDAACHAwAApgMAANUDAAADBAAAMQQAAF4EAABpBAAAbAQAAHAEAAB4BAAA" +
"hQQAAIsEAACVBAAAmgQAAKEEAAAIAAAACQAAAAoAAAALAAAADAAAAA0AAAAOAAAADwAAABkAAAAZ" +
"AAAACAAAAAAAAAAaAAAACAAAAKgEAAAaAAAACAAAALAEAAAaAAAACAAAALgEAAABAAAAHgAAAAAA" +
"AgAbAAAAAQABAAIAAAABAAAABQAAAAEAAAARAAAAAQADACAAAAAGAAAAAgAAAAcAAAAfAAAAAQAA" +
"AAAAAAAGAAAAAAAAAAYAAAAQBgAArAUAAAAAAAABKAABPAAGPGluaXQ+AAI+OwAEPjspVgAGRmlu" +
"aXNoAB1Kdm10aVJlZGVmaW5lQ2xhc3Nlc1Rlc3QuamF2YQA0TGFuZHJvaWQvanZtdGkvY3RzL0p2" +
"bXRpUmVkZWZpbmVDbGFzc2VzVGVzdCRDb25zdW1lcgA1TGFuZHJvaWQvanZtdGkvY3RzL0p2bXRp" +
"UmVkZWZpbmVDbGFzc2VzVGVzdCRDb25zdW1lcjsANkxhbmRyb2lkL2p2bXRpL2N0cy9Kdm10aVJl" +
"ZGVmaW5lQ2xhc3Nlc1Rlc3QkVHJhbnNmb3JtOwAsTGFuZHJvaWQvanZtdGkvY3RzL0p2bXRpUmVk" +
"ZWZpbmVDbGFzc2VzVGVzdDsAIkxkYWx2aWsvYW5ub3RhdGlvbi9FbmNsb3NpbmdDbGFzczsAHkxk" +
"YWx2aWsvYW5ub3RhdGlvbi9Jbm5lckNsYXNzOwAdTGRhbHZpay9hbm5vdGF0aW9uL1NpZ25hdHVy" +
"ZTsAEkxqYXZhL2xhbmcvT2JqZWN0OwAUTGphdmEvbGFuZy9SdW5uYWJsZTsAEkxqYXZhL2xhbmcv" +
"U3RyaW5nOwAFU3RhcnQAH1RSQU5TRk9STUVEIC0gR29vZGJ5ZSAtIHByaXZhdGUAHVRSQU5TRk9S" +
"TUVEIC0gSGVsbG8gLSBwcml2YXRlAC1UUkFOU0ZPUk1FRCAtIHBvc3QgRmluaXNoIHByaXZhdGUg" +
"bWV0aG9kIGNhbGwALFRSQU5TRk9STUVEIC0gcG9zdCBTdGFydCBwcml2YXRlIG1ldGhvZCBjYWxs" +
"ACxUUkFOU0ZPUk1FRCAtIHByZSBGaW5pc2ggcHJpdmF0ZSBtZXRob2QgY2FsbAArVFJBTlNGT1JN" +
"RUQgLSBwcmUgU3RhcnQgcHJpdmF0ZSBtZXRob2QgY2FsbAAJVHJhbnNmb3JtAAFWAAJWTAAGYWNj" +
"ZXB0AAthY2Nlc3NGbGFncwAEbmFtZQAIcmVwb3J0ZXIAA3J1bgAFc2F5SGkABXZhbHVlAAEAAAAA" +
"AAAAAQAAAAYAAAABAAAABwAAAAsBAAcOPC0AFAAHDocAEAAHDocAGAEABw6HPIc8hzyHAAAAAAIA" +
"AgABAAAAwAQAAAYAAABwEAUAAABbAQAADgADAAEAAgAAAMgEAAAJAAAAVCAAABsBEgAAAHIgAAAQ" +
"AA4AAAADAAEAAgAAAM4EAAAJAAAAVCAAABsBEwAAAHIgAAAQAA4AAAAEAAIAAgAAANQEAAAqAAAA" +
"VCAAABsBFwAAAHIgAAAQAHAQAwACAFQgAAAbARUAAAByIAAAEAByEAYAAwBUIAAAGwEWAAAAciAA" +
"ABAAcBACAAIAVCAAABsBFAAAAHIgAAAQAA4AAAEDAQACAYGABOQJAQKACgECpAoEAcgKAgMBIRgC" +
"AgQCHAQIHRcYAgUBIRwEFwcXARcQFwMCBQEhHAUXABcHFwEXEBcEAAAAAgAAAMQFAADKBQAAAQAA" +
"ANMFAAABAAAA4QUAAPQFAAABAAAAAQAAAAAAAAAAAAAAAAYAAAEAAAAIBgAAEAAAAAAAAAABAAAA" +
"AAAAAAEAAAAiAAAAcAAAAAIAAAAJAAAA+AAAAAMAAAAEAAAAHAEAAAQAAAABAAAATAEAAAUAAAAH" +
"AAAAVAEAAAYAAAABAAAAjAEAAAIgAAAiAAAArAEAAAEQAAADAAAAqAQAAAMgAAAEAAAAwAQAAAEg" +
"AAAEAAAA5AQAAAAgAAABAAAArAUAAAQgAAAEAAAAxAUAAAMQAAADAAAA9AUAAAYgAAABAAAAEAYA" +
"AAAQAAABAAAAMAYAAA==");
/**
* Tests that we can redefine Transform class from INITIAL_TRANSFORM to GOOD_TRANSFORM.
* <p>
* It uses doRedefine to do the transformation.
*/
private void checkRedefinedTransform(Runnable doRedefine) {
// The consumer that we use to observe the changes to the Transform class.
final StringCollector c = new StringCollector();
Transform t = new Transform(c);
// Run once without changes.
t.sayHi(new Runnable() {
public void run() {
c.accept("Initial test run. No changes.");
}
});
// Run once with obsolete methods.
t.sayHi(new Runnable() {
public void run() {
c.accept("Redefining calling function.");
doRedefine.run();
}
});
// Run once with new definition.
t.sayHi(new Runnable() {
public void run() {
c.accept("Final test run.");
}
});
String[] output = c.reports.toArray(new String[0]);
assertArrayEquals(
new String[]{
// The first call to sayHi
"Pre Start private method call",
"hello - private",
"Post Start private method call",
"Initial test run. No changes.",
"Pre Finish private method call",
"goodbye - private",
"Post Finish private method call",
// The second call to sayHi.
"Pre Start private method call",
"hello - private",
"Post Start private method call",
"Redefining calling function.",
"Pre Finish private method call",
"TRANSFORMED - Goodbye - private",
"Post Finish private method call",
// The final call to sayHi.
"TRANSFORMED - pre Start private method call",
"TRANSFORMED - Hello - private",
"TRANSFORMED - post Start private method call",
"Final test run.",
"TRANSFORMED - pre Finish private method call",
"TRANSFORMED - Goodbye - private",
"TRANSFORMED - post Finish private method call",
}, output);
}
@Test
public void testSucessfulRedefine() throws Exception {
checkRedefinedTransform(new Runnable() {
public void run() {
checkRedefinition(GOOD_TRANSFORM);
}
});
}
@Test
public void testSucessfulRetransform() throws Exception {
pushTransformationResult(GOOD_TRANSFORM.target, GOOD_TRANSFORM.dexData);
checkRedefinedTransform(new Runnable() {
public void run() {
setTransformationEvent(true);
assertEquals(JvmtiErrors.NONE, retransformClass(Transform.class));
}
});
}
// This is a class that we will transform for tests.
// NB This has the actual name Landroid/jvmti/cts/JvmtiRedefineClassesTest$Transform2;
static class Transform2 {
public void sayHi() {
Assert.fail("Should not be called!");
}
}
/**
* Test cases for failing redefines.
*/
private static final RedefineError[] FAILING_DEX_FILES = {
/**
* Base64 for this class.
*
* .class Landroid/jvmti/cts/JvmtiRedefineClassesTest$Transform2;
* .super Ljava/lang/Object;
* .source "JvmtiRedefineClassesTest.java"
*
* # annotations
* .annotation system Ldalvik/annotation/EnclosingClass;
* value = Landroid/jvmti/cts/JvmtiRedefineClassesTest;
* .end annotation
*
* .annotation system Ldalvik/annotation/InnerClass;
* accessFlags = 0x8
* name = "Transform2"
* .end annotation
*
* # direct methods
* .method constructor <init>()V
* .registers 1
* .prologue
* .line 33
* invoke-direct {p0}, Ljava/lang/Object;-><init>()V
* return-void
* .end method
*
* # virtual methods
* .method public sayHi()V
* .registers 1
* .prologue
* .line 35
* return-object v0
* .end method
*/
new RedefineError(JvmtiErrors.FAILS_VERIFICATION, Transform2.class,
"ZGV4CjAzNQBOhefYdQRcgqmkwhWsSyzb5I3udX0SnJ44AwAAcAAAAHhWNBIAAAAAAAAAAIwCAAAN" +
"AAAAcAAAAAYAAACkAAAAAQAAALwAAAAAAAAAAAAAAAMAAADIAAAAAQAAAOAAAAA4AgAAAAEAAAAB" +
"AAAIAQAAJwEAAGABAACOAQAAsgEAANIBAADmAQAA8gEAAPUBAAACAgAACAIAAA8CAAACAAAAAwAA" +
"AAQAAAAFAAAABgAAAAgAAAAIAAAABQAAAAAAAAAAAAAAAAAAAAAAAAALAAAABAAAAAAAAAAAAAAA" +
"AAAAAAQAAAAAAAAAAQAAADgCAAB+AgAAAAAAAAY8aW5pdD4AHUp2bXRpUmVkZWZpbmVDbGFzc2Vz" +
"VGVzdC5qYXZhADdMYW5kcm9pZC9qdm10aS9jdHMvSnZtdGlSZWRlZmluZUNsYXNzZXNUZXN0JFRy" +
"YW5zZm9ybTI7ACxMYW5kcm9pZC9qdm10aS9jdHMvSnZtdGlSZWRlZmluZUNsYXNzZXNUZXN0OwAi" +
"TGRhbHZpay9hbm5vdGF0aW9uL0VuY2xvc2luZ0NsYXNzOwAeTGRhbHZpay9hbm5vdGF0aW9uL0lu" +
"bmVyQ2xhc3M7ABJMamF2YS9sYW5nL09iamVjdDsAClRyYW5zZm9ybTIAAVYAC2FjY2Vzc0ZsYWdz" +
"AARuYW1lAAVzYXlIaQAFdmFsdWUAAAACAwIJBAgKFwcCAgEMGAEAAAAAAAIAAAAhAgAAGAIAACwC" +
"AAAAAAAAAAAAAAAAAAAhAAcOACMABw4AAAABAAEAAQAAAEgCAAAEAAAAcBACAAAADgACAAEAAAAA" +
"AE0CAAABAAAAEQAAAAEBAICABNQEAQHsBA4AAAAAAAAAAQAAAAAAAAABAAAADQAAAHAAAAACAAAA" +
"BgAAAKQAAAADAAAAAQAAALwAAAAFAAAAAwAAAMgAAAAGAAAAAQAAAOAAAAACIAAADQAAAAABAAAE" +
"IAAAAgAAABgCAAADEAAAAgAAACgCAAAGIAAAAQAAADgCAAADIAAAAgAAAEgCAAABIAAAAgAAAFQC" +
"AAAAIAAAAQAAAH4CAAAAEAAAAQAAAIwCAAA="),
/**
* Base64 for this class.
*
* static class Transform {
* private Consumer<String> reporter;
* public Transform(Consumer<String> reporter) {
* this.reporter = reporter;
* }
* private void Start() { }
* private void Finish() { }
* protected void sayHi(Runnable r) { }
* }
*/
new RedefineError(
JvmtiErrors.UNSUPPORTED_REDEFINITION_METHOD_MODIFIERS_CHANGED, Transform.class,
"ZGV4CjAzNQAf2DrkAAAAAAAAAAAAAAAAAAAAAAAAAAAwBQAAcAAAAHhWNBIAAAAAAAAAAGwEAAAa" +
"AAAAcAAAAAkAAADYAAAAAwAAAPwAAAABAAAAIAEAAAUAAAAoAQAAAQAAAFABAADAAwAAcAEAAHAB" +
"AABzAQAAdgEAAH4BAACCAQAAiAEAAJABAACvAQAA5QEAABwCAABUAgAAggIAAKYCAADGAgAA5QIA" +
"APkCAAAPAwAAIwMAACoDAAA1AwAAOAMAADwDAABJAwAATwMAAFkDAABgAwAACAAAAAkAAAAKAAAA" +
"CwAAAAwAAAANAAAADgAAAA8AAAATAAAAEwAAAAgAAAAAAAAAFAAAAAgAAABoAwAAFAAAAAgAAABw" +
"AwAAAQAAABcAAAABAAEAAgAAAAEAAAAFAAAAAQAAABEAAAABAAIAGAAAAAYAAAACAAAAAQAAAAAA" +
"AAAGAAAAAAAAAAYAAABMBAAA6AMAAAAAAAABKAABPAAGPGluaXQ+AAI+OwAEPjspVgAGRmluaXNo" +
"AB1Kdm10aVJlZGVmaW5lQ2xhc3Nlc1Rlc3QuamF2YQA0TGFuZHJvaWQvanZtdGkvY3RzL0p2bXRp" +
"UmVkZWZpbmVDbGFzc2VzVGVzdCRDb25zdW1lcgA1TGFuZHJvaWQvanZtdGkvY3RzL0p2bXRpUmVk" +
"ZWZpbmVDbGFzc2VzVGVzdCRDb25zdW1lcjsANkxhbmRyb2lkL2p2bXRpL2N0cy9Kdm10aVJlZGVm" +
"aW5lQ2xhc3Nlc1Rlc3QkVHJhbnNmb3JtOwAsTGFuZHJvaWQvanZtdGkvY3RzL0p2bXRpUmVkZWZp" +
"bmVDbGFzc2VzVGVzdDsAIkxkYWx2aWsvYW5ub3RhdGlvbi9FbmNsb3NpbmdDbGFzczsAHkxkYWx2" +
"aWsvYW5ub3RhdGlvbi9Jbm5lckNsYXNzOwAdTGRhbHZpay9hbm5vdGF0aW9uL1NpZ25hdHVyZTsA" +
"EkxqYXZhL2xhbmcvT2JqZWN0OwAUTGphdmEvbGFuZy9SdW5uYWJsZTsAEkxqYXZhL2xhbmcvU3Ry" +
"aW5nOwAFU3RhcnQACVRyYW5zZm9ybQABVgACVkwAC2FjY2Vzc0ZsYWdzAARuYW1lAAhyZXBvcnRl" +
"cgAFc2F5SGkABXZhbHVlAAABAAAAAAAAAAEAAAAHAAAACwEABw48LQARAAcOAA8ABw4AEwEABw4A" +
"AgACAAEAAAB4AwAABgAAAHAQBAAAAFsBAAAOAAEAAQAAAAAAgAMAAAEAAAAOAAAAAQABAAAAAACF" +
"AwAAAQAAAA4AAAACAAIAAAAAAIoDAAABAAAADgAAAAABAwEAAgCBgASQBwECrAcBAsAHAwTUBwID" +
"ARkYAgIEAhUECBYXEgIFARkcBBcHFwEXEBcDAgUBGRwFFwAXBxcBFxAXBAAAAAIAAAAABAAABgQA" +
"AAEAAAAPBAAAAQAAAB0EAAAwBAAAAQAAAAEAAAAAAAAAAAAAADwEAAAAAAAARAQAABAAAAAAAAAA" +
"AQAAAAAAAAABAAAAGgAAAHAAAAACAAAACQAAANgAAAADAAAAAwAAAPwAAAAEAAAAAQAAACABAAAF" +
"AAAABQAAACgBAAAGAAAAAQAAAFABAAACIAAAGgAAAHABAAABEAAAAgAAAGgDAAADIAAABAAAAHgD" +
"AAABIAAABAAAAJADAAAAIAAAAQAAAOgDAAAEIAAABAAAAAAEAAADEAAAAwAAADAEAAAGIAAAAQAA" +
"AEwEAAAAEAAAAQAAAGwEAAA="),
/**
* Base64 for this class.
*
* static final class Transform {
* private Consumer<String> reporter;
* public Transform(Consumer<String> reporter) {
* this.reporter = reporter;
* }
* private void Start() { }
* private void Finish() { }
* public void sayHi(Runnable r) { }
* }
*/
new RedefineError(
JvmtiErrors.UNSUPPORTED_REDEFINITION_CLASS_MODIFIERS_CHANGED, Transform.class,
"ZGV4CjAzNQA82MAwAAAAAAAAAAAAAAAAAAAAAAAAAAAwBQAAcAAAAHhWNBIAAAAAAAAAAGwEAAAa" +
"AAAAcAAAAAkAAADYAAAAAwAAAPwAAAABAAAAIAEAAAUAAAAoAQAAAQAAAFABAADAAwAAcAEAAHAB" +
"AABzAQAAdgEAAH4BAACCAQAAiAEAAJABAACvAQAA5QEAABwCAABUAgAAggIAAKYCAADGAgAA5QIA" +
"APkCAAAPAwAAIwMAACoDAAA1AwAAOAMAADwDAABJAwAATwMAAFkDAABgAwAACAAAAAkAAAAKAAAA" +
"CwAAAAwAAAANAAAADgAAAA8AAAATAAAAEwAAAAgAAAAAAAAAFAAAAAgAAABoAwAAFAAAAAgAAABw" +
"AwAAAQAAABcAAAABAAEAAgAAAAEAAAAFAAAAAQAAABEAAAABAAIAGAAAAAYAAAACAAAAAQAAABAA" +
"AAAGAAAAAAAAAAYAAABMBAAA6AMAAAAAAAABKAABPAAGPGluaXQ+AAI+OwAEPjspVgAGRmluaXNo" +
"AB1Kdm10aVJlZGVmaW5lQ2xhc3Nlc1Rlc3QuamF2YQA0TGFuZHJvaWQvanZtdGkvY3RzL0p2bXRp" +
"UmVkZWZpbmVDbGFzc2VzVGVzdCRDb25zdW1lcgA1TGFuZHJvaWQvanZtdGkvY3RzL0p2bXRpUmVk" +
"ZWZpbmVDbGFzc2VzVGVzdCRDb25zdW1lcjsANkxhbmRyb2lkL2p2bXRpL2N0cy9Kdm10aVJlZGVm" +
"aW5lQ2xhc3Nlc1Rlc3QkVHJhbnNmb3JtOwAsTGFuZHJvaWQvanZtdGkvY3RzL0p2bXRpUmVkZWZp" +
"bmVDbGFzc2VzVGVzdDsAIkxkYWx2aWsvYW5ub3RhdGlvbi9FbmNsb3NpbmdDbGFzczsAHkxkYWx2" +
"aWsvYW5ub3RhdGlvbi9Jbm5lckNsYXNzOwAdTGRhbHZpay9hbm5vdGF0aW9uL1NpZ25hdHVyZTsA" +
"EkxqYXZhL2xhbmcvT2JqZWN0OwAUTGphdmEvbGFuZy9SdW5uYWJsZTsAEkxqYXZhL2xhbmcvU3Ry" +
"aW5nOwAFU3RhcnQACVRyYW5zZm9ybQABVgACVkwAC2FjY2Vzc0ZsYWdzAARuYW1lAAhyZXBvcnRl" +
"cgAFc2F5SGkABXZhbHVlAAABAAAAAAAAAAEAAAAHAAAACwEABw48LQARAAcOAA8ABw4AEwEABw4A" +
"AgACAAEAAAB4AwAABgAAAHAQBAAAAFsBAAAOAAEAAQAAAAAAgAMAAAEAAAAOAAAAAQABAAAAAACF" +
"AwAAAQAAAA4AAAACAAIAAAAAAIoDAAABAAAADgAAAAABAwEAAgCBgASQBwECrAcBAsAHAwHUBwID" +
"ARkYAgIEAhUEGBYXEgIFARkcBBcHFwEXEBcDAgUBGRwFFwAXBxcBFxAXBAAAAAIAAAAABAAABgQA" +
"AAEAAAAPBAAAAQAAAB0EAAAwBAAAAQAAAAEAAAAAAAAAAAAAADwEAAAAAAAARAQAABAAAAAAAAAA" +
"AQAAAAAAAAABAAAAGgAAAHAAAAACAAAACQAAANgAAAADAAAAAwAAAPwAAAAEAAAAAQAAACABAAAF" +
"AAAABQAAACgBAAAGAAAAAQAAAFABAAACIAAAGgAAAHABAAABEAAAAgAAAGgDAAADIAAABAAAAHgD" +
"AAABIAAABAAAAJADAAAAIAAAAQAAAOgDAAAEIAAABAAAAAAEAAADEAAAAwAAADAEAAAGIAAAAQAA" +
"AEwEAAAAEAAAAQAAAGwEAAA="),
/**
* Base64 for this class.
*
* static class Transform {
* private Consumer<String> reporter;
* public Transform(Consumer<String> reporter) {
* this.reporter = reporter;
* }
* private void Finish() { }
* public void sayHi(Runnable r) { }
* }
*/
new RedefineError(
JvmtiErrors.UNSUPPORTED_REDEFINITION_METHOD_DELETED, Transform.class,
"ZGV4CjAzNQBG028hAAAAAAAAAAAAAAAAAAAAAAAAAAAABQAAcAAAAHhWNBIAAAAAAAAAADwEAAAZ" +
"AAAAcAAAAAkAAADUAAAAAwAAAPgAAAABAAAAHAEAAAQAAAAkAQAAAQAAAEQBAACcAwAAZAEAAGQB" +
"AABnAQAAagEAAHIBAAB2AQAAfAEAAJsBAADRAQAACAIAAEACAABuAgAAkgIAALICAADRAgAA5QIA" +
"APsCAAAPAwAAFgMAACEDAAAkAwAAKAMAADUDAAA7AwAARQMAAEwDAAAHAAAACAAAAAkAAAAKAAAA" +
"CwAAAAwAAAANAAAADgAAABIAAAASAAAACAAAAAAAAAATAAAACAAAAFQDAAATAAAACAAAAFwDAAAB" +
"AAAAFgAAAAEAAQACAAAAAQAAABAAAAABAAIAFwAAAAYAAAACAAAAAQAAAAAAAAAGAAAAAAAAAAUA" +
"AAAcBAAAvAMAAAAAAAABKAABPAAGPGluaXQ+AAI+OwAEPjspVgAdSnZtdGlSZWRlZmluZUNsYXNz" +
"ZXNUZXN0LmphdmEANExhbmRyb2lkL2p2bXRpL2N0cy9Kdm10aVJlZGVmaW5lQ2xhc3Nlc1Rlc3Qk" +
"Q29uc3VtZXIANUxhbmRyb2lkL2p2bXRpL2N0cy9Kdm10aVJlZGVmaW5lQ2xhc3Nlc1Rlc3QkQ29u" +
"c3VtZXI7ADZMYW5kcm9pZC9qdm10aS9jdHMvSnZtdGlSZWRlZmluZUNsYXNzZXNUZXN0JFRyYW5z" +
"Zm9ybTsALExhbmRyb2lkL2p2bXRpL2N0cy9Kdm10aVJlZGVmaW5lQ2xhc3Nlc1Rlc3Q7ACJMZGFs" +
"dmlrL2Fubm90YXRpb24vRW5jbG9zaW5nQ2xhc3M7AB5MZGFsdmlrL2Fubm90YXRpb24vSW5uZXJD" +
"bGFzczsAHUxkYWx2aWsvYW5ub3RhdGlvbi9TaWduYXR1cmU7ABJMamF2YS9sYW5nL09iamVjdDsA" +
"FExqYXZhL2xhbmcvUnVubmFibGU7ABJMamF2YS9sYW5nL1N0cmluZzsABVN0YXJ0AAlUcmFuc2Zv" +
"cm0AAVYAAlZMAAthY2Nlc3NGbGFncwAEbmFtZQAIcmVwb3J0ZXIABXNheUhpAAV2YWx1ZQAAAQAA" +
"AAAAAAABAAAABwAAAA0BAAcOAA4ABw4AEAEABw4AAAAAAgACAAEAAABkAwAABgAAAHAQAwAAAFsB" +
"AAAOAAEAAQAAAAAAagMAAAEAAAAOAAAAAgACAAAAAABvAwAAAQAAAA4AAAAAAQIBAAIAgYAE+AYB" +
"ApQHAgGoBwIDARgYAgIEAhQECBUXEQIFARgcBBcGFwEXDxcDAgUBGBwFFwAXBhcBFw8XBAAAAAIA" +
"AADQAwAA1gMAAAEAAADfAwAAAQAAAO0DAAAABAAAAQAAAAEAAAAAAAAAAAAAAAwEAAAAAAAAFAQA" +
"ABAAAAAAAAAAAQAAAAAAAAABAAAAGQAAAHAAAAACAAAACQAAANQAAAADAAAAAwAAAPgAAAAEAAAA" +
"AQAAABwBAAAFAAAABAAAACQBAAAGAAAAAQAAAEQBAAACIAAAGQAAAGQBAAABEAAAAgAAAFQDAAAD" +
"IAAAAwAAAGQDAAABIAAAAwAAAHgDAAAAIAAAAQAAALwDAAAEIAAABAAAANADAAADEAAAAwAAAAAE" +
"AAAGIAAAAQAAABwEAAAAEAAAAQAAADwEAAA="),
/**
* Base6is class.
*
* static class Transform {
* private Consumer<String> reporter;
* public Transform(Consumer<String> reporter) {
* this.reporter = reporter;
* }
* private void Start() { }
* private void Start2() { }
* private void Finish() { }
* public void sayHi(Runnable r) { }
* }
*/
new RedefineError(
JvmtiErrors.UNSUPPORTED_REDEFINITION_METHOD_ADDED, Transform.class,
"ZGV4CjAzNQC43HElAAAAAAAAAAAAAAAAAAAAAAAAAABgBQAAcAAAAHhWNBIAAAAAAAAAAJwEAAAb" +
"AAAAcAAAAAkAAADcAAAAAwAAAAABAAABAAAAJAEAAAYAAAAsAQAAAQAAAFwBAADkAwAAfAEAAHwB" +
"AAB/AQAAggEAAIoBAACOAQAAlAEAAJwBAAC7AQAA8QEAACgCAABgAgAAjgIAALICAADSAgAA8QIA" +
"AAUDAAAbAwAALwMAADYDAAA+AwAASQMAAEwDAABQAwAAXQMAAGMDAABtAwAAdAMAAAgAAAAJAAAA" +
"CgAAAAsAAAAMAAAADQAAAA4AAAAPAAAAFAAAABQAAAAIAAAAAAAAABUAAAAIAAAAfAMAABUAAAAI" +
"AAAAhAMAAAEAAAAYAAAAAQABAAIAAAABAAAABQAAAAEAAAARAAAAAQAAABIAAAABAAIAGQAAAAYA" +
"AAACAAAAAQAAAAAAAAAGAAAAAAAAAAYAAAB8BAAAFAQAAAAAAAABKAABPAAGPGluaXQ+AAI+OwAE" +
"PjspVgAGRmluaXNoAB1Kdm10aVJlZGVmaW5lQ2xhc3Nlc1Rlc3QuamF2YQA0TGFuZHJvaWQvanZt" +
"dGkvY3RzL0p2bXRpUmVkZWZpbmVDbGFzc2VzVGVzdCRDb25zdW1lcgA1TGFuZHJvaWQvanZtdGkv" +
"Y3RzL0p2bXRpUmVkZWZpbmVDbGFzc2VzVGVzdCRDb25zdW1lcjsANkxhbmRyb2lkL2p2bXRpL2N0" +
"cy9Kdm10aVJlZGVmaW5lQ2xhc3Nlc1Rlc3QkVHJhbnNmb3JtOwAsTGFuZHJvaWQvanZtdGkvY3Rz" +
"L0p2bXRpUmVkZWZpbmVDbGFzc2VzVGVzdDsAIkxkYWx2aWsvYW5ub3RhdGlvbi9FbmNsb3NpbmdD" +
"bGFzczsAHkxkYWx2aWsvYW5ub3RhdGlvbi9Jbm5lckNsYXNzOwAdTGRhbHZpay9hbm5vdGF0aW9u" +
"L1NpZ25hdHVyZTsAEkxqYXZhL2xhbmcvT2JqZWN0OwAUTGphdmEvbGFuZy9SdW5uYWJsZTsAEkxq" +
"YXZhL2xhbmcvU3RyaW5nOwAFU3RhcnQABlN0YXJ0MgAJVHJhbnNmb3JtAAFWAAJWTAALYWNjZXNz" +
"RmxhZ3MABG5hbWUACHJlcG9ydGVyAAVzYXlIaQAFdmFsdWUAAAEAAAAAAAAAAQAAAAcAAAANAQAH" +
"DgAQAAcOAA4ABw4ADwAHDgARAQAHDgAAAgACAAEAAACMAwAABgAAAHAQBQAAAFsBAAAOAAEAAQAA" +
"AAAAkgMAAAEAAAAOAAAAAQABAAAAAACXAwAAAQAAAA4AAAABAAEAAAAAAJwDAAABAAAADgAAAAIA" +
"AgAAAAAAoQMAAAEAAAAOAAAAAAEEAQACAIGABKgHAQLEBwEC2AcBAuwHBAGACAIDARoYAgIEAhYE" +
"CBcXEwIFARocBBcHFwEXEBcDAgUBGhwFFwAXBxcBFxAXBAAAAAIAAAAwBAAANgQAAAEAAAA/BAAA" +
"AQAAAE0EAABgBAAAAQAAAAEAAAAAAAAAAAAAAGwEAAAAAAAAdAQAABAAAAAAAAAAAQAAAAAAAAAB" +
"AAAAGwAAAHAAAAACAAAACQAAANwAAAADAAAAAwAAAAABAAAEAAAAAQAAACQBAAAFAAAABgAAACwB" +
"AAAGAAAAAQAAAFwBAAACIAAAGwAAAHwBAAABEAAAAgAAAHwDAAADIAAABQAAAIwDAAABIAAABQAA" +
"AKgDAAAAIAAAAQAAABQEAAAEIAAABAAAADAEAAADEAAAAwAAAGAEAAAGIAAAAQAAAHwEAAAAEAAA" +
"AQAAAJwEAAA="),
/**
* Base64 for this class.
*
* static class Transform {
* public Transform(Consumer<String> reporter) { }
* private void Start() { }
* private void Finish() { }
* public void sayHi(Runnable r) { }
* }
*/
new RedefineError(
JvmtiErrors.UNSUPPORTED_REDEFINITION_SCHEMA_CHANGED, Transform.class,
"ZGV4CjAzNQCn0K9/AAAAAAAAAAAAAAAAAAAAAAAAAADkBAAAcAAAAHhWNBIAAAAAAAAAACwEAAAY" +
"AAAAcAAAAAkAAADQAAAAAwAAAPQAAAAAAAAAAAAAAAUAAAAYAQAAAQAAAEABAACEAwAAYAEAAGAB" +
"AABjAQAAZgEAAG4BAAB0AQAAfAEAAJsBAADRAQAACAIAAEACAABuAgAAkgIAALICAADRAgAA5QIA" +
"APsCAAAPAwAAFgMAACEDAAAkAwAAKAMAADUDAAA7AwAAQgMAAAcAAAAIAAAACQAAAAoAAAALAAAA" +
"DAAAAA0AAAAOAAAAEgAAABIAAAAIAAAAAAAAABMAAAAIAAAATAMAABMAAAAIAAAAVAMAAAEAAQAC" +
"AAAAAQAAAAQAAAABAAAAEAAAAAEAAgAWAAAABgAAAAIAAAABAAAAAAAAAAYAAAAAAAAABQAAABQE" +
"AADIAwAAAAAAAAEoAAE8AAY8aW5pdD4ABD47KVYABkZpbmlzaAAdSnZtdGlSZWRlZmluZUNsYXNz" +
"ZXNUZXN0LmphdmEANExhbmRyb2lkL2p2bXRpL2N0cy9Kdm10aVJlZGVmaW5lQ2xhc3Nlc1Rlc3Qk" +
"Q29uc3VtZXIANUxhbmRyb2lkL2p2bXRpL2N0cy9Kdm10aVJlZGVmaW5lQ2xhc3Nlc1Rlc3QkQ29u" +
"c3VtZXI7ADZMYW5kcm9pZC9qdm10aS9jdHMvSnZtdGlSZWRlZmluZUNsYXNzZXNUZXN0JFRyYW5z" +
"Zm9ybTsALExhbmRyb2lkL2p2bXRpL2N0cy9Kdm10aVJlZGVmaW5lQ2xhc3Nlc1Rlc3Q7ACJMZGFs" +
"dmlrL2Fubm90YXRpb24vRW5jbG9zaW5nQ2xhc3M7AB5MZGFsdmlrL2Fubm90YXRpb24vSW5uZXJD" +
"bGFzczsAHUxkYWx2aWsvYW5ub3RhdGlvbi9TaWduYXR1cmU7ABJMamF2YS9sYW5nL09iamVjdDsA" +
"FExqYXZhL2xhbmcvUnVubmFibGU7ABJMamF2YS9sYW5nL1N0cmluZzsABVN0YXJ0AAlUcmFuc2Zv" +
"cm0AAVYAAlZMAAthY2Nlc3NGbGFncwAEbmFtZQAFc2F5SGkABXZhbHVlAAAAAAEAAAAAAAAAAQAA" +
"AAcAAAAMAQAHDgAOAAcOAA0ABw4ADwEABw4AAAACAAIAAQAAAFwDAAAEAAAAcBAEAAAADgABAAEA" +
"AAAAAGIDAAABAAAADgAAAAEAAQAAAAAAZwMAAAEAAAAOAAAAAgACAAAAAABsAwAAAQAAAA4AAAAA" +
"AAMBAIGABPQGAQKMBwECoAcDAbQHAAACAwEXGAICBAIUBAgVFxECBQEXHAUXABcGFwEXDxcDAAIA" +
"AADgAwAA5gMAAAEAAADvAwAAAAQAAAAAAAABAAAAAAAAAAAAAAAMBAAADwAAAAAAAAABAAAAAAAA" +
"AAEAAAAYAAAAcAAAAAIAAAAJAAAA0AAAAAMAAAADAAAA9AAAAAUAAAAFAAAAGAEAAAYAAAABAAAA" +
"QAEAAAIgAAAYAAAAYAEAAAEQAAACAAAATAMAAAMgAAAEAAAAXAMAAAEgAAAEAAAAdAMAAAAgAAAB" +
"AAAAyAMAAAQgAAADAAAA4AMAAAMQAAACAAAAAAQAAAYgAAABAAAAFAQAAAAQAAABAAAALAQAAA=="),
/**
* Base64 for this class.
*
* static class Transform3 {
* // NB This field has type Landroid/jvmti/cts/JvmtiRedefineClassesTest$Consumer;
* private Consumer<String> reporter;
* public Transform3(Consumer<String> reporter) { this.reporter = reporter; }
* private void Start() { }
* private void Finish() { }
* public void sayHi(Runnable r) { }
* }
*/
new RedefineError(
JvmtiErrors.NAMES_DONT_MATCH, Transform.class,
"ZGV4CjAzNQCc2B3nAAAAAAAAAAAAAAAAAAAAAAAAAAA0BQAAcAAAAHhWNBIAAAAAAAAAAHAEAAAa" +
"AAAAcAAAAAkAAADYAAAAAwAAAPwAAAABAAAAIAEAAAUAAAAoAQAAAQAAAFABAADEAwAAcAEAAHAB" +
"AABzAQAAdgEAAH4BAACCAQAAiAEAAJABAACvAQAA5QEAABwCAABVAgAAgwIAAKcCAADHAgAA5gIA" +
"APoCAAAQAwAAJAMAACsDAAA3AwAAOgMAAD4DAABLAwAAUQMAAFsDAABiAwAACAAAAAkAAAAKAAAA" +
"CwAAAAwAAAANAAAADgAAAA8AAAATAAAAEwAAAAgAAAAAAAAAFAAAAAgAAABsAwAAFAAAAAgAAAB0" +
"AwAAAQAAABcAAAABAAEAAgAAAAEAAAAFAAAAAQAAABEAAAABAAIAGAAAAAYAAAACAAAAAQAAAAAA" +
"AAAGAAAAAAAAAAYAAABQBAAA7AMAAAAAAAABKAABPAAGPGluaXQ+AAI+OwAEPjspVgAGRmluaXNo" +
"AB1Kdm10aVJlZGVmaW5lQ2xhc3Nlc1Rlc3QuamF2YQA0TGFuZHJvaWQvanZtdGkvY3RzL0p2bXRp" +
"UmVkZWZpbmVDbGFzc2VzVGVzdCRDb25zdW1lcgA1TGFuZHJvaWQvanZtdGkvY3RzL0p2bXRpUmVk" +
"ZWZpbmVDbGFzc2VzVGVzdCRDb25zdW1lcjsAN0xhbmRyb2lkL2p2bXRpL2N0cy9Kdm10aVJlZGVm" +
"aW5lQ2xhc3Nlc1Rlc3QkVHJhbnNmb3JtMzsALExhbmRyb2lkL2p2bXRpL2N0cy9Kdm10aVJlZGVm" +
"aW5lQ2xhc3Nlc1Rlc3Q7ACJMZGFsdmlrL2Fubm90YXRpb24vRW5jbG9zaW5nQ2xhc3M7AB5MZGFs" +
"dmlrL2Fubm90YXRpb24vSW5uZXJDbGFzczsAHUxkYWx2aWsvYW5ub3RhdGlvbi9TaWduYXR1cmU7" +
"ABJMamF2YS9sYW5nL09iamVjdDsAFExqYXZhL2xhbmcvUnVubmFibGU7ABJMamF2YS9sYW5nL1N0" +
"cmluZzsABVN0YXJ0AApUcmFuc2Zvcm0zAAFWAAJWTAALYWNjZXNzRmxhZ3MABG5hbWUACHJlcG9y" +
"dGVyAAVzYXlIaQAFdmFsdWUAAAAAAQAAAAAAAAABAAAABwAAAAwBAAcOAA4ABw4ADQAHDgAPAQAH" +
"DgAAAAIAAgABAAAAfAMAAAYAAABwEAQAAABbAQAADgABAAEAAAAAAIIDAAABAAAADgAAAAEAAQAA" +
"AAAAhwMAAAEAAAAOAAAAAgACAAAAAACMAwAAAQAAAA4AAAAAAQMBAAIAgYAElAcBArAHAQLEBwMB" +
"2AcCAwEZGAICBAIVBAgWFxICBQEZHAQXBxcBFxAXAwIFARkcBRcAFwcXARcQFwQAAAACAAAABAQA" +
"AAoEAAABAAAAEwQAAAEAAAAhBAAANAQAAAEAAAABAAAAAAAAAAAAAABABAAAAAAAAEgEAAAQAAAA" +
"AAAAAAEAAAAAAAAAAQAAABoAAABwAAAAAgAAAAkAAADYAAAAAwAAAAMAAAD8AAAABAAAAAEAAAAg" +
"AQAABQAAAAUAAAAoAQAABgAAAAEAAABQAQAAAiAAABoAAABwAQAAARAAAAIAAABsAwAAAyAAAAQA" +
"AAB8AwAAASAAAAQAAACUAwAAACAAAAEAAADsAwAABCAAAAQAAAAEBAAAAxAAAAMAAAA0BAAABiAA" +
"AAEAAABQBAAAABAAAAEAAABwBAAA"),
/**
* Base64 for this class.
*
* static class Transform extends Observable {
* // NB This field has type Landroid/jvmti/cts/JvmtiRedefineClassesTest$Consumer;
* private Consumer<String> reporter;
* public Transform(Consumer<String> reporter) { super(); this.reporter = reporter; }
* private void Start() { }
* private void Finish() { }
* public void sayHi(Runnable r) { }
* }
*/
new RedefineError(
JvmtiErrors.UNSUPPORTED_REDEFINITION_HIERARCHY_CHANGED, Transform.class,
"ZGV4CjAzNQAV2qEZAAAAAAAAAAAAAAAAAAAAAAAAAAA0BQAAcAAAAHhWNBIAAAAAAAAAAHAEAAAa" +
"AAAAcAAAAAkAAADYAAAAAwAAAPwAAAABAAAAIAEAAAUAAAAoAQAAAQAAAFABAADEAwAAcAEAAHAB" +
"AABzAQAAdgEAAH4BAACCAQAAiAEAAJABAACvAQAA5QEAABwCAABUAgAAggIAAKYCAADGAgAA5QIA" +
"APsCAAAPAwAAJwMAAC4DAAA5AwAAPAMAAEADAABNAwAAUwMAAF0DAABkAwAACAAAAAkAAAAKAAAA" +
"CwAAAAwAAAANAAAADgAAABAAAAATAAAAEwAAAAgAAAAAAAAAFAAAAAgAAABsAwAAFAAAAAgAAAB0" +
"AwAAAQAAABcAAAABAAEAAgAAAAEAAAAFAAAAAQAAABEAAAABAAIAGAAAAAcAAAACAAAAAQAAAAAA" +
"AAAHAAAAAAAAAAYAAABQBAAA7AMAAAAAAAABKAABPAAGPGluaXQ+AAI+OwAEPjspVgAGRmluaXNo" +
"AB1Kdm10aVJlZGVmaW5lQ2xhc3Nlc1Rlc3QuamF2YQA0TGFuZHJvaWQvanZtdGkvY3RzL0p2bXRp" +
"UmVkZWZpbmVDbGFzc2VzVGVzdCRDb25zdW1lcgA1TGFuZHJvaWQvanZtdGkvY3RzL0p2bXRpUmVk" +
"ZWZpbmVDbGFzc2VzVGVzdCRDb25zdW1lcjsANkxhbmRyb2lkL2p2bXRpL2N0cy9Kdm10aVJlZGVm" +
"aW5lQ2xhc3Nlc1Rlc3QkVHJhbnNmb3JtOwAsTGFuZHJvaWQvanZtdGkvY3RzL0p2bXRpUmVkZWZp" +
"bmVDbGFzc2VzVGVzdDsAIkxkYWx2aWsvYW5ub3RhdGlvbi9FbmNsb3NpbmdDbGFzczsAHkxkYWx2" +
"aWsvYW5ub3RhdGlvbi9Jbm5lckNsYXNzOwAdTGRhbHZpay9hbm5vdGF0aW9uL1NpZ25hdHVyZTsA" +
"FExqYXZhL2xhbmcvUnVubmFibGU7ABJMamF2YS9sYW5nL1N0cmluZzsAFkxqYXZhL3V0aWwvT2Jz" +
"ZXJ2YWJsZTsABVN0YXJ0AAlUcmFuc2Zvcm0AAVYAAlZMAAthY2Nlc3NGbGFncwAEbmFtZQAIcmVw" +
"b3J0ZXIABXNheUhpAAV2YWx1ZQAAAQAAAAAAAAABAAAABgAAAA0BAAcOAA8ABw4ADgAHDgAQAQAH" +
"DgAAAAIAAgABAAAAfAMAAAYAAABwEAQAAABbAQAADgABAAEAAAAAAIIDAAABAAAADgAAAAEAAQAA" +
"AAAAhwMAAAEAAAAOAAAAAgACAAAAAACMAwAAAQAAAA4AAAAAAQMBAAIAgYAElAcBArAHAQLEBwMB" +
"2AcCAwEZGAICBAIVBAgWFxICBQEZHAQXBxcBFw8XAwIFARkcBRcAFwcXARcPFwQAAAACAAAABAQA" +
"AAoEAAABAAAAEwQAAAEAAAAhBAAANAQAAAEAAAABAAAAAAAAAAAAAABABAAAAAAAAEgEAAAQAAAA" +
"AAAAAAEAAAAAAAAAAQAAABoAAABwAAAAAgAAAAkAAADYAAAAAwAAAAMAAAD8AAAABAAAAAEAAAAg" +
"AQAABQAAAAUAAAAoAQAABgAAAAEAAABQAQAAAiAAABoAAABwAQAAARAAAAIAAABsAwAAAyAAAAQA" +
"AAB8AwAAASAAAAQAAACUAwAAACAAAAEAAADsAwAABCAAAAQAAAAEBAAAAxAAAAMAAAA0BAAABiAA" +
"AAEAAABQBAAAABAAAAEAAABwBAAA"),
/**
* Array classes are never modifiable.
*
* The base64 data is just an empty dex file. It has no classes associated with it.
*/
new RedefineError(JvmtiErrors.UNMODIFIABLE_CLASS, Transform[].class,
"ZGV4CjAzNQCRAy8PAAAAAAAAAAAAAAAAAAAAAAAAAACMAAAAcAAAAHhWNBIAAAAAAAAAAHAAAAAA" +
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcAAAAcAAAAAIA" +
"AAAAAAAAAQAAAAAAAAAAEAAAAQAAAHAAAAA="),
};
@Test
public void testRedefineFailures() throws Exception {
// Just check each of the failing tests.
for (RedefineError e : FAILING_DEX_FILES) {
checkRedefinition(e);
}
}
private void checkRetransformation(RedefineError e) {
clearTransformations();
pushTransformationResult(e.target, e.dexData);
assertEquals(e.expectedError, retransformClass(e.target));
}
@Test
public void testRetransformFailures() throws Exception {
setTransformationEvent(true);
setPopTransformations(true);
for (RedefineError e : FAILING_DEX_FILES) {
checkRetransformation(e);
}
}
private static final String ONLOAD_TEST_CLASS_NAME =
"android.jvmti.cts.memory_dex.TransformTarget";
/**
* Base64 encoded version of the following class.
* package android.jvmti.cts.memory_dex;
* <p>
* public class TransformTarget {
* public void alpha() { }
* public void beta() { }
* }
*/
private static final byte[] ONLOAD_INITIAL_CLASS = Base64.getDecoder().decode(
"ZGV4CjAzNQAQT37mO0bz7SniP0I8RLnGvVsfM5ybXmdYAgAAcAAAAHhWNBIAAAAAAAAAANABAAAI" +
"AAAAcAAAAAMAAACQAAAAAQAAAJwAAAAAAAAAAAAAAAQAAACoAAAAAQAAAMgAAABwAQAA6AAAACgB" +
"AAAwAQAAYAEAAHQBAACKAQAAjQEAAJQBAACaAQAAAQAAAAIAAAAEAAAABAAAAAIAAAAAAAAAAAAA" +
"AAAAAAAAAAAABQAAAAAAAAAGAAAAAQAAAAAAAAAAAAAAAQAAAAEAAAAAAAAAAwAAAAAAAAC9AQAA" +
"AAAAAAEAAQABAAAArgEAAAQAAABwEAMAAAAOAAEAAQAAAAAAswEAAAEAAAAOAAAAAQABAAAAAAC4" +
"AQAAAQAAAA4AAAAGPGluaXQ+AC5MYW5kcm9pZC9qdm10aS9jdHMvbWVtb3J5X2RleC9UcmFuc2Zv" +
"cm1UYXJnZXQ7ABJMamF2YS9sYW5nL09iamVjdDsAFFRyYW5zZm9ybVRhcmdldC5qYXZhAAFWAAVh" +
"bHBoYQAEYmV0YQASZW1pdHRlcjogamFjay00LjI4AAIABw4AAwAHDgAEAAcOAAAAAQIAgYAE6AEB" +
"AYACAQGUAgALAAAAAAAAAAEAAAAAAAAAAQAAAAgAAABwAAAAAgAAAAMAAACQAAAAAwAAAAEAAACc" +
"AAAABQAAAAQAAACoAAAABgAAAAEAAADIAAAAASAAAAMAAADoAAAAAiAAAAgAAAAoAQAAAyAAAAMA" +
"AACuAQAAACAAAAEAAAC9AQAAABAAAAEAAADQAQAA");
/**
* Base64 encoded version of the following class.
* Note that this would be an illegal transformation if the class had been loaded as the first
* one.
* <p>
* package android.jvmti.cts.memory_dex;
* <p>
* public class TransformTarget {
* public void alpha(int abc) {
* }
* public int beta() {
* return 12;
* }
* public void gamma() {
* }
* }
*/
private static final byte[] ONLOAD_FINAL_CLASS = Base64.getDecoder().decode(
"ZGV4CjAzNQA5VqbusSyl8/G1EXrbm9uRuiHvkP4XixrMAgAAcAAAAHhWNBIAAAAAAAAAADgCAAAL" +
"AAAAcAAAAAQAAACcAAAAAwAAAKwAAAAAAAAAAAAAAAUAAADQAAAAAQAAAPgAAAC0AQAAGAEAAHYB" +
"AAB+AQAAgQEAALEBAADFAQAA2wEAAN4BAADiAQAA6QEAAO8BAAADAgAAAQAAAAIAAAADAAAABQAA" +
"AAEAAAAAAAAAAAAAAAUAAAADAAAAAAAAAAYAAAADAAAAcAEAAAEAAQAAAAAAAQACAAcAAAABAAAA" +
"CAAAAAEAAQAKAAAAAgABAAAAAAABAAAAAQAAAAIAAAAAAAAABAAAAAAAAAAfAgAAAAAAAAEAAQAB" +
"AAAACgIAAAQAAABwEAQAAAAOAAIAAgAAAAAADwIAAAEAAAAOAAAAAgABAAAAAAAVAgAAAwAAABMA" +
"DAAPAAAAAQABAAAAAAAaAgAAAQAAAA4AAAABAAAAAAAGPGluaXQ+AAFJAC5MYW5kcm9pZC9qdm10" +
"aS9jdHMvbWVtb3J5X2RleC9UcmFuc2Zvcm1UYXJnZXQ7ABJMamF2YS9sYW5nL09iamVjdDsAFFRy" +
"YW5zZm9ybVRhcmdldC5qYXZhAAFWAAJWSQAFYWxwaGEABGJldGEAEmVtaXR0ZXI6IGphY2stNC4y" +
"OAAFZ2FtbWEAAgAHDgAEAQAHDgAGAAcOAAkABw4AAAABAwCBgASYAgEBsAIBAcQCAQHcAgAAAAwA" +
"AAAAAAAAAQAAAAAAAAABAAAACwAAAHAAAAACAAAABAAAAJwAAAADAAAAAwAAAKwAAAAFAAAABQAA" +
"ANAAAAAGAAAAAQAAAPgAAAABIAAABAAAABgBAAABEAAAAQAAAHABAAACIAAACwAAAHYBAAADIAAA" +
"BAAAAAoCAAAAIAAAAQAAAB8CAAAAEAAAAQAAADgCAAA=");
private static class ExpectedMethod {
public final Class<?> returnType;
public final String name;
public final Class<?>[] params;
public ExpectedMethod(Class<?> returnType, String name, Class<?>... params) {
this.returnType = returnType;
this.name = name;
this.params = params;
}
public void ensureHasMethod(Class<?> klass) throws Exception {
try {
assertEquals(returnType, klass.getDeclaredMethod(name, params).getReturnType());
} catch (NoSuchMethodException e) {
Assert.fail("Could not find method: " + klass + ": " + name +
" (params: " + Arrays.toString(params) + "). Reason was " + e);
}
}
}
private void checkClassHasMethods(Class<?> target, ExpectedMethod[] methods) throws Exception {
for (ExpectedMethod m : methods) {
m.ensureHasMethod(target);
}
}
@Test
public void testCannotRetransformOnLoadTest() throws Exception {
// Just a sanity check along with below.
Class<?> target_class = new InMemoryDexClassLoader(
ByteBuffer.wrap(ONLOAD_INITIAL_CLASS),
getClass().getClassLoader()).loadClass(ONLOAD_TEST_CLASS_NAME);
checkClassHasMethods(
target_class,
new ExpectedMethod[]{
new ExpectedMethod(Void.TYPE, "alpha"),
new ExpectedMethod(Void.TYPE, "beta"),
});
assertTrue(JvmtiErrors.NONE != redefineClass(target_class, ONLOAD_FINAL_CLASS));
}
@Test
public void testRetransformOnLoad() throws Exception {
pushTransformationResult(ONLOAD_TEST_CLASS_NAME.replace('.', '/'), ONLOAD_FINAL_CLASS);
setTransformationEvent(true);
setPopTransformations(false);
checkClassHasMethods(
new InMemoryDexClassLoader(ByteBuffer.wrap(ONLOAD_INITIAL_CLASS),
getClass().getClassLoader()).loadClass(ONLOAD_TEST_CLASS_NAME),
new ExpectedMethod[]{
new ExpectedMethod(Void.TYPE, "alpha", int.class),
new ExpectedMethod(int.class, "beta"),
new ExpectedMethod(Void.TYPE, "gamma"),
});
}
private static native int redefineClass(Class<?> target, byte[] dex);
private static native int retransformClass(Class<?> target);
private static native void setTransformationEvent(boolean enable);
private static native void clearTransformations();
private static native void pushTransformationResult(String target, byte[] dexBytes);
private static native void setPopTransformations(boolean enable);
private static void pushTransformationResult(Class<?> target, byte[] dex) {
pushTransformationResult(target.getName().replace('.', '/'), dex);
}
}