1

2 つのアプリがあります。1 つはmy-app.apk、もう 1 つはmy-service.apkです。サービス アプリは、いくつかのメソッドを実行するためにプライマリ アプリによってバインドできる単一のAndroid Serviceを定義するだけです。これは AndroidのAIDLインターフェースを使用して行われ、これまでのところうまく機能しています。

サービスのインターフェースを変更したいのですが、何に気をつければいいのか悩んでいます。my-service.apkの IRemote.aidl ファイルを次のように変更しました。

package com.example.myservice;
interface IRemote {
  void printHello();
  void print(int i);
}

好奇心から、my-app.apk の IRemote.aidlを次のように変更しました (違いに注意してください!)。

package com.example.myservice;
interface IRemote {
  void printHello();
  void printYeahThisHasADifferentNameAndParam(String s);
}

今、私は完全に予想外の結果を得ました:

printYeahThisHasADifferentNameAndParam("hello world");

私のアプリケーションからのログ出力は「11」になりました。どうして??

  1. bindService() 呼び出しでSecurityExceptionが発生するとは予想していませんでしたが、まったく異なるインターフェイスを使用する状況ではこれで十分です。
  2. 私が期待していたのは、呼び出しの実行時にRemoteExceptionであり、メソッドが使用できないことを示していました。
  3. が完全に期待していなかったのは、異なるデータをパラメーターとして別のメソッドを呼び出すだけだということでした。低レベルの観点からは理解できますが。おそらく彼らは、このインターフェースのパフォーマンスを確保するためにそれを行ったのでしょう...

だからここに私の質問があります:

  1. 最適なアップグレード戦略は何ですか? 古いメソッドと順序を削除/変更しないでください。
  2. my-service.apkがアップグレード (再インストール) されると、 my-app.apkのサービスが失われることに気付きました。通常、サービスはシステムによって再スケジュールされます。これは通常、クラッシュ時に行われます。my-app.apkがサービスを再度取得するようにするにはどうすればよいですか? 新しくインストールされたパッケージに注意してください。

よろしくお願いします。:-)

乾杯、マーク

4

1 に答える 1

4

AIDL コンパイラによって生成されたコードを見ると、Binder を介した RPC がメソッドを連番で呼び出していることがわかります。インターフェイスのすべてのメソッドには、次のように番号が割り当てられます。

       SIZE = ::android::IBinder::FIRST_CALL_TRANSACTION + 0,
       SETSIZE = ::android::IBinder::FIRST_CALL_TRANSACTION + 1,
       READ = ::android::IBinder::FIRST_CALL_TRANSACTION + 2,
       WRITE = ::android::IBinder::FIRST_CALL_TRANSACTION + 3,
       SYNC = ::android::IBinder::FIRST_CALL_TRANSACTION + 4,

この番号は、呼び出し側で呼び出されたメソッドをフラット パーセル バッファーにマップするために使用され、IPC の受信側で生成されたメソッドを選択してシリアル化されたパラメーター データをアンマーシャルし、最終的に実際の実装を呼び出すために使用されます。

したがって1、呼び出し側でメソッド番号の定義を置き換えても、受信側に古い実装が残っている場合、完全に偽のデータで古い実装を呼び出すことになります。メソッド引数のシリアル化された Parcel データには (メソッド番号自体以外に) 型情報がないため、新しいメソッド呼び出しパラメーター バッファーを古いものとして逆シリアル化し、実装を呼び出そうとします。

于 2017-01-29T11:21:43.610 に答える