Android

关注公众号 jb51net

关闭
首页 > 软件编程 > Android > Android调用jar

Android通过bin二进制程序调用jar原理

作者:淘淘养乐多

最近在研究monkey测试,发现monkey测试的代码都是JAVA编写的,通过编译生成jar包,而我们在执行测试时直接执行/system/bin/monkey这个二进制程序的,那么它是如何能调起java程序的呢,本文小编给大家介绍了Android通过bin二进制程序调用jar原理,需要的朋友可以参考下

先来看看monkey二进程程序的生成.

development\cmds\monkey\Android.mk
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_MODULE := monkeylib
LOCAL_MODULE_STEM := monkey
include $(BUILD_JAVA_LIBRARY)
################################################################
include $(CLEAR_VARS)
LOCAL_MODULE := monkey
LOCAL_MODULE_CLASS := EXECUTABLES
LOCAL_SRC_FILES := monkey
LOCAL_REQUIRED_MODULES := monkeylib
include $(BUILD_PREBUILT)

Android.mk分了两部分,第一部分是编译生成monkey.jar,第二部分是把monkey这个文件编译生成monkey的二进制程序,看看monkey这个文件。

development\cmds\monkey\monkey
base=/system
export CLASSPATH=$base/framework/monkey.jar
.........
exec app_process $base/bin com.android.commands.monkey.Monkey "$@"

monkey这是一个shell文件,先设置把monkey.jar添加环境变量中,然后执行app_process这个二进制程序,同时传入monkey jar的路径和类名。

app_process是在frameworks\base\cmds\路径下,直接看它的main函数

frameworks\base\cmds\app_process\app_main.cpp
int main(int argc, char* const argv[])
{
    .........
    AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));//创建AndroidRuntime
   ..............
    while (i < argc) {
        const char* arg = argv[i++];
        if (strcmp(arg, "--zygote") == 0) {
            zygote = true;
            niceName = ZYGOTE_NICE_NAME;
        } else if (strcmp(arg, "--start-system-server") == 0) {
            startSystemServer = true;
        } else if (strcmp(arg, "--application") == 0) {
            application = true;
        } else if (strncmp(arg, "--nice-name=", 12) == 0) {
            niceName.setTo(arg + 12);
        } else if (strncmp(arg, "--", 2) != 0) {//monkey测试时,传入的是monkey jar的路径和包名,所以进入这个分支
            className.setTo(arg);//className包含com.android.commands.monkey.Monkey
            break;
        } else {
            --i;
            break;
        }
    }
    Vector<String8> args;
    if (!className.isEmpty()) {
        ...............
        args.add(application ? String8("application") : String8("tool"));
        runtime.setClassNameAndArgs(className, argc - i, argv + i);//com.android.commands.monkey.Monkey添加到AndroidRuntime中
        .............
    } else {
       ............
    }
    。。。。。。。。。。。。。
    if (zygote) {
        runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
    } else if (className) {//className为com.android.commands.monkey.Monkey
        runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
    } else {
        fprintf(stderr, "Error: no class name or --zygote supplied.\n");
        app_usage();
        LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
    }
}

app_process.cpp的main方法先解析argv参数,创建AndroidRuntime的实例,并传入类名,最后调用AndroidRuntime.start

framework/base/core/jni/AndroidRuntime.cpp
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
    ...........
    //当前环境是否在ANDROID_ROOT、ANDROID_RUNTIME_ROOT、ANDROID_TZDATA_ROOT
    const char* rootDir = getenv("ANDROID_ROOT");
    ...............
    const char* runtimeRootDir = getenv("ANDROID_RUNTIME_ROOT");
    ..................
    const char* tzdataRootDir = getenv("ANDROID_TZDATA_ROOT");
    .............
    JniInvocation jni_invocation;
    jni_invocation.Init(NULL);//jni初始化
    JNIEnv* env;
    if (startVm(&mJavaVM, &env, zygote) != 0) {//启动java虚拟机
        return;
    }
    onVmCreated(env);//java虚拟机创建
    if (startReg(env) < 0) {//注册jni
        ALOGE("Unable to register all android natives\n");
        return;
    }
    .............................................................................
    //jnv的环境设置和类型转换
    .............................................................................
    char* slashClassName = toSlashClassName(className != NULL ? className : "");//className为com.android.internal.os.RuntimeInit
    jclass startClass = env->FindClass(slashClassName);//得到java类,startClass为com.android.internal.os.RuntimeInit
    if (startClass == NULL) {
        ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
        /* keep going */
    } else {
        jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
            "([Ljava/lang/String;)V");//通过类名获得类名里的main方法
        if (startMeth == NULL) {
            ALOGE("JavaVM unable to find main() in '%s'\n", className);
            /* keep going */
        } else {
            env->CallStaticVoidMethod(startClass, startMeth, strArray);//由C调用JAVA,反射调起com.android.internal.os.RuntimeInit的main方法,进入到java世界
        }
    }
    ...............
}

start方法里面首先判断当前环境是否在ANDROID_ROOT、ANDROID_RUNTIME_ROOT、ANDROID_TZDATA_ROOT,然后调用startVm,startVm主要是设置虚拟机的一些参数,onVmCreated是通过jni的环境检查类名是否存在,即检查com.android.internal.os.RuntimeInit是否存在,最后通过反射调起java的main方法。

我们继续看com.android.internal.os.RuntimeInit的main方法

frameworks\base\core\java\com\android\internal\os\RuntimeInit.java
public static final void main(String[] argv) {
   .........
    commonInit();//做些log的打印和异常的捕获
    nativeFinishInit();//又进入C/C++世界
    ...............
}
virtual void onStarted()
    {
       ...............
        AndroidRuntime* ar = AndroidRuntime::getRuntime();
        ar->callMain(mClassName, mClass, mArgs);
        .....................
    }
framework/base/core/jni/AndroidRuntime.cpp
status_t AndroidRuntime::callMain(const String8& className, jclass clazz,
    const Vector<String8>& args)
{
    ................
    methodId = env->GetStaticMethodID(clazz, "main", "([Ljava/lang/String;)V");//通过类名找到静态方法名为main的id
    if (methodId == NULL) {
        ALOGE("ERROR: could not find method %s.main(String[])\n", className.string());
        return UNKNOWN_ERROR;
    }
     //args类型转换
    const size_t numArgs = args.size();
    stringClass = env->FindClass("java/lang/String");
    strArray = env->NewObjectArray(numArgs, stringClass, NULL);
    for (size_t i = 0; i < numArgs; i++) {
        jstring argStr = env->NewStringUTF(args[i].string());
        env->SetObjectArrayElement(strArray, i, argStr);
    }
    env->CallStaticVoidMethod(clazz, methodId, strArray);//调起类名里的main静态方法,即com.android.commands.monkey.Monkey的main方法
    return NO_ERROR;
}

总结:通过命令执行monkey时,先设置monkey.jar的环境变量,然后执行app_process的程序,并传入monkey二进制程序的路径和monkey的类名,这时就进入到了app_process程序。在app_process的main方法里,创建AndroidRuntime的实例,对参数进行校验,把com.android.internal.os.RuntimeInit包名传给AndroidRuntime;在AndroidRuntime里做jni的初始化,设置虚拟机参数,注册jni,然后反射com.android.internal.os.RuntimeInit的main静态方法,最后在AndroidRuntime里通过反射调起类名里的main方法。

app_process程序还是非常不错的,利用好它,我们可以仿照monkey程序,开发出一些特殊的程序。

以上就是Android通过bin二进制程序调用jar原理的详细内容,更多关于Android调用jar的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文