android-wifi-tetherのコアプログラムをビルドし直してみた。

Wifi-Adhoc モードを利用したテザリングをするルート化必須のアプリ「android-wifi-tether」

を利用すれば、Wifi-Adhoc モードを使えるんじゃないかと考え、オープンソースでもあるのでこのアプリのソースを読んでました。
ソースはここにあります→http://code.google.com/p/android-wifi-tether/
今回は、branch/wireless-tether のブランチにあるソースを使っています。

まだ全部理解してないものの、私が必要な部分はWifiのモード切り替えの部分だけなので、そこだけを引っ張って自分で新しくアドホックモードに切り替えるアプリを作ろうと試みました。

そこの解説は、後ほど書くとして。
切り替え部分の簡単なフローは

1、WifiAndroid標準APIからWifiをOFFにする
Wifiのネットワークインターフェースが見えなくなる)

2、Cで書かれたtetherという実行ファイルを実行する

これで、Wifiのモードが変わります。

tetherは、GoogleのOSの更新スクリプトであるEdfiyのインタプリタを拡張したものになっていて
tetherという実行ファイルが実際行っているのは、指定したPATHにあるEdifyスクリプトを実行しているだけです。
tether.edifyっていうのが実際に実行されるedifyスクリプトなんですが、そこで実際にやっていることは、wifiモジュール をロードしたり、iwconfig とifconfig を使って無線LANの設定をしたり、dns 立てたり、iptables でファイアーウォールの設定をしたりとかです。

dns とかファイアーウォール設定とかdhcpサーバーの立ち上げとかは、Wifiモード変更には関係ないので、そこら辺のセンテンスは削除して大丈夫です。

ここからが本題

以上のように、tether というプログラムが android-wifi-tether のコアプログラムです。 なので、これを使えば Wifiモード変更アプリを作れるように思い、実際に作ってみました。

ところが・・・・動きません!!!

デバックしてみると、tetherの中でtether.edifyのパスを直打ちしてあり、パスはパッケージ名に依存するのでandroid.tetherパッケージ以外だと。no such a file とか言われてtether.edifyを見つけられません。

んじゃ、tetherを編集してビルドし直します。
tetherのプログラムは $(PROJECT_ROOT)/native/tether-edify にあります。
tether.cでPATH指定しているところを全て自分のパッケージ名に変更します。

それではビルドしましょう

・・・・・・・・・・・・あれ?・・・・どうやってするんだろう

とりあえず、普通にビルドすることを試みます

ukinau$cd
ukinau$mkdir work
ukinau$mv $(PROJECT_ROOT)/native/tether-edify ~/work/
ukinau$cd ~/work/tether-edify
ukinau$mkdir jni
ukinau$mv * jni/
ukinau$cd ~/work/tether-edify

tether-edifyの初期のファイル構造はこんな感じ

  • tether-edify/
    • Android.mk
    • install.h
    • install.c
    • tether.c
    • tether.h
    • edify/
      • Android.mk
      • expr.c
      • expr.h
      • lexer.l
      • main.c
      • parser.y
      • README
      • yydefs.h

本来ならここでndk-buildすればいいはず

ukinau$ndk-build (tether-edifyのビルド)

 →エラー *** non-numeric second argument to ‘wordlist’ function: ”. Stop.
 ググルと「プロジェクトにmin-sdkVersionを指定しろ」とか出るけどプロジェクトと関係ないとこでビルドしてるので関係ないです。これはNDKの中のプログラムを少し変更します。
Android-NDK/build/gmsl/__gmslの512行目の

512 int_encode = $(gmsl_tr1)$(wordlist 1,$1,$(gmsl_input_int))

をコメントアウトして。以下のセンテンスを追加してください。

int_encode = $(gmsl_tr1)$(wordlist 1,$(words $1),$(gmsl_input_int))

ukinau$ndk-build (tether-edifyのビルド)

先ほどのエラーは解決
エラー undefined reference to ******っていうのがたくさんでます。
 これは、見るからにedifyが読み込めてないんでしょう。
 edifyを先にビルドした方がいいのか?と思い先にビルドを試みます

ukinau$cd ~/work/tether-edify/jni/edify
ukinau$mkdir jni
ukinau$mv * jni

この時点でのファイル構造はこんな感じ

  • tether-edify/
    • jni/
      • Android.mk
      • install.h
      • install.c
      • tether.c
      • tether.h
      • edify/
        • jni/
          • Android.mk
          • expr.c
          • expr.h
          • lexer.l
          • main.c
          • parser.y
          • README
          • yydefs.h
ukinau$ndk-build (edifyのビルド)

 →エラー no rule to make target build_host_executalble.mk
いろいろググったけど、edifyディレクトリ以下はandroid osから引っ張ってきたまんまだということが判明(osのソースはここで見れますhttps://android.googlesource.com/ )
んで、Android NDK では host向けのビルドはサポートしていないらしい。
これどうやってビルドしたんだよ・・・・orz

makeファイルを読んでみると、2個ビルドしているようだ。

# Build the host-side command line tool
include $(BUILD_HOST_EXECUTABLE)
# Build the device-side library
include $(BUILD_STATIC_LIBRARY)

 ってか、host-side command line toolいらないんじゃね?ということで1個目のビルド文を削除

ukinau$ndk-build (edifyのビルド)

警告 lexファイルとyaccファイルはサポートしてません
 警告だし無視、しかしなにも起きない。
 libedify.aとかライブラリが生成されると思っていたんですが、なにも起きない・・・
 ndk-sampleを見てると、STATIC_LIBRARYを使ってビルドしているものを発見
 そこでいろいろ試してみると、
 STATIC_LIBRARYは単独では生成されない?(生成されてもmakeが終わると削除される?)ので  同じmakeファイルでビルドしないといけないらしい
 なので、tether-edifyの方のmakeファイルを編集
  以下の記述をtether-edifyのビルド文の前に書く

Android.mk

edify_src_files := \
edify/lexer.l\
edify/parser.y\
edify/expr.c
edify_cflags := -x c
include $(CLEAR_VARS)
LOCAL_MODULE := libedify
LOCAL_SRC_FILES := $(edify_src_files)
LOCAL_CFLAGS := $(edify_cflags)
include $(BUILD_STATIC_LIBRARY)

ここにたどり着くのにかなり時間がかかりました。。。。
 マジ情報少なすぎ・・・・・・orz 英語情報すら皆無だった・・・・
ukinau$ndk-build (tether-edifyのビルド)

エラー undefined reference to ******っていうのがまだ出る
yyscanとかyyparseとか・・・
Lexファイルとかyaccファイルがやっぱりコンパイルできてないみたい。
  いろいろググると同じ現象の人発見
  http://stackoverflow.com/questions/5365079/compiling-a-flex-bison-parser-with-ndk
  どうやら、C言語に変換しないといけない。なので以下のコマンドで変換する

$flex lexer.l ==> lex.yy.c
$bison --defines=parser.h --output=parser.c parser.y ===> parser.h parser.

んで、Android.mkのコンパイルソースもlexファイルとyaccファイルからこのコンパイル済みの物に差し替える

ukinau$ndk-build (tether-edifyのビルド)

 →エラー undefined reference to ******
cutilsとhardware_legacyが読み込まれてないらしいLOCAL_SHARED_LIBRARYで指定してるつもりだったんだが・・・・
 どうやら、ヘッダーファイル(.h)と共有ライブラリ(.so)を取得しないといけないらしい。
OSのコードに入っているのでhttps://android.googlesource.com/からDLする
 共有ライブラリは、またビルドしてエラー吐かれてもいやなので、手元の端末のsystem/libから
 libcutils.soとlibhardware_legacy.soを引っ張ってきた。

ukinau$ndk-build (tether-edifyのビルド)

エラー undefined reference to ******   まだ変わらない、SHARED_LIBRARYが読み込まれてないようだ。
  指定の仕方が分からない。。。orz
ググリまくってこの記事にたどり着いた
  http://tueda.wikkii.com/wiki/Android%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0-NDK-%E5%85%B1%E6%9C%89%E3%83%A9%E3%82%A4%E3%83%96%E3%83%A9%E3%83%AA%28libpng%29%E3%82%92%E4%BD%BF%E3%81%86   どうやら、.soはプリビルドして、そこから生成されたモジュールをSHARED_LIBRARYに指定するようだ。
  また、ヘッダーファイルが存在するとき(.h)はLOCAL_C_INCLUDESで.hの場所を指定しないといけないみたい。

ukinau$ndk-build (tether-edifyのビルド)

Prebuilt : libcutils.so <= jni/external/lib/
Install : libcutils.so => libs/armeabi/libcutils.so
Prebuilt : libhardware_legacy.so <= jni/external/lib/
Install : libhardware_legacy.so => libs/armeabi/libhardware_legacy.so
Compile thumb : tether <= install.c
Compile thumb : tether <= tether.c
Compile thumb : edify <= lex.yy.c
Compile thumb : edify <= parser.c
Compile thumb : edify <= expr.c
StaticLibrary : libedify.a
Executable : tether
Install : tether => libs/armeabi/tether

わーーーーい!実行ファイルできた^^ 動作確認はしてないけど、多分使えると思う。 後日、githubに、makeファイルとか依存ライブラリとかまとめたものを載せます。

感想としては、情報少なすぎ。stack-over-flowとかAndroid NDK のgoogleグループとかに、 「android-wifi-tetherをビルドし直したいんだけど」って投稿はたびたび見かけたんだけど 返事がないものばかりで、全然参考にならなかった・・・・