diff options
-rw-r--r-- | runtime/java_vm_ext.cc | 28 | ||||
-rw-r--r-- | runtime/jni_internal.cc | 17 | ||||
-rw-r--r-- | runtime/runtime.h | 4 | ||||
-rw-r--r-- | runtime/ti/agent.cc | 14 | ||||
-rw-r--r-- | runtime/ti/agent.h | 10 | ||||
-rw-r--r-- | test/986-native-method-bind/expected.txt | 16 | ||||
-rw-r--r-- | test/986-native-method-bind/native_bind.cc | 19 | ||||
-rw-r--r-- | test/986-native-method-bind/src/art/Redefinition.java | 96 | ||||
-rw-r--r-- | test/986-native-method-bind/src/art/Test986.java | 34 | ||||
-rw-r--r-- | test/987-agent-bind/agent_bind.cc | 52 | ||||
-rw-r--r-- | test/987-agent-bind/expected.txt | 2 | ||||
-rw-r--r-- | test/987-agent-bind/info.txt | 1 | ||||
-rwxr-xr-x | test/987-agent-bind/run | 17 | ||||
-rw-r--r-- | test/987-agent-bind/src/Main.java | 21 | ||||
-rw-r--r-- | test/987-agent-bind/src/art/Main.java | 28 | ||||
-rw-r--r-- | test/987-agent-bind/src/art/Test987.java | 42 | ||||
-rw-r--r-- | test/Android.bp | 1 |
17 files changed, 276 insertions, 126 deletions
diff --git a/runtime/java_vm_ext.cc b/runtime/java_vm_ext.cc index b93b8f2a97..c8dc2f2d20 100644 --- a/runtime/java_vm_ext.cc +++ b/runtime/java_vm_ext.cc @@ -40,6 +40,7 @@ #include "ScopedLocalRef.h" #include "scoped_thread_state_change-inl.h" #include "sigchain.h" +#include "ti/agent.h" #include "thread-inl.h" #include "thread_list.h" @@ -268,7 +269,6 @@ class Libraries { detail += "No implementation found for "; detail += m->PrettyMethod(); detail += " (tried " + jni_short_name + " and " + jni_long_name + ")"; - LOG(ERROR) << detail; return nullptr; } @@ -929,6 +929,26 @@ bool JavaVMExt::LoadNativeLibrary(JNIEnv* env, return was_successful; } +static void* FindCodeForNativeMethodInAgents(ArtMethod* m) REQUIRES_SHARED(Locks::mutator_lock_) { + std::string jni_short_name(m->JniShortName()); + std::string jni_long_name(m->JniLongName()); + for (const ti::Agent& agent : Runtime::Current()->GetAgents()) { + void* fn = agent.FindSymbol(jni_short_name); + if (fn != nullptr) { + VLOG(jni) << "Found implementation for " << m->PrettyMethod() + << " (symbol: " << jni_short_name << ") in " << agent; + return fn; + } + fn = agent.FindSymbol(jni_long_name); + if (fn != nullptr) { + VLOG(jni) << "Found implementation for " << m->PrettyMethod() + << " (symbol: " << jni_long_name << ") in " << agent; + return fn; + } + } + return nullptr; +} + void* JavaVMExt::FindCodeForNativeMethod(ArtMethod* m) { CHECK(m->IsNative()); mirror::Class* c = m->GetDeclaringClass(); @@ -941,8 +961,14 @@ void* JavaVMExt::FindCodeForNativeMethod(ArtMethod* m) { MutexLock mu(self, *Locks::jni_libraries_lock_); native_method = libraries_->FindNativeMethod(m, detail); } + if (native_method == nullptr) { + // Lookup JNI native methods from native TI Agent libraries. See runtime/ti/agent.h for more + // information. Agent libraries are searched for native methods after all jni libraries. + native_method = FindCodeForNativeMethodInAgents(m); + } // Throwing can cause libraries_lock to be reacquired. if (native_method == nullptr) { + LOG(ERROR) << detail; self->ThrowNewException("Ljava/lang/UnsatisfiedLinkError;", detail.c_str()); } return native_method; diff --git a/runtime/jni_internal.cc b/runtime/jni_internal.cc index b146b51033..2626eefde2 100644 --- a/runtime/jni_internal.cc +++ b/runtime/jni_internal.cc @@ -2159,10 +2159,11 @@ class JNI { } CHECK_NON_NULL_ARGUMENT_FN_NAME("RegisterNatives", java_class, JNI_ERR); ScopedObjectAccess soa(env); - ObjPtr<mirror::Class> c = soa.Decode<mirror::Class>(java_class); + StackHandleScope<1> hs(soa.Self()); + Handle<mirror::Class> c = hs.NewHandle(soa.Decode<mirror::Class>(java_class)); if (UNLIKELY(method_count == 0)) { LOG(WARNING) << "JNI RegisterNativeMethods: attempt to register 0 native methods for " - << mirror::Class::PrettyDescriptor(c); + << c->PrettyDescriptor(); return JNI_OK; } CHECK_NON_NULL_ARGUMENT_FN_NAME("RegisterNatives", methods, JNI_ERR); @@ -2171,13 +2172,13 @@ class JNI { const char* sig = methods[i].signature; const void* fnPtr = methods[i].fnPtr; if (UNLIKELY(name == nullptr)) { - ReportInvalidJNINativeMethod(soa, c, "method name", i, return_errors); + ReportInvalidJNINativeMethod(soa, c.Get(), "method name", i, return_errors); return JNI_ERR; } else if (UNLIKELY(sig == nullptr)) { - ReportInvalidJNINativeMethod(soa, c, "method signature", i, return_errors); + ReportInvalidJNINativeMethod(soa, c.Get(), "method signature", i, return_errors); return JNI_ERR; } else if (UNLIKELY(fnPtr == nullptr)) { - ReportInvalidJNINativeMethod(soa, c, "native function", i, return_errors); + ReportInvalidJNINativeMethod(soa, c.Get(), "native function", i, return_errors); return JNI_ERR; } bool is_fast = false; @@ -2220,7 +2221,7 @@ class JNI { // the parent. ArtMethod* m = nullptr; bool warn_on_going_to_parent = down_cast<JNIEnvExt*>(env)->vm->IsCheckJniEnabled(); - for (ObjPtr<mirror::Class> current_class = c; + for (ObjPtr<mirror::Class> current_class = c.Get(); current_class != nullptr; current_class = current_class->GetSuperClass()) { // Search first only comparing methods which are native. @@ -2252,14 +2253,14 @@ class JNI { << "Failed to register native method " << c->PrettyDescriptor() << "." << name << sig << " in " << c->GetDexCache()->GetLocation()->ToModifiedUtf8(); - ThrowNoSuchMethodError(soa, c, name, sig, "static or non-static"); + ThrowNoSuchMethodError(soa, c.Get(), name, sig, "static or non-static"); return JNI_ERR; } else if (!m->IsNative()) { LOG(return_errors ? ::android::base::ERROR : ::android::base::FATAL) << "Failed to register non-native method " << c->PrettyDescriptor() << "." << name << sig << " as native"; - ThrowNoSuchMethodError(soa, c, name, sig, "native"); + ThrowNoSuchMethodError(soa, c.Get(), name, sig, "native"); return JNI_ERR; } diff --git a/runtime/runtime.h b/runtime/runtime.h index 20db628a75..b91cb0c9be 100644 --- a/runtime/runtime.h +++ b/runtime/runtime.h @@ -657,6 +657,10 @@ class Runtime { void AttachAgent(const std::string& agent_arg); + const std::list<ti::Agent>& GetAgents() const { + return agents_; + } + RuntimeCallbacks* GetRuntimeCallbacks(); void InitThreadGroups(Thread* self); diff --git a/runtime/ti/agent.cc b/runtime/ti/agent.cc index 0bba44c988..86f5282664 100644 --- a/runtime/ti/agent.cc +++ b/runtime/ti/agent.cc @@ -72,6 +72,11 @@ Agent::LoadError Agent::DoLoadHelper(bool attaching, } } +void* Agent::FindSymbol(const std::string& name) const { + CHECK(IsStarted()) << "Cannot find symbols in an unloaded agent library " << this; + return dlsym(dlopen_handle_, name.c_str()); +} + Agent::LoadError Agent::DoDlOpen(/*out*/std::string* error_msg) { DCHECK(error_msg != nullptr); @@ -86,18 +91,15 @@ Agent::LoadError Agent::DoDlOpen(/*out*/std::string* error_msg) { return kLoadingError; } - onload_ = reinterpret_cast<AgentOnLoadFunction>(dlsym(dlopen_handle_, - AGENT_ON_LOAD_FUNCTION_NAME)); + onload_ = reinterpret_cast<AgentOnLoadFunction>(FindSymbol(AGENT_ON_LOAD_FUNCTION_NAME)); if (onload_ == nullptr) { VLOG(agents) << "Unable to find 'Agent_OnLoad' symbol in " << this; } - onattach_ = reinterpret_cast<AgentOnLoadFunction>(dlsym(dlopen_handle_, - AGENT_ON_ATTACH_FUNCTION_NAME)); + onattach_ = reinterpret_cast<AgentOnLoadFunction>(FindSymbol(AGENT_ON_ATTACH_FUNCTION_NAME)); if (onattach_ == nullptr) { VLOG(agents) << "Unable to find 'Agent_OnAttach' symbol in " << this; } - onunload_= reinterpret_cast<AgentOnUnloadFunction>(dlsym(dlopen_handle_, - AGENT_ON_UNLOAD_FUNCTION_NAME)); + onunload_= reinterpret_cast<AgentOnUnloadFunction>(FindSymbol(AGENT_ON_UNLOAD_FUNCTION_NAME)); if (onunload_ == nullptr) { VLOG(agents) << "Unable to find 'Agent_OnUnload' symbol in " << this; } diff --git a/runtime/ti/agent.h b/runtime/ti/agent.h index 7408aeec35..b5ecba19d9 100644 --- a/runtime/ti/agent.h +++ b/runtime/ti/agent.h @@ -29,8 +29,14 @@ namespace ti { using AgentOnLoadFunction = jint (*)(JavaVM*, const char*, void*); using AgentOnUnloadFunction = void (*)(JavaVM*); +// Agents are native libraries that will be loaded by the runtime for the purpose of +// instrumentation. They will be entered by Agent_OnLoad or Agent_OnAttach depending on whether the +// agent is being attached during runtime startup or later. +// +// The agent's Agent_OnUnload function will be called during runtime shutdown. +// // TODO: consider splitting ti::Agent into command line, agent and shared library handler classes - +// TODO Support native-bridge. Currently agents can only be the actual runtime ISA of the device. class Agent { public: enum LoadError { @@ -56,6 +62,8 @@ class Agent { return !GetArgs().empty(); } + void* FindSymbol(const std::string& name) const; + LoadError Load(/*out*/jint* call_res, /*out*/std::string* error_msg) { VLOG(agents) << "Loading agent: " << name_ << " " << args_; return DoLoadHelper(false, call_res, error_msg); diff --git a/test/986-native-method-bind/expected.txt b/test/986-native-method-bind/expected.txt index 189217d761..3376e6f91b 100644 --- a/test/986-native-method-bind/expected.txt +++ b/test/986-native-method-bind/expected.txt @@ -1,8 +1,10 @@ -private static native void art.Test986$Transform.sayHi() = Java_art_Test986_00024Transform_sayHi -> Java_art_Test986_00024Transform_sayHi -Hello -private static native void art.Test986$Transform.sayHi() = Java_art_Test986_00024Transform_sayHi -> NoReallySayGoodbye +private static native void art.Test986$Transform.sayHi2() = Java_art_Test986_00024Transform_sayHi2 -> Java_art_Test986_00024Transform_sayHi2 +Hello - 2 +private static native void art.Test986$Transform.sayHi() = Java_art_Test986_00024Transform_sayHi__ -> NoReallySayGoodbye Bye -public static native void art.Main.bindAgentJNI(java.lang.String,java.lang.ClassLoader) = Java_art_Main_bindAgentJNI -> Java_art_Main_bindAgentJNI -public static native void art.Main.bindAgentJNIForClass(java.lang.Class) = Java_art_Main_bindAgentJNIForClass -> Java_art_Main_bindAgentJNIForClass -private static native void art.Test986.setNativeBindNotify(boolean) = Java_art_Test986_setNativeBindNotify -> Java_art_Test986_setNativeBindNotify -private static native void art.Test986.setupNativeBindNotify() = Java_art_Test986_setupNativeBindNotify -> Java_art_Test986_setupNativeBindNotify +private static native void art.Test986$Transform.sayHi() = Java_art_Test986_00024Transform_sayHi__ -> Java_art_Test986_00024Transform_sayHi2 +private static native void art.Test986$Transform.sayHi2() = Java_art_Test986_00024Transform_sayHi2 -> Java_art_Test986_00024Transform_sayHi2 +Hello - 2 +private static native void art.Test986$Transform.sayHi() = Java_art_Test986_00024Transform_sayHi__ -> Java_art_Test986_00024Transform_sayHi__ +private static native void art.Test986$Transform.sayHi2() = Java_art_Test986_00024Transform_sayHi2 -> Java_art_Test986_00024Transform_sayHi2 +Hello diff --git a/test/986-native-method-bind/native_bind.cc b/test/986-native-method-bind/native_bind.cc index 4f93f87dfe..eec635b2a0 100644 --- a/test/986-native-method-bind/native_bind.cc +++ b/test/986-native-method-bind/native_bind.cc @@ -38,11 +38,16 @@ static void doUpPrintCall(JNIEnv* env, const char* function) { env->CallStaticVoidMethod(klass.get(), targetMethod); } -extern "C" JNIEXPORT void JNICALL Java_art_Test986_00024Transform_sayHi( +extern "C" JNIEXPORT void JNICALL Java_art_Test986_00024Transform_sayHi__( JNIEnv* env, jclass klass ATTRIBUTE_UNUSED) { doUpPrintCall(env, "doSayHi"); } +extern "C" JNIEXPORT void JNICALL Java_art_Test986_00024Transform_sayHi2( + JNIEnv* env, jclass klass ATTRIBUTE_UNUSED) { + doUpPrintCall(env, "doSayHi2"); +} + extern "C" JNIEXPORT void JNICALL NoReallySayGoodbye(JNIEnv* env, jclass klass ATTRIBUTE_UNUSED) { doUpPrintCall(env, "doSayBye"); } @@ -106,5 +111,17 @@ extern "C" JNIEXPORT void JNICALL Java_art_Test986_setNativeBindNotify( } } +extern "C" JNIEXPORT void JNICALL Java_art_Test986_rebindTransformClass( + JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jclass k) { + JNINativeMethod m[2]; + m[0].name= "sayHi"; + m[0].signature = "()V"; + m[0].fnPtr = reinterpret_cast<void*>(Java_art_Test986_00024Transform_sayHi__); + m[1].name= "sayHi2"; + m[1].signature = "()V"; + m[1].fnPtr = reinterpret_cast<void*>(Java_art_Test986_00024Transform_sayHi2); + env->RegisterNatives(k, m, 2); +} + } // namespace Test986NativeBind } // namespace art diff --git a/test/986-native-method-bind/src/art/Redefinition.java b/test/986-native-method-bind/src/art/Redefinition.java deleted file mode 100644 index 0350ab42ad..0000000000 --- a/test/986-native-method-bind/src/art/Redefinition.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * 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 art; - -import java.util.ArrayList; -// Common Redefinition functions. Placed here for use by CTS -public class Redefinition { - // Bind native functions. - static { - Main.bindAgentJNIForClass(Redefinition.class); - } - - public static final class CommonClassDefinition { - public final Class<?> target; - public final byte[] class_file_bytes; - public final byte[] dex_file_bytes; - - public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { - this.target = target; - this.class_file_bytes = class_file_bytes; - this.dex_file_bytes = dex_file_bytes; - } - } - - // A set of possible test configurations. Test should set this if they need to. - // This must be kept in sync with the defines in ti-agent/common_helper.cc - public static enum Config { - COMMON_REDEFINE(0), - COMMON_RETRANSFORM(1), - COMMON_TRANSFORM(2); - - private final int val; - private Config(int val) { - this.val = val; - } - } - - public static void setTestConfiguration(Config type) { - nativeSetTestConfiguration(type.val); - } - - private static native void nativeSetTestConfiguration(int type); - - // Transforms the class - public static native void doCommonClassRedefinition(Class<?> target, - byte[] classfile, - byte[] dexfile); - - public static void doMultiClassRedefinition(CommonClassDefinition... defs) { - ArrayList<Class<?>> classes = new ArrayList<>(); - ArrayList<byte[]> class_files = new ArrayList<>(); - ArrayList<byte[]> dex_files = new ArrayList<>(); - - for (CommonClassDefinition d : defs) { - classes.add(d.target); - class_files.add(d.class_file_bytes); - dex_files.add(d.dex_file_bytes); - } - doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), - class_files.toArray(new byte[0][]), - dex_files.toArray(new byte[0][])); - } - - public static void addMultiTransformationResults(CommonClassDefinition... defs) { - for (CommonClassDefinition d : defs) { - addCommonTransformationResult(d.target.getCanonicalName(), - d.class_file_bytes, - d.dex_file_bytes); - } - } - - public static native void doCommonMultiClassRedefinition(Class<?>[] targets, - byte[][] classfiles, - byte[][] dexfiles); - public static native void doCommonClassRetransformation(Class<?>... target); - public static native void setPopRetransformations(boolean pop); - public static native void popTransformationFor(String name); - public static native void enableCommonRetransformation(boolean enable); - public static native void addCommonTransformationResult(String target_name, - byte[] class_bytes, - byte[] dex_bytes); -} diff --git a/test/986-native-method-bind/src/art/Test986.java b/test/986-native-method-bind/src/art/Test986.java index edd2e9d79f..aac73d33ab 100644 --- a/test/986-native-method-bind/src/art/Test986.java +++ b/test/986-native-method-bind/src/art/Test986.java @@ -32,6 +32,7 @@ public class Test986 { // A class with a native method we can play with. static class Transform { private static native void sayHi(); + private static native void sayHi2(); } public static void run() throws Exception { @@ -44,6 +45,10 @@ public class Test986 { SymbolMap.put(method, dest); } + private static void removeNativeTransform(Method method) { + SymbolMap.remove(method); + } + /** * Notifies java that a native method bind has occurred and requests the new symbol to bind to. */ @@ -58,14 +63,23 @@ public class Test986 { public static void doTest() throws Exception { Method say_hi_method = Transform.class.getDeclaredMethod("sayHi"); - // TODO We should test auto-binding but due to the way this is run that will be annoying. - Main.bindAgentJNIForClass(Transform.class); - Transform.sayHi(); + + // Test we will bind fine if we make no changes. + Transform.sayHi2(); + + // Test we can get in the middle of autobind setNativeTransform(say_hi_method, "NoReallySayGoodbye"); - Main.bindAgentJNIForClass(Transform.class); Transform.sayHi(); - Main.bindAgentJNIForClass(Main.class); - Main.bindAgentJNIForClass(Test986.class); + + // Test we can get in between manual bind. + setNativeTransform(say_hi_method, "Java_art_Test986_00024Transform_sayHi2"); + rebindTransformClass(); + Transform.sayHi(); + + // Test we can get rid of transform + removeNativeTransform(say_hi_method); + rebindTransformClass(); + Transform.sayHi(); } // Functions called from native code. @@ -73,10 +87,18 @@ public class Test986 { System.out.println("Hello"); } + public static void doSayHi2() { + System.out.println("Hello - 2"); + } + public static void doSayBye() { System.out.println("Bye"); } private static native void setNativeBindNotify(boolean enable); private static native void setupNativeBindNotify(); + private static void rebindTransformClass() { + rebindTransformClass(Transform.class); + } + private static native void rebindTransformClass(Class<?> trans); } diff --git a/test/987-agent-bind/agent_bind.cc b/test/987-agent-bind/agent_bind.cc new file mode 100644 index 0000000000..44366c1054 --- /dev/null +++ b/test/987-agent-bind/agent_bind.cc @@ -0,0 +1,52 @@ +/* + * 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. + */ + +#include <inttypes.h> +#include <memory> +#include <stdio.h> +#include <dlfcn.h> + +#include "android-base/stringprintf.h" +#include "jni.h" +#include "jvmti.h" + +// Test infrastructure +#include "jni_binder.h" +#include "jvmti_helper.h" +#include "test_env.h" +#include "scoped_local_ref.h" + +namespace art { +namespace Test987AgentBind { + +static void doUpPrintCall(JNIEnv* env, const char* function) { + ScopedLocalRef<jclass> klass(env, env->FindClass("art/Test987")); + jmethodID targetMethod = env->GetStaticMethodID(klass.get(), function, "()V"); + env->CallStaticVoidMethod(klass.get(), targetMethod); +} + +extern "C" JNIEXPORT void JNICALL Java_art_Test987_00024Transform_sayHi__( + JNIEnv* env, jclass klass ATTRIBUTE_UNUSED) { + doUpPrintCall(env, "doSayHi"); +} + +extern "C" JNIEXPORT void JNICALL Java_art_Test987_00024Transform_sayHi2( + JNIEnv* env, jclass klass ATTRIBUTE_UNUSED) { + doUpPrintCall(env, "doSayHi2"); +} + +} // namespace Test987AgentBind +} // namespace art diff --git a/test/987-agent-bind/expected.txt b/test/987-agent-bind/expected.txt new file mode 100644 index 0000000000..ee4a4247bd --- /dev/null +++ b/test/987-agent-bind/expected.txt @@ -0,0 +1,2 @@ +Hello +Hello - 2 diff --git a/test/987-agent-bind/info.txt b/test/987-agent-bind/info.txt new file mode 100644 index 0000000000..ae4a651442 --- /dev/null +++ b/test/987-agent-bind/info.txt @@ -0,0 +1 @@ +Tests that native methods are bound from agent libs. diff --git a/test/987-agent-bind/run b/test/987-agent-bind/run new file mode 100755 index 0000000000..e92b873956 --- /dev/null +++ b/test/987-agent-bind/run @@ -0,0 +1,17 @@ +#!/bin/bash +# +# Copyright 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. + +./default-run "$@" --jvmti diff --git a/test/987-agent-bind/src/Main.java b/test/987-agent-bind/src/Main.java new file mode 100644 index 0000000000..9ce6242c62 --- /dev/null +++ b/test/987-agent-bind/src/Main.java @@ -0,0 +1,21 @@ +/* + * 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. + */ + +public class Main { + public static void main(String[] args) throws Exception { + art.Test987.run(); + } +} diff --git a/test/987-agent-bind/src/art/Main.java b/test/987-agent-bind/src/art/Main.java new file mode 100644 index 0000000000..8b01920638 --- /dev/null +++ b/test/987-agent-bind/src/art/Main.java @@ -0,0 +1,28 @@ +/* + * 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 art; + +// Binder class so the agent's C code has something that can be bound and exposed to tests. +// In a package to separate cleanly and work around CTS reference issues (though this class +// should be replaced in the CTS version). +public class Main { + // Load the given class with the given classloader, and bind all native methods to corresponding + // C methods in the agent. Will abort if any of the steps fail. + public static native void bindAgentJNI(String className, ClassLoader classLoader); + // Same as above, giving the class directly. + public static native void bindAgentJNIForClass(Class<?> klass); +} diff --git a/test/987-agent-bind/src/art/Test987.java b/test/987-agent-bind/src/art/Test987.java new file mode 100644 index 0000000000..ae97ff25c3 --- /dev/null +++ b/test/987-agent-bind/src/art/Test987.java @@ -0,0 +1,42 @@ +/* + * 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 art; + +public class Test987 { + // A class with a native method we can play with. + static class Transform { + private static native void sayHi(); + private static native void sayHi2(); + } + + public static void run() throws Exception { + doTest(); + } + + public static void doTest() throws Exception { + Transform.sayHi(); + Transform.sayHi2(); + } + // Functions called from native code. + public static void doSayHi() { + System.out.println("Hello"); + } + + public static void doSayHi2() { + System.out.println("Hello - 2"); + } +} diff --git a/test/Android.bp b/test/Android.bp index d8a3f0eeed..2b711cdc12 100644 --- a/test/Android.bp +++ b/test/Android.bp @@ -277,6 +277,7 @@ art_cc_defaults { "945-obsolete-native/obsolete_native.cc", "984-obsolete-invoke/obsolete_invoke.cc", "986-native-method-bind/native_bind.cc", + "987-agent-bind/agent_bind.cc", ], shared_libs: [ "libbase", |