diff options
author | 2017-01-27 09:00:15 -0800 | |
---|---|---|
committer | 2017-01-30 16:22:44 -0800 | |
commit | 7916f20d9251773a8543f7f15d76ce21110acf96 (patch) | |
tree | 47a3e35fc479a0e814261afe5ce707288dcf3454 | |
parent | f22bf9f809def57c96a19d932467a175bbd9c08c (diff) |
Enable redefining Bootclasspath classes
Test: mma -j40 test-art-host
Change-Id: I84fff0b428fbaeaba003269614310fdab576bcd6
-rw-r--r-- | runtime/openjdkjvmti/ti_class_loader.cc | 9 | ||||
-rw-r--r-- | runtime/openjdkjvmti/ti_redefine.cc | 70 | ||||
-rw-r--r-- | runtime/openjdkjvmti/ti_redefine.h | 4 | ||||
-rwxr-xr-x | test/938-load-transform-bcp/build | 17 | ||||
-rw-r--r-- | test/938-load-transform-bcp/expected.txt | 2 | ||||
-rw-r--r-- | test/938-load-transform-bcp/info.txt | 1 | ||||
-rwxr-xr-x | test/938-load-transform-bcp/run | 17 | ||||
-rw-r--r-- | test/938-load-transform-bcp/src-ex/TestMain.java | 35 | ||||
-rw-r--r-- | test/938-load-transform-bcp/src/Main.java | 122 | ||||
-rwxr-xr-x | test/939-hello-transformation-bcp/build | 17 | ||||
-rw-r--r-- | test/939-hello-transformation-bcp/expected.txt | 3 | ||||
-rw-r--r-- | test/939-hello-transformation-bcp/info.txt | 6 | ||||
-rwxr-xr-x | test/939-hello-transformation-bcp/run | 17 | ||||
-rw-r--r-- | test/939-hello-transformation-bcp/src/Main.java | 126 | ||||
-rw-r--r-- | test/ti-agent/common_load.cc | 2 |
15 files changed, 416 insertions, 32 deletions
diff --git a/runtime/openjdkjvmti/ti_class_loader.cc b/runtime/openjdkjvmti/ti_class_loader.cc index b68fc60c6c..c2f17924da 100644 --- a/runtime/openjdkjvmti/ti_class_loader.cc +++ b/runtime/openjdkjvmti/ti_class_loader.cc @@ -61,9 +61,14 @@ namespace openjdkjvmti { bool ClassLoaderHelper::AddToClassLoader(art::Thread* self, art::Handle<art::mirror::ClassLoader> loader, const art::DexFile* dex_file) { + art::ScopedObjectAccessUnchecked soa(self); art::StackHandleScope<2> hs(self); - art::Handle<art::mirror::Object> java_dex_file_obj(hs.NewHandle(FindSourceDexFileObject(self, - loader))); + if (art::ClassLinker::IsBootClassLoader(soa, loader.Get())) { + art::Runtime::Current()->GetClassLinker()->AppendToBootClassPath(self, *dex_file); + return true; + } + art::Handle<art::mirror::Object> java_dex_file_obj( + hs.NewHandle(FindSourceDexFileObject(self, loader))); if (java_dex_file_obj.IsNull()) { return false; } diff --git a/runtime/openjdkjvmti/ti_redefine.cc b/runtime/openjdkjvmti/ti_redefine.cc index b76d74ae79..4f679f4680 100644 --- a/runtime/openjdkjvmti/ti_redefine.cc +++ b/runtime/openjdkjvmti/ti_redefine.cc @@ -464,7 +464,8 @@ void Redefiner::ClassRedefinition::FindAndAllocateObsoleteMethods(art::mirror::C art::ScopedAssertNoThreadSuspension ns("No thread suspension during thread stack walking"); art::mirror::ClassExt* ext = art_klass->GetExtData(); CHECK(ext->GetObsoleteMethods() != nullptr); - CallbackCtx ctx(art_klass->GetClassLoader()->GetAllocator()); + art::ClassLinker* linker = driver_->runtime_->GetClassLinker(); + CallbackCtx ctx(linker->GetAllocatorForClassLoader(art_klass->GetClassLoader())); // Add all the declared methods to the map for (auto& m : art_klass->GetDeclaredMethods(art::kRuntimePointerSize)) { ctx.obsolete_methods.insert(&m); @@ -733,33 +734,32 @@ class RedefinitionDataHolder { bool Redefiner::ClassRedefinition::FinishRemainingAllocations( int32_t klass_index, /*out*/RedefinitionDataHolder* holder) { + art::ScopedObjectAccessUnchecked soa(driver_->self_); art::StackHandleScope<2> hs(driver_->self_); holder->SetMirrorClass(klass_index, GetMirrorClass()); // This shouldn't allocate art::Handle<art::mirror::ClassLoader> loader(hs.NewHandle(GetClassLoader())); - holder->SetSourceClassLoader(klass_index, loader.Get()); - if (loader.Get() == nullptr) { - // TODO Better error msg. - RecordFailure(ERR(INTERNAL), "Unable to find class loader!"); - return false; - } - art::Handle<art::mirror::Object> dex_file_obj(hs.NewHandle( - ClassLoaderHelper::FindSourceDexFileObject(driver_->self_, loader))); - holder->SetJavaDexFile(klass_index, dex_file_obj.Get()); - if (dex_file_obj.Get() == nullptr) { - // TODO Better error msg. - RecordFailure(ERR(INTERNAL), "Unable to find class loader!"); - return false; - } - holder->SetNewDexFileCookie(klass_index, - ClassLoaderHelper::AllocateNewDexFileCookie(driver_->self_, - dex_file_obj, - dex_file_.get()).Ptr()); - if (holder->GetNewDexFileCookie(klass_index) == nullptr) { - driver_->self_->AssertPendingOOMException(); - driver_->self_->ClearException(); - RecordFailure(ERR(OUT_OF_MEMORY), "Unable to allocate dex file array for class loader"); - return false; + // The bootclasspath is handled specially so it doesn't have a j.l.DexFile. + if (!art::ClassLinker::IsBootClassLoader(soa, loader.Get())) { + holder->SetSourceClassLoader(klass_index, loader.Get()); + art::Handle<art::mirror::Object> dex_file_obj(hs.NewHandle( + ClassLoaderHelper::FindSourceDexFileObject(driver_->self_, loader))); + holder->SetJavaDexFile(klass_index, dex_file_obj.Get()); + if (dex_file_obj.Get() == nullptr) { + // TODO Better error msg. + RecordFailure(ERR(INTERNAL), "Unable to find dex file!"); + return false; + } + holder->SetNewDexFileCookie(klass_index, + ClassLoaderHelper::AllocateNewDexFileCookie(driver_->self_, + dex_file_obj, + dex_file_.get()).Ptr()); + if (holder->GetNewDexFileCookie(klass_index) == nullptr) { + driver_->self_->AssertPendingOOMException(); + driver_->self_->ClearException(); + RecordFailure(ERR(OUT_OF_MEMORY), "Unable to allocate dex file array for class loader"); + return false; + } } holder->SetNewDexCache(klass_index, CreateNewDexCache(loader)); if (holder->GetNewDexCache(klass_index) == nullptr) { @@ -846,6 +846,13 @@ jvmtiError Redefiner::Run() { // cleaned up by the GC eventually. return result_; } + int32_t counter = 0; + for (Redefiner::ClassRedefinition& redef : redefinitions_) { + if (holder.GetSourceClassLoader(counter) == nullptr) { + runtime_->GetClassLinker()->AppendToBootClassPath(self_, redef.GetDexFile()); + } + counter++; + } // Disable GC and wait for it to be done if we are a moving GC. This is fine since we are done // allocating so no deadlocks. art::gc::Heap* heap = runtime_->GetHeap(); @@ -864,16 +871,19 @@ jvmtiError Redefiner::Run() { // TODO We need to update all debugger MethodIDs so they note the method they point to is // obsolete or implement some other well defined semantics. // TODO We need to decide on & implement semantics for JNI jmethodids when we redefine methods. - int32_t cnt = 0; + counter = 0; for (Redefiner::ClassRedefinition& redef : redefinitions_) { art::ScopedAssertNoThreadSuspension nts("Updating runtime objects for redefinition"); - art::mirror::Class* klass = holder.GetMirrorClass(cnt); - ClassLoaderHelper::UpdateJavaDexFile(holder.GetJavaDexFile(cnt), - holder.GetNewDexFileCookie(cnt)); + if (holder.GetSourceClassLoader(counter) != nullptr) { + ClassLoaderHelper::UpdateJavaDexFile(holder.GetJavaDexFile(counter), + holder.GetNewDexFileCookie(counter)); + } + art::mirror::Class* klass = holder.GetMirrorClass(counter); // TODO Rewrite so we don't do a stack walk for each and every class. redef.FindAndAllocateObsoleteMethods(klass); - redef.UpdateClass(klass, holder.GetNewDexCache(cnt), holder.GetOriginalDexFileBytes(cnt)); - cnt++; + redef.UpdateClass(klass, holder.GetNewDexCache(counter), + holder.GetOriginalDexFileBytes(counter)); + counter++; } // Ensure that obsolete methods are deoptimized. This is needed since optimized methods may have // pointers to their ArtMethod's stashed in registers that they then use to attempt to hit the diff --git a/runtime/openjdkjvmti/ti_redefine.h b/runtime/openjdkjvmti/ti_redefine.h index 85df6e1024..4492db0f56 100644 --- a/runtime/openjdkjvmti/ti_redefine.h +++ b/runtime/openjdkjvmti/ti_redefine.h @@ -127,6 +127,10 @@ class Redefiner { art::mirror::Class* GetMirrorClass() REQUIRES_SHARED(art::Locks::mutator_lock_); art::mirror::ClassLoader* GetClassLoader() REQUIRES_SHARED(art::Locks::mutator_lock_); + const art::DexFile& GetDexFile() { + return *dex_file_; + } + art::mirror::DexCache* CreateNewDexCache(art::Handle<art::mirror::ClassLoader> loader) REQUIRES_SHARED(art::Locks::mutator_lock_); diff --git a/test/938-load-transform-bcp/build b/test/938-load-transform-bcp/build new file mode 100755 index 0000000000..898e2e54a2 --- /dev/null +++ b/test/938-load-transform-bcp/build @@ -0,0 +1,17 @@ +#!/bin/bash +# +# Copyright 2016 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. + +./default-build "$@" --experimental agents diff --git a/test/938-load-transform-bcp/expected.txt b/test/938-load-transform-bcp/expected.txt new file mode 100644 index 0000000000..16c3f8f726 --- /dev/null +++ b/test/938-load-transform-bcp/expected.txt @@ -0,0 +1,2 @@ +ol.foo() -> 'This is foo for val=123' +ol.toString() -> 'This is toString() for val=123' diff --git a/test/938-load-transform-bcp/info.txt b/test/938-load-transform-bcp/info.txt new file mode 100644 index 0000000000..875a5f6ec1 --- /dev/null +++ b/test/938-load-transform-bcp/info.txt @@ -0,0 +1 @@ +Tests basic functions in the jvmti plugin. diff --git a/test/938-load-transform-bcp/run b/test/938-load-transform-bcp/run new file mode 100755 index 0000000000..adb1a1c507 --- /dev/null +++ b/test/938-load-transform-bcp/run @@ -0,0 +1,17 @@ +#!/bin/bash +# +# Copyright 2016 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. + +./default-run "$@" --jvmti --no-app-image diff --git a/test/938-load-transform-bcp/src-ex/TestMain.java b/test/938-load-transform-bcp/src-ex/TestMain.java new file mode 100644 index 0000000000..3757a0f778 --- /dev/null +++ b/test/938-load-transform-bcp/src-ex/TestMain.java @@ -0,0 +1,35 @@ +/* + * 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. + */ + +import java.lang.reflect.Method; +import java.util.OptionalLong; +public class TestMain { + public static void runTest() { + // This should be our redefined OptionalLong. + OptionalLong ol = OptionalLong.of(123); + try { + // OptionalLong is a class that is unlikely to be used by the time this test starts. + Method foo = OptionalLong.class.getMethod("foo"); + System.out.println("ol.foo() -> '" + (String)foo.invoke(ol) + "'"); + System.out.println("ol.toString() -> '" + ol.toString() + "'"); + } catch (Exception e) { + System.out.println( + "Exception occured (did something load OptionalLong before this test method!: " + + e.toString()); + e.printStackTrace(); + } + } +} diff --git a/test/938-load-transform-bcp/src/Main.java b/test/938-load-transform-bcp/src/Main.java new file mode 100644 index 0000000000..13bc5da461 --- /dev/null +++ b/test/938-load-transform-bcp/src/Main.java @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2016 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. + */ + +import java.lang.reflect.*; +import java.util.Base64; + +class Main { + public static String TEST_NAME = "938-load-transform-bcp"; + + /** + * base64 encoded class/dex file for + * + * // Yes this version of OptionalLong is not compatible with the real one but since it isn't used + * // for anything in the runtime initialization it should be fine. + * + * package java.util; + * public final class OptionalLong { + * private long val; + * + * private OptionalLong(long abc) { + * this.val = abc; + * } + * + * public static OptionalLong of(long abc) { + * return new OptionalLong(abc); + * } + * + * public String foo() { + * return "This is foo for val=" + val; + * } + * + * public String toString() { + * return "This is toString() for val=" + val; + * } + * } + */ + private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( + "yv66vgAAADQAKQoADAAaCQADABsHABwKAAMAHQcAHgoABQAaCAAfCgAFACAKAAUAIQoABQAiCAAj" + + "BwAkAQADdmFsAQABSgEABjxpbml0PgEABChKKVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQAC" + + "b2YBABsoSilMamF2YS91dGlsL09wdGlvbmFsTG9uZzsBAANmb28BABQoKUxqYXZhL2xhbmcvU3Ry" + + "aW5nOwEACHRvU3RyaW5nAQAKU291cmNlRmlsZQEAEU9wdGlvbmFsTG9uZy5qYXZhDAAPACUMAA0A" + + "DgEAFmphdmEvdXRpbC9PcHRpb25hbExvbmcMAA8AEAEAF2phdmEvbGFuZy9TdHJpbmdCdWlsZGVy" + + "AQAUVGhpcyBpcyBmb28gZm9yIHZhbD0MACYAJwwAJgAoDAAXABYBABtUaGlzIGlzIHRvU3RyaW5n" + + "KCkgZm9yIHZhbD0BABBqYXZhL2xhbmcvT2JqZWN0AQADKClWAQAGYXBwZW5kAQAtKExqYXZhL2xh" + + "bmcvU3RyaW5nOylMamF2YS9sYW5nL1N0cmluZ0J1aWxkZXI7AQAcKEopTGphdmEvbGFuZy9TdHJp" + + "bmdCdWlsZGVyOwAxAAMADAAAAAEAAgANAA4AAAAEAAIADwAQAAEAEQAAACoAAwADAAAACiq3AAEq" + + "H7UAArEAAAABABIAAAAOAAMAAAAFAAQABgAJAAcACQATABQAAQARAAAAIQAEAAIAAAAJuwADWR63" + + "AASwAAAAAQASAAAABgABAAAACgABABUAFgABABEAAAAvAAMAAQAAABe7AAVZtwAGEge2AAgqtAAC" + + "tgAJtgAKsAAAAAEAEgAAAAYAAQAAAA4AAQAXABYAAQARAAAALwADAAEAAAAXuwAFWbcABhILtgAI" + + "KrQAArYACbYACrAAAAABABIAAAAGAAEAAAASAAEAGAAAAAIAGQ=="); + private static final byte[] DEX_BYTES = Base64.getDecoder().decode( + "ZGV4CjAzNQAOe/TYJCvVthTToFA3tveMDhwTo7uDf0IcBAAAcAAAAHhWNBIAAAAAAAAAAHwDAAAU" + + "AAAAcAAAAAYAAADAAAAABgAAANgAAAABAAAAIAEAAAkAAAAoAQAAAQAAAHABAACMAgAAkAEAAFYC" + + "AABeAgAAYQIAAGQCAABoAgAAbAIAAIACAACUAgAArwIAAMkCAADcAgAA8gIAAA8DAAASAwAAFgMA" + + "AB4DAAAyAwAANwMAADsDAABFAwAAAQAAAAUAAAAGAAAABwAAAAgAAAAMAAAAAgAAAAIAAAAAAAAA" + + "AwAAAAMAAABIAgAABAAAAAMAAABQAgAAAwAAAAQAAABIAgAADAAAAAUAAAAAAAAADQAAAAUAAABI" + + "AgAABAAAABMAAAABAAQAAAAAAAMABAAAAAAAAwABAA4AAAADAAIADgAAAAMAAAASAAAABAAFAAAA" + + "AAAEAAAAEAAAAAQAAwARAAAABAAAABIAAAAEAAAAEQAAAAEAAAAAAAAACQAAAAAAAABiAwAAAAAA" + + "AAQAAwABAAAASgMAAAYAAABwEAAAAQBaEgAADgAEAAIAAwAAAFIDAAAGAAAAIgAEAHAwBQAgAxEA" + + "BQABAAMAAABYAwAAFwAAACIAAwBwEAEAAAAbAQoAAABuIAMAEAAMAFNCAABuMAIAIAMMAG4QBAAA" + + "AAwAEQAAAAUAAQADAAAAXQMAABcAAAAiAAMAcBABAAAAGwELAAAAbiADABAADABTQgAAbjACACAD" + + "DABuEAQAAAAMABEAAAABAAAAAAAAAAEAAAACAAY8aW5pdD4AAUoAAUwAAkxKAAJMTAASTGphdmEv" + + "bGFuZy9PYmplY3Q7ABJMamF2YS9sYW5nL1N0cmluZzsAGUxqYXZhL2xhbmcvU3RyaW5nQnVpbGRl" + + "cjsAGExqYXZhL3V0aWwvT3B0aW9uYWxMb25nOwART3B0aW9uYWxMb25nLmphdmEAFFRoaXMgaXMg" + + "Zm9vIGZvciB2YWw9ABtUaGlzIGlzIHRvU3RyaW5nKCkgZm9yIHZhbD0AAVYAAlZKAAZhcHBlbmQA" + + "EmVtaXR0ZXI6IGphY2stNC4yMgADZm9vAAJvZgAIdG9TdHJpbmcAA3ZhbAAFAQAHDjwtAAoBAAcO" + + "AA4ABw4AEgAHDgAAAQICAAIFgoAEkAMCCawDBgHIAwIBiAQAAA0AAAAAAAAAAQAAAAAAAAABAAAA" + + "FAAAAHAAAAACAAAABgAAAMAAAAADAAAABgAAANgAAAAEAAAAAQAAACABAAAFAAAACQAAACgBAAAG" + + "AAAAAQAAAHABAAABIAAABAAAAJABAAABEAAAAgAAAEgCAAACIAAAFAAAAFYCAAADIAAABAAAAEoD" + + "AAAAIAAAAQAAAGIDAAAAEAAAAQAAAHwDAAA="); + + public static ClassLoader getClassLoaderFor(String location) throws Exception { + try { + Class<?> class_loader_class = Class.forName("dalvik.system.PathClassLoader"); + Constructor<?> ctor = class_loader_class.getConstructor(String.class, ClassLoader.class); + return (ClassLoader)ctor.newInstance(location + "/" + TEST_NAME + "-ex.jar", + Main.class.getClassLoader()); + } catch (ClassNotFoundException e) { + // Running on RI. Use URLClassLoader. + return new java.net.URLClassLoader( + new java.net.URL[] { new java.net.URL("file://" + location + "/classes-ex/") }); + } + } + + public static void main(String[] args) { + // TODO WHAT TO TRANSFORM + addCommonTransformationResult("java/util/OptionalLong", CLASS_BYTES, DEX_BYTES); + enableCommonRetransformation(true); + try { + /* this is the "alternate" DEX/Jar file */ + ClassLoader new_loader = getClassLoaderFor(System.getenv("DEX_LOCATION")); + Class<?> klass = (Class<?>)new_loader.loadClass("TestMain"); + if (klass == null) { + throw new AssertionError("loadClass failed"); + } + Method run_test = klass.getMethod("runTest"); + run_test.invoke(null); + } catch (Exception e) { + System.out.println(e.toString()); + e.printStackTrace(); + } + } + + // Transforms the class + private static native void enableCommonRetransformation(boolean enable); + private static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); +} diff --git a/test/939-hello-transformation-bcp/build b/test/939-hello-transformation-bcp/build new file mode 100755 index 0000000000..898e2e54a2 --- /dev/null +++ b/test/939-hello-transformation-bcp/build @@ -0,0 +1,17 @@ +#!/bin/bash +# +# Copyright 2016 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. + +./default-build "$@" --experimental agents diff --git a/test/939-hello-transformation-bcp/expected.txt b/test/939-hello-transformation-bcp/expected.txt new file mode 100644 index 0000000000..90fd25828d --- /dev/null +++ b/test/939-hello-transformation-bcp/expected.txt @@ -0,0 +1,3 @@ +ol.toString() -> 'OptionalLong[-559038737]' +Redefining OptionalLong! +ol.toString() -> 'Redefined OptionalLong!' diff --git a/test/939-hello-transformation-bcp/info.txt b/test/939-hello-transformation-bcp/info.txt new file mode 100644 index 0000000000..d230a382bd --- /dev/null +++ b/test/939-hello-transformation-bcp/info.txt @@ -0,0 +1,6 @@ +Tests basic functions in the jvmti plugin. + +Note this function is reliant on the definition of java.util.OptionalLong not +changing. If this classes definition changes we will need to update this class +so that the CLASS_BYTES and DEX_BYTES fields contain dex/class bytes for an +OptionalLong with all the same methods and fields. diff --git a/test/939-hello-transformation-bcp/run b/test/939-hello-transformation-bcp/run new file mode 100755 index 0000000000..c6e62ae6cd --- /dev/null +++ b/test/939-hello-transformation-bcp/run @@ -0,0 +1,17 @@ +#!/bin/bash +# +# Copyright 2016 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. + +./default-run "$@" --jvmti diff --git a/test/939-hello-transformation-bcp/src/Main.java b/test/939-hello-transformation-bcp/src/Main.java new file mode 100644 index 0000000000..bdf7f592ef --- /dev/null +++ b/test/939-hello-transformation-bcp/src/Main.java @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2016 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. + */ + +import java.util.Base64; +import java.util.OptionalLong; +public class Main { + + /** + * This is the base64 encoded class/dex. + * + * package java.util; + * import java.util.function.LongConsumer; + * import java.util.function.LongSupplier; + * import java.util.function.Supplier; + * public final class OptionalLong { + * // Make sure we have a <clinit> function since the real implementation of OptionalLong does. + * static { EMPTY = null; } + * private static final OptionalLong EMPTY; + * private final boolean isPresent; + * private final long value; + * private OptionalLong() { isPresent = false; value = 0; } + * private OptionalLong(long l) { this(); } + * public static OptionalLong empty() { return null; } + * public static OptionalLong of(long value) { return null; } + * public long getAsLong() { return 0; } + * public boolean isPresent() { return false; } + * public void ifPresent(LongConsumer c) { } + * public long orElse(long l) { return 0; } + * public long orElseGet(LongSupplier s) { return 0; } + * public<X extends Throwable> long orElseThrow(Supplier<X> s) throws X { return 0; } + * public boolean equals(Object o) { return false; } + * public int hashCode() { return 0; } + * public String toString() { return "Redefined OptionalLong!"; } + * } + */ + private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( + "yv66vgAAADQAOAoACAAwCQAHADEJAAcAMgoABwAwCAAzCQAHADQHADUHADYBAAVFTVBUWQEAGExq" + + "YXZhL3V0aWwvT3B0aW9uYWxMb25nOwEACWlzUHJlc2VudAEAAVoBAAV2YWx1ZQEAAUoBAAY8aW5p" + + "dD4BAAMoKVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQAEKEopVgEABWVtcHR5AQAaKClMamF2" + + "YS91dGlsL09wdGlvbmFsTG9uZzsBAAJvZgEAGyhKKUxqYXZhL3V0aWwvT3B0aW9uYWxMb25nOwEA" + + "CWdldEFzTG9uZwEAAygpSgEAAygpWgEACWlmUHJlc2VudAEAJChMamF2YS91dGlsL2Z1bmN0aW9u" + + "L0xvbmdDb25zdW1lcjspVgEABm9yRWxzZQEABChKKUoBAAlvckVsc2VHZXQBACQoTGphdmEvdXRp" + + "bC9mdW5jdGlvbi9Mb25nU3VwcGxpZXI7KUoBAAtvckVsc2VUaHJvdwEAIChMamF2YS91dGlsL2Z1" + + "bmN0aW9uL1N1cHBsaWVyOylKAQAKRXhjZXB0aW9ucwcANwEACVNpZ25hdHVyZQEAQjxYOkxqYXZh" + + "L2xhbmcvVGhyb3dhYmxlOz4oTGphdmEvdXRpbC9mdW5jdGlvbi9TdXBwbGllcjxUWDs+OylKXlRY" + + "OwEABmVxdWFscwEAFShMamF2YS9sYW5nL09iamVjdDspWgEACGhhc2hDb2RlAQADKClJAQAIdG9T" + + "dHJpbmcBABQoKUxqYXZhL2xhbmcvU3RyaW5nOwEACDxjbGluaXQ+AQAKU291cmNlRmlsZQEAEU9w" + + "dGlvbmFsTG9uZy5qYXZhDAAPABAMAAsADAwADQAOAQAXUmVkZWZpbmVkIE9wdGlvbmFsTG9uZyEM" + + "AAkACgEAFmphdmEvdXRpbC9PcHRpb25hbExvbmcBABBqYXZhL2xhbmcvT2JqZWN0AQATamF2YS9s" + + "YW5nL1Rocm93YWJsZQAxAAcACAAAAAMAGgAJAAoAAAASAAsADAAAABIADQAOAAAADgACAA8AEAAB" + + "ABEAAAAnAAMAAQAAAA8qtwABKgO1AAIqCbUAA7EAAAABABIAAAAGAAEAAAALAAIADwATAAEAEQAA" + + "AB0AAQADAAAABSq3AASxAAAAAQASAAAABgABAAAADAAJABQAFQABABEAAAAaAAEAAAAAAAIBsAAA" + + "AAEAEgAAAAYAAQAAAA0ACQAWABcAAQARAAAAGgABAAIAAAACAbAAAAABABIAAAAGAAEAAAAOAAEA" + + "GAAZAAEAEQAAABoAAgABAAAAAgmtAAAAAQASAAAABgABAAAADwABAAsAGgABABEAAAAaAAEAAQAA" + + "AAIDrAAAAAEAEgAAAAYAAQAAABAAAQAbABwAAQARAAAAGQAAAAIAAAABsQAAAAEAEgAAAAYAAQAA" + + "ABEAAQAdAB4AAQARAAAAGgACAAMAAAACCa0AAAABABIAAAAGAAEAAAASAAEAHwAgAAEAEQAAABoA" + + "AgACAAAAAgmtAAAAAQASAAAABgABAAAAEwABACEAIgADABEAAAAaAAIAAgAAAAIJrQAAAAEAEgAA" + + "AAYAAQAAABQAIwAAAAQAAQAkACUAAAACACYAAQAnACgAAQARAAAAGgABAAIAAAACA6wAAAABABIA" + + "AAAGAAEAAAAVAAEAKQAqAAEAEQAAABoAAQABAAAAAgOsAAAAAQASAAAABgABAAAAFgABACsALAAB" + + "ABEAAAAbAAEAAQAAAAMSBbAAAAABABIAAAAGAAEAAAAXAAgALQAQAAEAEQAAAB0AAQAAAAAABQGz" + + "AAaxAAAAAQASAAAABgABAAAABwABAC4AAAACAC8="); + private static final byte[] DEX_BYTES = Base64.getDecoder().decode( + "ZGV4CjAzNQCvAoivSJqk6GdYOgJmvrM/b2/flxhw99q8BwAAcAAAAHhWNBIAAAAAAAAAAPgGAAAq" + + "AAAAcAAAAA0AAAAYAQAADQAAAEwBAAADAAAA6AEAAA8AAAAAAgAAAQAAAHgCAAAkBQAAmAIAACoE" + + "AAA4BAAAPQQAAEcEAABPBAAAUwQAAFoEAABdBAAAYAQAAGQEAABoBAAAawQAAG8EAACOBAAAqgQA" + + "AL4EAADSBAAA6QQAAAMFAAAmBQAASQUAAGcFAACGBQAAmQUAALIFAAC1BQAAuQUAAL0FAADABQAA" + + "xAUAANgFAADfBQAA5wUAAPIFAAD8BQAABwYAABIGAAAWBgAAHgYAACkGAAA2BgAAQAYAAAYAAAAH" + + "AAAADAAAAA0AAAAOAAAADwAAABAAAAARAAAAEgAAABMAAAAVAAAAGAAAABsAAAAGAAAAAAAAAAAA" + + "AAAHAAAAAQAAAAAAAAAIAAAAAQAAAAQEAAAJAAAAAQAAAAwEAAAJAAAAAQAAABQEAAAKAAAABQAA" + + "AAAAAAAKAAAABwAAAAAAAAALAAAABwAAAAQEAAAYAAAACwAAAAAAAAAZAAAACwAAAAQEAAAaAAAA" + + "CwAAABwEAAAbAAAADAAAAAAAAAAcAAAADAAAACQEAAAHAAcABQAAAAcADAAjAAAABwABACkAAAAE" + + "AAgAAwAAAAcACAACAAAABwAIAAMAAAAHAAkAAwAAAAcABgAeAAAABwAMAB8AAAAHAAEAIAAAAAcA" + + "AAAhAAAABwAKACIAAAAHAAsAIwAAAAcABwAkAAAABwACACUAAAAHAAMAJgAAAAcABAAnAAAABwAF" + + "ACgAAAAHAAAAEQAAAAQAAAAAAAAAFgAAAOwDAACtBgAAAAAAAAIAAACVBgAApQYAAAEAAAAAAAAA" + + "RwYAAAQAAAASAGkAAAAOAAMAAQABAAAATQYAAAsAAABwEAAAAgASAFwgAQAWAAAAWiACAA4AAAAD" + + "AAMAAQAAAFIGAAAEAAAAcBACAAAADgABAAAAAAAAAFgGAAACAAAAEgARAAMAAgAAAAAAXQYAAAIA" + + "AAASABEAAwACAAAAAABjBgAAAgAAABIADwADAAEAAAAAAGkGAAADAAAAFgAAABAAAAACAAEAAAAA" + + "AG4GAAACAAAAEgAPAAIAAgAAAAAAcwYAAAEAAAAOAAAAAgABAAAAAAB5BgAAAgAAABIADwAFAAMA" + + "AAAAAH4GAAADAAAAFgAAABAAAAAEAAIAAAAAAIQGAAADAAAAFgAAABAAAAAEAAIAAAAAAIoGAAAD" + + "AAAAFgAAABAAAAACAAEAAAAAAJAGAAAEAAAAGwAXAAAAEQAAAAAAAAAAAAEAAAAAAAAADQAAAJgC" + + "AAABAAAAAQAAAAEAAAAJAAAAAQAAAAoAAAABAAAACAAAAAEAAAAEAAw8VFg7PjspSl5UWDsAAzxY" + + "OgAIPGNsaW5pdD4ABjxpbml0PgACPigABUVNUFRZAAFJAAFKAAJKSgACSkwAAUwAAkxKAB1MZGFs" + + "dmlrL2Fubm90YXRpb24vU2lnbmF0dXJlOwAaTGRhbHZpay9hbm5vdGF0aW9uL1Rocm93czsAEkxq" + + "YXZhL2xhbmcvT2JqZWN0OwASTGphdmEvbGFuZy9TdHJpbmc7ABVMamF2YS9sYW5nL1Rocm93YWJs" + + "ZTsAGExqYXZhL3V0aWwvT3B0aW9uYWxMb25nOwAhTGphdmEvdXRpbC9mdW5jdGlvbi9Mb25nQ29u" + + "c3VtZXI7ACFMamF2YS91dGlsL2Z1bmN0aW9uL0xvbmdTdXBwbGllcjsAHExqYXZhL3V0aWwvZnVu" + + "Y3Rpb24vU3VwcGxpZXIAHUxqYXZhL3V0aWwvZnVuY3Rpb24vU3VwcGxpZXI7ABFPcHRpb25hbExv" + + "bmcuamF2YQAXUmVkZWZpbmVkIE9wdGlvbmFsTG9uZyEAAVYAAlZKAAJWTAABWgACWkwAEmVtaXR0" + + "ZXI6IGphY2stNC4yMgAFZW1wdHkABmVxdWFscwAJZ2V0QXNMb25nAAhoYXNoQ29kZQAJaWZQcmVz" + + "ZW50AAlpc1ByZXNlbnQAAm9mAAZvckVsc2UACW9yRWxzZUdldAALb3JFbHNlVGhyb3cACHRvU3Ry" + + "aW5nAAV2YWx1ZQAHAAcOOQALAAcOAAwBAAcOAA0ABw4ADgEABw4AFQEABw4ADwAHDgAWAAcOABEB" + + "AAcOABAABw4AEgEABw4AEwEABw4AFAEABw4AFwAHDgACAgEpHAUXARcQFwQXFBcAAgMBKRwBGAYB" + + "AgUJABoBEgESAYiABKQFAYKABLwFAYKABOQFAQn8BQYJkAYFAaQGAQG4BgEB0AYBAeQGAQH4BgIB" + + "jAcBAaQHAQG8BwEB1AcAAAAQAAAAAAAAAAEAAAAAAAAAAQAAACoAAABwAAAAAgAAAA0AAAAYAQAA" + + "AwAAAA0AAABMAQAABAAAAAMAAADoAQAABQAAAA8AAAAAAgAABgAAAAEAAAB4AgAAAxAAAAEAAACY" + + "AgAAASAAAA4AAACkAgAABiAAAAEAAADsAwAAARAAAAUAAAAEBAAAAiAAACoAAAAqBAAAAyAAAA4A" + + "AABHBgAABCAAAAIAAACVBgAAACAAAAEAAACtBgAAABAAAAEAAAD4BgAA"); + + public static void main(String[] args) { + // OptionalLong is a class that is unlikely to be used by the time this test starts and is not + // likely to be changed in any meaningful way in the future. + OptionalLong ol = OptionalLong.of(0xDEADBEEF); + System.out.println("ol.toString() -> '" + ol.toString() + "'"); + System.out.println("Redefining OptionalLong!"); + doCommonClassRedefinition(OptionalLong.class, CLASS_BYTES, DEX_BYTES); + System.out.println("ol.toString() -> '" + ol.toString() + "'"); + } + + // Transforms the class + private static native void doCommonClassRedefinition(Class<?> target, + byte[] class_file, + byte[] dex_file); +} diff --git a/test/ti-agent/common_load.cc b/test/ti-agent/common_load.cc index 621d45a1bc..c5ed46034d 100644 --- a/test/ti-agent/common_load.cc +++ b/test/ti-agent/common_load.cc @@ -115,6 +115,8 @@ static AgentLib agents[] = { { "935-non-retransformable", common_transform::OnLoad, nullptr }, { "936-search-onload", Test936SearchOnload::OnLoad, nullptr }, { "937-hello-retransform-package", common_retransform::OnLoad, nullptr }, + { "938-load-transform-bcp", common_retransform::OnLoad, nullptr }, + { "939-hello-transformation-bcp", common_redefine::OnLoad, nullptr }, }; static AgentLib* FindAgent(char* name) { |