2011-04-07 42 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

相關問題