Android Zaurusの日記

ザウルスをアンドロイドにしてあげる
本館 Android Zaurus

2012-01-30 んふんふ。コンプリート。

Transformer Primeで有線LAN

17:02 |  Transformer Primeで有線LANを含むブックマーク

dmesgを見ていたらUSB Hostモジュールとして

<6>[    8.162292] usbcore: registered new interface driver asix

が登録されていた。USBイーサの石。ということで、ビックカメラで下記を購入。


BUFFALO 10/100M USB2.0用 LANアダプタ (Wii&MacBookAir対応) LUA3-U2-ATX

BUFFALO 10/100M USB2.0用 LANアダプタ (Wii&MacBookAir対応) LUA3-U2-ATX


早速、家に帰ってつないでみたら、dmesgに

<6>[  100.845783] tegra_usb_resume+
<6>[  100.889849] tegra_usb_resume-
<6>[  101.181095] usb 1-1.2: new high speed USB device using tegra-ehci and address 3
<6>[  101.241086] usb 1-1.2: New USB device found, idVendor=0b95, idProduct=7720
<6>[  101.242163] usb 1-1.2: New USB device strings: Mfr=1, Product=2, SerialNumber=3
<6>[  101.242764] usb 1-1.2: Product: AX88772 
<6>[  101.243787] usb 1-1.2: Manufacturer: ASIX Elec. Corp.
<6>[  101.244357] usb 1-1.2: SerialNumber: 556D27
<6>[  102.133280] asix 1-1.2:1.0: eth0: register 'asix' at usb-tegra-ehci.2-1.2, ASIX AX88772 USB 2.0 Ethernet, 4c:e6:76:xx:xx:xx
<6>[  102.184767] eth0: link down
<6>[  102.190679] ADDRCONF(NETDEV_UP): eth0: link is not ready
<6>[  103.795184] ADDRCONF(NETDEV_CHANGE): eth0: link becomes ready
<6>[  103.807939] eth0: link up, 100Mbps, full-duplex, lpa 0xC5E1

logcatに

D/ConnectivityService(  177): ConnectivityChange for ETHERNET: CONNECTED/CONNECTED
D/ConnectivityService(  177): Setting TCP values: [4095,87380,110208,4096,16384,110208] which comes from [net.tcp.buffersize.wifi]
D/ConnectivityService(  177): adding dns /192.168.62.200 for ETHERNET
D/ConnectivityService(  177): adding dns /8.8.8.8 for ETHERNET
D/ConnectivityService(  177): changing default proxy to 
D/ConnectivityService(  177): sending Proxy Broadcast for 
D/ConnectivityService(  177): addDefaultRoute for ETHERNET (eth0), GatewayAddr=192.168.62.200
D/Tethering(  177): Tethering got CONNECTIVITY_ACTION
D/Tethering(  177): MasterInitialState.processMessage what=3
V/TweetDeck(  771): ETHERNET CONNECTION UP
I/MediaUploader(  820): No need to wake up
D/GTalkService(  352): [ReonnectMgr] ### report Inet condition: status=false, networkType=9
I/ActivityManager(  177): Start proc com.asus.cm for broadcast com.asus.cm/.push.PushControlReceiver: pid=950 uid=1000 gids={3003, 1015, 3002, 3001}
D/ConnectivityService(  177): reportNetworkCondition(9, 0)
D/ConnectivityService(  177): Inet connectivity change, net=9, condition=0,mActiveDefaultNetwork=9
D/ConnectivityService(  177): starting a change hold
D/GTalkService(  352): [RawStanzaProvidersMgr] ##### searchProvidersFromIntent
D/CMC->CMConfig(  950): DMConfig.init()
D/CMC->CMConfig(  950): mFumoHandlerName=DefaultFumoHandler
D/GTalkService(  352): [ReonnectMgr] ### report Inet condition: status=false, networkType=9
D/ConnectivityService(  177): reportNetworkCondition(9, 0)
D/ConnectivityService(  177): Inet connectivity change, net=9, condition=0,mActiveDefaultNetwork=9
D/ConnectivityService(  177): currently in hold - not setting new end evt

netcfgの結果は

$ netcfg
lo       UP                                   127.0.0.1/8   0x00000049 00:00:00:00:00:00
dummy0   DOWN                                   0.0.0.0/0   0x00000082 aa:02:9a:xx:xx:xx
usb0     DOWN                                   0.0.0.0/0   0x00001002 62:80:3d:xx:xx:xx
sit0     DOWN                                   0.0.0.0/0   0x00000080 00:00:00:00:00:00
ip6tnl0  DOWN                                   0.0.0.0/0   0x00000080 00:00:00:00:00:00
wlan0    UP                                     0.0.0.0/0   0x00001003 c8:60:00:xx:xx:xx
eth0     UP                                192.168.62.3/24  0x00001043 4c:e6:76:xx:xx:xx

ブラウザやマーケットも有線LAN経由でアクセス出来る。ConnectivityManagerに手を入れないと、マーケットは「ネットワークの回復を待っています」というダイアログが出て使えないと思っていたのだが、いつの間にか TYPE_ETHERNET としてイーサネットのサポートが入っていた。 ConnectivityManager.TYPE_ETHERNET のようなフレームワークで使用されている。ethデバイスが追加されるとDHCPなどの面倒を見てくれるようだ。root権限は不要。


有線LANでも使えると嬉しい人も中には居るのではなかろうか。ただし、 ro.sercure=1 かつ ro.debuggable=0 なので、充電しつつLAN経由でのadb接続は残念ながら出来ない。またTetheringデバイスからeth0が除外されているので、簡易WiFiルータとしても使えない。


モジュールがカーネルにスタティックリンクされているせいか、一度接続してからUSBアダプタを抜いて再接続すると、リブートするまでイーサネットに接続できなくなる。

2012-01-27 んふんふ。96%からなかなか進まない。

Transformer Primeのマルチコアとクロック

17:33 |  Transformer Primeのマルチコアとクロックを含むブックマーク

ASUS タブレットパソコン Eee Pad TF201 TF201-GD64D

ASUS タブレットパソコン Eee Pad TF201 TF201-GD64D


Tegra 3初物ということで、発売日に購入。とある勉強会でUstream用に購入当日にまさかの実戦投入。勉強会を始めてから2時間程して、電源つないでいるのになぜか電池がきれそうになり、よく見たらちゃんとタブレットとキーボードが接続されていなかった。というか、タブレット側の電池だけで2時間もUstream出来たのが驚き。


4コアということで、コアがどんなクロックで推移するのか気になったので、CPUクロックを3秒ごとにprintfするCプログラムを書いて眺めてみた。そのまとめ。

  • GovernorはInteractive
  • 設定可能なクロックは102MHzから1.4GHz
    • 102 204 370 475 620 760 880 1000 1100 1200 1300 1400
  • 1.2GHzまでしか使わない
    • /system/etc/normalmode.shで
echo 1 > /sys/module/cpu_tegra/parameters/system_mode
echo 1200 > /sys/kernel/tegra_cap/core_cap_level

これが効いているらしく、ログに

V/NvPowerMgr(  416): setPowerState(): scaling, capLevel, capState, userCap, aggressiveness = 1, 1200, 1, 1200000, 29
    • turbomode.shを使うとスペック通りに、1コア時Max 1.4GHz、マルチコア時Max 1.3GHzで動作する
  • アプリケーションによるマルチコア利用
    • ホーム画面のスワイプは2コアを1.2GHzで回す高負荷処理
      • 思ったより重い処理なのでむやみにぶいんぶいんすると電池持ちに影響するかも
    • Grow Ballは4コア全開
    • Rip Tideは3コアしか使わない
      • 通常処理に2コア。水滴などのTegra 3追加効果の処理に1コア。
    • twiccaは更新時に3コアまで全力で使う
    • 他のアプリはほとんど2コアの全力で収まってしまう
    • コンカレントGCに別コアを起こすような挙動は見られない
  • 1.2GHz x 2 -> 760MHz x 2 -> 1.2GHz x 1 -> 600MHz x 1のような推移
    • 負荷に応じてコア数とクロックをうまく調整してくれている
  • sleepで寝ないv8
    • ブラウザでGoogle Newsを開いた状態でsleepすると204, 370, 620をうろうろする
    • すべてのアプリを閉じてホームに戻ってからsleepすると、102MHz
    • PC版Googleホームでも同様にsleepしてもCPUクロックが落ちない。v8が寝ない。
    • PC版Googleホームはsleepしなくても370, 620, 880, 1200をうろうろする
    • PC版iGoogle
    • Mobile版は102MHzに落ち着く。

どうもsleepしても、ブラウザがActive状態だとv8は寝ないようなので、sleepするときはブラウザを閉じてからの方が、電池持ちがよくなりそう。これは他のAndroid端末に共通なのかもしれない。

2012-01-13

Android Security読書感想文

16:51 |  Android Security読書感想文を含むブックマーク

タオソフトウェアさん*1が執筆されて、インプレスさん*2から出版されている「Android Security」を、なぜか献本頂いた。ありがとうございました。


こんな人は是非読むべきだと思う。

  • Androidアプリケーションを受託開発している
  • Androidアプリケーションを外注しようとしている
  • Androidアプリケーションを開発しているが、セキュリティについては考えたこともない
  • 普通のAndroidユーザだが、パーミッションの意味をあまりよく分かっていない

開発者だけでなく、普通のAndroidユーザに薦めたいのは、P.117からの「6.5 疑われやすいパーミッションの組み合わせ」だ。立ち読みでもいいから一度目を通してもらいたい。あまりAndroidアプリが危険が危ないと煽るつもりはないが、どういう危険性があるかというのは認識しておくべきだと思う。


それにしても、READ_PHONE_STATEを要求するアプリ大杉だろ。

2012-01-11

Levels in Renderscript(超訳)

15:04 |  Levels in Renderscript(超訳)を含むブックマーク

Levels in RenderscriptというRenderscriptを解説した記事が本家に上がったので、久々に超訳。誤訳などあればご指摘を。


ICSではRenderscript(RS)がアップデートされた。いくつかの新しい機能が加えられ、アプリケーションで計算を簡単に高速化出来るようになっている。大量の処理が必要な大きなデータバッファがある場合、計算の高速化のためにRSは興味深い。この例ではレベル/サチュレーション処理をビットマップに施してみる。


この場合、サチュレーションはすべてのピクセルと色行列のかけ算として実装され、レベルはいくつかの演算で実装されるのが常套だ。


1. 入力レベルの調整

2. ガンマ補正

3. 出力レベルの調整

4. 有効値へのクランプ


単純な実装はこのようになる。


for (int i=0; i < mInPixels.length; i++) {
    float r = (float)(mInPixels[i] & 0xff);
    float g = (float)((mInPixels[i] >> 8) & 0xff);
    float b = (float)((mInPixels[i] >> 16) & 0xff);

    float tr = r * m[0] + g * m[3] + b * m[6];
    float tg = r * m[1] + g * m[4] + b * m[7];
    float tb = r * m[2] + g * m[5] + b * m[8];
    r = tr;
    g = tg;
    b = tb;

    if (r < 0.f) r = 0.f;
    if (r > 255.f) r = 255.f;
    if (g < 0.f) g = 0.f;
    if (g > 255.f) g = 255.f;
    if (b < 0.f) b = 0.f;
    if (b > 255.f) b = 255.f;

    r = (r - mInBlack) * mOverInWMinInB;
    g = (g - mInBlack) * mOverInWMinInB;
    b = (b - mInBlack) * mOverInWMinInB;

    if (mGamma != 1.0f) {
        r = (float)java.lang.Math.pow(r, mGamma);
        g = (float)java.lang.Math.pow(g, mGamma);
        b = (float)java.lang.Math.pow(b, mGamma);
    }

    r = (r * mOutWMinOutB) + mOutBlack;
    g = (g * mOutWMinOutB) + mOutBlack;
    b = (b * mOutWMinOutB) + mOutBlack;

    if (r < 0.f) r = 0.f;
    if (r > 255.f) r = 255.f;
    if (g < 0.f) g = 0.f;
    if (g > 255.f) g = 255.f;
    if (b < 0.f) b = 0.f;
    if (b > 255.f) b = 255.f;

    mOutPixels[i] = ((int)r) + (((int)g) << 8) + (((int)b) << 16)
                    + (mInPixels[i] & 0xff000000);
}

このコードはビットマップがすでにロードされていて、処理のために整数配列に移されていることを想定している。ビットマップはすでにロードされているので、これは簡単だ。


    mInPixels = new int[mBitmapIn.getHeight() * mBitmapIn.getWidth()];
    mOutPixels = new int[mBitmapOut.getHeight() * mBitmapOut.getWidth()];
    mBitmapIn.getPixels(mInPixels, 0, mBitmapIn.getWidth(), 0, 0,
    mBitmapIn.getWidth(), mBitmapIn.getHeight());

データ処理のループが終われば、描画のためにビットマップに戻すことも簡単だ。


    mBitmapOut.setPixels(mOutPixels, 0, mBitmapOut.getWidth(), 0, 0,
               mBitmapOut.getWidth(), mBitmapOut.getHeight());

フィルター本体の定数計算や、(ボタンなどの)コントロールの制御、画像表示などのコードを含めて、アプリケーション全体のコード量は232行程度になる。手元の実機では800x423の画像処理におおよそ140-180msecかかる。


もしこれで十分でなかったらどうする?


画像処理のコア部分をRSに移植するのはとても簡単だ。上記のピクセル処理本体をRSで実装しなおすとこうなる。コードはhttp://code.google.com/p/android-renderscript-samples/source/browse/Levelsにある。


void root(const uchar4 *in, uchar4 *out, uint32_t x, uint32_t y) {
    float3 pixel = convert_float4(in[0]).rgb;     // 3要素ベクトル
    pixel = rsMatrixMultiply(&colorMat, pixel);   // ライブラリ関数
    pixel = clamp(pixel, 0.f, 255.f);             // ライブラリ関数
    pixel = (pixel - inBlack) * overInWMinInB;    // ベクトル演算
    if (gamma != 1.0f)
        pixel = pow(pixel, (float3)gamma);        // ライブラリ関数
    pixel = pixel * outWMinOutB + outBlack;       // ベクトル演算
    pixel = clamp(pixel, 0.f, 255.f);             // ライブラリ関数
    out->xyz = convert_uchar3(pixel);             // ライブラリ関数
}

コード行数が極端に少なくて済むのは、浮動小数点のベクトルや行列演算、フォーマット変換があらかじめ組み込まれているからだ。また、ループが存在しないことに着目して欲しい。


準備のためのコードは、スクリプトをロードする必要があるので、ほんの少し複雑になる。


    mRS = RenderScript.create(this);
    mInPixelsAllocation = Allocation.createFromBitmap(mRS, mBitmapIn,
                                 Allocation.MipmapControl.MIPMAP_NONE,
                                 Allocation.USAGE_SCRIPT);
    mOutPixelsAllocation = Allocation.createFromBitmap(mRS, mBitmapOut,
                                 Allocation.MipmapControl.MIPMAP_NONE,
                                 Allocation.USAGE_SCRIPT);
    mScript = new ScriptC_levels(mRS, getResources(), R.raw.levels);

このコードはRSのコンテキストを生成している。続いて、2つのメモリアロケーションをこのコンテキストを使って生成し、ビットマップデータのRS用コピーを保持する。最後にデータ処理のためにスクリプトをロードする。


ソースコードには、他にもいくつか小さなコードの塊があり、定数に変更があった時に計算し直してスクリプトへコピーしている。グローバル変数はスクリプトからリフレクションされているので、簡単に行える。


    mScript.set_inBlack(mInBlack);
    mScript.set_outBlack(mOutBlack);
    mScript.set_inWMinInB(mInWMinInB);
    mScript.set_outWMinOutB(mOutWMinOutB);
    mScript.set_overInWMinInB(mOverInWMinInB);

先に述べたように、すべてのピクセルを処理するためのループがない。ビットマップデータを処理し、結果をコピーするRSコードはこうなる。


    mScript.forEach_root(mInPixelsAllocation, mOutPixelsAllocation);
    mOutPixelsAllocation.copyTo(mBitmapOut);

最初の行はスクリプトと入力アロケーションを取り出して、結果を保持する出力アロケーションを設定している。たったこれだけで、ネイティブにコンパイルされたバージョンのスクリプトを、アロケーションに入っているすべてのピクセルに対して、1つづつ一度だけ呼び出す。しかし、Dalvikの実装とは異なり、プリミティブ(コンパイルされたスクリプト)は自動的に複数のスレッドを生成して処理を行う。ネイティブコードの効率と合わさることで、大きなパフォーマンス向上を生んでいる。ガンマ関数のありなしで計算コストが大きく異なるので、両方の結果を下に示す。


800x423の画像

DeviceDalvikRSGain
Xoom174ms39ms4.5x
Galaxy Nexus139ms30ms4.6x
Tegra 30 device136ms19ms7.2x

ガンマ補正を加えた場合の800x423の画像

DeviceDalvikRSGain
Xoom994ms259ms3.8x
Galaxy Nexus787ms213ms3.7x
Tegra 30 device783ms104ms7.5x

ゲインが大きいほど、簡単なコーディングで得られる見返りが大きいことを示す。


訳注: Xoom, GN, Tegra 3というのは理にかなった選択。

Xoom: 2コア、VFP3

GN: 2コア、NEON

Tegra 3: 4コア、NEON

Tegra 30というのは、単なる記憶違いもしくはTegra 3が正式名称になるまえに30と呼び習わしていたのかもしれない。

2011-09-12 Top Favorites枠ありがとうございました。

DevQuiz 2011 - Go

12:34 |  DevQuiz 2011 - Goを含むブックマーク

解答晒し。誰が書いても似た様になるだろうけど。


1つだけ疑問。オリジナルのCountColorの引数がpngになっていたけど、image/pngをimportした時に、名前が衝突してpng.Decode()が呼び出せない。io.Readerの変数名がpngというのも気持ち悪いのでsrcに変更したけど、本当はどうすべきだったのか*1

package main

import (
	"fmt"
	"io"
	"strings"
	"image"
	"image/png"
	/* add more */
)

func rgbaToInt(s image.Color) uint32 {
	r, g, b, a := s.RGBA()
	i32 := r + g<<8 + b<<16 + a<<24 
	return i32
}

func CountColor(src io.Reader) int {
	hash := make(map[uint32] int)

	dec, e := png.Decode(src)
	if e != nil {
		fmt.Println(e)
		return -1
	}

	for y := dec.Bounds().Min.Y; y < dec.Bounds().Max.Y; y++ {
		for x := dec.Bounds().Min.X; x < dec.Bounds().Max.X; x++ {
			color := dec.At(x, y)
			if hash[rgbaToInt(color)] != 1 {
			   hash[rgbaToInt(color)] = 1
			}
		}
	}
	return len(hash)
}

/* これらの関数は提出時に自動挿入されます。 */
func main() {
	png := GetPngBinary()
	cnt := CountColor(png)
	fmt.Println(cnt)
}

DevQuiz 2011 - Android

12:34 |  DevQuiz 2011 - Androidを含むブックマーク

誰が書いても似た様になるだけなので、解答晒さない。


AndroidEclipse環境はとても賢い。Eclipse様の仰るとおりにインプリメントしただけ。

  • AIDLファイルをプロジェクトにDrag & Drop
    • src/com/google/android/apps/gddquizに置けと怒られる
    • そうする
  • ServiceConnectionのメンバー変数定義
    • connect/disconnectのメソッドを定義しろと怒られる
    • そうする
  • 適宜Shift-Ctrl-Oでimportの整理
  • あとはAIDLのドキュメントの通り
    • Ctrl-Spaceで補完しまくり
    • Log.dに出してこぴぺ

DevQuiz 2011 - 一人ゲーム

12:34 |  DevQuiz 2011 - 一人ゲームを含むブックマーク

解答晒し。やや長いのでpatebin。

http://pastebin.com/9mZBtu1H

  • まず、ロボット的に最短に近い手数を出す。(ruledengine)
    • 奇数かつ5で割り切れる数が1以上なら、取り除く(evalremove5)
    • それ以外は半分
    • 繰り返せば最短に近い手数が出そう
  • ロボットが出した手数まで全探索(walkaroundengine)
    • 単純な2分木探索
  • 取り除かれた数字には-1をいれておくことで、配列のコピーを避ける

DevQuiz 2011 - スライドパズル

12:34 |  DevQuiz 2011 - スライドパズルを含むブックマーク

解答晒し。やや長いのでpatebin。

http://pastebin.com/ayQbs5UA

  • 単純なA*(のハズ)
  • 16個プロセスを立ち上げて分散
    • mod16番目の問題をそれぞれが対応
    • 1プロセスあたり100MB程度のメモリ消費
  • キュー済みかどうかの判定がstrcmp
  • 正解文字列生成にsort
    • bubble sortを実装
  • しかし、100問しか解けなかった
    • 参考になりません

C言語だと再発明する車輪が多すぎです。

*1:@adakoda 情報: importでPNG "image/png"とするとエイリアスがつけられる。

dskdsk 2011/09/22 15:30 import imgpng "image/png"ならimgpng.Decode()で衝突しません。