AndFix解析——(上)
アリババはこの間、オンラインの緊急バグを解決するためのAndroidライブラリをオープンしました.
自分の経験に基づいて、長すぎる文字を一気に見る人は少ないので、複数編に分けて分析するつもりです.これはこのライブラリ解析の最初の編です.
まず、その中のDemoコードを見てみましょう.ここで、ロードライブラリを呼び出すコードは次のようになります.
まずPatchManagerのコンストラクション関数によって
PatchManagerコンストラクション関数
では、
もとはContextオブジェクトの参照を維持し、AndFixManagerオブジェクトを初期化し、mPatchDirオブジェクトはPatchファイルを格納するフォルダであり、Patchの集合を初期化し、ClassLoaderを持つMapもある.
その中のいくつかの内容の声明は以下の通りです.
コンストラクション関数の解析はここで終わります.まずPatchとAndFixManagerの2つのクラスに深くフォローしません.
PatchManager init(String version)
次に
次に、上記のコードの次のコードを分析します.
まずelse内の内容を見て、elseの実行力
ソースコードのコメントのように、以前の2つのフォルダの下にあったすべてのパッチファイルが削除されます.
では、
コードは簡単ですが、mPatchDirフォルダの下のファイルをパラメータとして
上のコードはよく理解されていますが、この時、私たちはすでに完全に
次に、私たちはdemoに従って歩き続け、2つの方法を実行します.1つの
簡単に言えば、上記の方法は、/data/data/{パッケージ名}/apatchディレクトリにパッチファイルをコピーし、OptiFileフォルダに存在する場合は削除します.次に、別の
この方法で主にしていることは注釈でわかりますが、ここでは最初の分析が終わります.
原文住所:http://yunair.github.io/blog/2015/09/25/AndFix-%E8%A7%A3%E6%9E%90(%E4%B8%8A).html
AndFix
Android開発者にとっては本当に良いニュースです.自分の経験に基づいて、長すぎる文字を一気に見る人は少ないので、複数編に分けて分析するつもりです.これはこのライブラリ解析の最初の編です.
まず、その中のDemoコードを見てみましょう.ここで、ロードライブラリを呼び出すコードは次のようになります.
/**
* sample application
*
* @author sanping.li@alipay.com
*
*/
public class MainApplication extends Application {
private static final String TAG = "euler";
private static final String APATCH_PATH = "/out.apatch";
/**
* patch manager
*/
private PatchManager mPatchManager;
@Override
public void onCreate() {
super.onCreate();
// initialize
mPatchManager = new PatchManager(this);
mPatchManager.init("1.0");
Log.d(TAG, "inited.");
// load patch
mPatchManager.loadPatch();
Log.d(TAG, "apatch loaded.");
// add patch at runtime
try {
// .apatch file path
String patchFileString = Environment.getExternalStorageDirectory()
.getAbsolutePath() + APATCH_PATH;
mPatchManager.addPatch(patchFileString);
Log.d(TAG, "apatch:" + patchFileString + " added.");
} catch (IOException e) {
Log.e(TAG, "", e);
}
}
}
まずPatchManagerのコンストラクション関数によって
PatchManager
オブジェクトが初期化されていることがわかります.PatchManagerコンストラクション関数
では、
PatchManager
対象の中には何があるのか、深く理解してみましょう.public PatchManager(Context context) {
this.mContext = context;
this.mAndFixManager = new AndFixManager(this.mContext);
this.mPatchDir = new File(this.mContext.getFilesDir(), "apatch");
this.mPatchs = new ConcurrentSkipListSet();
this.mLoaders = new ConcurrentHashMap();
}
もとはContextオブジェクトの参照を維持し、AndFixManagerオブジェクトを初期化し、mPatchDirオブジェクトはPatchファイルを格納するフォルダであり、Patchの集合を初期化し、ClassLoaderを持つMapもある.
その中のいくつかの内容の声明は以下の通りです.
private final Context mContext;
private final AndFixManager mAndFixManager;
private final File mPatchDir;
private final SortedSet<Patch> mPatchs;
private final Map<String, ClassLoader> mLoaders;
コンストラクション関数の解析はここで終わります.まずPatchとAndFixManagerの2つのクラスに深くフォローしません.
PatchManager init(String version)
次に
PatchManager
クラスのinit(String version)
関数を分析し、まずコードを見てみましょう.public void init(String appVersion) {
// mPatchDir , , , Log
if(!this.mPatchDir.exists() && !this.mPatchDir.mkdirs()) {
Log.e("PatchManager", "patch dir create error.");
} else if(!this.mPatchDir.isDirectory()) {
// ,
this.mPatchDir.delete();
} else {
// _andfix_ SharedPreferences ,
SharedPreferences sp = this.mContext.getSharedPreferences("_andfix_", 0);
String ver = sp.getString("version", (String)null);
if(ver != null && ver.equalsIgnoreCase(appVersion)) {
this.initPatchs();
} else {
this.cleanPatch();
sp.edit().putString("version", appVersion).commit();
}
}
}
次に、上記のコードの次のコードを分析します.
// _andfix_ ver null, ver
if(ver != null && ver.equalsIgnoreCase(appVersion)) {
this.initPatchs();
} else {
this.cleanPatch();
sp.edit().putString("version", appVersion).commit();
}
まずelse内の内容を見て、elseの実行力
cleanPatch()
と外部を初期化したときに渡されたバージョン番号をSharedPreferencesに入れます.cleanPatch()
どんな操作をしたのか、中に入ってみましょうprivate void cleanPatch() {
// mPatchDir
File[] files = this.mPatchDir.listFiles();
File[] arr$ = files;
int len$ = files.length;
for(int i$ = 0; i$ < len$; ++i$) {
File file = arr$[i$];
// OptFile
this.mAndFixManager.removeOptFile(file);
// file , , file ,
if(!FileUtil.deleteFile(file)) {
Log.e("PatchManager", file.getName() + " delete error.");
}
}
}
ソースコードのコメントのように、以前の2つのフォルダの下にあったすべてのパッチファイルが削除されます.
では、
this.initPatchs()
何をしたかを分析してみましょう.private void initPatchs() {
File[] files = this.mPatchDir.listFiles();
File[] arr$ = files;
int len$ = files.length;
for(int i$ = 0; i$ < len$; ++i$) {
File file = arr$[i$];
this.addPatch(file);
}
}
コードは簡単ですが、mPatchDirフォルダの下のファイルをパラメータとして
addPatch(File)
メソッドに渡しました.ではthis.addPatch(file)
は何をしましたか.// .apatch Patch , Patch,
// Patch Patch mPatchs
private Patch addPatch(File file) {
Patch patch = null;
// ".apatch"
if(file.getName().endsWith(".apatch")) {
try {
patch = new Patch(file);
this.mPatchs.add(patch);
} catch (IOException var4) {
Log.e("PatchManager", "addPatch", var4);
}
}
return patch;
}
上のコードはよく理解されていますが、この時、私たちはすでに完全に
init(String version)
という方法を歩いてきました.再びPatchというクラスが現れましたが、私たちは依然としてそれを片側に置いています.紙幅の制限のため、最初のクラスはこのクラスを分析しません.次に、私たちはdemoに従って歩き続け、2つの方法を実行します.1つの
mPatchManager.loadPatch()
、1つのmPatchManager.addPatch(patchFileString)
、loadPatch()
方法はこのライブラリが置換を実行する核心方法です.私は後で単独で文章を書いて分析します.だから、この文章の最後に、私たちはaddPatch(String)
という方法についてフォローします.public void addPatch(String path) throws IOException {
File src = new File(path);
File dest = new File(this.mPatchDir, src.getName());
if(dest.exists()) {
// mPatchDir , AndFixManager
this.mAndFixManager.removeOptFile(dest);
}
// src dest, NIO
FileUtil.copyFile(src, dest);
// addPatch ,
Patch patch = this.addPatch(dest);
if(patch != null) {
// loadPatch(Patch)
this.loadPatch(patch);
}
}
簡単に言えば、上記の方法は、/data/data/{パッケージ名}/apatchディレクトリにパッチファイルをコピーし、OptiFileフォルダに存在する場合は削除します.次に、別の
addPatch(File)
メソッドを呼び出し、次にloadPatch()
メソッドを再ロードします.private Patch addPatch(File file) {
Patch patch = null;
if(file.getName().endsWith(".apatch")) {
try {
patch = new Patch(file);
// file patch mPatchs Set
this.mPatchs.add(patch);
} catch (IOException var4) {
Log.e("PatchManager", "addPatch", var4);
}
}
return patch;
}
この方法で主にしていることは注釈でわかりますが、ここでは最初の分析が終わります.
原文住所:http://yunair.github.io/blog/2015/09/25/AndFix-%E8%A7%A3%E6%9E%90(%E4%B8%8A).html