月別アーカイブ: 2014年4月

PicUntu導入

一昨年,Rockchip SoC が搭載された Stick 型や Box 型のデバイスがかなりの勢いで発売されました.HDMI 端子に TV を,USB 端子にマウスを繋いで電源を供給すれば,Android 端末として動作するというものです.最近では Amazon でも比較的簡単に入手することができ,DualCore や QuadCore の Cortex-A9 環境が 5000~10000円という破格値で売られています.

FirefoxOS on AndroidStick もこの PicUntu の最小インストールをスタート地点にしています.

PicUntu とは?

PicUntu とは,その Rockchip SoC 搭載の AndroidStick で動作している Ubuntu Distribution で,DualCore の RK3066,QuadCore の RK3166 がターゲットとして開発が進んでいます.とりあえず 手順に従って導入し,LXDE のデスクトップ環境を構築してみました.

PicUntu_LXDE

導入方法はサイトを見ていただければよいのですが,サイトは英語ということもあるので,FirefoxOS を載せるベースとなる準備段階までをメモしておきます.ここでは RK3066 ベースの mk808b を例としておきますが,PicUntu の開発ストリームは RK3166 ベースに移行していますので,最新環境に追従したい方は別途情報を収集してください.

用意するもの

  • Android Stick 本体
  • microSD カード (4GB 以上)
  • 電源供給用 miniUSB-USB ケーブル
  • miniHDMI-HDMI ケーブル (TV やモニタに接続)
  • USB ハブ,キーボード,マウス
  • USB-LAN (option; ASIX AX88772 は動作確認済)
  • USB-WiFi (option; Ralink RT2870 は動作確認済)

mk808b の PicUntu は内蔵 Wi-Fi や内蔵 Bluetooth が使えませんので,必要に応じて USB-LAN や USB-WiFi を導入します.
(※ kernel を再構築すれば Wi-Fi は使えそうなのですが再構築 kernel の搭載に成功してません.さらに mk808b はクローンが存在し,異なるチップが載ってたりして開けないと分からないため厄介です.)

インストール手順としては,bootloader と kernel の入った ROM イメージを本体の NAND flash に書き込む作業と,root ファイルシステムを microSD に書き込む作業の2つです.先人が詳しい説明を書かれていますので,そちらも参考にしてみてください.

ROMイメージのNAND flash への書き込み

RK3066 の PicUntu は NAND flash の Recovery 領域に bootloader と kernel の ROM イメージを置くため,Recovery 領域から起動する必要がありますが,残念ながら購入時の Android ではできません.そのためカスタム ROM の導入(要は root 化)が必要です.メジャーなところでは Finless ROM があります.mk808b 向けの Finless ROM は V1.7 を使いましたが,書いた時点より上がってるので探してみてください.ただし PicUntu の導入には新しい必要はありません.

RK3066 の PicUntu は開発が止まっていますので 0.9RC3 が最新のようです.ダウンロードファイルより ROM イメージ(*.img) を取り出します.

WindowsPC にて ROM パッケージに含まれる RKAndroidTools(ROM_Flash_Tool_xxx.exe) で NAND flash への書き込みを行います.

  • まず「本体裏の左側の穴をピンで突きながら電源を入れる」ことで bootloader モードに入ります.ドライバが要求されますので,ROMパッケージに含まれる rockusb.inf を指定してインストールします.インストールできれば NAND flash の書き込みが出来る状態です.
  • RKAndroidTools を起動します.recovery の Path を PicUntu の ROM イメージに書き直し,「Flash ROM」で書き込みが完了します.

Root ファイルシステムの microSD への書き込み

PicUntu は microSD 上の ext4fs を使います.rootfs のファイルは 「picuntu-linuxroot-0.9-RC*.tgz」 の形で配布されていますので,PC Linux や GParted LiveCD などを使って,microSD にパーティションを作成してラベル “linuxroot” で ext4fs にフォーマットした後,mount して rootfs のファイルを展開します.

起動

microSD を本体に挿して電源を入れ直します.カスタム ROM の Android が起動し,terminal を起動して recovery モードでリブートします.terminal がない場合は Google Play から入手してください.

$ su
# reboot recovery

コンソールが接続されたモニタに表示され,root:12qwaszx で login できれば成功です.

あとは煮るなり焼くなりどうぞ.apt-get install で用意されている arm 版 package が PC と同じ感覚で導入できます(速度は…同じ感覚とはいきませんが)

Firefox Developers Conference 2014 in Kyoto に参加してきました

京都にて Firefox の開発者向けカンファレンスが開催されました.13:00~19:00 の長丁場ながら200人以上が参加したとか.詳しい内容は Slideshare などで公開されてます.

FirefoxOS が注目される中,Webプラットフォームへの転換期にいるのが実感できました.Webがあらゆる表現を包括できれば後はそれベースで全て語れるわけで,プラットフォームとして十分価値があります.発表もWebアプリ技術が中心でしたから,Web を作ってきた人達はアプリ開発への移行も期待できます.

とはいえまだ動く実機が少なく,アピールするには実機が普及しないことには始まりません.会場には実機が展示されていましたが,まだまだ手にするには時間が掛かりそうです.作るほうも単に作ればいいと言うものではなく,ベースとなるプラットフォームも UI/UXに必要なパフォーマンス・機器間の接続・規格の取り込みなどの進化が必要です.FirefoxOS が動く実機環境を(無理矢理)構築している自分としても何か一端の役に立てればと思います.

先月の勉強会に引き続き同じネタで LT 発表してきました(全然進展してませんが).懇親会会場だったこともあってすごい盛り上がりの中だったのでネタを仕込んでおくべきだったと仕切りに後悔(^^;)


あと,フォクすけを賭けたじゃんけんには初戦敗退でした…

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 アドレスで行えばこの問題は起こりません.

 

FreeBSD で VPN サーバ環境

以前より自室に BSD で常時運転サーバを立てていたものの,外からアクセスするのにサービス毎に firewall に穴を開けるか,Web で操作するかをしてたのですが,いい加減面倒になってきたところで何か手段がないか探してたタイミングで SoftEther が Open 化されたということで(VPNとは何かを頭に叩き込んで)導入してみました.

SoftEther のインストール

SoftEther のビルドは実に簡単で,download ページGitHub からソースコードを取得して,configure,gmake install で終わりです.実に簡単.iconv が無くて make が通らない場合は,Makefile に -I/usr/local/include とか -L/usr/local/lib とかつければよいです.

インストール先が /usr/vpnserver とか /usr/vpnclient に設定されているのでやや違和感があります./usr/local/vpn/vpnserver 辺りに直しています.

自室サーバでは VPN サーバ機能だけを root で起動し,自室内 LAN とはローカルブリッジで接続することで外にいる端末をローカル LAN に接続できるようになります(ローカルブリッジなどの設定は後述).

# vpnserver start

VPN サーバの設定

室内 LAN は ルータ・終端装置(ONU)を介して WAN と接続していて,ルータ内はローカル LAN を構成して NAT で運用されているものとします.VPN サーバの FreeBSD はローカルLAN内に接続しています.

基本設定

VPN サーバの設定は vpncmd でも出来ますが,LAN 内のWindows PC から「サーバ管理マネージャ」をインストールすれば GUI で設定できます.

  • 新しい接続設定→ホスト名(サーバIP),ポート番号(どれか一つ),サーバ管理モード,管理パスワード
  • 接続
  • 仮想HUBの作成→仮想HUB名,パスワード
  • 仮想HUBの管理→ユーザの管理→新規作成→ユーザ名,パスワード認証,パスワード

ローカルブリッジの設定

ローカルブリッジとは,VPN を通して外部の仮想ネットワークと内部の物理ネットワークを接続する手段です.これを使えば仮想ネットワークをLAN内PCに参加させる手間が省けます.

  • ローカルブリッジ設定→仮想HUB(先に作成した仮想HUB名),LANカード(I/F名)→ローカルブリッジの作成

なお,「仮想 HUB とローカルブリッジを組んだ」 I/F は VPN からアクセスできないという OS 上の制約があるようです.そのため,VPN サーバがローカル LAN 内にある場合でも I/F は2つ用意しないといけないようです.自室では VPN 専用に USB-Ethernet 変換で I/F を増設しました.

L2TPの設定 

最近はスマートフォンが VPN 経由のリモートアクセス(L2TP)に対応しているので,利用できるようにその設定を行います.

  • IPsec/L2TP 設定→L2TPサーバー機能を有効にする,IPsec事前共有鍵(任意文字列)

ファイアウォールの設定

室内 LAN はルータを介して WAN(ONU) に接続しているので,外部から VPN サーバにアクセスするポート制御が必要です.構成によりますが,以下のポートを IP マスカレードに設定する必要があります.

  • UDP port 500 (IKE)
  • UDP port 4500 (IPSec NAT-Traversal)
  • UDP port 1701 (L2TP)
  • ESP port (Encapsulated Security Payload) … VPNスルー機能

VPN クライアントの設定

クライアントは OS に合わせて VPN クライアントを用意し,仮想 LAN カードを作成して VPN サーバ(WAN から見える IP または FQDN) の 仮想 HUB,ユーザ名,パスワードを設定して接続します.接続が完了すると ローカル LAN で DHCP が動いていればその IP アドレスが仮想 LAN カードに設定されます.

iPhone や Android の場合は,VPN メニューから VPN サーバ(WAN から見える IP または FQDN),ユーザ名(@仮想HUB名),パスワード,シークレット文字列(IPsec事前共有鍵で設定した文字列) を設定して接続します.

これで,外にいながら自室のローカル LAN と同じ条件で端末を扱うことができます(たぶん).速度は圧縮などの技術でかなり使えるレベルになってきています(とはいえペイロードにカプセル化したパケット載せてるんだから過剰に期待するのも酷というもの…).