Why java.sql.DriverManager.getCallerClassLoader() is native? - java

The method DriverManager.getCallerClassLoader() in class java.sql.DriverManager is declared as native. I understand that all the class loaders references in an application are available in the current executing JVM. Also, my basic understanding about native method is that it's used to call the method defined in native libraries and they execute outside the JVM execution environment.
My question is, what is that needed by DriverManager.getCallerClassLoader() which requires its implementation to be native?

My basic understanding about native method is that its used to call the method defined in native libraries
This is correct, native methods represent calls of the code that is part of a natively compiled library
and they execute outside the JVM execution environment
That is what native methods typically do. That is, the native methods that Java users write. However, native methods are not limited in what they can do: once you're outside of JVM, you can do what you wish. In fact, Java's built-in classes such as Class<T>, heavily rely on the ability to do so, with dozens of native method sprinkled around their Java code.
One of these methods is package-private java.lang.Class<T>.getClassLoader0 (yes, with a zero). The implementation of ClassLoader.getCallerClassLoader ultimately refer to this method, which queries the internals of JVM to fetch the class loader.
Note that DriverManager cannot forward the call to ClassLoader.getCallerClassLoader, because that would return the DriverManager's class loader (because DriverManager would be the caller of getCallerClassLoader). It is not possible for the DriverManager to repeat the "magic" of ClassLoader's getCallerClassLoader either, because it is located in a different package (i.e. not in the java.lang), so Class<T>.getClasLoader0 is not accessible. That is why it is forced to move the getCallerClassLoader into the native territory, where the native code can obtain the calling class and fetch its class loader without restrictions.

Related

Can i control JNI native method invocation name in Java?

I stuck with a problem. I use Chilkat for Java and as i understand there is no, any Maven Repo for it. As it is a two-component library - i need to inject .dll, via System.load(). This part is clear to me, but also they provides something, like wrapper, which calls methods in .dll.
So, i don't want to import their .jar to my project, but, then i call native methods by my own it fails with java.lang.UnsatisfiedLinkError. Because, then java tries to invoke a native method it adds some stuff at the beginning of it's name. For example: if i declare native method in my package, then it will be invoked, java will add all package hierarchy names to it's name.
Can i somehow call directly the native method by it's name, without any runtime "adaptations" ?
javac can generate the bindings you might be looking for ...DLL export viewer (among several others) can list exported methods. Or for SO, just use dumpbin /EXPORTS ./filename. That method names would change at runtime is not a reality, this only happens once when obfuscating them, at build time - which usually excludes all the objects, which need to stay accessible (for reflection).
Just start a new JNI project and learn how it works with vastly reduced complexity. There still is a chance, that this one JAR might pass licensing information in the native assembly - or that the native assembly performs cryptographic functionality for the JAR. An a commercial library is not to be treated alike open source - I'd read THEIR licensing terms, to begin with.

Restricting C++ code from accessing certain classes in JNI

I have two classes in a Java program. Class A and Class B.
Class B contains a native function that will execute C++ code.
As far as I know, the C++ code will run in the same process as the Java code.
The question that I have is that how can I limit the C++ code from accessing the Java memory and reading Class A's parameters?
I am afraid you are out of luck. Unlike reflection, JNI is completely unsecurable: CallVoidMethod() or GetIntField() can access everything.
To a certain extent, obfuscation can help. If class A is obfuscated, human-readable names of all its fields and methods are gone. Usually obfuscators generate stable, predictable names, but with an easy trick they can be randomized. Proguard can also 'optimize' your class, inlining some methods. Methods that don't exist anymore, cannot be called via JNI.
But still, the fields will be there, the methods that are called from 'outside' will still be there and maybe even preserve their names. So, better don't load a JNI library that you cannot trust into your process. Well, this is true for any DLL.

View.isInEditMode() statically?

I'm using JNI in my app. In Java classes which need native things I load the native library like so:
static
{
System.loadLibrary("nativeegl");
}
To be honest I don't know what the static thing does exactly, but I guess this is to make sure that the nativeegl library is loaded before anything else. Don't remember where I got this pattern from.
Now if this is a View subclass, and I'm using the graphical editor in Android Studio, the editor can't load the view subclass because of this exception:
java.lang.UnsatisfiedLinkError: no nativeegl in java.library.path
Since View.isInEditMode() is an instance method, I can't use it within the static{} block.
Is there an alternative? Maybe I can load the library differently?
Now that I think about it, one possible workaround is to split your View code into two classes: the actual View, and a separate standalone class that contains your JNI code, including the static block. For the purposes of the rest of this answer, I'll call these FooView and BarWrapper, respectively.
Then, only reference BarWrapper from code in FooView that is inside an if (isInEditMode()) block.
This may prevent BarWrapper from being loaded by the Java/pseudoAndroid environment used by the GUI builder, and therefore not trigger the attempt to load your native library. Leastways, the Dalvik classloading rules would cause BarWrapper to be ignored, as classes only get loaded when they are first used, and in your case you would be skipping over all code that uses BarWrapper. Hopefully, the GUI builder code adheres to how Dalvik handles it, though that's far from assured, since it's running on a Java VM, not an Android VM (Dalvik or ART).
It may make your code a bit more clunky, as you have to split out your logic between two classes instead of just one. But, it may be worth an experiment.

Is there any solution about Load Time Bytecode Transformation without specify javaagent option in java command line

As an Open Source Lifecycle Framework API provider, I want to try my best to hiding internal designs with an implicit manner to Provide Lifecycle API, so that will bring much more convenience to API Client.
It is expected to avoid doing configuration for both Core Java Applications and Java EE Applications, but the reality is that I am using java command -javaagent:${path}/Lifecycle.jar option to enable my own ClassFileTransformer at class load time.
After some searches, some unclear directions were found. I need some Java Guy to summarize and guide us.
agentmain vs premain
intergration with specified runtime environment, such as Glassfish's ByteCodePreprocessor, which has the following method to perform byte code transformation:
public byte[] preprocess(String classname, byte[] classBytes);
My confusions about those directions:
For Core Java Application, it seems that we can modify startup class' main method to adapt agentmain solution. Is there some other options?
For using JavaEE Container, such as Glassfish, I can use ByteCodePreprocessor to modify class byte code, but I need to create some new classes, but I don't know where to store those new class files, or how to design or apply a new ClassLoader to load the newly created class files during preprocessing a class file.
(BTW Lifecycle API will follow a meta-driven style, which is very close with JPA without EntityManager interface, and most of them is just Annotations and CallbackContext interface and LifecycleEvent interface for now.)
Well, the only other method I could think of would be using a custom class loader which you could register at run time. This is how frameworks like Powermock do their heavy lifting. However, this requires some setup as well, but it can be done programatically.
As long as your framework has well defined entry points and as long as all code is run from within your application, you could apply a custom class loader which could instrument all loaded classes.
However, this will not work for classes already loaded. (You could break the parent first patern, but this might raise ClassCastExceptions on instances from outside your framework.)
Avoiding this would require you to override the system class loader which is equally verbose. For the sake of completeness, here is an excerpt of the javadoc of ClassLoader.getSystemClassLoader:
If the system property "java.system.class.loader" is defined when this
method is first invoked then the value of that property is taken to be
the name of a class that will be returned as the system class loader.
The class is loaded using the default system class loader and must
define a public constructor that takes a single parameter of type
ClassLoader which is used as the delegation parent. An instance is
then created using this constructor with the default system class
loader as the parameter. The resulting class loader is defined to be
the system class loader.
In this custom class loader, you could just always return instrumented classes.
The difference between agentmain and premain is that the former is invoked when you attach an agent to a running JVM (via the attach API) while the latter is invoked if the agent is specified on the command line at the JVM's startup. Registering an agent at runtime might actually be a solution for you. The blog entry that I linked offers a quite good description of that.

native java bytecode instrumentation

for bytecode instrumentation in java, there is the asm framework and the bcel and javaassist libraries.
However I need to do instrumentation in native code, since some java classes are already loaded by the time the javaagent runs, eg java.lang.Thread, java.lang.Class, etc
is there any library for instrumenting java classes in native code?
Edit:
Seems there is a bit of confusion.
What I want is:
Create a native java agent, which uses JVMTI apis to change the bytecode of a class while its being loaded, using the OnClassLoad event hook.
I encountered this problem during my doctoral research. The answer that worked best for me was to perform the byte-code modification in a separate JVM using a java library (I used ASM).
I used the JVMTI class load hook to capture the class file and transmit it to the separate JVM using a tcp connection. Once the class had been modified within the separate JVM I returned it to the JVMTI Agent, which copies it into VM memory and returns a pointer to the modified class file to the JVM.
I found that it was too difficult to weave classes within the same JVM as was being profiled as the system class files I wanted to modify (java.lang.Object, for example) had to be loaded before any class files I needed to perform weaving. I hunted for c/c++ bytecode libraries without much success, before settling on the separate JVM approach I finally used.
You can parameterize the JVMTI agent with the hostname/port of the weaver JVM, or you could use some form of discovery, depending on your requirements.
The JIT will turn byte code into native code. If you want to produce native code, you need to let the JIT do it or write native code which is called via JNI.
Perhaps what you are trying to achieve can be done simpler another way.
Create a native java agent, which uses JVMTI apis to change the bytecode of a class while its being loaded, using the OnClassLoad event hook.
Though you don't need to do what you want. Why make the solution more complicated (and less likely to work) than it needs to be?
You cannot change the byte code of a class once it has been loaded. You can either make sure your instrumentation runs before it is loaded, or you can create a new ClassLoader, and re-load the classes inside of it by not asking the parent class. You can't use those classes with code loaded outside of the ClassLoader though, as that code will refer to the earlier loaded, non-altered class.

Categories