2011-04-07 61 views
28

我正在研究依赖于ELF二进制文件的Android应用程序: 我们的Java代码与此二进制文件进行交互以完成任务。这个 运行时需要在应用程序启动和 应用程序退出/按需启动和终止。在Android应用程序中托管可执行文件

问题:

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

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

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

请指教。

谢谢。

回答

37

1)不,不应该有限制,除了那些访问系统文件,因此需要根。最好的地方是直接访问/ data/data/[your_package_name]以避免污染别处。

2)关于编译本地库的非常详尽的讨论可以在这里找到:​​。另一种选择是用于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
  • 使用上面的代码运行您的可执行文件。

员额使用assets文件夹,insted的是Android的建议对静态文件的raw文件夹:

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

要访问数据的文件夹,您可以在这里按照指示: http://developer.android.com/guide/topics/data/data-storage.html#filesInternal 此外,还有的File#setExecutable(boolean);方法应该工作而不是shell命令。

因此,把一切融合在一起,我会尝试:当然

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 = getFileStreamPath (FILENAME); 
file.setExecutable(true); 

中,这一切都只能用一次安装后进行。您可以在onCreate()或任何检查文件存在的内容中进行快速检查,并在文件不存在的情况下执行所有这些命令。

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

+0

@Aleadam:感谢您的回复。是的,源代码被编译为ARM可执行文件,并且我尝试在命令行上通过rooted Android手机执行它,并且它工作正常。我需要的是一种打包此可执行文件的方法在我的Android项目中,将它复制到内部文件系统(/ data/data/),然后从那里执行它 – Samuh 2011-04-13 01:01:16

+0

很酷,那么我认为你的状态良好。或者它只是做一个特定的,快速的工作? – Aleadam 2011-04-13 03:45:54

+0

@Samuh检查更新的答案 – Aleadam 2011-04-13 04:46:28

1

我已经使用NDK做了类似的事情。我的策略是使用NDK重新编译程序并编写一些调用到程序的main函数中的封装JNI代码。

我不确定NDK代码的生命周期是什么样的。即使是方便长时间运行的服务,也可以由系统启动和停止。您可能必须关闭您的NDK线程,并在必要时重新启动它。

+0

我同意这一点 - JNI包装是未来的正常方式。如果可能的话,我还要重新设计,以便ELF不是正常的守护进程 - 长时间运行的进程对电池寿命不利。 – 2011-04-07 16:15:52

+0

我没有这个二进制的源代码;只是特定机器体系结构的可执行文件。 :-( – Samuh 2011-04-07 17:04:24

9

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

1)在你的SDK项目,把可执行文件在/资产的文件夹

2)编程得到的字符串的文件目录(/数据/数据/ your_app_name /文件)这样

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

3。)在您的应用程序的项目的Java代码:从/资产文件夹到你的应用程序的“文件”子文件夹中复制的可执行文件(通常是/数据/数据/ your_app_name /文件)用这样的功能:

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); 

注意的是,这里所指的任何文件(如输入和输出文件)都必须有自己的完整路径弦乐建。这是因为这是一个单独产生的过程,它没有关于“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());

+0

您使用哪个copyFile()方法? – x29a 2015-06-30 21:17:16

+0

IOUtils。复制(进出)commons-io软件包工程:http://stackoverflow.com/a/51753/134761 – angularsen 2015-10-25 22:19:49

+0

如果有人澄清了所需的参数代码,这将是一件好事。你可以直接在“executableFilePath”后面写一个参数。例子 – Zillinium 2018-01-24 01:53:17

相关问题