Android の実行環境

概要

Android のアプリを動かしている仕組みを整理します。 全体像を概観することを目的としています。 細かな部分は推測になっている所があります。 (間違いがあれば教えてください。)

参考情報

解説

Android の全体構成

全ての土台は Android 用に拡張した Linux Kernel。 Linux Kernel が持つメモリ管理、プロセス管理、権限によるセキュリティモデル、ドライバモデル、共有ライブラリの仕組みを使う。 ディスプレイ、カメラ、USB などのデバイスドライバ、共有メモリドライバ(Shared Memory Driver)、電源管理(Power Management)、プロセス間通信(Inter-Process Communication; IPC)のための Binder Driver を含む。 Binder Driver については KMC Staff Blog:AndroidのBinderによるプロセス間のメソッド呼び出し(メモ) が参考になる。 プロセス間通信は、startActivity, sendBroadcast などにより他のアプリのコンポーネントと通信する際に使われる。 Android におけるプロセス構成については後述。

Linux Kernel に Libraries 層が積み重なり、Linux Kernel の機能を使って様々な機能を実現する。 Libc (C 言語用の基本機能)、WebKit (HTML レンダリングエンジン)、SQLite (リレーショナルデータベース)、OpenGL|ES (組み込み向け 3 次元グラフィックス)、Surface Manager (描画)、Audio Manager (音源再生)などの機能を含む。 Libc は GNU Libc ではなく Bionic Libc。 Bionic Libc は組み込み向けの Libc で、GNU Libc とは互換性がない。

Libraries の一部に Android Runtime が含まれる。 以前は Dalvik 仮想マシン (Dalvik VM) を使用していたが、Android 5.0 からは ART (Android RunTime) に変更されている。 本記事中では、Dalvik VM と ART を総称して Android Runtime としている。 Android Runtime については後述。

Libraries 層に Application Framework 層が積み重なり、Java API を提供する。 Libraries はネイティブコードで提供されており、Application Framework 層が Java コードから各機能を使用できるようにする。

これら様々な層(機能)を土台として Applications は動作している。

Android のプロセス構成

プロセスはプログラムの実行単位。 基本的に、メモリ領域はプロセス単位で確保され、プロセスが異なるメモリ領域にはアクセスできない。 Android の主要なプロセスと各プロセスを構成するモジュールは下図のとおり。

Anatomy & Physiology of an Android の内容を基に、推測により一部編集を加えている。 Service Manager は個別のプロセスではなく Runtime Process 内で動作すると推測。 Surface Flinger, Audio Flinger は赤色で示しているページがあり Driver の一種と推測し、Libraries 層としては Surface Manager, Audio Manager とする方が適切と判断。 黄色の Runtime は元資料では Dalvik VM だが ART も同様であると推測し、黄色の Rutime として総称。 Home, Contacts は Application の一例であるため、Application で総称。 外側の角四角はプロセス、内側の丸四角はモジュールと推測。

プロセスの起動順序

ブートローダーは Linux Kernel をロードし、Linux Kernel は Init プロセスを起動する。 Init プロセスはバックグラウンドサービスを提供する様々な Daemon プロセスを起動する。 例えば、USB Daemon, Android Debug Bridge Daemon, Debugger Daemon など。

続いて、Init プロセスは Zygote プロセスを起動する。 Zygote プロセスは起動時にアプリケーション実行に必要なライブラリ一式をロード(メモリ領域に展開)する。 Zygote プロセスは Android Runtime のインスタンスを保持し、アプリの起動要求に応じて自身を複製して新しい Android Runtime インスタンスを生成する。 これにより、Android Runtime インスタンスの生成を高速化する。 また、copy-on-write の仕組みにより、メモリへの書き込みが発生する場合のみメモリ領域の複製を行うため footprint の最小化 (メモリ使用量の削減) につながる。 Zygote の仕組みが無い場合にはアプリの起動要求の度にライブラリ一式がロードされるため、ロード時間が必要となり、ロードされたライブラリ一式がメモリ領域を消費する。Zygote については KMC Staff Blog:AndroidでのJavaプログラムの起動やZygoteまわりのメモ が参考になる。

Zygote プロセスの次は Runtime プロセスを起動する。 Runtime プロセスは Service Manager を初期化する。 Service Manager はサービスの登録と検索を担う。

Runtime プロセスは Zygote プロセスに起動要求を送信し、Android Runtime インスタンス(新規プロセス)を生成する。 生成されたプロセスで各種 System Service を起動する。 Surface Manager, Audio Manager などのネイティブシステムサービス、 Activity Manager, Window Manager, Location Manager などの Android システムサービスが System Service に含まれる。 (各種 System Serivce が同一プロセスで動作するのか、別プロセスで動作するのかは読み取れなかったが、1 つの角四角に含まれるので同一プロセスと推測。)

以上で、システムの起動が完了。

アプリの起動は、Zygote プロセスに起動要求を送信し Android Runtime インスタンスを生成することにより行われる。 つまり、アプリ毎にプロセスが生成される。

アクセス権

Android では Linux のマルチユーザーシステムを用いてアクセス権を管理する。

Android システムはアプリ毎に Linux ユーザー ID を割り振る。 アプリのファイルとプロセスは割り振られたユーザーを所有者とする。 ファイルのアクセス権は Android システムにより、プロセスとファイルの所有者が異なる場合にはアクセスできないように設定される。

プロセスはアプリ毎に生成されており、異なる所有者が設定されている。 これにより、他のアプリのファイルやメモリ領域にはアクセスできないようになり、安全性が高まる。

Android Runtime

Android Runtime は Android アプリの実行環境を意味する。 Android 4.x までは Dalvik VMAndroid 5.0 以降は ART が Android Runtime に該当する。

Android Runtime は Zygote から複製された後、アプリの共有ライブラリをロードする。 ロードされるファイルは Dalvik VM と ART で異なる。

緑四角はネイティブコード、青四角は非ネイティブコード、緑文字は環境依存、青文字は環境非依存を意味する。

odex ファイルは機種に合わせて最適化した dex ファイル。 odex ファイルの内容はネイティブコードではないが、機種に依存した内容となる。 ネイティブコードへは実行時に JIT (Just In Time) コンパイルされる。