在安卓应用程序中托管可执行文件

2022-09-01 02:31:41

我正在开发一个依赖于ELF二进制文件的Android应用程序:我们的Java代码与此二进制文件交互以完成工作。此运行时需要在应用程序启动和应用程序退出/按需时启动和终止。

问题:

  1. 我假设我们将能够使用 Runtime.exec() API 执行此二进制文件。对于我需要将库放在文件夹结构中的位置,是否有任何限制?系统运行时如何找到此可执行文件?是否有某种类路径设置?

  2. 由于应用程序具有此运行时的依赖项,因此我正在考虑将其包装在服务周围,以便可以根据需要启动或停止它。在Android项目中处理此类可执行文件的最佳方法是什么?

  3. 假设我没有此可执行文件的源代码,还有什么其他选择?

请指教。

谢谢。


答案 1

1)不,除了那些访问系统文件并因此需要root的约束之外,不应该有任何约束。最好的地方是直接到/data/data/[your_package_name],以避免其他地方的污染。

2)关于针对本机库进行编译的非常彻底的讨论可以在这里找到:http://www.aton.com/android-native-libraries-for-java-applications/。另一个选项是arm的交叉编译器(这是用于编译内核的编译器,它是免费的:http://www.codesourcery.com/sgpp/lite/arm)。如果您计划维护执行 cammand 的服务,请注意,android 可以随时停止和重新启动服务。

3)现在,如果你没有源代码,我希望你的文件至少被编译为arm可执行文件。如果没有,我甚至不明白你怎么能运行它。


您将通过在 java 类中运行以下命令来执行该文件:

String myExec = "/data/data/APPNAME/FILENAME";
Process process = Runtime.getRuntime().exec(myExec);
DataOutputStream os = new DataOutputStream(process.getOutputStream());
DataInputStream osRes = new DataInputStream(process.getInputStream());

我对您的可执行文件一无所知,因此您可能需要也不需要实际获取 inputStream 和 outputStream。


我假设运行adb来推送二进制文件是不可能的,所以我正在寻找一种简洁的方法来打包它。我发现了一篇关于在您的应用程序中包含可执行文件的精彩帖子。在这里查看: http://gimite.net/en/index.php?Run%20native%20executable%20in%20Android%20App

重要的部分是这个(强调我的):

从 Android Java 应用程序,使用文件夹assets

  • 将二进制文件包含在资产文件夹中。
  • 用于获取 .getAssets().open(FILENAME)InputStream
  • 将其写入(例如 ),您的应用程序有权写入文件并使其可执行。/data/data/APPNAME/data/data/net.gimite.nativeexe
  • 使用上面的代码运行。/system/bin/chmod 744 /data/data/APPNAME/FILENAME
  • 使用上述代码运行可执行文件。

帖子使用文件夹,而不是Android为静态文件建议的文件夹:assetsraw

提示: 如果要在编译时将静态文件保存在应用程序中,请将该文件保存在项目 res/raw/ 目录中。你可以用 openRawResource() 打开它,传递 R.raw。资源标识。此方法返回可用于读取文件(但不能写入原始文件)的 InputStream。

要访问数据文件夹,您可以按照此处的说明进行操作:http://developer.android.com/guide/topics/data/data-storage.html#filesInternal 此外,还有一种方法应该有效,而不是shell命令。File#setExecutable(boolean);

所以,把所有东西放在一起,我会尝试:

InputStream ins = context.getResources().openRawResource (R.raw.FILENAME)
byte[] buffer = new byte[ins.available()];
ins.read(buffer);
ins.close();
FileOutputStream fos = context.openFileOutput(FILENAME, Context.MODE_PRIVATE);
fos.write(buffer);
fos.close();


File file = context.getFileStreamPath (FILENAME);
file.setExecutable(true);

当然,所有这些操作在安装后只应执行一次。您可以在内部进行快速检查,或者检查文件是否存在,并在文件不存在时执行所有这些命令。onCreate()

让我知道它是否有效。祝你好运!


答案 2

以下是有关如何打包和运行可执行文件的完整指南。我基于我在这里和其他链接找到的内容,以及我自己的试验和错误。

1.) 在 SDK 项目中,将可执行文件放在 /assets 文件夹中

2.)以编程方式获取该文件目录的字符串(/data/data/your_app_name/files),如下所示

String appFileDirectory = getFilesDir().getPath();
String executableFilePath = appFileDirectory + "/executable_file";

3.) 在应用的项目 Java 代码中:将可执行文件从 /assets 文件夹复制到应用的“files”子文件夹(通常是 /data/data/your_app_name/files)中,函数如下所示:

private void copyAssets(String filename) {

AssetManager assetManager = getAssets();

InputStream in = null;
OutputStream out = null;
Log.d(TAG, "Attempting to copy this file: " + filename); // + " to: " +       assetCopyDestination);

try {
    in = assetManager.open(filename);
    Log.d(TAG, "outDir: " + appFileDirectory);
    File outFile = new File(appFileDirectory, filename);
    out = new FileOutputStream(outFile);
    copyFile(in, out);
    in.close();
    in = null;
    out.flush();
    out.close();
    out = null;
} catch(IOException e) {
Log.e(TAG, "Failed to copy asset file: " + filename, e);
} 

Log.d(TAG, "Copy success: " + filename);
}

4.) 更改executable_file的文件权限,使其实际可执行。使用 Java 调用来执行此操作:

File execFile = new File(executableFilePath);
execFile.setExecutable(true);

5.) 像这样执行文件:

Process process = Runtime.getRuntime().exec(executableFilePath);

请注意,此处引用的任何文件(如输入和输出文件)都必须构造其完整路径 String。这是因为这是一个单独的生成过程,它对“pwd”是什么没有概念。

如果你想读取命令的stdout,你可以这样做,但到目前为止,它只适用于系统命令(如“ls”),而不是可执行文件:

BufferedReader reader = new BufferedReader(
new InputStreamReader(process.getInputStream()));
int read;
char[] buffer = new char[4096];
StringBuffer output = new StringBuffer();
while ((read = reader.read(buffer)) > 0) {
    output.append(buffer, 0, read);
}
reader.close();
process.waitFor();

Log.d(TAG, “output: ” + output.toString());


推荐