AndroidVitals徹底活用

63e891c4f79dbdeb70aa8ebb8104c8d5?s=47 kr9ly
February 08, 2019

 AndroidVitals徹底活用

63e891c4f79dbdeb70aa8ebb8104c8d5?s=128

kr9ly

February 08, 2019
Tweet

Transcript

  1. Android Vitals徹底活⽤ Droid Kaigi 2019 Day2 Room3 14:00〜 @kr9ly(からくり)

  2. ⾃⼰紹介 Twitter: @kr9ly Androidエンジニアだいたい7年⽬くらい(あやふや) クラシルという料理動画のアプリ作ってます

  3. みんな⼤好き Google Play

  4. Google PlayはAndroidアプリを 公開するためのサービス

  5. 我々はAndroidアプリを 公開すること ⾃体 が⽬的ではない

  6. 我々はAndroidアプリを 公開すること ⾃体 が⽬的ではない アプリを公開して ユーザーに価値を提供する そのためにはアプリの 快適さ が必要不可⽋

  7. Google Playは 快適な Androidアプリを 公開するためのサービス

  8. 快適な アプリを提供するために Android Vitalsを徹底的に活⽤する

  9. 快適さとは︖

  10. 快適さとは︖ ユーザーに価値のある体験を提供できること 致命的にユーザー体験を損ねる体験がないこと ⾼いパフォーマンスであること

  11. Android Vitalsでウォッチできるもの 致命的にユーザー体験を損ねる体験 クラッシュレート、クラッシュの詳細 ANRレート、ANRの詳細 ⾼いパフォーマンス 起動時間の分布 レンダリング時間の分布

  12. 致命的にユーザー体験を損ねる体験についての 指標 クラッシュ ANR

  13. クラッシュレート、クラッシュの詳細 Crashlyticsとほぼ同じだが、Crashlyticsが初期化される前のクラッシ ュも捕捉できる︕(クラシルでも昔あった)

  14. 影響したバージョン、OSの割合、端末の種類、スタックトレース

  15. Proguardの難読化解除 Proguardで難読化している場合はmapping.txtをちゃんとアップロード しておく(⾃動化しとくと楽)

  16. リリース前レポート活⽤してますか︖ テストトラックで公開すると⾃動テストが⾛る クラシルではアルファ版トラックに公開してから本番トラックに公 開

  17. とりあえずただテストを⾛らせてみるだけでも便利 それなりにいい感じにアプリ内を巡回してくれる アプリのUI構造を解析してからテストしてくれる

  18. RoboScriptでテスト内容を指定できる 割愛します くわしくは https:// rebase.google.com/docs/test-lab/robo-ux-test? hl=ja#scripting

  19. 注意点 実⾏されるまでに結構時間がかかることがある(数時間待つことも 結構ある) リリースのタイミングにも影響するので、ご利⽤は計画的に

  20. リリース前レポート活⽤しよう 別に限定公開してなくてもテストトラック -> 本番トラックのフローを 踏むのがおすすめ

  21. ANRの⼀覧 弊社アプリは起動時がほとんどっぽい…

  22. ANRの詳細 ANRが発⽣した際(メインスレッドが応答せずに5秒経ったタイミン グ)のスレッドダンプが⾒られる

  23. ANR発⽣時点でどの部分を実⾏していたか分かる どこでロックを取得しているか分かる(デッドロックになってない かも頑張れば分かる) なんとなく検討を付ける⼿掛かりになる

  24. パフォーマンス指標 起動時間の分布 レンダリング時間の分布

  25. 起動時間の分布 えっ私のコード遅すぎ…︖(最初に⾒た時の感想)

  26. 起動時間の分布 起動時間の分布グラフ 90パーセンタイルの起動時間(下位10パーセントの起動時間) 99パーセンタイルの起動時間(下位1パーセントの起動時間) がわかる

  27. レンダリング時間の分布 えっ私のコード遅すぎ…︖(⼆回⽬)

  28. レンダリング時間の分布 レンダリング時間の分布グラフ 90パーセンタイルのレンダリング時間(下位10パーセントのレンダ リング時間) 99パーセンタイルのレンダリング時間(下位1パーセントのレンダリ ング時間) がわかる

  29. 遅いなら調べてみましょう メソッドトレースを⽣成して調べる 特定の実⾏期間で実⾏されたコードのスタックトレースと各メソッドの 実⾏時間が⾒られるスゴイやつ

  30. 最初に注意点 メソッドトレーシング中は実⾏時間が遅くなる 絶対値としては実⾏時間は参考にならない 10秒 -> 5秒とかに縮めても⼤したことないことも

  31. メソッドトレーシングを⾛らせる⽅法 Android Studioから メソッドトレーシングを⾛らせる⽅法 デバッガを起動する

  32. プロファイラを起動する

  33. Recordボタンを押す

  34. 終わりたくなったらStopで⽌める

  35. この⽅法の利点 お⼿軽 コード側をいじる必要が無い 即座に結果を⾒られる

  36. この⽅法の⽋点 メソッドトレーシングを開始/終了するタイミングを厳密にいじれな い 起動時のベンチマークには使えない(プロファイラーをアタッチし て起動してもトレースをすぐ起動できない) 1フレームだけ測定するとかできない

  37. コード上からメソッドトレーシングをコントロ ールする 実⾏するメソッドは⼆つ android.os.Debug.startMethodTracing android.os.Debug.stopMethodTracing

  38. メソッドトレーシングを開始する https://developer.android.com/reference/android/os/Debug#startMet hodTracing(java.lang.String, int) tracePath メソッドトレースのファイル名、分かりやすい名前を付け る bufferSize トレースファイルの最⼤サイズをバイトで渡す、デフォル トだと8MB

  39. 注意点 bufferSizeは簡単にあふれる あふれたら出⼒がそこで途切れてしまうので、 とりあえず200MBくらいにしておくのがおすすめ bufferSizeが⼤きいと出⼒時間が⻑くなるけど気⻑に待つ

  40. (⼩⼀時間ハマりました)

  41. メソッドトレーシングを停⽌する https://developer.android.com/reference/android/os/Debug#stopMet hodTracing() 何も難しいことはない

  42. 起動時間を取る場合 Application.onCreateの先頭でスタート public class KurashiruApplication extends Application { @Override public

    void onCreate() { super.onCreate(); Debug.startMethodTracing("sample", 200 * 1024 * 1024); ... } }
  43. 最初のフレームの表⽰まで取るのがおすすめ public class MainActivity { @Override protected void onCreate(Bundle savedInstanceState)

    { ... setContentView(R.layout.activity_main); new Handler().postDelayed(new Runnable() { @Override public void run() { Debug.stopMethodTracing(); } }, 16); ... } }
  44. 起動時間を⾼速化した例 起動処理を並列化して対応した事例のご紹介

  45. 改善前 Viewレンダリング直前までで10秒程度

  46. 注⽬したポイント Daggerの初期化処理が遅い(Cognitoの初期化処理が遅い) Three-Ten Backportのゾーン情報の初期化が遅い

  47. Daggerの初期化処理が遅い(Cognitoの初期化 処理が遅い) public class EventLogSender { private final KinesisFirehoseRecorder recorder;

    @Inject public EventLogSender(KinesisFirehoseRecorder recorder) { this.recorder = recorder; } ... } Injectする際の初期化処理に時間がかかっている
  48. 別にフォアグラウンド上でやる必要はない アプリケーションの分析⽤のログ送信処理

  49. Lazy<T>を使う public class EventLogSender { private final Lazy<KinesisFirehoseRecorder> recorderLazy; @Inject

    public EventLogSender(Lazy<KinesisFirehoseRecorder> recorderLazy) { this.recorderLazy = recorderLazy; } public void send() { doBackground(() -> { recorderLazy.get(); }) } }
  50. Three-Ten Backportのゾーン情報の初期化が遅い 例えば OffsetDateTime.now() <- 初回のこれが遅い この処理でメインスレッドをブロックされるのはもったいない

  51. バックグラウンドスレッド上で初期化 public class KurashiruApplication extends Application { @Override public void

    onCreate() { ... doBackground(() -> { ZoneId.systemDefault(); }); } } Application.onCreateの先頭でやればある程度の短縮が⾒込める
  52. 改善後 View初期化まで3秒に短縮

  53. 注意点 処理がメインスレッド上でしか実⾏できない場合はNG スレッドセーフでない処理もNG SDKの類が意外とスレッドセーフじゃないもの多いです

  54. レンダリング時間を最適化した際のTips スクロールがカクカク状態を解消した時の話ちょっとだけ

  55. トリガーの仕込みがキモ public void onScrollChange(RecyclerView recyclerView, int dx, int dy) {

    if (dy > 200) { Debug.startMethodTracing("sample", 200 * 1024 * 1024); new Handler().postDelayed(() -> { Debug.stopMethodTracing(); }, 16); } } 閾値を超えたスワイプを検知したら1フレーム分測定
  56. 意外な処理が遅いことも getWindowVisibleDisplayFrame(visibleRect); View.getWindowVisibleDisplayFrameが遅かった

  57. ⼤事なこと ボトルネックを探す ボトルネックを取り除く 地道にやる

  58. トレース結果を取得する⽅法

  59. トレース結果の出⼒先 多分 Context.getExternalFilesDir で取得できるディレクトリに出⼒し ている ⾃分がやったときは /sdcard/Android/data/${applicationId}/files でした 詳しくは: https://developer.android.com/studio/pro

    le/generate- trace-logs?hl=ja
  60. Android Vitalsでは クラッシュ ANR 起動時間 レンダリング速度 をウォッチできる︕

  61. Android Vitalsを徹底的に活⽤して 快適 なアプリをリリースしよう︕

  62. 実際に改善した︖ ちょっとだけ… 快適なアプリへの道のりはつらく険しい

  63. あとはここに⾊々書いてあります https://developer.android.com/topic/performance/vitals/ ⼀読をおすすめ