Androidを支える技術<II>輪読会 5.2(5.2.1 ~ 5.2.3)
日付:3/11
章:5.2
調査者:ichimura.icon
バイトコードを実行するプロセスとその始まり
Androidのさまざまなプログラムはjavaで書かれている
このjavaで書かれたバイトコードを実行するためのプロセスがZygote
Zygoteと、それを実行するapp_processについて解説
app_processとそのmain()関数
実行環境はapp_processというコマンドで実行
javaでいうところのjavaコマンド
実行の流れ
引数にバイトコードのパッケージを指定
バイトコード実行環境を準備
指定されたパッケージをロード
ロードしたクラスに実装されているstatic void main()を呼び出す
Androidでの実行環境は、AppRuntimeというC++のクラスで実装されている
実行ファイルの名前
/system/bin/app_processにある
main()関数の最初でAppRuntimeを起動する
コマンドライン引数に応じて、次の2つのうちどちらかの実行モードとなる
1. 指定された特定のクラスをロードして実行するモード
2. Zygoteをロードして待機状態になるモード
クラスを直接実行する例
Androidではadb(Android Debug Bridge shell)からpmというコマンドを実行してアプリをインストールしたりアンインストールしたりできる
abdのpmコマンドは、/system/bin/pmを実行しているだけ
/system/bin/pmの状態(コードはいらないと思う)
️exec app_process ~でapp/processを実行している
引数で渡しているcom.android.commands.pm.PMは実際にPackageManagerを読んで、apkのインストールなどを行うJavaクラスとなっている
クラス名を渡して特別な引数を指定しないと、app_processはバイトコード実行環境を立ち上げた後に、引数で指定されたクラスをロードしてそのmain()メソッドを呼び出す
このようなapp_processの使い方は単純だが使い方としてはかなり特殊な例となる
Zygoteモードでの起動
app_processに--zygoteというオプションをつけると、app/processはZygoteモードとして立ち上がる
initから起動されるシステムサービスの1つ
init.rcにエントリがある
init.rcのZygote部分の最初の行でapp_processが起動されていて、--zygoteがついている
zygoteモード時のapp_process
はじめに引数判定をし、引数に応じてzygoteかRuntimeInitを実行する
binder関連の初期化を行った後、指定されたクラスをロードしてそのmain()メソッドを呼び出すというクラス
名前の通り、実行環境を初期化するクラス
アプリやJavaのコマンドなどを実行するときには最初に実行する
Zygoteモードでの起動
必要なクラスライブラリをロードした後に、ソケットをlistenして要求を待つ
このソケットに対してどこかからクラス名の指定が来る
プロセスをforkした後にRuntimeInitを呼び出す
指定されたクラスをロードし、そのmain()メソッドを呼び出す
ZygoteInitのmain()メソッドの3つの処理
app_processはZygoteモードで起動されると、ZygoteInitクラスをロードしてそのmain()メソッドを呼び出す
重要なポイント
①preload()で共有したいクラスを全てロード
②SytemServerプロセスを起動
5.2.6で詳しく扱う
SystemServerもJavaクラスを使うため、①をした状態からforkして、なるべくコードを保持している実メモリを複数のプロセスで共有しようとしている
forkによるメモリの共有は1.2.5項のコラム参照
③runSelectLoop()でソケットを待ち、やってきたメッセージに応じて処理
依頼があり次第forkしてsetuid()を実行
そのクラスをロードしてmainを実行
通常のアプリの場合、ActivityThreadクラスがロードされ、main()メソッドが実行される
基本はこのメソッドで動き続けて戻ってこない
④MethodAndArgsCallerがthrowされたらcatchして、引数のメソッドを呼ぶ
MethodAndArgsCallerはExceptionのサブクラス
forkした後の子プロセスが、実際にクラスのmain()を実行する時に実行される
preload()メソッドでロードされるクラス達
preloadClasses()で、/system/etc/preloaded-classesに書かれているクラスがロードされる
この時クラスは4000以上ロードされる
ここでロードされるクラス群は、Zygoteに依頼してforkされる通常のアプリも、SystemServerも全てmmapしたコード領域を共有する
コード領域がmmapされたままのメモリなので、3.2.2項で扱ったページの種類でいうと同期可能ページとしても扱われる
共有されるだけでなく、必要に応じて回収もされる
zygoteと直接mmapできるバイトコード実行環境の組み合わせは非常にメモリ効率のいい仕組み
応用
code:sample.kt
質疑応答