安定的で合理的なデバッグ作業を実現するApply Changes @ C96

ひさしぶりに技術同人誌に寄稿しました。TechBoosterのC96(夏コミ)新刊です。4日目南ナ49abのようです。boothで予約も出来るようです。

techbooster.booth.pm

今回はAndroid Studio 3.5でInstant Runの代替機能のように紹介されて登場したApply Changesと呼ばれる機能について、掘り下げて解説しています。とは言ったものの、実のところ20ページ弱あって長過ぎると思い、ソースコードまで追っかけた部分をバッサリ切り落としたので、このエントリでは補遺としてそれをまとめておこうと思います。

本エントリはあくまで補遺なので、上記同人誌の本文を参照できる人でないと読み進めるのは辛いと思います。Apply Changesについて後述するProject Marbleの投稿を読んでいて理解している人なら大丈夫かもしれません(一応)。

Instant Runについておさらいしたい場合は、2016年にわたしがまだQiitaを使っていた頃にまとめてあるので、そちらを見てください。

Instant Runはデバッグビルドに特化した技術でしたが、Apply Changesは実のところデバッグも意識しつつデバッグビルドに特化しないデプロイメント技術である、と言ったほうが適切かもしれません。今回の草稿の情報源の多くはAndroid Studio開発チーム?の外郭チームっぽいProject Marbleのメンバーによるブログ投稿なのですが、実はこの投稿だけではInstant Runが実現したビルドの省力化のうち、Apply Changes以外の部分については言及していないんですね。なので「じゃあInstant Runで実現していたアレやコレはどーなったの?」という話も実はあるのですが(たとえばターゲットと無関係なABIやリソースをスキップするビルドの最適化部分とか)、その辺はまだ文章としての情報が無いので言及していません。

と、前置きしたところで、本題に入ります。

(1) Apply ChangesはAndroid Studioの機能の一部として存在しています。Android Gradle Pluginではありません。Instant Runがビルドの最適化を中心とした機能であったのに対し、Apply Changesはあくまでビルドされたアプリケーションの更新適用("apply" "changs")に本質があって、これは主としてGradleで操作するものではありません。いずれにしろ、AOSPで参照すべきブランチはstudio-master-devです。

(2) Apply Changesの主要な実装部分は、AOSPでいえばtools/base/deployに含まれています。ここにApply Changesにおけるdeployerの実装、差分のジェネレーター、Androidターゲット側で動作するdeployagentとの通信スタックやそこで使われるprotocol bufferの定義ファイルなどが含まれています。

(3) 一方で、Apply Changesの実装をカバーしているように見えるけど、多分Instant Runの改良部分なのではないかと思われるコードも、tools/adt/ideaの中のandroid/src/com/android/tools/idea/以下、特にstats, deploy, runにいくつかあります。runディレクトリにはアプリケーションのデプロイメントについて特に詳しく解説したREADME.mdが含まれているのですが、ここにはApply Changesへの言及はひとつもなく、どうやらInstant Run時代のデプロイメントについてのみまとめた内容であるようです。

(4) 本稿ではAndroid 8.0でARTのRuntime Instrumentationのために新しく実装されたJVMTIによってhot code replaceapply code changesが実現しているということを説明していますが、具体的にはUpdateMethodsCode()という関数がこれを実現しています(AOSPページでpermalinkを取得する方法がわからなかったのでmasterへのリンクです…!)。JVMTIはOracleのhot code replaceで使われている技術で、Java Platform Debugger Architectureと呼ばれる一連のデバッガー関連仕様の一つです。標準的なコード置換技術なので、JVMTIをサポートしているどんなIDEでも原理的にはデバッガーからコードの差し替えが可能になっているかもしれません。

(5) なお、これと関連して、tools/adt/idea/android/src/com/android/tools/idea/fd/actionsでは、JVMTIが「有効になっていれば」Instant Runは実行されないようになっています。先に言及したQiita記事で軽く言及していますが、パスの途中にあるfdというのはInstant Runの機能の一部となるfast deploymentの略であると考えられます(Instant Runランタイムのjarにも含まれている名前です)。

(6) ちなみにApply Changesと関係があるのかはわからないのですが、adbにもfastdeployという機能?が新しく追加されていて、この中にdeployagent、deploypatchgeneratorといったツールのソースがいくつかあります。これらは「Androidターゲット上で動作する実行ファイル」であり、Apply Changesで使われているものと一致するかもしれません。

…というわけで、Apply Changesについてわたし以上に興味のある人は、この辺りから深入りできるのではないかと思いますので、ぜひソースコードリーディングにチャレンジしてみてください。