今日は Android のマルチプロセス実行メカニズムと IPC の紹介をまとめます。内容は以下の通りです:
- Android におけるプロセス
- Android IPC の紹介
- マルチプロセスモードの有効化
- Android のマルチプロセス実行メカニズム
Android におけるプロセス#
まず、プロセスは独立して実行されるプログラムと理解できます。あるプログラムが起動すると、システムはそのプログラムのためにプロセスを作成し、必要なシステムリソースを割り当て、プロセスを準備キューに追加します。プロセススケジューラはどのプロセスを実行するかを管理します。
Android のアプリケーションは 1 つのプロセスにすることも、多プロセスに設定することもできます。各プロセスは独立した空間で実行され、Android は各プロセスに仮想マシンを割り当てます。異なる仮想マシンはメモリ割り当てにおいて異なるアドレス空間を持ち、異なるプロセスは自然にプロセス間通信を必要とします。
Android のプロセスは以下の通りです:
- フロントエンドプロセス:ユーザーと直接対話できるか、フロントエンドにバインドされたサービスが存在するプロセス;
- 可視プロセス:ユーザーに見えるがクリックできない;
- サービスプロセス:バックグラウンドで実行されるサービスが存在するプロセス;
- バックグラウンドプロセス:フロントエンドプロセスに対してのプロセス;
- 空プロセス:キャッシュ的な意味でのプロセスと理解され、システムはいつでも空プロセスを回収できます。
その優先順位はフロントエンドプロセス > 可視プロセス > サービスプロセス > バックグラウンドプロセス > 空プロセスです。
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
属性を設定してマルチプロセスを有効にします。設定時にはプライベートプロセスとグローバルプロセスに設定できます。以下のように:
<!--プライベートプロセス-->
<!--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 つのアプリケーションの署名が同じである
テスト中に、すでに 1 つのプロセスが起動している場合、同じプロセスに設定されたコンポーネントを起動すると、2 つ目のアプリケーションが異常終了することがわかりました。この点については、ソースコードを読んでさらに理解する必要があります。
- どのようにして 2 つのアプリケーションのコンポーネントを同じプロセスに設定するのでしょうか?
Android のマルチプロセス実行メカニズム#
Android は各プロセスに独立した仮想マシンを割り当てます。異なる仮想マシンはメモリ割り当てにおいて異なるアドレス空間を持つため、異なる仮想マシンで同じクラスのオブジェクトにアクセスすると複数のコピーが生成されます。つまり、2 つのプロセスに同じクラスの 2 つのコピーが存在し、これらのクラスは互いに干渉しません。一方を変更してももう一方には影響しません。これにより、異なるプロセスで実行される 4 つの主要コンポーネントは、メモリを介してデータを共有しようとすると、常に共有に失敗します。マルチプロセスによる問題は以下の通りです:
- 静的メンバーとシングルトンパターンが完全に無効になる
マルチプロセスでは同じクラスの複数のコピーが存在し、変更が互いに影響しないため、効果がありません;
- スレッド同期メカニズムが完全に無効になる
スレッド同期メカニズムがロックするのは 1 つのオブジェクトではないため、効果がありません;
- SharePreference の信頼性が低下する
SharePreference は MODE_MULTI_PROCESS を設定してマルチプロセスをサポートできますが、使用は推奨されません。なぜなら、特定のバージョンでは効果がなく、API 23 以降は廃止されたため、MODE_MULTI_PROCESS を使用して SharePreference のマルチプロセスをサポートするのは信頼できません。解決策は、ContentProvider を中間層として使用し、SharePreferences がマルチプロセスをサポートできるようにすることです。
具体的には、他のプロセスが ContentProvider を介して別のプロセスにアクセスし、データは SharePreference に保存され、ContentProvider を介してデータの追加、削除、検索、更新を行うことができます。
- Application が複数回作成される
コンポーネントが新しいプロセスで実行されると、プロセスの作成プロセスは実際にはアプリケーションの起動プロセスです。したがって、Application が複数回作成されることになります。同じプロセスで実行されるコンポーネントは同じ仮想マシンと同じ Application に属し、異なるプロセスのコンポーネントは複数の仮想マシンと Application に属します。
Application の onCreate メソッドは一般的に初期化操作に使用されます。Application の onCreate メソッドが複数回呼び出される場合、エラーを避けるためにプロセス名に基づいて判断し、関連する初期化を行うことができます。
上記は Android のマルチプロセス実行メカニズムと IPC の紹介です。Android における IPC の実装方法には Bundle、ファイル転送、AIDL、Messenger、ContentProvider などがあります。この部分の内容は後で整理して共有します。