• スポンサードリンク

Androidのlibpngでハマった↓

Android NDK

Androidでlibpngを使おうとしてハマってしまった。わかってしまえば対策は簡単なんだけど、もしかすると同じような人がいるかもしれないので参考になればと思い記事にしときます。

とりあえず結論

Androidのシステムに元々含まれている共有ライブラリを自前でコンパイルしてAPK内に入れる場合には違う名前にしたほうが無難って事ですね。

経緯

ふとしたことからlibpng1.6系ではSimplified APIと言う簡単にpngデータを読み書き出来るAPI群が追加されたことを知ったので、ちょっと使ってみようかと思ったのが事の始まり。

例えばRGBのバイト配列で画像データがあったとして、pngとしてファイルに出力するには、

みたいなことをするだけで、ファイルに書き出せるらしい。お〜楽ちんじゃん。

最新版のlibpng(1.6.10)をダウンロードしてきてNDKでAndroid.mkを作ってlibpng.soとしてビルド。JNI経由で呼び出すための自前の共有ライブラリ(libjni_pngtest.so)も作って、Javaから呼びだそうとしました。
ビルドまでは特に問題なくできたんですが、いざ実行すると

としてライブラリを読み込むところで、libjni_pngtest.soのリンクに失敗して読み込めないのです。ちなみにその上側のlibpng.soを読み込んでいるところをコメントアウトしても一緒です。
なんでやねんってクラッシュダンプをみると、

まさに使おうとしているpng_image_write_to_fileが見つからんからリンクでけへんやんって怒っています。
ちなみに、JNI_OnLoadが定義されてへんよとは言われていますが、libpng.so自体はapk内のを使ってload出来ているようです(2-4行目)。
libpngのコンフィグかビルド間違えたかなぁと思って、objdumpでlibpng.soのシンボルを調べてみました。
長いので前後を省略していますが、

png_image_write_to_file有るやん。訳わかりません。グルグル先生に聞いたりもしてみましたがよくわかりませんでした。

原因発覚

で、しばらく悩んだ挙句に、ふと、Androidのシステムのライブラリにlibpng.soが有るんじゃないかと思いAOSPの中を覗いてみると・・・有りました。
つまりapk内のlibpng.soが既にloadされていたとしてもシステム側のlibpng.soへリンクしようとしているか、またはapk内のlibpng.soをloadしたかのようにlogに出力するにもかかわらず、実際にはシステム側のlibpng.soしかloadしていないかのどちらかで、しかもシステム側のlibpng.soにはpng_image_write_to_fileが含まれていないって事のようです。
端末内のlibpng.soを引っこ抜いてobjdumpしてみると・・・やはりpng_image_write_to_fileが含まれていませんでした\(^o^)/?

ちなみに、2014/5/8時点で最新のAOSPをビルドしてできるgenericのlibpng.soにはpng_image_write_to_fileが含まれていました。

対応策

余計な時間を取られてしまいましたが、ここまで判れば対策は簡単ですね。自前でコンパイルしてapkに入れている方のlibpng.soの名前を変えて(今回はlibpng16.so)、そちらにリンクすればOKでした。もちろん事情が許せばスタティックリンクしてもOK。

libpngはシステムのライブラリには含まれていますが、NDKにはexportされていませんし、STABLE-APIにもなっていないのでしかたがないのですが、それならそれでAPK側のライブラリを優先してくれたら良いのにって思うのは自分だけ?

やっぱり結論

ということで、結論は、システム側に含まれる共有ライブラリをAPK内に含める場合には別名でビルドしましょうってことですね。もちろんスタティックリンク出来る場合ならそれでもいいですが、大人の事情でスタティックリンクしたくない場合も有りますよね。libpngにかぎらずlibjpeg, libsqlite, libsslなども元々システム内に含まれているようなので、せっかく最新版を自前でコンパイルしてapkに入れても、気をつけないと実は使われていないってパターンもありうるのかも。

ということで今回はおしまいです。お疲れ様でした。

« »

  • スポンサードリンク