APK ファイルの「インストール」をタップするか、Play ストアからアプリをダウンロードすると、舞台裏で複雑な一連の操作が始まります。単純な進行状況バーのように見えるものは、実際には、パッケージの解析、暗号化の検証、権限管理、ファイルの抽出、コードの最適化などの数十のステップを表しています。このプロセスを理解すると、インストールが失敗する場合がある理由と、その対処方法を説明するのに役立ちます。
この記事では、システムが APK を受け取った瞬間からアプリを起動する準備が整う時点まで、Android インストール パイプラインの主要なステップをすべて順を追って説明します。
ステップ 1: インストールの開始
インストール プロセスの開始方法は、ソースに応じて異なります。
- プレイストア: Play ストア アプリは、APK (または分割 APK) をダウンロードし、一部のユーザー確認をバイパスする特別な権限でシステムのパッケージ インストーラーを呼び出します。
- サイドローディング: APK ファイルを開くと、Android はパッケージ インストーラー アクティビティを起動します。 Android 8.0 以降では、インストールするアプリには、特定のソースに対する「不明なアプリのインストール」権限が必要です。
- ADB: adb install コマンドは、グラフィカル インストーラーを完全にバイパスして、USB 経由でパッケージ マネージャー サービスと直接通信します。
ソースに関係なく、すべてのインストールは最終的に同じシステム サービス、パッケージマネージャーサービス (PMS) に到達します。これは、Android 上のすべてのパッケージ操作の中心機関です。
ステップ 2: パッケージの解析
何よりもまず、システムは何をインストールしようとしているのかを理解する必要があります。 PackageManagerService は パッケージパーサー を呼び出して、APK ファイルを読み取り、そのメタデータを抽出します。
パーサーは、APK 内から AndroidManifest.xml ファイルを読み取ります。このバイナリ XML ファイルには、次の重要な情報が含まれています。
- パッケージ名: アプリの一意の識別子 (例: com.example.myapp)
- バージョンコードと名前: これがアップグレードか新規インストールかを判断するために使用されます
- 最小およびターゲット SDK バージョン: デバイスとの互換性を決定します
- 宣言された権限: アプリが要求する権限と、アプリが定義するカスタム権限の両方
- コンポーネント: アプリが登録するアクティビティ、サービス、ブロードキャスト受信機、コンテンツ プロバイダー
- ハードウェアとソフトウェアの機能: カメラ、GPS、特定の OpenGL バージョンなどの要件
マニフェストの形式が間違っているか、APK 構造が無効な場合、この段階でインストールは失敗し、「解析エラー」メッセージが表示されます。これは、サイドロードされた APK のインストールが失敗する最も一般的な理由の 1 つです。
ステップ 3: 互換性チェック
マニフェストが解析されると、システムは一連の互換性チェックを実行します。
- SDKのバージョン: アプリの minSdkVersion がデバイスの API レベルより高い場合、インストールは拒否されます。
- ABI の互換性: APK にネイティブ ライブラリが含まれている場合、システムはそれらがデバイスの CPU アーキテクチャと一致するかどうかを確認します。 armeabi-v7a ライブラリのみを含む APK は、x86 専用デバイスにはインストールされません。
- 必要な機能: アプリが必要なハードウェア機能 (android.hardware.telephony など) を宣言している場合、システムはデバイスがそれらをサポートしていることを確認します。
- 利用可能なストレージ: システムは、抽出されたネイティブ ライブラリや最適化された DEX ファイル用のスペースを含め、アプリをインストールするのに十分な空きスペースがあるかどうかを確認します。
ステップ 4: 署名の検証
これは、インストール プロセスで最も重要な手順の 1 つです。 Android は、APK の暗号署名を検証して、その整合性と信頼性を保証します。
検証プロセスは、どの署名スキームが存在するかによって異なります。
V1 署名 (JAR 署名)
システムは、署名ファイル (.SF、.RSA、または .DSA の META-INF/ ディレクトリをチェックします)。 APK 内の各ファイルは、マニフェストにリストされているダイジェストと照合して検証されます。すべてのファイルを個別にハッシュする必要があるため、これは時間がかかります。
V2 署名 (APK 署名スキーム v2)
Android 7.0 で導入されたこのスキームは、APK 全体をバイナリ BLOB として署名します。署名ブロックは、ZIP 中央ディレクトリと中央ディレクトリの終端レコードの間に挿入されます。個々のエントリを解凍する必要がなく、生のバイトで動作するため、検証がはるかに高速になります。
V3 署名 (キーローテーション)
Android 9.0 から利用できる V3 は、キー ローテーションのサポートにより V2 を拡張します。これには、古い署名キーと新しい署名キーをリンクするローテーション証明構造が含まれており、開発者は更新の互換性を維持しながら署名キーを変更できます。
V4 署名 (増分)
Android 11 では、増分インストール用に V4 が導入されました。これは、デバイスにストリーミングされる個々のブロックの検証を可能にするマークル ツリー ベースの署名を提供します。
何らかの理由で署名の検証が失敗した場合、インストールはただちに中止されます。 APK検証ツール を使用して、インストール前に APK の署名を確認できます。
署名照合の更新
同じパッケージ名のアプリがすでにインストールされている場合、システムは追加のチェックを実行します。新しい APK の署名証明書は、既存のインストールの証明書と一致する必要があります。これにより、悪意のある者が正規のアプリを改ざんされたバージョンに置き換えることを防ぎます。署名が一致しない場合は、「アプリがインストールされていません: パッケージは同じ名前の既存のパッケージと競合しています。」というエラーが表示されます。
ステップ 5: ユーザーの確認
サイドロード インストールの場合、システムは次のようなインストール確認ダイアログを表示します。
- アプリ名とアイコン (APK のリソースから抽出)
- アプリが要求する権限 (古い Android バージョンの場合)
- 新規インストールかアップデートか
- アプリのソースまたは潜在的なリスクに関する警告
Android 12 以降では、実行時の権限はインストール時ではなく、アプリが最初に必要とするときに個別に付与されるため、確認画面がよりシンプルになります。
ステップ 6: ファイルの抽出と配置
ユーザーが確認すると (Play ストアのインストールの場合は自動的に)、システムはファイルの抽出と配置を開始します。
APKストレージ
APK ファイル自体は /data/app/[package-name]-[random]/base.apk にコピーされます。分割 APK インストールの場合、split_config.arm64_v8a.apk などの追加ファイルがベース APK と一緒に配置されます。ダウンロード フォルダー内の元の APK は変更または削除されません。
ネイティブライブラリの抽出
APK にネイティブ ライブラリ (lib/ ディレクトリ内) が含まれている場合、それらは /data/app/[package-name]-[random]/lib/[abi]/ に抽出されます。新しい Android バージョンでは、アプリはネイティブ ライブラリを APK 内で圧縮したままにし、android:extractNativeLibs="false" を使用して直接ロードすることを選択でき、これによりストレージ スペースが節約されます。
データディレクトリの作成
システムは、アプリのプライベート データ ディレクトリを /data/data/[package-name]/ (またはマルチユーザー デバイスの場合は /data/user/0/[package-name]/ に作成します。このディレクトリは、アプリに割り当てられた一意の Linux UID によって所有され、他のアプリが root 権限なしでアクセスできないようにします)。
ステップ 7: DEX の最適化
このステップでは、Android がアプリのバイトコードをデバイスの特定のハードウェアに最適化された形式に変換します。このプロセスは Android の歴史の中で大きく進化してきました。
Dalvik 時代 (Android 4.4 以前)
元の Dalvik 仮想マシンは、Just-In-Time (JIT) コンパイルを使用していました。インストール中に、classes.dex ファイルは、検証および最適化されたバイトコードを含む ODEX ファイルに最適化されました。これは比較的高速でしたが、ほとんどのコードが依然として解釈されるため、実行時のアプリの実行が遅くなります。
AOT を使用した ART (Android 5.0 ~ 6.0)
Android ランタイム (ART) が Dalvik に代わって、Ahead-Of-Time (AOT) コンパイルを導入しました。インストール中に、DEX バイトコード全体がネイティブ マシン コードにコンパイルされました。これにより、アプリの実行は高速になりましたが、インストール時間とストレージ使用量が大幅に増加しました。一部のアプリはインストールに数分かかりました。
プロファイルガイド付きコンパイル (Android 7.0 以降)
最新の Android はハイブリッド アプローチを採用しています。インストール中に、重要な起動パスのみがコンパイルされます。ユーザーがアプリを実行すると、システムは頻繁に使用されるコード パスを特定する実行プロファイルを収集します。アイドル メンテナンス中 (通常は夜間の充電中)、システムはこれらのホット パスをネイティブ コードにコンパイルします。これにより、インストール速度、ストレージ使用量、実行時のパフォーマンスのバランスが取れます。
コンパイルされたコードは、/data/dalvik-cache/ に保存されるか、または .odex、.vdex、および .art ファイルとして APK と一緒に保存されます。 .vdex ファイルには検証済みの DEX コードが含まれ、.odex ファイルにはコンパイルされたネイティブ コードが含まれ、.art ファイルには高速起動のための事前に初期化されたヒープ イメージが含まれています。
ステップ 8: 権限の登録
PackageManagerService は、アプリの宣言された権限とコンポーネントをシステムに登録します。
- インストール時の権限 (INTERNET や VIBRATE など) は、ユーザーの介入なしで自動的に付与されます。
- 実行時の権限 (like CAMERA or LOCATION are registered but not granted.アプリは実行時にそれらを要求する必要があります)。
- インテントフィルター は登録されているため、どのアプリがどのアクション (URL を開く、コンテンツの共有など) を処理できるかをシステムが認識します。
- コンテンツプロバイダー はその当局に登録されているため、他のアプリがクエリできるようになります。
ステップ 9: システム統合
最後のステップでは、アプリを Android システムに統合します。
- パッケージデータベースの更新: システムのパッケージ データベース (/data/system/packages.xml) は、割り当てられた UID、権限、コンポーネント宣言などの新しいアプリの情報で更新されます。
- ランチャー通知: ホーム画面ランチャーは新しいアプリを通知されるため、アプリのアイコンを表示できます。
- 放送: システムは PACKAGE_ADDED ブロードキャストを送信し、他のアプリが新しいインストールに反応できるようにします (たとえば、バックアップ アプリがバックアップをスケジュールする場合があります)。
- SELinux コンテキスト: アプリのファイルには、ターゲット SDK バージョンと宣言された権限に基づいて、適切な SELinux セキュリティ コンテキストのラベルが付けられます。
インストールが失敗する理由
インストール パイプラインを理解すると、一般的な障害の診断に役立ちます。
- 「解析エラー」: APK が破損しているか、不完全であるか、マニフェストの形式が不正です。これは、ダウンロードが不完全であったり、ファイルが不適切に変換されたりした場合によく発生します。
- 「アプリがインストールされていません」(署名の不一致): You are trying to update an app with an APK signed by a different key.まず既存のバージョンをアンインストールする必要があります。
- 「ストレージが不十分です」: APK、抽出されたライブラリ、DEX 最適化出力用のスペースが不足しています。実際に必要なスペースは通常、APK サイズの 2 ~ 3 倍です。
- 「パッケージが既存のパッケージと競合します」: パッケージ名は同じですが、署名が異なります。 Play ストアとサイドロード バージョンを切り替えるときによく発生します。
- バージョンのダウングレードがブロックされました: デフォルトでは、Android は新しいバージョンの上に古いバージョンをインストールすることを禁止します。 ADB は、adb install -d を使用してこれをオーバーライドできます。
分割APKインストール
分割 APK を (App Bundle から) インストールする場合、プロセスは若干異なります。システムは セッションベースのインストール API を使用します。
- 新しいインストールセッションが作成されます
- 分割された各 APK はセッションに書き込まれます
- セッションがコミットされ、完全な検証パイプラインがトリガーされます
- すべての分割には、パッケージ名、バージョン コード、署名証明書が一致している必要があります。
これは、XAPK インストーラーや APK と APK の統合 などのツールで複数ファイルのインストールを処理するために使用されるメカニズムです。
ADB経由でのインストール
adb install を使用すると、プロセスはグラフィカル インストーラーをバイパスしますが、同じ内部パイプラインに従います。 ADB は、ソケット接続を通じてパッケージ マネージャー サービスと通信します。 GUI では使用できない追加のフラグもサポートしています。
- -r: 既存のアプリを置き換えます (再インストールを許可します)
- -d: バージョンのダウングレードを許可します
- -g: すべての実行時権限を直ちに付与します
- -t: テスト専用 APK のインストールを許可します
- --install-multiple: 単一セッションで分割 APK をインストールする
アンインストール中に何が起こるか
完全を期すために、アプリが削除されると何が起こるかを次に示します。
- アプリのプロセスが強制終了される
- APKと抽出されたライブラリは/data/app/から削除されます
- アプリのプライベート データ ディレクトリは削除されます (ユーザーがデータを保持することを選択した場合を除く)
- コンパイル済みの DEX キャッシュ ファイルが削除される
- パッケージデータベースが更新されました
- PACKAGE_REMOVED ブロードキャストが送信されます
- ランチャーはアプリアイコンを削除します
Android 10 以降では、スコープ指定ストレージの適用により、外部ストレージ (/Android/data/[package]/ および /Android/obb/[package]/ 上のアプリ固有のファイルも削除されることに注意してください)。
PackageManager を理解するとデバッグ時間が節約できる理由
Android のインストール プロセスは、セキュリティ チェック、ファイル操作、システム統合の一連の慎重に調整されたものです。改ざんされたアプリからユーザーを保護することから、特定のハードウェアのパフォーマンスを最適化することまで、各ステップには目的があります。インストールが失敗した場合、エラーは通常、このパイプラインの特定のステップを示しており、プロセスを理解すると、問題を迅速に診断して解決するのに役立ちます。
Play ストアからのインストール、APK の手動サイドローディング、ADB によるビルドのプッシュはすべて、同じ基礎となるパイプラインを通じて行われます。このパイプラインにより、デバイス上のすべてのアプリが検証され、正しく配置され、ハードウェアに合わせて最適化されていることを確認できます。