カテゴリー別アーカイブ: FirefoxOS

FirefoxOS の色反転問題

AndroidStick に FirefoxOS を乗せる時に引っかかった問題として,色反転問題があります.詳しく調べ切れていないのですが,JellyBeans をベースとする場合には通常使う色フォーマットが Android とは異なることで現れるようです.

Window の色フォーマット決定

色フォーマットは場面ごとに使う手段によって決まるため,ここでは Window に描画されるフォーマットについて扱います.Window 向けのフォーマットは Gonk 層との境界 gecko/widget/gonk/libdisplay/GonkDisplayJB.cpp にある GonkDisplayJB() の surfaceformat にて決められます.

GonkDisplayJB::GonkDisplayJB()
{
  :
    if (!err && mFBDevice) {
        :
        /* The emulator actually reports RGBA_8888, but EGL doesn't return
         * any matching configuration. We force RGBX here to fix it. */
        surfaceformat = HAL_PIXEL_FORMAT_RGBX_8888;
    }
    :
    if (!err && mHwc) {
        :
        surfaceformat = HAL_PIXEL_FORMAT_RGBA_8888;
    }
    :
}

ここでは,Framebuffer が open できたらまず RGBX_8888 を設定し,Hwcomposer が open できたら RGBA_8888 に設定しなおすようです.Hwcomposer は画面の全部または一部を反転・回転・拡縮などを制御する Android 実装機能ですが,FirefoxOS では API 1.1 以上でないと使えないようで,まだ API 1.0 がほとんどの状況で使えない場合が多いです.AndroidStick の Hwcomposer もそうでした.

つまり「Hwcomposerが使えない」場合は surfaceformat は RGBX_8888 が選択されることになります.これは 1pixel が 32bit で扱われるとともに, Red,Green,Blue と 8bit とずつ並ぶフォーマットです(最後は空の8bit).ちなみに RGBA_8888 は 最後が alpha 情報が入るフォーマット,BGRA_8888 は並びが Blue,Green,Red,Alpha と並ぶフォーマットです.

画面モードの選択

フォーマットは選択されましたが,実際に Gonk 層へは EGL ライブラリを通じて設定されます. EGL では FirefoxOS や Android が期待するフォーマット情報を渡し,それにマッチする画面モードを返します.

その中にビット幅も情報に含まれるのですが,その値を取得するのは gecko/widget/gonk/nsWindows.cpp にある ColorDepth() です.先ほどの surfaceformat を参照して決めているようですが…

static uint32_t
ColorDepth()
{
    switch (GetGonkDisplay()->surfaceformat) {
    case GGL_PIXEL_FORMAT_RGB_565:
     return 16;
    case GGL_PIXEL_FORMAT_RGBA_8888:
     return 32;
    }
    return 24; // GGL_PIXEL_FORMAT_RGBX_8888
}

先ほど surfaceformat は RGBX_8888 が選択されていたので 24 が戻ります.Android で実装される EGL が正しく 24bit で RGBX のモードを持っていれば正しく表示されるはずですが,そうでなければ期待しないモードに設定されてしまいます.その結果がこれ.

色反転homescreen

キツネさんが青い…(T_T)

どうも RGBX_8888, 24bit と指定される EGL には BGRA_8888 相当が選択されてしまったようで,初期の段階では Red と Blue が反転してしまう問題が起こってしまっていました.

EGL の仕組みを知らなかったこともあって,なぜこうなるかまでたどり着くのにかなり掛かりましたが,Hwcomposer が有効な場合と同じ「最初に設定した surfaceformat を RGBA_8888 に修正」することで EGL の持つ正しいモードに設定されて解決しました.

Gonk 層に期待すること

Gonk 層,つまり Linux Kernel (Config) や Driver や Android Library は Android をベースにしている場合,Android が動くようにチューニングされています.そのため,FirefoxOS を動かすと必ずしも Android とは動作条件や受け渡す情報が同じにならないため,想定していない状態に陥ると残念ながら期待通りには動作しません.

となると,Gonk 層は Android だけでなく FirefoxOS が期待する条件でも動くように実装されている必要があります.これは地道に「Gonk 層は何が期待されているのか」を探っていくしかないでしょうね…

 

 

FirefoxOS v1.4 のアドレス解決

FxOS on AndroidStick にて v1.3 までは DNS によるアドレス解決がすんなりできていたのですが,v1.4 では全くできなくなっていて調査したところ,ソフト構成の変更があったようです.

ソフト構成の変更点

ソースを辿ってみたところ,名前解決は NSPR 実装の gecko/nsprpub/pr/src/misc/prnetdb.c 内にある PR_GetAddrInfoByName() にて実施していました.この API 内では,GETADDRINFO() にて変数 _pr_getaddrinfo に設定された関数を呼び出され,この変数はライブラリから検索されて見つかった関数が設定されています.

v1.3 までは gecko/other-licenses/android/getaddrinfo.c の __wrap_getaddrinfo() に誘導されていましたが,v1.4 からはこの other-licenses/android が無効になり,bionic の getaddrinfo() が直接呼ばれるようになったようです.

gecko/moz.build にて MOZ_WIDGET_TOOLKIT が ‘gonk’ の場合,other-licenses/android が無効にされているのが分かります.

- if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('android', 'gonk'):
- add_tier_dir('base', ['other-licenses/android'])
+ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':
+ add_tier_dir('base', ['other-licenses/android'])

bionic の getaddrinfo() は netd にアドレス解決を依頼します.ソケットを介して “getaddrinfo” コマンドが送られてアドレスを解決するようですが,この応答が timeout してアドレス解決できなくなっていたようです.netd は android の daemon なので ”setprop net.dnsN” で解決しそうに思いますが,残念ながらこの方法では解決しませんでした.

※追記(4/19): FxOS は multicastDNS に対応しているため,導入ネットワークに接続していればこの問題は発生しないと思われます.つまり自室内LANは未対応…

netd への登録

android には netd が open した socket にコマンドを送り込むコマンド “/system/bin/ndc” が用意されています.これを使うと netd に直接 DNS サーバ情報を送り込めるようです.これを用いて以下のように netd に google DNS サーバのアドレスを設定したところ,v1.4 でのアドレス解決ができるようになりました.

# ndc
Usage: ndc [sockname] <monitor>|<cmd> [arg1] [arg2...]
# ndc resolver setdefaultif eth0
# ndc resolver setifdns eth0 ^ 8.8.8.8 8.8.4.4
Using alt socket netd
200 0 Resolver command succeeded

書式はソースから起こしたのですが,resolver が名前解決コマンド,setifdns がサブコマンドでI/Fへのサーバ情報設定,”^” はドメイン名で「省略」を表し,後ろの2つはサーバIPアドレスです.

今のところ手動で対応する必要がありますが,実施するなら netd の起動後の script に設定しておくのがよいかと思います.

補足ですが,ストレージ制御の vold にも “/system/bin/vdc” コマンドが用意されており,これらの daemon の挙動チェックに外部コマンドが用意されているのはなかなか便利です.残念ながらコマンド一覧が見当たらないのですが,ソースから起こしておくと便利かもしれません.

Proxy への影響

FirefoxOS は一部を除いて HTTP でのアクセスが基本ですので,proxy を設定すれば URL のアドレス解決は proxy サーバに委ねられるため,この問題は proxy サーバのアドレス解決だけが影響を受けます.proxy サーバの設定を IP アドレスで行えばこの問題は起こりません.

 

FirefoxOS のローカルミラー

FirefoxOS は commit が頻繁に行われ,master branch だけ追従してるとおかしな動作の時に拾うと残念なツリーになってしまうので,version branch で安定した環境も並列して構築しておきたいとなると,同じツリーをリモートから頻繁に取るのも何なのでローカルミラーが欲しくなります.

Android では本家に解説があります.

http://source.android.com/source/downloading.html#using-a-local-mirror

FirefoxOS の初回ビルド方法はMDNに解説があります.これが前提知識となりますので一度はトレースしておくのがよいかと思います.

https://developer.mozilla.org/ja/docs/Mozilla/Boot_to_Gecko/Preparing_for_your_first_B2G_build

FirefoxOS の場合は Android のモジュール管理ツールである repo を使いつつも shell script で自動化されているため,少々ややこしい手順が必要でした.またここでは git の操作が必要なので,git の知識が必要です.もしかしたらもっと単純で簡単な方法があるかもしれませんが.

ディレクトリイメージ

この例ではローカルミラーは以下のようなディレクトリを想定しています.青文字の “server:/opt/git/b2g” は「ホスト名 server」の「/opt/git/b2g ディレクトリ」のため,環境に合わせて読み替えてください.

server:/opt/git/b2g
|-- B2G
|-- projects
    |-- .repo
    |-- gaia.git
    |-- gecko.git
    :

リポジトリの取得

まず,server(以下 shell prompt が ‘$’) にて最初のベースリポジトリを clone します.

$ cd /opt/git/b2g
$ git clone git://github.com/mozilla-b2g/B2G.git

リポジトリを初期化します.ここでは取得するベースとして ICS である emulator.xml を選択していますが,JellyBeans ベースなら emulator-jb.xml,Kitkat ベースなら emulator-kk.xml を指定します.機種を選択する場合は,b2g-manifest ディレクトリの xml ファイルを選択します.この sync は環境によってはかなりの時間を要します.

$ mkdir /opt/git/b2g/projects
$ cd /opt/git/b2g/projects
$ ../B2G/repo init -u git://github.com/mozilla-b2g/b2g-manifest.git -m emulator.xml --mirror
$ ../B2G/repo sync

ローカルへの対応

ローカル用の manifest に変更して,ローカル用のブランチ(local-master)に commit します.(リモートが更新された場合はリモートに追従して rebase または merge していきます.)

$ cd /opt/git/b2g/.repo/manifests
$ git checkout -b local-master origin/master
$ patch -p1 < emulator.xml.patch
$ git commit
$ git checkout default

local 用の manifest は remote のアドレスをローカルミラーの位置に修正したものを用意しておきます. 上記に登場した emulator.xml.patch は以下のようになります.

--- a/emulator.xml 2014-02-22 18:29:29.000000000 +0900
+++ b/emulator.xml 2014-03-22 01:28:46.000000000 +0900
@@ -2,18 +2,18 @@
<manifest>
<remote  name="aosp"
-        fetch="https://android.googlesource.com/" />
+        fetch="server:/opt/git/b2g/projects" />
 <remote name="caf"
-        fetch="git://codeaurora.org/" />
+        fetch="server:/opt/git/b2g/projects" />
 <remote name="b2gmozilla"
-         fetch="https://git.mozilla.org/b2g" />
+         fetch="server:/opt/git/b2g/projects" />
 <remote name="b2g"
-         fetch="git://github.com/mozilla-b2g/" />
+         fetch="server:/opt/git/b2g/projects" />
 <remote name="mozilla"
-       fetch="git://github.com/mozilla/" />
+       fetch="server:/opt/git/b2g/projects" />
 <remote name="mozillaorg"
-     fetch="https://git.mozilla.org/releases" />
- <remote name="apitrace" fetch="git://github.com/apitrace/" />
+     fetch="server:/opt/git/b2g/projects" />
+ <remote name="apitrace" fetch="server:/opt/git/b2g/projects" />
 <default revision="refs/tags/android-4.0.4_r2.1"
          remote="caf"
          sync-j="4" />

ベースが JellyBeans や KitKat の場合はマニフェストファイルが base-jb.xml,base-kk.xml に分かれているのでそれぞれローカルの対応が必要です.

 ローカルビルド

ローカル環境(以下 shell prompt が ‘%’)では通常の手順通り config.sh を実行しますが,manifest リポジトリにローカルミラーの位置に,branch にローカル用 branch を指定して実行します.

% mkdir ~/work/b2g
% cd ~/work/b2g
% GITREPO=server:/opt/git/b2g/projects/.repo/manifests BRANCH=local-master ./config.sh emulator
% ./build.sh

 ローカルで新しいターゲットを追加する場合

ローカル向けに新しいターゲットを追加するには,次の手順を実施します.

  1. server:/opt/git/b2g/B2G にて config.sh にターゲット情報(例えば new-target)を追加して default  branch に commit
  2. server:/opt/git/b2g/projects/.repo/manifests にてターゲット用 manifest を作成してローカルbranch(local-master) に commit
  3. ローカルビルドは config.sh の引数に上記 1. で指定したターゲット名(new-target)を指定します.
    % GITREPO=server:/opt/git/b2g/projects/.repo/manifests BRANCH=local-master ./config.sh new-target

 

関西FirefoxOS勉強会 6th に参加してきました

前回に続き今回も勉強会に参加してきました.

XULRunner の解説,アプリの多言語化解説,アプリ間通信解説と今回濃い内容でした.単語や情報としては知っていても実際どう書いていくのかはやってみないと知る機会がないので,勉強会はそれを知るいい機会かと思います.

そして今回は現状の FirefoxOS on AndroidStick の紹介ということでLTにて発表しました.


本当は実機を持ち込んで動かしたかったところですが,HDMI出力環境が会場にないだろうということで持ち込まないといけなかったのと,急遽思いついて資料を前日から当日深夜に作ってた状態なので,今回は残念ながらパスしました.実際にはさらに今のままでは配線や起動するまでの操作が大変で,まだまだこれからな感じです.さらに技術的な話とするにはまずここでメモとして書いてからですかね…

FirefoxOS on Android Stick (現状報告)

いろいろ試行錯誤した結果,「mk808b」に FirefoxOS を載せてなんとなく動いています.技術的な解説は別の機会でするとして,今のところ確認できてることは以下の通りです.

  • Recovery 上の Linux 経由での FirefoxOS v1.3 起動 (Recovery 起動 のため Android 起動必要)
  • homescreen 表示と USBマウス/キーボード操作
  • USB Ethernet でネットワーク接続(Wi-Fi は×)
  • webm(動画) と ogg(音楽) の ソフト再生,Gallery App の画像表示
  • MarketPlace からの App インストール

fxos-home fxos-web fxos-marketplace fxos-movie

試行錯誤の途中には,色がおかしくなる問題・メディアストレージが見えない問題・Console 表示問題などを解決しています.一見素直に動いているのですが,裏では大量のエラーを吐いている状態のため時間経過と共に動作が不安定になってきます.これはバイナリで供給している部分(kernel や Android ライブラリなど)があり,ソースから build した部分と不整合があるためです.これだとちょっとまだ実用には遠そうです.

kernel の不整合は,公開 git があるので config を今動いているものに合わせて driverを有効にし, build と ROM化すれば解決しそうなのですが,config 情報や build 条件が見つかっていないためうまくいっていません.これができれば Wi-Fi なども突破できそうなのですが…

Android ライブラリの不整合は,バイナリ供給元がソース非公開にしていることや,FirefoxOS がベースにしている Android バージョンと元のバージョンが合っていないことが原因です.これもなかなか一筋縄ではいかなさそうです.

ベースにしている PicUntu の開発ストリームはすでに次の世代のSoCである RK3188 に移行しています.kernel や driver の追従には RK3188 搭載 Stick をターゲットにした方がいいかも知れません.手元には搭載 Stick の「mk908」も準備中です.

 

FirefoxOS on Android Stick (準備)

最近は次世代 Web platform として ChromeOS, Tizen そして FirefoxOS が熱いのですが,その中でも Community 活動が活発な FirefoxOS に注目しています.

しかしいざ試してみようとしても端末はまだ手に入りにくく,Simulator で遊ぶか build 環境を整えて Emulator で試すくらいだったのですが,build 環境が Android ベースだったので Android が自由にいじれる環境があれば試せるなぁとおぼろげに思っていました.
Android 環境といえば手元には Nexus7(2012)があるのですが,Android の build や ROM 事情をよく知らないこと,そもそも実用で使ってるので環境をつぶすわけにもいかず,結局 Nexus7 を生贄にするのは断念しました.

その後, Android Stick の紹介を偶然見て割と安く手に入るということを周回遅れで知り,
「これで動かせるんじゃないの?」ということでちょっと足を突っ込んでみたのが始まりです.

Android Stick でメジャーなものとして「mk808」があり, 登場して結構経っていて,技術的には枯れていて情報が出回っているだろうということで選択してみました.とはいえ実際に情報を漁ってみるとまずメーカー情報自体がほとんどなくClone製品まであるということやソフト環境も野良情報ばかりで結構大変でしたが.

  • SoC は Rockchip RK3088,内部に Cortex-A9 Dual を抱えてて,Android を動かせるだけのスペックは備えている
  • HDMI 出力専用で FullHD まで出せて USB, Wi-Fi, Bluetooth に対応.

しかし Bagleboard や Pandaboard のように full build で試せるわけではないので,それに近い環境を探す必要があります.この SoC では Ubuntu ベースの Linux Distribution 「PicUntu」の開発が活発で,それをベースに Emulator 環境を載せていけばなんとかなりそうな気がします(本当か?).