4

をパーセル化(またはシリアル化)して、Androidの別のプロセスにClassLoader送信することは可能かどうか疑問に思っています。/を実装していません。MessageClassLoaderParcelableSerializable

これを行う方法についてのヒントはありますか?前もって感謝します!

4

3 に答える 3

3

クラスローダー

クラス ローダーは基本的にハッシュ テーブルであり、そのエントリはクラス名でキー付けされ、VM にロードされたバイト コードをポイントします。Java ではコードの操作が許可されていないため、VM 自体にロードされたバイト コードは、もちろん Java プロセスには制限されません。バイトコードは JIT VM によって CPU 固有のコードにコンパイルされており、メモリの場所やその他の低レベルの構造が含まれていることに注意してください。

クラスローダーは元のバイトコードを指し示すことができるため、同じ VM 内でクラスローダーを (シリアライゼーションまたはその他の方法で) 共有することができます。ただし、シリアル化してから別の VM に逆シリアル化するには、クラス ローダーでバイト コードをシリアル化する必要があります。そして問題があります。

クラスローダーのシリアル化

思考実験として、他のプロセスがコードを逆シリアル化できるようにするには、どのようにコードをシリアル化しますか?

これをクラスサイズのチャンクとして処理する必要があるため、シリアル化されたエンティティはクラス インターフェイス全体を持ちます。バイトコード内のシンボルへのポインターを「未解決」にする必要があります。イントロスペクションが引き続き機能するように、クラスの文字列とシンボル テーブル全体をコピーする必要もあります。

今定義したのは、クラス ファイル自体です (クラス メンバーの初期化とシリアル化のわずかな違いです)。

繰り返しますが、クラス ファイル クラスのシリアル化されたバージョンです。

DEXの難問

ただし、Android はクラス ファイルを DEX にプリコンパイルします。これは、最適化されたバージョンの JAR を含む単一のファイルです。クラスは事前に相互にリンクされており、すべての文字列シンボルは同じ共有文字列/シンボル プールに置かれています。したがって、Android で共有可能な最小のコンポーネントは DEX です。

多くの場合、アプリまたはデバイスのメーカーは ODEX ファイルを作成します。これは、特定の CPU およびアーキテクチャ (ビッグ エンディアンまたはリトルエンディアン システムを含む) に合わせてコンパイルされた DEX ファイルです。

Android では、ODEX ファイルはシリアル化されたクラス ローダーと考えることができます。

リモート クラスの読み込み

問題の核心は、1 つのプロセスが元のプロセスから見えるクラス ファイルをどのようにロードできるかということです。yorkwは、私が提案したようなことを行うクラス ローダーを見つけたと提案しました。アプローチは、最初のプロセスがクラス ルックアップ サービスを実装し、クラス バイトコードを返すことです。ただし、上記の DEX の問題により、Android では直接動作しません。

解決?

したがって、実装するソリューションはすべて (O)DEX に基づいています。基本的に、クライアントがサーバーと通信して (O)DEX ファイルを要求し、それを単一のエンティティとしてロードする必要があります。それをロードすると、新しいクラスローダーが返されます

今、私はこれを行ったことがありません.Androidがこのアプローチを台無しにするDEXファイルを1つだけロードすることを許可している可能性は十分にあります. YMMV

この議論が役に立てば幸いです...


TL;DRクラスローダーをシリアライズすることはできません。ただし、同じ結果を生成する (O)DEX ファイルをロードするように別のプロセスを説得できる場合があります。

于 2012-07-27T00:24:39.023 に答える
1

ClassLoader の強力なネイティブ コンポーネントとその機能を考えると、ClassLoader を他のプロセスと共有することが可能であるとは想像できません。少なくとも意味のある方法ではありません。

于 2012-07-20T20:05:58.893 に答える
1

いいえ、残念ながらできません。ClassLoader の一部のサブセットをパーセル化できる可能性がありますが、私はそれをお勧めしません。

別のアプリケーションからカスタム クラスを読み込もうとしていることが問題である場合はParcel、クラスを他のアプリケーションにコピーすることで読み取ることができるはずです (両方のアプリケーションで同じパッケージにあることを確認してください)。最初のアプリケーションで、次のようにパーセルに書き込むだけです。

parcel.writeParcelable(myCustomParcelable, 0);

そして、小包を受け取った反対側では、次のように読んでください。

MyCustomParcelable myCustomParcelable = (MyCustomParcelable)parcel.readParcelable(getClassLoader());
于 2012-07-20T19:53:20.160 に答える