Andorid內Aspectj切面失效分析
背景
通過切面程式設計,可以做一些原始碼的bug修復,也可以動態插入模組,最近發現開發期間切面插入的記憶體洩漏檢測失效,本文為排查aop失效的一些採坑記錄
app類查詢
既然結果是記憶體洩漏檢測工具不生效,有可能是sdk沒整合,也有可可能是切面邏輯沒生效。
首先檢查構建內是否存在目的碼,檢測辦法有很多,可以反編譯,也可以利用Andorid的構建工具。 我們一apk為輸入,檢查一下dex內是否存在特定類的定義:
./findClassDefinition "Lcom/squareup/leakcanary/LeakCanary;"
#!/usr/bin/env bash ################################################################## ## ##find class definition inside apk ## ## ##Author: Chaobin Wu ##Email : [email protected] ## ################################################################# die() { echo "$*" exit 1 } target=$1 unzip app.apk -d apk dex=(apk/*.dex) for file in "${dex[@]}"; do if [ -f $file ]; then echo $file /Users/aven/Android/sdk/build-tools/28.0.3/dexdump -f $file |grep "Class descriptor"|grep $target fi done
觀察日誌,記憶體洩漏的SDK已經正常整合在apk中,可以縮小排查範圍:切面織入是否正常
織入排查
這一步主要藉助構建日誌,如果不知道關鍵詞,需要猜測,比如我們進行切面使用的是aspectj,結合aspect的gralde外掛,因此可能從這兩塊入手
通過原始碼分析,我們使用的aspect外掛會在織入程式碼的的整個過程中列印日誌:
@Override void transform(Context context , Collection<TransformInput> inputs , Collection<TransformInput> referencedInputs , TransformOutputProvider outputProvider , boolean isIncremental) throws IOException, TransformException, InterruptedException { def hasAjRt = false for (TransformInput transformInput : inputs) { for (JarInput jarInput : transformInput.jarInputs) { if (jarInput.file.absolutePath.contains(ASPECTJRT)) { hasAjRt = true break } } if (hasAjRt) break } //clean if (!isIncremental){ outputProvider.deleteAll() } if (hasAjRt){ doAspectTransform(outputProvider, inputs) } else { println "there is no aspectjrt dependencies in classpath, do nothing " inputs.each {TransformInput input -> input.directoryInputs.each {DirectoryInput directoryInput-> def dest = outputProvider.getContentLocation(directoryInput.name, directoryInput.contentTypes, directoryInput.scopes, Format.DIRECTORY) FileUtil.copyDir(directoryInput.file, dest) println "directoryInput = ${directoryInput.name}" } input.jarInputs.each {JarInput jarInput-> def jarName = jarInput.name def dest = outputProvider.getContentLocation(jarName, jarInput.contentTypes, jarInput.scopes, Format.JAR) FileUtil.copyFile(jarInput.file, dest) println "jarInput = ${jarInput.name}" } } } }
通過關鍵詞aspect我們在構建日誌中發現了疑點:
[exec] All input files are considered out-of-date for incremental task ':xxx:transformClassesWithAspectTransformForWubaRelease'. [exec] there is no aspectjrt dependencies in classpath, do nothing [exec] directoryInput = 227d4cde62a03f51cebc924536e7bc58a25234d7 [exec] jarInput = android.local.jars:umeng-analytics-v6.0.6.jar:2eb55ec9f71567b44cd7ff07aaee798f8e6399fe_7fbda719eb29ecc1fe8606561b0f5e00 [exec] jarInput = org.aspectj:aspectjrt:1.8.9_7cbb886c3064be16fb8fef6099002200
there is no aspectjrt dependencies in classpath, do nothing
整個提示在外掛原始碼中也可以找到出處,本意是判定當前編譯路徑中不包含切面所需要的aspectjrt,結合日誌和原始碼,整個錯誤提示是有問題的,
[exec] jarInput = org.aspectj:aspectjrt:1.8.9_7cbb886c3064be16fb8fef6099002200
這個輸出我們可以知道依賴是存在的。
這裡我們為了方便管理過濾原始碼,提高效率和程式碼簡潔性,使用了android-aspectjx
在專案的github主頁上,也發現類似返回:
https://github.com/HujiangTechnology/gradle_plugin_android_aspectjx/issues/50
總結一下就是1.1.1之前的版本在jdk8環境下切面處理失敗,導致編譯正常,但是沒有成功織入程式碼,具體修復說明詳見:https://github.com/HujiangTechnology/gradle_plugin_android_aspectjx/commit/ceab2726c0a574f6df28382eb5e75d7ecfc512ee
從提交摘要來看,作者將對aspectjrt的判斷邏輯調整了了,針對非test的case不在判斷。
問題修復
修復切面失效的有兩個辦法:1.升級android-aspeect外掛到修改版本;2.不使用該外掛,自行配置java編譯器引數 方案1可以選擇升級到2.x
驗證織入是否成功,可以檢查編譯檔案,相比較排查apk檔案,更加直觀。具體路徑為build/intermediates/transforms/ajx/
一層層遞進查詢,知道看到一堆的jar檔案,這些就是class的歸檔jar包,通過遍歷這些jar找到你的目標插入程式碼類,就可以肉眼確認切面是否插入成功。
#!/usr/bin/env bash ################################################################## ## ##find keyword inside jar ## ## ##Author: Chaobin Wu ##Email : [email protected] ## ################################################################# die() { echo "$*" exit 1 } echo "start" target=$1 jar=(xx/build/intermediates/transforms/ajx/wuba/debug/*.jar) for file in "${jar[@]}"; do if [ -f $file ]; then echo $file unzip -l $file |grep $target fi done
相關連線
- https://github.com/HujiangTechnology/gradle_plugin_android_aspectjx/blob/v1.0.10/aspectjx/src/main/groovy/com/hujiang/gradle/plugin/android/aspectjx/AspectTransform.groovy
- https://github.com/HujiangTechnology/gradle_plugin_android_aspectjx/issues/50
- https://github.com/HujiangTechnology/gradle_plugin_android_aspectjx/commit/ceab2726c0a574f6df28382eb5e75d7ecfc512ee