2013-04-22 63 views
3

作爲非Android人的序言(某些Linux民衆可能知道此信息的答案):有沒有辦法在Android中關閉動態加載的庫?

Android中的每個應用程序都運行在Dalvik虛擬機的一個實例中。當啓動一個應用程序時,一個名爲ActivityManager的實體寫入一個管道,通知另一個實體Zygote需要啓動一個應用程序。 Zygote是一個空白頁面的Dalvik VM實例,預先加載了庫,在通過管道傳遞後,它克隆自己,克隆將其權限級別降低到與要啓動的應用相關聯的Linux用戶。這在啓動應用程序時節省了時間和內存 - 考慮重新加載所有庫並每次都進行所有設置的替代方法。

我的問題是,Zygote中有一個特定的庫,我想在這個特定的進程中關閉,因爲我想使用我自己的庫版本。我已將我的本地代碼與MY .so文件鏈接起來,該文件被複制到適當的文件夾中,並在應用程序啓動時通過Java層「System.load('xyz')」加載,但是當我的代碼運行時,它會調用原系統庫的功能,而不是我的。當我運行「cat/proc/NNNN/maps」時,我可以看到舊庫和我的內存一樣。

有沒有辦法在我的應用程序中關閉特定的庫?如果沒有,是否有辦法確保對該庫中的函數的任何/每個調用都傳遞給MY版本而不是舊版本?

謝謝!

+0

「關閉」,如卸載以前加載的共享庫?似乎沒有辦法。請參閱:https://groups.google.com/forum/?fromgroups=#!topic/android-ndk/59Xu4kKjgnA和https://groups.google.com/forum/?fromgroups=#!topic/android-ndk/ sf56xVIySfI – MarsAtomic 2013-04-22 16:46:25

+0

@MarsAtomic:這些帖子是關於卸載應用程序本身加載的庫,稍有不同。如果你管理自己的'dlopen()'/'dlclose()'調用,而不是依賴'System.load()',你可以實際做到。由於一切都在應用程序的控制之下,因此可以安全地進行操作。這真的是你想更新共享庫而不重新啓動應用程序(或更可能是服務)的場景,而這裏的問題是關於覆蓋系統的庫副本。 – fadden 2013-04-22 18:10:37

+0

大家好!實際上,我想卸載Zygote中默認加載的庫,以便我可以自己加載不同版本的庫(在我的DVM實例中),並將通常會轉到原始庫的調用轉到我的庫中。 – ZachM 2013-04-24 18:29:24

回答

2

在最好的情況下關閉共享庫(使用dlclose())是非常棘手的,因爲它會取消映射庫的代碼。如果稍後調用該代碼(可能是C++析構函數),該程序將立即崩潰。由於該庫是由您的代碼加載的,因此另一個線程將在您卸載映射的時刻在該庫中執行代碼,這完全有可能導致崩潰。

所以,不要那樣做。 :-)

如果您可以將您的庫版本構建爲靜態庫並將其直接鏈接到您的代碼中,則應該完全可以避免此問題。

FWIW,各種圖書館(特別是SSL和ICU)都鏈接到Dalvik中,沒有明確地由zygote加載,所以如果你試圖替換其中一個,你會得到/system/lib版本,不管你是從哪個分支合子與否。

+0

嗨fadden!謝謝!我同意不這樣做。我拉了一些其他整潔的內存技巧直接從內存中取消映射,但我最終選擇使用dlopen()來自己打開它,然後只需使用dlsym()就可以取出我需要的函數指針。這更可靠。 – ZachM 2013-04-24 18:32:27

+0

此外,作爲關於正確性的說明 - 如果您正在使用小型庫和/或僅將其與一個應用程序一起使用,我會建議fadden的答案涉及使用靜態庫。我爲Android的自定義構建構建了一套應用程序,因此將它靜態鏈接到20個不同的東西中會浪費,因此在這種情況下,請使用dlopen()/ dlsym()/ dlclose()的建議! – ZachM 2013-04-24 18:33:56

+0

FWIW,你的方法就是爲什麼JNI有'UnregisterNatives' - 如果你用'dlsym()'找到的任何符號都是本地方法實現,你可以在調用'dlclose()'之前註銷它們。 – fadden 2013-04-24 19:26:31

相關問題