Androidでdlopenするファイルパス

| No Comments | No TrackBacks

BridJ hackingは作者の人と引き続き連携して進めている。少しずつ先に進むのでなかなか楽しい。昨日はBridJが内部的に使っているdyncallにsoファイルをフルパスで渡さなければならない問題を解決した(これまで動いていたと思っていた部分に、どうやらスタブでごまかしていたものがあったようだ)。

dyncallはCのコードで、内部的にはdlopen()を呼び出しているだけなので、JavaのSystem.loadLibrary()とは異なり、自分で共有ライブラリのパスを解決してフルパスを渡してやる必要がある。Debianなどでは*.soがシンボリックリンクになっていないので、明示的にLDScriptを追跡してやる必要があるのだけど、BridJはそこまで実装してあった。なにげに細かいところまで作り込まれている。

Androidの場合、共有ライブラリはリソースとして.apkに含まれていて、Javaアプリケーション側ではストリームを開くことが出来るだけで、実際のアプリケーションは*.soファイルのパスを知ることは無い。少なくともAndroid 2.2まではそうなっていた(Android 2.3には、ApplicationInfoにnativeLibraryDirというフィールドが存在していて、多分これがネイティブライブラリのパスになっている)。

実際には、少なくともエミュレーターの場合は、apkが未解凍のままで置いてあることはなく、/data/data/アプリケーションパッケージ名/ というディレクトリが作成されて、そこに展開されたファイルが格納されている、ようだ(ClassLoader.class.getClassLoader().getResource("lib/armeabi/libbridj.so") のような呼び出しで、URIを得ることが出来る)。エミュレーターの場合、これとは別に/data/data/アプリケーションパッケージ名/.apk! のようなディレクトリもあるのだけど、手持ちのHTC Desireではこれが別のパスになっていたので、このパッケージのほうのURIは使えなかった。ともあれ、ライブラリのファイルパスはこの方法で得られたので(Androidのアプリケーションパッケージ名を得るために、ユーザーに追加コードを書かせる必要が生じたが)、これで.soファイルをロードして、パッケージ同梱の共有ライブラリもロードすることができた。

実際に自分のアプリケーションがちゃんと動作するかどうかは、これから試してみないと分からない。

あと、ライブラリローダ部分をハックしていてハマったのは、同じネイティブライブラリをフルパス無しでもう一度読み込もうとすると、なぜかSEGVが発生してしまうというものだ。もしかしたらこれが自分のアプリケーションでも発生していたのかもしれない(違う気もする)。System.loadLibrary()でファイル名を渡して2度呼び出しても、そのようなエラーが生じることはなかったので、ネイティブライブラリの手動読み込みを妨げる何かしらの問題がbionicあるいはdalvikにあるのかもしれない。

No TrackBacks

TrackBack URL: http://veritas-vos-liberabit.com/noteon/mt-tb.cgi/159

Leave a comment