将 Dalvik 字节码动态生成到正在运行的 Dalvik/Android 应用程序中

Posted

技术标签:

【中文标题】将 Dalvik 字节码动态生成到正在运行的 Dalvik/Android 应用程序中【英文标题】:Dynamically Generating Dalvik Bytecode into a running Dalvik/Android application 【发布时间】:2011-02-06 08:21:22 【问题描述】:

关于在运行时动态生成 java 字节码并将其加载到正在运行的 Dalvik VM 中,这个问题已被多次询问(并回答),但是有没有办法在运行时将 dex 文件/字节码加载到应用程序中?

谢谢

【问题讨论】:

【参考方案1】:

Dalvik 团队希望构建一流的运行时代码生成库。我们以android bug 6322 跟踪功能请求。不幸的是,我们有很长的性能和正确性问题列表,因此我无法为您提供我们何时会花时间解决此问题的时间表。

有一些替代方案,但它们都需要一些工作:

在标准 JVM 上运行您的应用程序,并在那里执行所有运行时代码生成。将 .class 文件从内存转储到文件,然后对这些文件运行 dx。如果您相当老练,您可以将所有这些工作集成到您的构建中。

将开源 dx 工具作为项目库包含在内,并在您的应用程序中(可能在应用程序的类加载器中)以编程方式执行它。这将使您的应用程序的二进制文件膨胀。

【讨论】:

感谢您的回答。有什么阻止我现在编写自己的代码生成器吗?我为 .Net->Flash 和 .Net->.Net 编写了一个,而 Dex 就像 Java .Class 和 Flash .ABC 文件之间的交叉。另外,感谢您的链接。我给它加了星标并添加了一条评论(要求它的 API 类似于 .Net 的 DLR)。 您现在绝对可以编写自己的代码生成器。如果你给它一个 Apache 许可证,那就更好了! 更新:看看 dexmaker 让这一切变得简单:code.google.com/p/dexmaker 现在 Android 正在转向 ART,发布这样一个库的机会有多大?新的执行模型还能实现吗? @lxgr 查看相关问题:***.com/questions/23739261/…【参考方案2】:

有没有办法加载dex 文件/字节码到应用程序中 运行时间?

看看DexFileDexClassLoader

【讨论】:

上一个话题:***.com/questions/1001944/android-remote-code-loading/…【参考方案3】:

A related answer 建议 Dexmaker 用于动态 Dalvik 字节码生成。

【讨论】:

【参考方案4】:

我使用 ASM 和 BCEL 生成 Java 类,然后将它们转换为 Dex 文件。 最后,我创建了 jar 文件以在设备上动态加载。

你可以查看我的代码:)

https://github.com/sciruela/android

【讨论】:

【参考方案5】:

如果在任何 C 或 C++ 程序中,您想要加载并调用 DEX 类,您可以在 AndroidRuntime 中查看 Dalvik VM 的启动方式 - 例如 frameworks/base/cmds/app_process/app_main.cpp:

status_t app_init(const char* className, int argc, const char* const argv[])

    LOGV("Entered app_init()!\n");

    AndroidRuntime* jr = AndroidRuntime::getRuntime();
    jr->callMain(className, argc, argv);

    LOGV("Exiting app_init()!\n");
    return NO_ERROR;

由于“jr”AndroidRuntime 已经启动,callMain() 将被调用:

status_t AndroidRuntime::callMain(
    const char* className, int argc, const char* const argv[])

    JNIEnv* env;
    jclass clazz;
    jmethodID methodId;

    LOGD("Calling main entry %s", className);

    env = getJNIEnv();
    if (env == NULL)
        return UNKNOWN_ERROR;

    clazz = findClass(env, className);
    if (clazz == NULL) 
        LOGE("ERROR: could not find class '%s'\n", className);
        return UNKNOWN_ERROR;
    

    methodId = env->GetStaticMethodID(clazz, "main", "([Ljava/lang/String;)V");
    if (methodId == NULL) 
        LOGE("ERROR: could not find method %s.main(String[])\n", className);
        return UNKNOWN_ERROR;
    
<...>
    env->CallStaticVoidMethod(clazz, methodId, strArray);
    return NO_ERROR;

从上面我们可以看到 DEX 类的代码是如何加载的,CallStaticVoidMethod() 将开始解释 DEX 代码。

【讨论】:

以上是关于将 Dalvik 字节码动态生成到正在运行的 Dalvik/Android 应用程序中的主要内容,如果未能解决你的问题,请参考以下文章

参考 Dalvik 或 Java 虚拟机?

Android 对动态语言不利

Android中啥是Dex文件

java 动态代理总结

Clojure 运行原理之字节码生成篇

科普N次元JAVA虚拟机Dalvik虚拟机和ART虚拟机简要对比