huazi

huazi

《Android開発の芸術探求》ノート-第2章

IPC は Inter-Process Communication の略で、プロセス間通信またはクロスプロセス通信を意味し、2 つのプロセス間で通信するプロセスです。

スレッドは CPU のスケジューリングの最小単位であり、同時にスレッドは有限のシステムリソースです。プロセスは通常、実行単位を指し、1 つのプロセスには複数のスレッドが含まれる場合があります。プロセスには 1 つのスレッドのみが含まれる場合もあります。

マルチプロセスは 2 つのタイプに分かれます。1 つ目は、アプリケーション自体が何らかの理由でマルチスレッドモードを採用する必要がある場合であり、もう 1 つは現在のアプリケーションが他のアプリケーションからデータを取得する必要がある場合です。

Android では、マルチプロセスを使用する方法は 1 つだけであり、AndroidManifest で四大コンポーネントに android属性を指定することです。それ以外の方法はありません。adb shell psコマンドを使用してプロセス情報を表示できます。

プロセス名が「:」で始まるプロセスは、現在のアプリケーションのプライベートプロセスであり、他のアプリケーションのコンポーネントは同じプロセスで実行できません。
プロセス名が「:」で始まらないプロセスはグローバルプロセスであり、他のアプリケーションは ShareUID の方法を使用して同じプロセスで実行できます。システムは各アプリケーションに固有の UID を割り当て、同じ UID を持つアプリケーションのみがデータを共有できます。
Android では、各プロセスには独自の仮想マシンが割り当てられ、各仮想マシンには異なるアドレス空間が割り当てられます。プロセス内またはプロセス外で実行される四大コンポーネントは、メモリを共有してデータを共有しようとする場合、共有に失敗します。

マルチプロセスにより、次の問題が発生する場合があります:

  1. 静的メンバーとシングルトンパターンが完全に無効になります。
  2. スレッド同期メカニズムが完全に無効になります。
  3. SharePreferences の信頼性が低下します。
  4. Application が複数回作成されます。

1 と 2 については同じ問題であり、ロックオブジェクトやグローバルクラスのロックではスレッド同期を保証できません。なぜなら、異なるプロセスのロックは同じオブジェクトではないからです。

SharePreferences は、2 つのプロセスが同時に書き込み操作を行うことをサポートしていません。なぜなら、SharePreferences の内部は xml ファイルの読み書きによって実現されており、並行して読み書きすると問題が発生する可能性があるからです。

異なるプロセスで実行されるコンポーネントは、異なる仮想マシンとアプリケーションに属しています。プロセスを起動するたびに、Application の onCreate が実行されます。

IPC の基本概念#

IPC の基本的な概念は、Serializable インターフェース、Parcelable インターフェース、および Binder を含みます。Serializable と Parcelable はオブジェクトのシリアル化プロセスを完了するために使用され、Intent と Binder を使用してデータを転送する場合には Serializable と Parcelable が必要です。

Serializable インターフェース#

Serializable は Java で提供されるシリアル化インターフェースであり、オブジェクトに標準のシリアル化および逆シリアル化操作を提供します。
serialVersionUIDはシリアル化および逆シリアル化プロセスを補助するためのものであり、原則として、シリアル化されたデータのserialVersionUIDは現在のクラスのserialVersionUIDと同じである場合にのみ正常に逆シリアル化できます。シリアル化するとき、システムは現在のクラスのserialVersionUIDをシリアル化ファイルに書き込みます。逆シリアル化するとき、システムはファイルのserialVersionUIDが現在のクラスのserialVersionUIDと同じかどうかをチェックし、一致すれば正常に逆シリアル化され、一致しなければ正常に逆シリアル化できません。通常、serialVersionUIDを手動で指定する必要があります。指定しない場合、現在のクラスが変更されると、現在のクラスのハッシュ値が再計算され、それがserialVersionUIDに割り当てられます。

  1. 静的メンバ変数はクラスに属し、オブジェクトには属していないため、シリアル化プロセスには参加しません。
  2. transientでマークされた変数はシリアル化プロセスに参加しません。

Parcelable#

Android で提供される新しいシリアル化方法であり、インターフェースです。シリアル化機能はwriteToParcelによって実現されます。Intent、Bundle、Bitmap はすべてこのインターフェースを実装しており、直接シリアル化できます。

Serializable は Java のインターフェースであり、使用は簡単ですが、コストが高いため、シリアル化および逆シリアル化には多くの I/O 操作が必要です。

Parcelable は使用が煩雑ですが、効率が高く、推奨されます。

シリアル化オブジェクトをデバイスに保存するか、オブジェクトをシリアル化してネットワーク経由で転送する場合は、Serialzalble を使用することをお勧めします。

Binder#

Android 開発では、Binder は主に Service、AIDL、および Messenger で使用されます。通常の Service の Binder はプロセス間通信に関与しません。Messenger の基盤は AIDL です。Binder の一意の識別子は通常、現在の Binder クラス名で表されます。

Binder は ServiceManager が各種 Manager(ActivityManager、WindowManager など)と対応する ManagerService を接続するための橋渡しをするものです。

システムが生成した Binder クラスのパラメータ解析:

  • DESCRIPTOR は Binder の一意の識別子であり、通常は現在の Binder クラス名を使用します。
  • asInterface (android.os.IBinder obj) は、サーバー側の Binder オブジェクトをクライアント側で必要な AIDL インターフェースタイプのオブジェクトに変換するために使用されます。この変換はプロセス間で行われるため、クライアントとサーバーが同じプロセスにある場合、このメソッドはサーバーの Stub オブジェクト自体を返し、それ以外の場合はシステムによってラップされた Stub.proxy オブジェクトを返します。
  • adBinder は現在の Binder オブジェクトを返します。
  • onTransact は、サーバーの Binder スレッドプールで実行され、クライアントがリクエストを送信すると、リモートリクエストはこのメソッドで処理されます。

Binder の動作メカニズムには 2 つの注意点があります:

  1. クライアントがリモートリクエストを送信すると、現在のスレッドはデータがサーバープロセスから返されるまで一時停止し、時間がかかります。
  2. サーバーの Binder メソッドは Binder スレッドプールで実行されるため、Binder メソッドは時間のかかるかどうかに関係なく同期的に実装する必要があります。

Binder の動作メカニズムの図:
Binder の動作フロー.png

Binder はサーバーで実行され、サーバーが何らかの理由で終了すると、リモート呼び出しが失敗します。Binder にはlinkToDeathunLinkToDeathという 2 つのメソッドがあり、Binder のデスティネーションを設定できます。

Binder のメソッド isBinderAlive を使用することで、Binder が生きているかどうかを判断することもできます。

Android の IPC 方法#

  1. Bundle
    Bundle は Parcelable インターフェースを実装しているため、プロセス間で簡単に転送できます。

  2. ファイル共有
    2 つのプロセスが同じファイルを読み書きしてデータを交換します。同時読み書きは問題があり、同時に書き込む場合はできるだけ避け、複数のスレッドの書き込み操作を制限するためにスレッド同期を使用することを検討してください。
    SharePreferences もファイルの一種であり、システムは読み書きにキャッシュポリシーを持っており、マルチプロセスモードでは読み書きが信頼性が低くなります。

  3. Messenger の使用
    Messenger は軽量な IPC であり、基盤は AIDL です。Messenger はクライアントのメッセージを直列化して処理します。主にメッセージを送信するために使用されます。
    動作原理の図:
    Messenger の動作原理.png

  4. AIDL の使用
    AIDL を使用してプロセス間通信を行うには、サーバーとクライアントの 2 つの側面があります。大まかな流れは次のとおりです:まず、クライアントリクエストを監視するために Service を作成し、次に AIDL ファイルを作成し、この AIDL でクライアントに公開されるインターフェースを宣言し、次に Service でこの AIDL インターフェースを実装します。クライアントはサーバーの Service にバインドし、バインドが成功したら、サーバーが返す Binder オブジェクトを AIDL インターフェースの型に変換し、その後 AIDL メソッドを呼び出します。

  5. ContentProvider の使用
    Android では、異なるアプリケーション間でデータを共有するための専用の方法であり、基盤は Binder です。ContentProvider は基礎データストレージに要件を課しません。

まず、Provider を登録する必要があります。android:authoritiesは Provider の一意の識別子であり、これを使用して Provider にアクセスできます。

Provider の onCreate はメインスレッドで実行され、他のメソッドは Binder スレッドプールで実行されます。query、update、insert、delete は複数のスレッドで同時に実行されるため、メソッド内でスレッド同期を適切に行う必要があります。

  1. ソケットの使用

ソケットはネットワーク通信の概念です。

  • TCP は接続指向のプロトコルであり、安定した双方向通信機能を提供します。
  • UDP は接続指向ではないプロトコルであり、不安定な単方向通信機能を提供しますが、双方向通信も提供でき、効率が良く、正確な転送を保証することはできません。

Binder プール#

AIDL を使用する場合の大まかな流れ:まず、Service と AIDL インターフェースを作成し、AIDL ファイルを作成し、公開する AIDL インターフェースをこのファイルで宣言し、次に Service でこの AIDL インターフェースを実装します。クライアントはサーバーの Service にバインドし、バインドが成功したら、サーバーが返す Binder オブジェクトを AIDL インターフェースの型に変換し、その後 AIDL メソッドを呼び出します。

プロジェクトの規模が非常に大きい場合、多くの Service を作成することは適切ではありません。なぜなら、Service はシステムリソースであり、多くの Service を作成するとアプリケーションが重くなるからです。したがって、すべての AIDL を同じ Service に配置することが最善です。

Binder プールの役割は、各ビジネスモジュールの Binder リクエストをリモート Service に一元的に転送し、Service の作成を繰り返すことを避けることです。

BinderPool は AIDL の開発効率を大幅に向上させ、多くの Service の作成を回避するため、AIDL に導入することをお勧めします。

適切な IPC 方法の選択#

名前利点欠点適用シナリオ
Bundle簡単で使いやすい転送できるのは Bundle がサポートするデータ型のみコンポーネント間のプロセス通信
ファイル共有簡単で使いやすい高並行シナリオには適さず、リアルタイムなプロセス間通信はできない並行アクセスがなく、シンプルなデータの交換、リアルタイム性が低いシナリオ
AIDL機能が強力で、一対多の並行通信がサポートされ、リアルタイム通信が可能使用がやや複雑で、スレッド同期を適切に処理する必要がある一対多通信が RPC 要件を持つ場合
Messenger機能は一般的で、一対多の直列通信がサポートされ、リアルタイム通信が可能高並行シナリオをうまく処理できず、RPC をサポートせず、データはメッセージを介して転送され、転送できるのは Bundle がサポートするデータ型のみ低並行の一対多のリアルタイム通信、RPC 要件がないか、結果を返さない RPC 要件がある場合
ContentProviderデータソースアクセスにおいて機能が強力で、一対多の並行データ共有がサポートされ、Call メソッドを使用して拡張できる制約された AIDL と見なすことができ、主にデータソースの CRUD を提供する一対多のプロセス間データ共有
ソケット機能が強力で、バイトストリームをネットワーク経由で転送でき、一対多の並行リアルタイム通信がサポートされる実装の詳細がやや煩雑で、直接的な RPC をサポートしないネットワークデータ交換
読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。