kawasin73 / knowledge

気になったツールやサイト、勉強した内容をまとめます。
8 stars 0 forks source link

本 : Android を支える技術 Ⅱ #35

Closed kawasin73 closed 3 years ago

kawasin73 commented 3 years ago

目次

IMG_0101

kawasin73 commented 3 years ago

1 章 Android と Activity の基礎知識

1.1 : Activity が実現する世界

1.1.1 : スマホにおける画面遷移の標準を提供

スマホは1画面に1つの機能を実装するのが基本。画面遷移が多くなる。

1.1.2 : たくさんのアプリが共同でタスクをこなす

スワップアウトが無効になっているから、マルチタスクの状況はサーバーとは異なる。 その代わり、Activity は半手動でスワップアウトのような機構を実現している。 たくさんのアプリが連携する。その分同時に複数のアプリが動く。

1.2 : 入門 Activity プログラミング

1.2.1 : まずは HelloActivity から

1.2.2 : ある A という Activity から HelloActivity を起動してみる

明示的インテント

1.2.3 : テキストファイルを別のアプリで開いてみる

ACTION_VIEW インテント、暗黙的インテント FLAG_ACTIVITY_NEW_TASK フラグをつけると、新しいスタックが作られる。

1.2.4 : ギャラリーアプリなどで画像を選ぶ

ACTION_PICK インテントと onActivityResult()

1.2.5 : Activity が再生成された時の対応

kawasin73 commented 3 years ago

2 章 アプリのインストールとその情報

2.1 : Google Play の衝撃

2.1.1 : Google Play を実現するために必要な2つの前提

kawasin73 commented 3 years ago

3 章 カーネル側から見たメモリ不足

3.1 : メモリ不足時のカーネル側の振る舞い

全体像の説明

3.1.1 : メモリ不足時のカーネル側の振る舞い、全体像

lmkd にメッセージを送ることで oom_score_adj を更新し、そしてこのスコアに応じて、メモリ不足の時には lowmemorykiller ドライバや OOM Killer がスコアの高いプロセスを kill することでメモリを解放する。 Linux のメモリ不足の仕組みだけだと運任せになるので2段構えになっている。

slab アロケータのメモリもゾーンアロケータと同じタイミングで回収が試みられる。 メモリを回収した後もメモリが不足した場合、緊急事態として OOM Killer が発動

3.2.3 : OOM Killer と oom_score

/proc/<process id>/oom_score で確認できる。SIGKILL で kill する。Linux の OOM Killer に頼るには Android のアプリの kill は頻度が高すぎる。

3.2.4 : oom_score_adj と OOM Killer の挙動のカスタマイズ

/proc/<process id>/oom_score_adj には -1000 から 1000 までの値を設定可能。 root 権限が必要。小さいほど kill されなくなる。

3.3 : Android の Low Memory Killer

3.3.1 : フラッシュメモリの仕組みと Android のスワップ事情

3.3.2 : Low Memory Killer の基礎知識

Low Memory Killer は、Android 上で OOM Killer をカスタマイズしている仕組みや、もっと前の段階でメモリを空ける仕組み

3.3.3 : lowmemorykiller モジュールと shrinker

Linux ではカーネルはファイルシステムの知識を持たず、キャッシュの解放はファイルシステム自身がコールバックを呼び出すようになっている。これが shrinker このコールバックを使って裏に回った Activity のプロセスを kill するのに活用 メモリ逼迫でカーネルが shrink_slab() を呼び出す。これがディスクキャッシュを削減するタイミング。このタイミングのコールバックを登録するのが register_shinker() というインカーネル API。登録されるコールバックを shinker と呼ぶ。 Android 独自の lowmemorykiller というカーネルモジュールが shrinker を使って裏の Activity を kill する。 oom_score_adj を元に kill する Activity を選ぶ。その時のメモリの切迫具合に応じて段階的に kill される。

kawasin73 commented 3 years ago

4 章 スタックから見た!Activity のライフサイクル

4.1 : ActivityStack とタスク

4.1.1 : なぜ Activity をスタック構造で管理するのか

画面が小さいので一つの画面に一つの役割を持たせるのが一般的。そのため、画面遷移が必然的に頻繁に起こる。 ある画面を再利用したくなる。前後の遷移と画面を切り離すことが重要。C などの関数がコールスタックで実現されるのに似ている。

4.1.2 : タスク

タスクとは複数の Activity が連携して1つの仕事をこなす単位。 バックキーを押して辿ることのできる Activity を含む

4.1.3 : タスク作成を意識する難しさ

基本的には新しい Activity が別のタスクになるのかは system がよしなに判断してくれる。launchMode で制御もできる

4.1.4 : Activity を管理するスタック

ActivityStack

4.1.5 : ActivityStack とタスクの戻り先フラグ

ActivityStack にはホーム画面用とそれ以外用(アプリの)の2つの ActivityStack インスタンスがある。一般的なタスクは作成される都度アプリの ActivityStack に載せられる。 タスク内の Acitivity の順序は変えられない。タスクの順番はアクセスするたびに ActivityStack の一番上に移動する ActivityStack はタスクのリストを保持している。 一旦ホーム画面に行った後に別のタスクにアクセスすると戻り先が Home であるというフラグが立つ。

4.1.6 : launchMode とインテントフラグ

launchMode は AndroidManifest.xml の 要素に設定する。

kawasin73 commented 3 years ago

5 章 アプリのプロセスから見る!Activity の生成と再生成

5.1 : アプリ側プロセスの Activity

5.1.1 : プロセスの生成からアプリのプロセスになるまで

Zygote からプロセスを fork。ソケットでエントリポイントとなるクラス名 (ActivityThread) や uid を受け取る。ActivityManagerService が Zygote に依頼する。 ActivityThread#main() の時点では apk の情報はわからないので ActivityManagerService に問い合わせる。これが ActivityThread#attach()

5.1.2 : アプリのプロセスが、Activity を生成するまで

attach() が終わると ActivityManagerService が ActivityThread の scheduleLaunchActivity() を呼ぶ。このときに token が作られてアプリのプロセスに渡される。token が Activity の id になる。

5.2 : バイトコードを実行するプロセスとその始まり

5.2.1 : app_process とその main() 関数

app_process コマンドでバイトコードの実行環境を実行できる。2つのモードがある。

  1. preload() で共有したいクラスを全てロード
  2. SystemServer プロセスを起動
  3. runSelectLoop() でソケットを待ち、やってきたメッセージに応じて処理
  4. MethodAndArgsCaller が throw されたら catch して、引数のメソッドを呼ぶ

exception を使うのはコールスタックを一番上まで戻すため。

5.2.3 : preload() メソッドでロードされるクラス達

preloadClasses() では、/system/etc/preloaded-classes に書かれているクラスがロードされる。

5.2.4 : runSelectLoop() メソッド処理概要

selectReadable() で server ソケットと peer ソケットを待つ。

5.2.5 : Zygote の forkAndSpecialize() と Process.start() メソッド

ZygoteConnection#runOnce() Process.start() が Zygote にメッセージを書き込む。

5.2.6 : startSystemServer() メソッドと SystemServer のプロセス

SystemServer プロセスは他のプロセスよりも大きな権限が必要になるので事前に fork する。

5.3 : ActivityThread とは何か?

5.3.1 : ActivityThread の 3 つの重要なメソッド

kawasin73 commented 3 years ago

6 章 Android の始まり

6.1 : ブートローダーとその周辺

6.1.1 : 電源を入れてから init を起動するまでの概要

Device Tree はデバイスのパラメータを記述。デバイスドライバが読み取って利用する

6.2.3 : fastboot 概要

USB でホスト PC と通信できるモードが fastboot 大抵はボリュームダウンを押しながら電源を入れる。

6.2.4 : ブートローダの話、終わりに

6.3 : init プロセスとその始まり

6.3.1 : init プロセスとその処理概要

kawasin73 commented 3 years ago

Appendix

A.1 Activity の onSaveInstanceState() デフォルト実装

A.1.1 : 基本事項のおさらい

EditText の情報などは onSaveInstance で自動的に保存されている

A.1.2 : 実際の Activity の onSaveInstanceState() のコード

mWidnow.saveHierarchyState()

A.1.3 : PhoneWindow の saveHierarchyState()

フォーカスの当たっている View などを保存する

A.1.4 : Parcel と Parcelable

Binder のための配慮

A.1.5 : View の saveHierarchyState() より先の処理

ただ、dispatchSaveInstanceState() を呼ぶだけ。各 View の onSaveInstanceState() が発動される。

A.1.6 : dispatchSaveInstanceState() を眺める

フラグが SAVE_DISABLED になっていない View が対象