java - 复制并执行 native 服务二进制文件并检查日志

标签 java android shell android-ndk java-native-interface

我正在构建一个使用 native 服务二进制文件的应用程序。

现在我的要求是:

将 native 服务二进制文件放在应用程序的 Assets 文件夹中。

  1. 当应用程序运行时,将此 native 文件复制到设备中(路径类似于 getExternalFilesDir(null))
  2. 在设备中执行这个二进制文件。
  3. 在日志中检查文件是否已成功执行。

现在要复制文件,我使用了:

private void copyAssets() {
    AssetManager assetManager = getAssets();
    String[] files = null;
    try {
        files = assetManager.list("");
    } catch (IOException e) {
        Log.e("tag", "Failed to get asset file list.", e);
    }
    for (String filename : files) {
        if (filename.equals("native-file")) { // native-file is the file name present is assets folder
            InputStream in = null;
            OutputStream out = null;
            try {
                in = assetManager.open(filename);
                File outFile = new File(getExternalFilesDir(null), 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);
            }
            break;
        }
    }
}

在复制执行我正在使用的文件之后:

File sdCard = getExternalFilesDir(null); // directory where native file is placed
Process proc = Runtime.getRuntime().exec("sh -c shell " + sdCard.getAbsolutePath() + "/native-file "+ sdCard.getAbsolutePath() +"/native-file.log\" "); // command 1
proc = Runtime.getRuntime().exec("sh -c less " + sdCard.getAbsolutePath() +"/native-file.log\""); // command 2

问题:

  1. 如何确保文件已放置。
  2. 如何确保它被执行。因为我在运行应用程序时无法找到并记录文件 (native-file.log)。

PS - 由于专有问题,我无法提供我的 JNI 文件。所以我想我们可以使用开源 asl库。(有一个名为 asl-native 的 native 文件)

最佳答案

您当前的代码并不太远,但是您需要注意一些细节:

  1. 如前所述,您无法执行您放入/sdcard 中的文件。 .但是,您可以执行内部存储器中的文件。因此,而不是 getExternalFilesDir(null) , 使用 getFilesDir()
  2. 将可执行文件复制到目标目录后,您需要使其可执行。您可以运行 Runtime.getRuntime().exec("chmod 755 " + getFilesDir() + "/native-file").waitFor();或尝试使用私有(private) android.os.FileUtils类(如 https://stackoverflow.com/a/11408378/3115956 )。
  3. 启动应用程序时不需要任何额外的“sh -c shell”,这就足够了:Process proc = Runtime.getRuntime().exec(getFilesDir() + "/native-file");
  4. 如果您想从可执行文件中读取 stdout/stderr 输出(以验证它是否正确运行),您可以执行以下操作:这个:

    InputStream stdout = proc.getInputStream();
    InputStream stderr = proc.getErrorStream();
    BufferedReader br = new BufferedReader(new InputStreamReader(stdout));
    String line;
    while ((line = br.readLine()) != null)
        System.out.println("stdout: " + line);
    br = new BufferedReader(new InputStreamReader(stderr));
    while ((line = br.readLine()) != null)
        System.out.println("stderr: " + line);
    

为了简化第 1 步和第 2 步,并避免自己处理 native 二进制文件的不同架构,您可以重命名命令行可执行文件以匹配模式 lib<something>.so并将其放入 libs/<abi>项目中的目录。然后它将被 APK 打包器拾取并像任何 native 库一样打包。要执行它,您可以简单地执行 Process proc = Runtime.getRuntime().exec(getApplicationInfo().nativeLibraryDir + "/libnative-file.so");

关于java - 复制并执行 native 服务二进制文件并检查日志,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26943176/

相关文章:

java - Jsoup URL.get()/post() 内存不足错误

java - 使用袖珍狮身人面像进行语音识别的准确性很差

linux - 在 Debian 服务器上通过 ssh 连接到 Git 用户时没有(自定义)答案

linux - 尝试使用 sudo 将文件附加到根拥有的文件时权限被拒绝

javascript - 我有错误:E/RecyclerView:未连接适配器;跳过布局

java - 检测标准输入的空输入

java - 删除 JSON 对象

android - videoview特定位置的launch方法

shell - 激活 conda 失败(采购 ~/.bashrc)

java - Android - 适配器数据更改后,滚动到 ListFragment 中 ListView 中的位置