Travisのandroid.componentsで毎回100秒かかっていたのを0.01秒にできた話


もともとはこちらのMediumのエントリで紹介されていた高速化を試そうと思ったのがきっかけで、色々試行錯誤して結構高速化できたのでその経緯を残しておきます。

まずは紹介された方法をためした

Mediumのエントリの手法は意訳すると

sdkディレクトリをまとめてcacheしちゃえばacceptが高速化されて速くなるぜ!

というもの。で、その通り更新してみると...以下の問題が発生した。

  1. キャッシュを作る時に400秒くらいかかってる。(デフォルトの180秒タイムアウトに引っかるのでcache.timeoutに600秒セットした)
  2. 作ったキャッシュがでかい。2GB超えてる。
  3. キャッシュを再展開する時に400秒くらいかかってる。

この時点で「あれ?遅くなってね?」と思ったがsdkディレクトリをまるごとキャッシュするということが辛い様子。一方でそもそものandroid.componentsでかかっている時間がわからなかったので調べてみた。

android.componentsでかかる時間

単純に修正前に成功していたTravisビルドのログにあるInstalling Android dependenciesに出てくる秒数をたしたところ約100秒だった。
(秒数はそれぞれのandroid.components設定によって変わるのでご参考まで)

ただし、Installing Android dependenciesはキャッシュの再展開をしていると思われるSetting up build cacheよりも前に実行されるのでどんなに頑張ってもキャッシュを効かせることができない。

sdkmanagerで自前acceptを行う

前述のMediumのエントリの中で触れられているが、もともとlicenseのaccept処理はsdkmanagerを使うことでコマンドライン実行でき、それをinstallで行い、結果をキャッシュしてしまえ!というもの。
ということは、すでにTravisのOSイメージにインストールされているsdkmanagerを使いつつ、accept結果をキャッシュできればよさそう、ということでトライ。

こんな感じ。

echo y | $ANDROID_HOME/tools/bin/sdkmanager 'platform-tools' > /dev/null

これを使ってandroid.componentsでacceptしていたものと同じものをsdkmanagerで処理するシェルスクリプトを作り実行。一旦キャッシュなし。

約200秒。

うーん、何が違うのか分からないけどandroid.componentsよりも遅い。でも初回だけなら我慢できそうな気がするので次のステップへ。

accpet結果をキャッシュする

sdkmanagerスクリプトを使いつつ、キャッシュを効かせるためにymlに以下を追加。

.travis.yaml抜粋
cache:
  directories:
    # Android SDK licenses
    - ${ANDROID_HOME}/licenses/

そして、sdkmanagerスクリプトに${ANDROID_HOME}/licenses/が存在していたらaccept処理をスキップするよう分岐も追加。

一度ビルドをしてキャッシュさせて、2回目...

0.01秒。(acceptスキップしたからそりゃ早いよね)

その後のgradleタスクでもエラーはなく、念のため吐き出されたapkは実機に配信してもちゃんと使えています。

ビルド全体ではもともと11分~12分かかっていた処理(Travis build stagesも使っているのでandroid.componentsが2回走ってた)ものが8〜9分で完了するようになりました。

まとめ

以下のことを行うことでlicenceのaccept処理にキャッシュを効かせることができ、毎回100秒かかっていたところを0.01秒にできました。

  1. android.componentsを消して、sdkmanagerを使ってacceptするスクリプトをinstallで実行する
  2. ${ANDROID_HOME}/licenses/をキャッシュする

sdkmanagerスクリプトは参考までにこちらのGistにアップしておきました。。