今日は、Android のマルチプロセス実行メカニズムと IPC の概要をまとめます。内容は以下の通りです:
- Android のプロセス
- Android の IPC の概要
- マルチプロセスモードの開始
- Android のマルチプロセス実行メカニズム
Android のプロセス#
まず、プロセスは独立して実行されるプログラムと理解できます。あるプログラムが起動すると、システムはそのプログラムのためにプロセスを作成し、必要なシステムリソースを割り当てます。同時に、そのプロセスをプロセスの待機キューに追加します。プロセススケジューラは、どのプロセスを実行するかを管理します。
Android のアプリケーションは、1 つのプロセスとして実行することも、複数のプロセスとして構成することもできます。各プロセスは独自の空間で実行され、Android は各プロセスに仮想マシンを割り当てます。異なる仮想マシンは、メモリ割り当てにおいて異なるアドレス空間を持ちます。異なるプロセスは、プロセス間通信が関わってきます。
Android のプロセスは以下の通りです:
- フォアグラウンドプロセス:ユーザーと直接やり取りできるか、フォアグラウンドにバインドされた Service が存在するプロセス
- 可視プロセス:ユーザーには見えるがクリックできない
- サービスプロセス:バックグラウンドで実行される Service が存在するプロセス
- バックグラウンドプロセス:フォアグラウンドプロセスに対しての相対的なプロセス
- 空のプロセス:キャッシュのような意味でのプロセスで、システムはいつでも空のプロセスを回収できます。
優先度は、フォアグラウンドプロセス > 可視プロセス > サービスプロセス > バックグラウンドプロセス > 空のプロセスです。
Android の IPC の概要#
IPC(Inter-Process Communication)は、プロセス間通信またはクロスプロセス通信を指します。どのオペレーティングシステムにも、プロセス間通信を完了するための適切な IPC メカニズムが必要です。たとえば、Windows ではクリップボードやパイプなどを使用してプロセス間通信を行います。Linux では、チャネル、共有メモリ、セマフォなどを使用してプロセス間通信を行います。Android は Linux をベースにしていますが、モバイルデバイスの特性に合わせて、専用のプロセス間通信方式である Binder を提供しています。したがって、Android の IPC メカニズムと言えば、一般的には Android の Binder メカニズムを指します。
IPC の使用シーン:
- アプリケーション自体がマルチプロセスモードを採用する必要がある場合。Android では、アプリケーションごとに最大メモリ制限が設定されているため、より多くのメモリスペースを確保するために、一部のモジュールを独立したプロセスに配置する必要があります。その場合、モジュール間の相互作用にはプロセス間通信が必要です。
- アプリケーション自体が他のアプリケーションとクロスプロセスでの相互作用が必要な場合。ContentProvider や AIDL などを使用する場合、IPC の範疇に入ります。たとえば、Android のテレビボックス IPTV のミドルウェアでは、これらの方法が大量に使用されています。
注意:Android のメモリ制限はメーカーによって異なります。デフォルトの初期メモリ割り当ては 16M で、具体的な設定は system/build.prop ファイルにあります。
マルチプロセスモードの開始#
Android では、4 つの主要なコンポーネントの中でandroid:process
属性を設定することで、マルチプロセスを開始します。設定する際には、プライベートプロセスとグローバルプロセスの 2 つのオプションがあります。以下のように設定します:
<!--プライベートプロセス-->
<!--com.manu.progress:remote-->
<activity
android:name="com.manu.process.SampleActivity"
android:process=":remote"/>
<!--グローバルプロセス-->
<!--com.manu.remote-->
<activity
android:name="com.manu.process.SampleActivity"
android:process="com.manu.remote"/>
プライベートプロセスに設定する場合、他のアプリケーションのコンポーネントは同じプロセスで実行できません。グローバルプロセスに設定する場合、2 つのアプリケーションを同じ ShareUID に設定し、2 つのアプリケーションのコンポーネントを同じプロセスで実行できます。さらに、2 つのアプリケーションの署名も同じである必要があります。これにより、2 つのアプリケーションのコンポーネントを同じプロセスで実行し、データディレクトリなどのプライベートデータを共有することができます。
では、2 つのアプリケーションのコンポーネントを同じプロセスに設定するにはどうすればよいでしょうか?
- 2 つのアプリケーションに同じ ShareUID を設定します。
- 2 つのアプリケーションのコンポーネントのプロセスを同じプロセス名に設定します。
- 2 つのアプリケーションの署名が同じであることを確認します。
テスト中に気づいたのですが、すでにプロセスが起動している場合、同じプロセスに設定されたコンポーネントを起動すると、2 番目のアプリケーションが異常終了します。この点については、ソースコードを読んで原因をより詳しく理解する必要があります。
- 2 つのアプリケーションのコンポーネントを同じプロセスに設定するにはどうすればよいですか?
Android のマルチプロセス実行メカニズム#
Android は、各プロセスに独立した仮想マシンを割り当てます。異なる仮想マシンは、メモリ割り当てにおいて異なるアドレス空間を持つため、同じクラスのオブジェクトに異なるプロセスからアクセスすると、複数のコピーが作成されます。つまり、2 つのプロセスには同じクラスの 2 つのコピーがあり、それらは互いに影響を受けません。1 つを変更してももう 1 つには影響しません。これにより、異なるプロセスで実行される 4 つの主要なコンポーネントは、メモリを介してデータを共有する場合、共有に失敗します。マルチプロセスによる問題は以下の通りです:
- 静的メンバーとシングルトンパターンが完全に無効になる
マルチプロセスでは、同じクラスの複数のコピーが存在し、変更が反映されないため、効果がありません。
- スレッド同期メカニズムが完全に無効になる
スレッド同期メカニズムは、同じオブジェクトをロックするため、効果がありません。
- SharePreference の信頼性が低下する
SharePreference は MODE_MULTI_PROCESS を設定してマルチプロセスをサポートできますが、推奨されていません。一部のバージョンでは機能しない場合があり、API 23 以降では非推奨となっています。したがって、MODE_MULTI_PROCESS を使用して SharePreference をマルチプロセスでサポートすることは信頼性がありません。解決策は、ContentProvider を中間層として使用して SharePreferences をサポートすることです。
具体的には、他のプロセスが ContentProvider を介して別のプロセスにアクセスし、データは SharePreference に格納されています。ContentProvider を使用してデータの追加、削除、検索、更新を実装することで操作できます。
- Application の複数作成
コンポーネントが新しいプロセスに実行されると、プロセスの作成は実際にはアプリケーションの起動プロセスです。したがって、Application が複数回作成されることになります。同じプロセスで実行されるコンポーネントは、同じ仮想マシンと同じ Application に属しています。異なるプロセスのコンポーネントは、異なる仮想マシンと Application に属しています。
Application の onCreate メソッドは通常、初期化操作に使用されます。複数回 onCreate メソッドが呼び出される場合、エラーを回避するためにプロセス名を確認して関連する初期化を行うことができます。
上記は、Android のマルチプロセス実行メカニズムと IPC の概要です。Android では、Bundle、ファイル転送、AIDL、Messenger、ContentProvider など、IPC の実装方法があります。これらの内容は、後続の整理と共有で詳しく説明します。