我为 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.apkmy_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.zip
或 foo.jar
而不是 foo .dex
它会自动为您压缩输出文件。
关于java - 为什么控制台 android java 应用程序在没有 ODEX 文件的情况下无法工作,而 GUI 应用程序运行良好?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19683139/