2012/03/11

android-x86を動かす

私は、RSSでブログチェックをしている。
メールも、twitterやSNSなどもほとんど活用してない。
基本的に、ブログやホームページをチェックする程度だ。

今週、ITproさんに興味ある記事があった。

Android 4.0をx86パソコンで動かしてみよう
http://itpro.nikkeibp.co.jp/article/COLUMN/20120227/383202/

やってみよう。

広島の方ではAndroidのハッカソンが行われているようなので、対抗して一人ハッカソンだ。
・・・嘘です。単なる偶然です。


私はVirtualBoxで動かしたかったので、書いてあることはほとんど読まず、android-x86のページを見た。
いや、書いてあるとおりにやったら動かなかったので、普通にやったというところか。
ITproのページではgrub周りを変更してあるし、ベースとなるPCがうちと違うためだ。

インストールせず、isoファイルをそのままCD-ROMみたいにして動かすと、動いた。


もちろん、これだけをやりたいわけではない。
ちょっと昔の話をしよう。

私がSonyのRC-S620/Sを購入した後だったか前だったか、Android 2.3が発表された。
初のNFC API対応だった。
ソースをダウンロードして、NfcServiceを見て、このくらいなら移植できるんじゃないか、と思った。

そしてやってるうちに、2.3.3だか2.3.4だかが出てきて、一気に複雑になって挫折したのだ。
まあ、おかげでJNIやらなんやらを試すことができたのだが、なんとなくもったいない気持ちだった。
その後、BeagleBoardに自前ライブラリなどは載せたものの、Androidの標準APIとはつなげられなかったので、何とかしたいと思っていたような気がする。

というわけで、今回の一人土日ハッカソンは、「android-x86で少しくらいパソリを動かす」だ。
全部動かそう、とか、APIとつなげよう、なんて大それたことを2日でやっちゃいかん。


まず、android-x86のソースを見て困ったのが、NfcService周りのソースがないこと。
コンパイルされないようにしているわけではなく、そもそも入ってないのだ。
これは、android-4.0.3_r1から持ってきた。

 

持ってきたからと言って、そのまま使えるわけではない。
次の作業は、NfcServiceからlibnfc-nxpを分離する作業だ。
libnfc-nxpという名前からするとlibnfcの分派のように聞こえるが、全く別物だ。
こちらは、NXPがじきじきにメンテナンスしているものだ。
たぶん、これ

NfcServiceは、packages/app/Nfc以下にある。
そしてAPIは、frameworks/base/core以下にある。
見たところ、API側はいじられてないようなので、方針としてAPIには手をなるべく入れないことにした。
Javaはわからないので、あまり触りたくない、というのが本心だ。


2.3.4くらいのときと違って、packages/app/Nfc以下も整理されていた。
nxpを制御する部分がかなり分離されているのだ。
これは、好都合だった。

やってからわかったことだけ書くと、DeviceHost.javaがネイティブとのインターフェースになり、それをうまいこと実装すれば移植しやすいようである。
それがわかるまでは、NfcServiceから先に手をつけ、DEPやLLCPをごそごそ削り、システム側と整合が取れなくなってコンパイルエラーやら動かないやらでてんやわんやだった。

やるなら、まずnxpパッケージを削除して自前のパッケージを追加し、そこにDeviceHostのimplementsクラスを作るとよさそうだ。
名前をNativeNfcManagerクラスにしておくと、NfcServiceとつなげやすい。

あとは、NativeNfcManager側のLLCPを無効にしたりしつつ、NfcServiceで使わないものを整理していくと、そこそこ形が整う。
注意としては・・・ビルドだろうか。
android-x86だが、どうも1回だけしかmでビルドしないと、依存関係がうまく解決できていないのか、VirtualBoxで実行しても異常動作を起こすことが多かった。
ソースを変更せず、もう一度mするとうまくいったので、順序の問題っぽい。
これがわかるまで、動きが毎回違うのかと思って苦労した。


ここまでは、NfcServiceだけの話。
私はパソリを動かしたいので、USBもなんとかせんといかん。

libusbを移植して自前の環境を持ってこようかと思ったが、Android 3.2のときにUSB Host機能を使ってパソリを動かしたことを思い出した。
そのライブラリをNfcServiceで動かせば、あっさり動くだろう。

 

・・・動かなかった。
タイミングの関係だか書き方が悪いのだかわからんが、動かなかった。

アプリでUSB Host機能を動かすとわかるが、普通はユーザに「このUSB機器をつないでもいい?」という認証を求めてくる。
(求める要求はアプリで果敢といかんが、画面はシステムが出してくれる。)
この認証画面が出てくるのが、NfcServiceの起動と重なり、認証させる画面と同時くらいにサービスを動かそうとするためか「サービス起動に失敗した」ダイアログが表示され続け、認証画面にたどりつけなかったのだ。
まあ、書き方が悪かったんだろうね・・・。


しかし、通常使うのであれば、わざわざダイアログが出てきて認証させることがいやだ。
パソリだけを優遇してやろう。

と、今では書いているが、そうするまでかなり迷った。
ダイアログを出させて認証させてから動かす方がよいかどうか、だ。
最終的には「いいんじゃないの」としたけどね。

この「特別扱い」の実行が最後までわからなかった。
frameworks/base/services/java/com/android/server/usb/UsbSettingsManager.javaを見ると、認証しているのはcheckPermission()だ。
これは、USB Host用とUSB Accessory用とそれぞれある。
私としては、認証済みリストにパソリを最初から含めたような作りにしたかった。

認証済みのものは、/data/system/usb_device_manager.xmlにファイルとしておかれているようだった。
ソースで見る限り、だが。
ならば、このファイルを作って置いておけばいいだろう。
・・・と思ってからが長かった。
だめなのだ。私にはわからんかった。

Androidを移植したことがあるとわかるが、最初のルートファイルシステムをどう作るかは機種によってまちまちだ。
私はSmartQ5とBeagleBoardしかないのだが、それですら違いがあるのだ。
android-x86では、どうも/dataに相当する部分はマウントしないみたいである。
最初、/data/system/usb_device_manager.xmlというファイルを置いていたのだが、読んでくれなくてadb shellで確認した。

ならば、とinit.rcの起動処理くらいにcpで/etc/に置いたファイルをコピーするようにしたが、それもだめ。
/etc/init.shのタイミングだとコピーはできたが、UsbSettingsManagerのコンストラクタには間に合っていないのか、だめ。

いろいろ考えて実践したあげく、こうした。

    public boolean hasPermission(UsbDevice device) {
        synchronized (mLock) {
        	//PaSoRi OK(hiro99ma)
            if((device.getVendorId() == 0x054c) && (device.getProductId() == 0x02e1)) {
                Slog.d(TAG, "I am PaSoRi.");
                return true;
            }

ああ、笑うがいいさ。
格好が悪いが、べた書きでしか対応できなかった。


こうすると、android-x86が起動するとNfcServiceが起動し、パソリも自動的に認証して、NfcServiceのenableでポーリング開始を書いていたら、ポーリングしてくれた。
長かった・・・。

明日は、ポーリングをやりっぱなしではなく定期的に行うようにして、検知したらインテントを投げるように変更したいものだ。
ほら、やっぱりAPIとつなげるってところまでは無理そうやん。

0 件のコメント:

コメントを投稿

コメントありがとうございます。
スパムかもしれない、と私が思ったら、
申し訳ないですが勝手に削除することもあります。