Hatena::ブログ(Diary)

Islands in the byte stream

2014-08-13

fb-adb - 改良版adb shell

Facebookが adb shell の改良版を開発しているみたい。

https://github.com/facebook/fb-adb

"adb"とつけてはいるけど、実際には"adb shell" と "adb rcmd" だけを処理して他のサブコマンドはadbにフォワードしているだけ。

改良したところはREADMEによれば以下の点だ。

  • Binary clean (no LF -> CRLF mangling)
  • transmits and updates window size
  • distinguishes standard output and standard error
  • properly muxes streams with independent flow control
  • allows for ssh-like pty allocation control
  • propagates program exit status instead of always exiting with status 0
  • properly escapes program arguments
  • kills remote program
  • provides a generic facility to elevate to root without re-escaping

ざっくり言うと、いろいろまともにしたってことだけど、特に「adb shell $command」のstatus codeを返すようにした」とか「adb shellのstderrをちゃんとstderrとして出すようにした」あたりはかなりうれしくて、adbをwrapするツールを作りやすくなったと思われる。

例:

# exit status
$ adb shell false
$ echo $?
0

$ fb-adb shell false
$ echo $?
1

# stderr
$  adb shell 'echo foo >&2' >/dev/null # 何も表示されない
$  fb-adb shell 'echo foo >&2' >/dev/null
foo

当初GenyMotionで動かない という問題がありましたが、現在は解消されています。

2014-08-09

The Renaissance of TypeScript in Ruby

More and more TypeScript toolchains emerge in these days but unfortunately it was not true in the Ruby world: typescript-rails didn't work on Rails4.

Now it works on Rails4. typescript-rails, which provides us with the power of TypeScript in Ruby on Rails, is now controlled under the typescript-ruby group and new maintainers. We are also waiting for more maintainers and pull requests to employ tons of TypeScript best practices.

2014-07-16

YAPC::Asia 2014でninjinkunといっしょにモバイルアプリ開発について話します

以下のトークが採択されました。2日目の藤原洋記念ホールにて、15:20からです。

Mobile First Development for Perl Mongers

最近はPerlはあまりやっていないのですが、サーバーサイドとクライアントサイド(モバイルアプリ)をいい感じに協調して働くための仕組みを考えたりしています。YAPC::Asiaにくるエンジニアはサーバーサイドの方が多いと思うので、そういう方たちにとって面白い話ができたらいいなと思っています。

ところで、このトークは ninjinkun といっしょにやります。トークの内容が似た感じなので合体してみたのですが、せっかくだから2人でお互いの状況を話つつ、モバイルアプリ開発やサーバーサイドとの連携についてディスカッションしようと思います。

2014-07-09

maven artifactsのupload/downloadサーバは簡単につくれる

Androidのエコシステムをなんとかしないといけないとの思いから、maven repository serverを作り始めた。

https://github.com/android-frontier/tiny-maven-repository

要は、特定のパスにPUT(bodyはjarなどのbinaryがそのまま渡る)でアップロードし、GETでPUTしたファイルを配信する仕組みだけがあれば最低限の機能としては十分だ。上のサーバはアップロードしたファイルの maven-metadata.xml を読んでgradleのdependencies宣言を生成するなど、多少の便利機能をつけてある。

今後の予定としては、アップロードをgithubアカウントでできるようにしたり、aarの場合は要求するAndroidのバージョンや依存ライブラリを表示したりなどしたい。また、いまはRailsで実装しているが、Androidとの親和性を考えてJavaで実装しなおそうと思っている。

2014-07-04

DalvikバイトコードのMethod数65k制限について

Androidアプリケーションにはアプリケーションのメソッド数が65kを超えられないという制限があるのだけど、その詳細を知らなかったので調べた。

参考: Does the Android ART runtime have the same method limit limitations as Dalvik?

まとめると

  • メソッド数制限の実体は(VMとしての)DalvikではなくDalvik bytecodeのinvoke系で使うmethod idが16bit intであること
  • つまり、アプリケーションで定義したメソッド数が65kを超えるかどうかではなく、ひとつのdex fileで参照しているメソッド数が65kを超えるときに問題が起きる
  • ARTもDalvik bytecodeを一旦介する以上、同じ制限をもつ

という感じか。さらに手元で試してみたところ、問題が起きるケースではdx(1)が例外を吐くので、そもそもビルドが通らなくなる。メソッド数Android 2.3系でのみインストールできなくなるという問題があったと思ったが、最近のツールだとそもそもビルドが通らなくなるのでapkのなかのメソッド数をCIで数えてチェックする必要はないのかもしれない。


以下検証実験:

まず、ひとつのdexでメソッドを沢山定義するとdx(1)が以下のようなエラーを報告する。

https://github.com/gfx/Android-TooManyMethodsInDex/tree/over65k-definitions

$ ./gradlew assembleDebug

(snip)

:app:dexDebug

trouble writing output: Too many method references: 65569; max is 65536.
You may try using --multi-dex option.
References by package:
     2 android.app
     1 android.util
     1 android.widget
 65559 com.example.gfx.over65methods
     6 java.lang
:app:dexDebug FAILED

ひとつのdexでの定義数を65k未満に抑えつつ、Android frameworkのメソッドを参照してmethod ref idが65kを突破したケースも同様:

https://github.com/gfx/Android-TooManyMethodsInDex/tree/by-external-refs

:app:dexDebug

trouble writing output: Too many method references: 65537; max is 65536.
You may try using --multi-dex option.
References by package:
     2 android.app
     5 android.util
     1 android.widget
 65523 com.example.gfx.over65methods
     6 java.lang
:app:dexDebug FAILED

外部ライブラリによってメソッド数が増えすぎる場合、以下のような例外が出ることもあるようだ:

https://github.com/gfx/Android-TooManyMethodsInDex/tree/method-id-not-in-range

:app:dexDebug

UNEXPECTED TOP-LEVEL EXCEPTION:
java.lang.IllegalArgumentException: method ID not in [0, 0xffff]: 65536
	at com.android.dx.merge.DexMerger$6.updateIndex(DexMerger.java:501)
	at com.android.dx.merge.DexMerger$IdMerger.mergeSorted(DexMerger.java:276)
	at com.android.dx.merge.DexMerger.mergeMethodIds(DexMerger.java:490)
	at com.android.dx.merge.DexMerger.mergeDexes(DexMerger.java:167)
	at com.android.dx.merge.DexMerger.merge(DexMerger.java:188)
	at com.android.dx.command.dexer.Main.mergeLibraryDexBuffers(Main.java:439)
	at com.android.dx.command.dexer.Main.runMonoDex(Main.java:287)
	at com.android.dx.command.dexer.Main.run(Main.java:230)
	at com.android.dx.command.dexer.Main.main(Main.java:199)
	at com.android.dx.command.Main.main(Main.java:103)
:app:dexDebug FAILED