java - 为什么控制台 android java 应用程序在没有 ODEX 文件的情况下无法工作,而 GUI 应用程序运行良好?

标签 java android dalvik dex

我为 Android 4.1.2 编写了两个简单的 java 程序。

1)控制台程序:

public class console_hello_world
{
    console_hello_world() {
        System.out.println("Init!");
    }
    protected static int method() {
        System.out.println("Method!");
        return 0;
    }
    public static void main(String[] args)
    {   console_hello_world variable=new console_hello_world();
        variable.method();
        System.out.println("Hello World!");
    }
}

它是以这样的方式构建的(正如你所看到的,这个脚本也启动了这个程序):

#!/bin/bash

DX="~/Programs/android-sdk-linux/build-tools/18.0.1/dx"
REMOTE_PATH=/data/local/tmp

CLASS_NAME="console_hello_world"
javac "${CLASS_NAME}.java"
${DX} --dex --output="classes.dex" "${CLASS_NAME}.class"
zip "${CLASS_NAME}.zip" "classes.dex"

ADB="~/Programs/android-sdk-linux/platform-tools/adb"
"${ADB}" push "${CLASS_NAME}.zip" $REMOTE_PATH/
"${ADB}" shell mkdir $REMOTE_PATH/dalvik-cache

"${ADB}" shell "logcat -c"
"${ADB}" shell ANDROID_DATA=$REMOTE_PATH dalvikvm -cp "$REMOTE_PATH/${CLASS_NAME}.zip" ${CLASS_NAME}
"${ADB}" shell "logcat -d" > out.log

2)GUI应用程序:

package com.example.my_app;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;

public class my_app_activity extends Activity
{
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }

    /** Called when the user clicks the button */
    public void onButtonClickMethod(View view)
    {
        // do smth
        EditText editText = (EditText) findViewById(R.id.edit_message);
        String message = editText.getText().toString();
        message += " + something!\n";
        editText.setText(message);
    }
}

它是按照标准方式构建的。

每个应用程序都启动正常。 我启动控制台程序的方式是在之前插入的bash脚本中。

然后我删除了每个程序的ODEX文件:

/data/local/tmp/dalvik-cache/data@local@tmp@console_hello_world.zip@classes.dex

/data/dalvik-cache/data@app@com.example.my_app-1.apk@classes.dex

(没关系 - 我的 GUI 应用程序名称是“my_app-1.apk”)

对于控制台程序,我还删除了“/data/local/tmp/dalvik-cache/”目录并从根目录创建了新目录,访问标志更改为 771(相同的访问标志“/data/dalvik-cache/”目录下有)。因此,如果 Dalvik VM 不是从 root 启动,则无法写入“/data/local/tmp/dalvik-cache/”。

完成所有这些步骤后:

1) GUI 应用程序仍然可以正常工作。 Dalvik VM 进程无法访问“/data/dalvik-cache/”,并且未创建新的 ODEX 文件。

2)控制台应用程序抛出异常:

Dalvik VM unable to locate class 'console_hello_world'
java.lang.NoClassDefFoundError: console_hello_world
    at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.ClassNotFoundException: console_hello_world
    at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:61)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:501)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:461)
    ... 1 more

这对我来说是令人惊讶的。

因为我认为ODEX文件只是classes.dex文件的验证和优化版本,该文件位于存档中,应用程序可以在没有它的情况下工作。

我的 GUI 应用程序证明了这个理论。但控制台应用程序则不然。

有人可以解释一下,为什么控制台 android java 应用程序在没有 ODEX 文件的情况下无法工作,同时 GUI 应用程序感觉很好?

更新:

我更彻底地测试了我的 GUI 应用程序。

如果我在启动“my_app-”之前删除odex文件“/data/dalvik-cache/data@app@com.example.my_app-1.apk@classes.dex” 1.apk”第一次,“my_app-1.apk”之后就不起作用了。这是Android日志(我稍微修改了dalvik):

W/ActivityThread( 4133): Application com.example.my_app can be debugged on port 8100...
I/dalvikvm( 4133): dvmJarFileOpen. fileName = /data/app/com.example.my_app-1.apk; odexOutputName = (null)
I/dalvikvm( 4133): dvmOpenCachedDexFile. fileName = /data/app/com.example.my_app-1.apk; cacheFileName = /data/dalvik-cache/data@app@com.example.my_app-1.apk@classes.dex
E/dalvikvm( 4133): Dex cache directory isn't writable: /data/dalvik-cache
I/dalvikvm( 4133): Unable to open or create cache for /data/app/com.example.my_app-1.apk (/data/dalvik-cache/data@app@com.example.my_app-1.apk@classes.dex)
D/AndroidRuntime( 4133): Shutting down VM

但是,如果我在多次启动 my_app-1.apk 后删除 ODEX 文件,则 my_app-1.apk 一切正常。 Android 日志中也没有读取“/data/app/com.example.my_app-1.apk”文件。我猜想,Android 将 ODEX 放在 RAM 中的某个位置进行优化,然后在需要时设置一个指向它的指针。

所以,法登先生是对的,所有同意他观点的人也是对的! :)

如果有人能回答我所说的 Android 将应用程序保留在 RAM 中进行优化是否正确,并且向我解释一下是什么服务/应用程序/等...导致了这个 Android 作弊,那就太好了。

最佳答案

odex 文件始终是必需的。必须从 zip 文件中提取 classes.dex,必要时进行字节交换,并执行一些基本的结构验证。对于 GUI 应用程序,包管理器将在必要时自动重新创建它; PM 拥有更新 /data/dalvik-cache 所需的权限。

该过程的完整说明可以在 Dalvik 源代码 ( dalvik/docs/dexopt.html ) 中找到。 (其中有些内容有点过时,但大部分都是正确的。)

顺便说一句,在您的创建步骤中,如果您告诉 dx 创建 foo.zipfoo.jar 而不是 foo .dex 它会自动为您压缩输出文件。

关于java - 为什么控制台 android java 应用程序在没有 ODEX 文件的情况下无法工作,而 GUI 应用程序运行良好?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19683139/

相关文章:

java - Android Studio - 平台和插件更新以及 Java @ OSX

java - 使用 JNA 发布到 POSIX 信号量

android - 将 Kotlin 文件编译为 Dex 会生成 ClassNotFoundException (kotlin.jvm.internal.Intrinsics)

java - 将 Jetty 8 升级到 Jetty 9

java - 主要对象是匿名 JAAS 安全性

android - 如何在屏幕中间显示我的 Admob 横幅广告?

java - 使用 String 参数调用时 JNI 崩溃

java - 在API 23之前定位时实现breakStrategy

android - malloc 和 dlmalloc 之间的区别

c# - Mono for Android 是如何工作的以及 C# 和 Dalvik 之间的关系是什么?