記事ディレクトリ
序文
ホットフィックスとは何ですか?
アプリケーションがオンラインになった後は、バグを適時に修正する必要があるため、新しいインストール パッケージをリリースする必要はなく、パッチ パッケージをリリースするだけで、ユーザーが意識することなくバグを修正できます。
ホットフィックスを行うにはどうすればよいですか?
- サーバー: パッチパッケージ管理
- クライアント側: ホットフィックスを実行します
- 開発側: パッチパッケージを生成する
ホットフィックスで解決する必要がある問題
開発側
- パッチパックとは何ですか?
パッチ パッケージは、バグを修正する dex ファイルおよび jar パッケージです。
- パッチパックを生成するにはどうすればよいですか?
バグ修正された Java ファイルは、javac によってクラス ファイルにコンパイルされ、そのクラス ファイルは、パッチ パッケージである dx ツールによって dex ファイルまたは jar パッケージにパッケージ化されます。
- 難読化を有効にした後はどうなるでしょうか?
難読化を有効にすると、クラス名とパッケージ名が変更されますが、難読化によって生成されたパッケージ名とクラス名が変更されないようにするには、マッピング ファイルを通じて解決する必要があります。
- 変更を比較してパッチ パッケージ (gradle) を自動的に生成しますか?
Gradle がホットフィックスを生成するためのプラグイン方式は、問題が小さく、記述されるコードがそれほど多くない状況に適しています。
ユーザー端末 - いつホットフィックスを実行するのですか?
修正プログラムを完了するには、バグ クラスをロードする前に実行する必要があります。早いほどよいでしょう。
- アプリがすでに実行中で、クラスがすでにロードされている場合でも、ホットフィックスを実行できますか?
このクラスが既にロードされている場合、キャッシュ内に存在し、dex ファイルからこのクラスのクラス ファイルが検索されないため、ホット リペアはできません。
- ホットフィックスが完了したら、パッチ パッケージの dex ファイルと元の dex ファイルを削除する必要がありますか?
削除できません。
パッチパッケージのdexファイルが削除され、キャッシュが空になると、元のバグのないプロセスが再度実行されます;元の
dexファイルが削除されると、dexファイルに含まれるすべてのロジックコードが削除され、アプリは動作しないでしょう。 - (ホットフィックスを使用して) ホットフィックスを実行するにはどうすればよいですか?
パッチ パッケージをダウンロードし、リフレクション技術を使用して DexPathList の makeElement メソッドを通じてバグ修正された Element[] 配列を生成し、リフレクション技術を通じてバグ修正された Element[] 配列を取得し、バグ修正された要素を修正しますバグのあるElement[]とElement[]を新しい配列につなぎ合わせ、クラスロードを行う際にはバグを修正したdexファイル内のクラスを先にロードすることでホットリペアを実現します。
- Android バージョンの互換性の問題
- AndroidN (Android7.0) ホットスポット コードには JIT インスタント コンパイルがあり、解決策は、PathClassLoader をカスタマイズし、キャッシュ コード ロジックを削除して、バグ修正されたコードを最初にロードすることです。
- Dalvik (Android5.0) 仮想マシンには、異なる dex ファイルとの互換性の問題があり、他の dex ファイルのクラスを直接使用しないと、dex ファイル内のクラスにラベルが付けられ、ロードできなくなるバグを修正しましたdexファイル。
解決策は、バイトコード インストルメンテーション テクノロジを使用してバグのある dex ファイルにバイトコード ファイルをコーディングし、他の dex ファイルのクラスを参照し、ラベルの識別を排除することです。これにより、dex 内のクラスをホット リペアでロードすることでバグを修復できるようになります。ファイルによりホットフィックスが完了します。 - バージョンが異なると、一部のメソッドのメソッド名、パラメータの数、パラメータのタイプが異なるため、それらも調整する必要があります。
1. Android の一般的なホットフィックス ソリューション
ティンカー (テンセント) | QZone (テンセント) | アンドフィックス(アリ) | 堅牢 (美団) | |
---|---|---|---|---|
クラスの置き換え | Y | Y | N | N |
だから交換してください | Y | Y | N | N |
リソースの交換 | Y | Y | N | N |
すべてのプラットフォームで有効 | Y | Y | Y | Y |
時間内に効果的 | N | N | Y | Y |
パフォーマンスの損失 | 小さい | より大きな | 小さい | 小さい |
パッチサイズ | 小さい | より大きな | 一般的 | 一般的 |
透明性のある開発 | Y | Y | N | N |
複雑さ | 小さい | 小さい | 複雑 | 複雑 |
グラドルサポート | Y | N | N | N |
ロムボリューム | より大きな | 小さい | 小さい | 小さい |
成功率 | より高い | より高い | 一般的 | 最高 |
AndFix( 补丁包是.dex文件
)
は、Ali によって開発されたホットフィックス フレームワークですが、放棄され、長年にわたって保守されていません。
彼のホットフィックスの実装原理は次のとおりです。
ネイティブ層の Java 層を動的に置き換え、ネイティブ層を介して Java 層のコードをフックする方法です。
Robust( 补丁包是.dex文件
)
は Meituan によって開発され、現在 Douyin はこのホットフィックス ソリューションを採用しており、時間内に有効になる可能性があります。
彼のホットフィックスの実装原理は次のとおりです。gradle
プラグインを使用して、私たちが作成したクラス内で、コンパイル時に静的インターフェイス変数が生成され、そのインターフェイス変数がメソッド内で判断されます。
ホットフィックスを実行する必要がある場合は、インターフェイスの実装クラスを作成し、クラスのロードとリフレクションを通じて、作成したクラスを見つけてインスタンスを作成し、それを修正するクラス内の静的インターフェイス変数に割り当てる必要があります。私たちのメソッドは、インターフェース変数が空でないと判断された場合、バグ修正の目的を達成するために、実装クラスのビジネスロジックを実行し、時間内に有効になります。
Tinker( 补丁包是差分包
)
は Tencent によって開発されました。現在、WeChat はこのホットフィックス ソリューションを採用しています。利点は、クラス、パッケージ、リソース ファイルを修復できることです。
彼のホットフィックスの実装原理は次のとおりです:
バグのある apk ファイルとバグのある apk ファイルから差分パッケージ パッチが生成されます. このパッチ ファイルが私たちのパッチ パッケージです. 差分パッケージとバグのある apk をダウンロードします修復を生成します。バグ APK。リソース ファイルの修復がない場合は、ホット リペアを実現するために、クラス ロードとリフレクション テクノロジを通じてバグ修正クラスをロードできる .dex ファイルが生成されます。
2. ClassLoaderクラスロード機構
2.1 Android クラスローダー
ClassLoader の継承関係:
- クラスローダー
- ブートクラスローダー
用于加载Android Framework层class文件
- BaseDexClassLoader
包含了DexPathList{dexElement[]、findClass()、makeElement[]}
- パスクラスローダー
额外提供的动态类加载器
加载指定的dex、以及jar、zip、apk中的classes.dex
- DexClassLoader
Android应用程序类加载器
加载指定的dex、以及jar、zip、apk中的classes.dex
- パスクラスローダー
- ブートクラスローダー
使用例:
public class MyApplication extends Application {
private final String TAG = MyApplication.class.getSimpleName();
@Override
public void onCreate() {
super.onCreate();
//获取使用ClassLoader的场景
ClassLoader classLoader1 = TKActivity.class.getClassLoader();
ClassLoader classLoader2 = AppCompatActivity.class.getClassLoader();
ClassLoader classLoader3 = Application.class.getClassLoader();
ClassLoader classLoader4 = getClassLoader();
Log.e(TAG, "classLoader1:" + classLoader1.toString());
Log.e(TAG, "classLoader2:" + classLoader2.toString());
Log.e(TAG, "classLoader3:" + classLoader3.toString());
Log.e(TAG, "classLoader4:" + classLoader4.toString());
}
}
打印日志:
E/MyApplication: classLoader1:dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.tangkun.xiangxuestudy-4SJ9lfa-q8--dmTGHgBPbA==/base.apk"],nativeLibraryDirectories=[/data/app/com.tangkun.xiangxuestudy-4SJ9lfa-q8--dmTGHgBPbA==/lib/arm64, /system/lib64, /product/lib64]]]
E/MyApplication: classLoader2:dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.tangkun.xiangxuestudy-4SJ9lfa-q8--dmTGHgBPbA==/base.apk"],nativeLibraryDirectories=[/data/app/com.tangkun.xiangxuestudy-4SJ9lfa-q8--dmTGHgBPbA==/lib/arm64, /system/lib64, /product/lib64]]]
E/MyApplication: classLoader3:java.lang.BootClassLoader@4c33cb2
E/MyApplication: classLoader4:dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.tangkun.xiangxuestudy-4SJ9lfa-q8--dmTGHgBPbA==/base.apk"],nativeLibraryDirectories=[/data/app/com.tangkun.xiangxuestudy-4SJ9lfa-q8--dmTGHgBPbA==/lib/arm64, /system/lib64, /product/lib64]]]
2.2 親委託の仕組み
PathClassLoader を使用してページ上のクラスのフル パスをロードする場合、コードは次のようになります:
getClassLoader().loadClass("com.tangkun.study.MainActivity");
この時点で、getClassLoader メソッドは PathClassLoader を返しますが、このクラスにはloadClass メソッドがありません。そのため、このメソッドをそのクラスから探します。親クラス BaseDexClassLoader の場合、このクラスにはloadClas メソッドもありません。そのため、親クラス ClassLoader からこのメソッドを探します。コードは次のとおりです。
//ClassLoader.java
//这一段就是双亲委托机制代码,要找到某个class文件,先委托给父类parent去查找,
//如果父类没有查找到,则通过子类去查找class文件,并且找到的class文件会被存放在缓存中
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException{
//若class被加载过了,会存到缓存中。所以先从缓存中查找是否存在class
//缓存中的class是从native层中查找得来
Class<?> c = findLoadedClass(name);
if (c == null) {
try {
//parent是BootClassLoader
if (parent != null) {
//调用BootClassLoader.loadClass去查找class;
//这里会调用到native层的findLoadedClass方法,从缓存中查找class
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
}
//如果父类无法加载到class,则从PathClassLoader中去查找class
if (c == null) {
//findClass是一个抽象方法,在子类BaseDexClassLoader中实现了该方法
c = findClass(name);
}
}
return c;
}
//BaseDexClassLoader.java
private final DexPathList pathList;
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
List<Throwable> suppressedExceptions = new ArrayList<Throwable>();
//pathList是传入的DexPathList对象,所以我们从DexPathList类中查看findClass方法
Class c = pathList.findClass(name, suppressedExceptions);
//省略非核心代码
return c;
}
//DexPathList.java
//一个dex文件对应dexElements数组中一个元素Element;
//因为我们打出来的apk包中可能存在多个dex文件,所以是数组。
//DexPathList包含了内部类Element
private Element[] dexElements;
public Class<?> findClass(String name, List<Throwable> suppressed) {
//从dex文件数组中遍历每个dex文件
for (Element element : dexElements) {
//Android中,多个java文件会被编译成多个.class文件,多个class文件会被打包成一个dex文件
//一个dex文件中包含多个class文件,所以从class文件集合中去查找某一个确定的class文件
//最后会调用到native层去查找这个class
Class<?> clazz = element.findClass(name, definingContext, suppressed);
if (clazz != null) {
return clazz;
}
}
//省略非核心代码
return null;
}
2.3 クラス検索プロセス
クラス検索プロセス:
- まず、キャッシュからクラスが存在するかどうかを確認します。
- キャッシュに存在しない場合は、親クラスに委任され、親クラスはクラスが存在するかどうかを確認します。
- 親クラスがクラスを見つけられない場合、現在のサブクラスがクラスを見つけます。
3. 杭計装ホットリペア作業期間修理着地
パッチ パッケージの作成プロセス:
1. バグを修正した後、クラスのクラス ファイルを生成します。
2. 次のコマンドを実行します。
dx --dex --output=patch.jar com/tangkun/study/Utils.class
パッチ パッケージを適用します。 oldElement に patchElment (パッチ パッケージで生成された) + oldElement (元の APK) を割り当てます。
1. プログラムの PathClassLoader オブジェクトを取得します
。 2. PathClassLoader の親クラス BaseDexClassLoader の pathList オブジェクトをリフレクションによって取得します
。 3. 取得します。 pathList の dexElements オブジェクト (oldElement)
4. パッチ パッケージを要素配列に変換します: patchElement (リフレクションは makePathElements を実行します)
5. patchElement+oldElement = newElement (Array.newInstance) をマージします
6. リフレクションは oldElement を newElement に割り当てます
makePathElements パラメータ:
1. パッチ パッケージ: List[new File(“/sdcard/patch.jar”)]
2. OptimizedDirectory プライベート ディレクトリを渡すだけです (例: context.getCacheDir())
3. ArrayList requestedExceptions = new ArrayList();
3.1 バイトコード計測とは何ですか?
いわゆるバイトコード インストルメンテーションとは、バイトコード ファイルにコードを記述することであり、クラス ファイルはバイトコード ファイルに属します。
作成した Java ファイルがコンパイルされると、クラス ファイルが生成されます。クラス ファイルはバイナリ形式です。0101 形式では、この形式のファイルに直接エンコードすることはできません。したがって、次のような他のツールを使用してバイトコード ファイル コードを記述する必要があります第三方框架ASM
。
バイトコードを直接操作するのはどのような処理ですか?
byte[]
ファイル入力ストリームを介してバイトコード ファイルをバイト配列 ( ) に読み取ります。- バイト配列 ( )
byte[]
内のデータを変更します。 - ファイル出力ストリームを介して、
byte[]
バイト配列 () をバイトコード ファイルに書き込みます。
3.2 ASM
.java文件生成的.class文件
概念: ASMは、クラス ファイルの形式に従ってクラスを解析、変更、生成するバイトコード ( ) を操作するためのフレームワークであり、クラスを動的に生成したり、既存のクラスの機能を拡張したりできます。
Gson フレームワークと同様に、json 形式の文字列を操作するために使用されます。
ASM の使用方法
まず、build.gradle の ASM ライブラリに依存する必要があります。次に、バイトコード インストルメンテーション (クラス、メソッド、プロパティなど) を使用し、ASM アノテーションを追加して、インストルメンテーション実装クラスを導入します。インストルメンテーションの実装クラスで対応する関数を完成させます。
最初と最後では、ファイル入出力ストリームを使用してバイトコード ファイルの読み取りと書き込みを行う必要があります。中間では、ASM の助けを借りて、自分でインストルメンテーション コードの作成を実装する必要があります。手書きのインスツルメンテーション コード以前は、実装する必要がある関数を Java ファイルに記述し、クラス ファイルをコンパイルして生成し、次に javap コマンドを使用してクラス ファイル内のコードを表示し ( )、これらのコードと ASM 関数を使用して完了します。インストル也可以通过ASM Bytecode Viewer插件来查看,我的AS由于版本原因,即使安装了这个插件还是看不了java文件的字节码代码;但是可以通过编译后生成的class文件,然后再利用这个插件查看,嘿嘿(*^▽^*)
メンテーション コードの作成。
次に、バグ修正後のクラス ファイルを取得し、SDK の dx ツールを使用してコマンド ライン コマンドを実行してクラス ファイルを dex ファイルまたは jar ファイルに変換します。後で加熱修理に使用するための dex ファイル。
3.3 ホットリペアの実装
1. プログラムの PathClassLoader オブジェクトを取得します
。 2. リフレクションによって PathClassLoader 親クラス BaseDexClassLoader の pathList オブジェクトを取得します。
3. リフレクションによって pathList の dexElements オブジェクト (oldElement) を取得します
。 4. パッチ パッケージを Element 配列に変換します: patchElement (リフレクションにより makePathElements を実行)
5. patchElement+ oldElement = newElement (Array.newInstance) をマージします。
6. リフレクションにより、oldElement が newElement に割り当てられます。
3.4 ホットフィックスに存在するバージョン互換性の問題
AndroidN (つまり Andorid7.0)
JIT インスタント コンパイルとコンパイルを実行し、アプリで頻繁に使用されるいくつかのコード (ホット コードとも呼ばれます) をプロファイル ファイルに保存します。携帯電話がアイドル状態のときにこれらのホット コードが実行され、キャッシュが生成されます。
したがって、フック技術を使用してバグを修正したクラスをバグを修正したクラス配列の前に配置しても、キャッシュの理由により、バグを修正した要素配列にはアクセスできず、Get が実行されるため、ホット フィックスは失敗します。クラスをキャッシュから直接読み込んでいますが、このキャッシュ内のクラスにはバグがあります。したがって、ホットフィックスは機能しません。
上記の問題を解決するにはどうすればよいでしょうか?
実行時に PathClassLoader を置き換えるソリューションを採用し、カスタム PathClassLoader を再作成しますが、キャッシュされたコードは書き直さないでください。パフォーマンスに多少の影響はありますが、バグと比較すると、このパフォーマンスの低下はまだ価値があります。カスタム PathClassLoader は書き換えないため、キャッシュ ロジックでは、ホット フィックスの後、バグが修正されたクラスの実行が優先されるため、問題は解決されます。
Android5.0 Dalvik 仮想マシン
5.0 以下で使用されている仮想マシンは Darvik であり、異なる dex ファイルを使用するという問題があります。バグのある dex ファイルのクラスが他の dex ファイルのクラスを直接参照していない場合 ( )、このクラスはマークされます
需要对别的dex文件中类进行导包才行,反射不可以
。 isVerified; このマークの後、バグのある dex ファイルは他の dex ファイルのクラスを使用できなくなります。
上記の問題を解決するにはどうすればよいでしょうか?
バイトコード インスツルメンテーション テクノロジを使用すると、バグのあるクラスによってコンパイルされたクラス ファイルにバイトコード インスツルメンテーション テクノロジを通じて、別の dex ファイル内のクラスがインストルメンテーション テクノロジを通じてパッケージに書き込まれるため、バグが存在するクラスの isVerified マークがキャンセルされます。ホットフィックスによってバグ修正された dex ファイル内のクラスをバグ修正されたクラス配列の先頭に追加すると、バグ修正されたクラス内のコードが最初に実行されるようになります。
拡張知識:
バージョンが異なると、メソッド名、メソッド内のパラメータの数、型も異なるため、これらの状況に合わせてバージョンを調整する必要があります。
例: DexPathList クラスの makePathElements メソッドは、Element[] 配列を生成するために使用されます。バグ修正を優先するために、ホットフィックスによってバグ修正用の dex ファイルをこの配列の先頭に追加します。ただし、バージョンごとにこの方法にはいくつかの違いがあります。例:
Android9.0.0: makePathElements(List<File> files, File optimizedDirectory,List<IOException> suppressedExceptions)
Android5.1.0:makeDexElements(ArrayList<File> files, File optimizedDirectory, ArrayList<IOException> suppressedExceptions)
4. 自動パッチソリューション
4.1 カスタムプラグイン
独自のプラグインを開発するには 3 つの方法があります。
- Build script脚本
- プラグインを build.gradle に記述します。これは通常、単純なロジックに使用され、build.gradle ファイル内でのみ表示されます。
- buildSrc ディレクトリ
- プラグインのソース コードを buildSrc/src/main/groovy/ に配置します。このプロジェクトでのみ表示されます。
- Plugin インターフェイスを実装し、apply メソッドをオーバーライドします。
- 独立したプロジェクト
- 独立した Java プロジェクト/モジュールのファイルはウェアハウス (Jcenter) に公開できるため、他のプロジェクトが簡単にインポートできます。
4.2 パッチ パッケージにどのファイルをパッケージ化する必要があるかを決定する
キャッシュ メカニズムを使用して、前のクラス ファイルとこのクラス ファイルによって生成された md5 値を保存できます。
- キャッシュにそのようなクラス ファイルがない場合は、クラス ファイルが新しく作成されたことを意味するため、パッチ パッケージにパッケージ化する必要があります。
- このクラス ファイルがキャッシュ内にある場合は、キャッシュ内のクラス ファイルの md5 値が、再生成したクラス ファイルの md5 値と一致するかどうかを比較します。不一致とは、新しいクラス ファイルにコードが変更されていることを意味します。パッチ パッケージにパッケージ化する必要もあります。
- キャッシュ ファイルと新しく生成されたクラス ファイルの md5 値が同じ場合、パッチ パッケージに含める必要はありません。
拡張知識:
Java コードを通じてコマンド ラインを実行し、パッケージ化操作を実行できます。
- .javaを.classにコンパイルする
Runtime.getRuntime().exe("javac -bootclasspath android.jar路径 java源码和R.java路径");
- .class を .dex にコンパイルします
Runtime.getRuntime().exe("dx --dex classes路径");
4.3 コードの混乱の問題の解決策
-applyMapping 設定を通じて、今回の難読化後のクラス名が前回の難読化後のクラス名と同じであることを確認する必要があります。
コードを難読化すると、マッピングファイルが生成され、マッピングファイルがキャッシュされ、難読化されていないファイル名やメソッド名などを見つけて処理します。
面接の質問
1. ホットフィックス ソリューションとその違いについて教えてください。
ティンカー (テンセント) | QZone (テンセント) | アンドフィックス(アリ) | 堅牢 (美団) | |
---|---|---|---|---|
クラスの置き換え | Y | Y | N | N |
だから交換してください | Y | Y | N | N |
リソースの交換 | Y | Y | N | N |
すべてのプラットフォームで有効 | Y | Y | Y | Y |
時間内に効果的 | N | N | Y | Y |
パフォーマンスの損失 | 小さい | より大きな | 小さい | 小さい |
パッチサイズ | 小さい | より大きな | 動き | 動き |
透明性のある開発 | Y | Y | N | N |
複雑さ | 小さい | 小さい | 複雑 | 複雑 |
グラドルサポート | Y | N | N | N |
ロムボリューム | より大きな | 小さい | 小さい | 小さい |
成功率 | より高い | より高い | 動き | 最高 |
AndFix( 补丁包是.dex文件
)
は、Ali によって開発されたホットフィックス フレームワークですが、放棄され、長年にわたって保守されていません。
彼のホットフィックスの実装原理は次のとおりです。
ネイティブ層の Java 層を動的に置き換え、ネイティブ層を介して Java 層のコードをフックする方法です。
Robust( 补丁包是.dex文件
)
は Meituan によって開発され、現在 Douyin はこのホットフィックス ソリューションを採用しており、時間内に有効になる可能性があります。
彼のホットフィックスの実装原理は次のとおりです。gradle
プラグインを使用して、私たちが作成したクラス内で、コンパイル時に静的インターフェイス変数が生成され、そのインターフェイス変数がメソッド内で判断されます。
ホットフィックスを実行する必要がある場合は、インターフェイスの実装クラスを作成し、クラスのロードとリフレクションを通じて、作成したクラスを見つけてインスタンスを作成し、それを修正するクラス内の静的インターフェイス変数に割り当てる必要があります。私たちのメソッドは、インターフェース変数が空でないと判断された場合、バグ修正の目的を達成するために、実装クラスのビジネスロジックを実行し、時間内に有効になります。
Tinker( 补丁包是差分包
)
は Tencent によって開発されました。現在、WeChat はこのホットフィックス ソリューションを採用しています。利点は、クラス、パッケージ、リソース ファイルを修復できることです。
彼のホットフィックスの実装原理は次のとおりです:
バグのある apk ファイルとバグのある apk ファイルから差分パッケージ パッチが生成されます. このパッチ ファイルが私たちのパッチ パッケージです. 差分パッケージとバグのある apk をダウンロードします修復を生成します。バグ APK。リソース ファイルの修復がない場合は、ホット リペアを実現するために、クラス ロードとリフレクション テクノロジを通じてバグ修正クラスをロードできる .dex ファイルが生成されます。
2. ホットリペアにはどのような技術が使用されていますか? 親委託の仕組みについて教えてください。クラスのロードとリフレクションを通じてサーマル修復を実装する方法を教えてください。
ホットフィックスでは、クラスのロードとリフレクションの手法が使用されます。
親委任メカニズムとは、クラスが PathClassLoader を通じてロードされるとき、まずその親クラスにクラスのロードが委託され、親クラスが正常にロードできなかった場合、サブクラスがクラスをロードすることを意味します。
ホットリペア機能を実現するには、Hookテクノロジーを使用する必要があります。
つまり、バグのあるクラスをロードする前に、まずバグを修正したクラスをロードしてホット リペア技術を実現します。
class クラスは dex ファイルに含まれており、アプリが apk にパッケージ化されると、.dex ファイルが生成されます。ホットリペアを行う場合は、バグを修正したdexファイルを生成し、リフレクション技術を使用してPathClassLoaderの取得を前提にその親クラスBaseDexClassLoaderをリフレクションで取得し、(DexPathList)pathList内のプロパティを取得する必要があります。次に、このプロパティの Element[] 配列を取得します。この Element[] 配列はバグのある配列です。
配列内の各 Element 要素は dex ファイルに対応するため、リフレクション技術を通じてバグ修正された dex ファイルをダウンロードし、makeElement メソッドを使用してバグ修正された Element[] 配列を生成するだけで済みます。
最終的に、バグが修正された Element[] 配列とバグが修正された Element[] 配列が新しい配列を形成します。バグが修正された配列要素が前にあり、バグのある配列要素が後ろにあります。クラスがロードおよびロードされるときに、バグが修正された Element 配列の要素に最初にロードされるクラス クラスが、バグを修正します。