0

我为 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)图形用户界面应用:

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/”目录具有)。/data/local/tmp/dalvik-cache/因此,如果 Dalvik VM 不是从根目录启动,它就无法写入“ ”。

所以在所有这些步骤之后:

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 应用程序证明了这个理论。但控制台应用程序没有。

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

更新:

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

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

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 作弊负责。

4

1 回答 1

2

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

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

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

于 2013-10-30T15:05:45.043 回答