Good question! I had to dig a bit to figure this out.

There are a slew of JNI methods in libandroid_runtime.so that don't get bound by default, when you're using the dalvikvm command. Unfortunately, you can't just do a System.loadLibrary("android_runtime"), because this doesn't actually bind all the native methods.

However, after some digging, it turns out there is an internal, non-public, not guaranteed to be there class called com.android.internal.util.WithFramework, whose purpose is to load libandroid_runtime.so and bind all its JNI methods.

To use it, just throw com.android.internal.util.WithFramework in front of your class name, on the dalvikvm command, like so:

dalvikvm -cp /some/path/classes.dex com.android.internal.util.WithFramework my.example.cls "This is an argument"

(Note: This only works on pre-M devices, due to the WithFramework class being removed in M - thanks for the heads up @JaredRummler)


For android M, I found this method to work.
Create a helloworld.sh script to accompany your jar\zip file:

#!/system/bin/sh
# Copied by example from am command
base=/system
export CLASSPATH=/path/to/your/jar/HelloWorld.jar
exec app_process $base/bin HelloWorldMainClass "$@"

app_process seems to start your java code with all java classes and shared libs loaded, so you can use both SDK classes like android.util.log.Log AND "secret" native classes, e.g. ActivityManagerNative, that are used in other adb shell commands, and are not present in the SDK.

BTW, for the java shell command I created, I had to resort to using reflection for the above classes, because it seems to me there is no way to compile properly without cloning and building the entire AOSP...
If someone knows an easier way to e.g. use ActivityManagerNative in java code without reflection, I'd appreciate the help.