andfix热修复核心代码解析

前言

https://ke.qq.com/webcourse/index.html#course_id=130901&term_id=100146035&taid=1287279008153429&vid=r1417pykrgc
学习了下这个视频的热修复方法。成功实现,但是还是遇到了一些问题。这里记录下,帮助大家学习。

代码分析

首先先简单的代码分析一下。

//问题代码
class Calculator {
    fun calc(): Int {
        return 100 / 0
    }
}

//修复后代码
class Calculator {
    @Replace(clazz = "**.Calculator", method = "calc")
    fun calc(): Int {
        return 100
    }
}

原理:替换Art虚拟机中有问题的类的方法,为修复后的方法。(Android 5.0以上)
视频中已有详细介绍,这里就不多赘述了。

fun loadDex(context: Context, dexName: String) {
        val cacheFile: File
        if (Environment.getExternalStorageState() == Environment.MEDIA_MOUNTED) {
            cacheFile = context.externalCacheDir
        } else {
            cacheFile = context.cacheDir
        }
        val file = File(cacheFile, "dxtest")
        file.deleteOnExit()
        val dexFile = DexFile(File("/storage/emulated/0/", dexName).absolutePath)

        val iterator = dexFile.entries()
        while (iterator.hasMoreElements()) {
            val clazzName = iterator.nextElement()
            val clazz = Class.forName(clazzName)
            //遍历类方法根据注解替换
            clazz.declaredMethods.forEach { method ->
                val replacObj = method.getAnnotation(Replace::class.java)
                val replaceClazz = Class.forName(replacObj.clazz)
                val replaceMethod = replaceClazz.getDeclaredMethod(replacObj.method, *method.parameterTypes)
                fixMethod(replaceMethod, method)
            }
        }
    }
....
private external fun fixMethod(replaceMethod: Method, method: Method)

先单独把修复后的Calculator.class打包,利用dx命令打包成out.dex,然后放到/storage/emulated/0/目录下。

JNIEXPORT void JNICALL
Java_**_fixMethod(JNIEnv *env, jobject thiz,jobject replaceMethod, jobject method) {
    art::mirror::ArtMethod *artReplaceMethod = (art::mirror::ArtMethod *) env->FromReflectedMethod(
            replaceMethod);

    art::mirror::ArtMethod *artMethod = (art::mirror::ArtMethod *) env->FromReflectedMethod(
            method);

    artReplaceMethod->access_flags_ = artMethod->access_flags_;
    artReplaceMethod->declaring_class_ = artMethod->declaring_class_;
    artReplaceMethod->dex_code_item_offset_ = artMethod->dex_code_item_offset_;
    artReplaceMethod->dex_method_index_ = artMethod->dex_method_index_;
    artReplaceMethod->hotness_count_ = artMethod->hotness_count_;
    artReplaceMethod->method_index_ = artMethod->method_index_;
    artReplaceMethod->ptr_sized_fields_.dex_cache_resolved_methods_ = artMethod->ptr_sized_fields_.dex_cache_resolved_methods_;
    artReplaceMethod->ptr_sized_fields_.dex_cache_resolved_types_ = artMethod->ptr_sized_fields_.dex_cache_resolved_types_;
    artReplaceMethod->ptr_sized_fields_.entry_point_from_jni_ = artMethod->ptr_sized_fields_.entry_point_from_jni_;
    artReplaceMethod->ptr_sized_fields_.entry_point_from_quick_compiled_code_ = artMethod->ptr_sized_fields_.entry_point_from_quick_compiled_code_;
}

按照视频中所说的,把ArtMehod中的变量一一替换。

问题记录

  1. 困扰我最久的是,访问sdcard,6.0以上需要手动申请,这也是自己粗心。视频中貌似也没有详细提到。而且最让我头疼的是logcat中的报错信息。
Caused by: java.io.IOException: No original dex files found for dex location /storage/emulated/0/out.dex
...

于是开始百度,google

image.png

没有讲到权限问题的。
这里值得一提的是曾今在使用VirtualApk插件化技术的时候,也是遇到这种问题,必须要手到申请下权限,不然就会报错。

后面灵光一闪。添加了权限申请就好了。

  1. 视频中提到了需要使用到art_method.h,但是里面的东西又不能全部拿来用,因为会涉及到很多其他的头文件,所以只要ArtMethod的结构体就好了。
    android源码很大,这里我没有去下载,直接访问http://androidxref.com/7.0.0_r1/xref/art/runtime/art_method.h#mirror
    查看自己需要的内容。
/*
 * Copyright (C) 2011 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef ART_RUNTIME_ART_METHOD_H_A
#define ART_RUNTIME_ART_METHOD_H_A


namespace art {

    union JValue;

    class OatQuickMethodHeader;

    class ProfilingInfo;

    class ScopedObjectAccessAlreadyRunnable;

    class StringPiece;

    class ShadowFrame;

    namespace mirror {
        class Array;

        class Class;

        class IfTable;

        class PointerArray;
        
        class ImtConflictTable {
            enum MethodIndex {
                kMethodInterface,
                kMethodImplementation,
                kMethodCount,  // Number of elements in enum.
            };

        private:
            union {
                uint32_t data32_[0];
                uint64_t data64_[0];
            };

        };

        class ArtMethod {
        public:
            uint32_t declaring_class_;
            uint32_t access_flags_;
            uint32_t dex_code_item_offset_;
            uint32_t dex_method_index_;
            uint16_t method_index_;
            uint16_t hotness_count_;
            struct PtrSizedFields {
                ArtMethod **dex_cache_resolved_methods_;
                uint32_t *dex_cache_resolved_types_;
                void *entry_point_from_jni_;
                void *entry_point_from_quick_compiled_code_;
            } ptr_sized_fields_;

        };

    }
} // namespace art

#endif  // ART_RUNTIME_ART_METHOD_H_A

我这里去掉了一些不需要的内容,最重要的是要把ArtMethod结构体中的参数列出来。

  1. 测试,在华为荣耀v9中可以。在内置的android虚拟机中,debug模式下可以,正常运行后无法替换,比较奇怪,后续有发现原因,再补充。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,753评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,668评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,090评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,010评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,054评论 6 395
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,806评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,484评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,380评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,873评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,021评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,158评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,838评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,499评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,044评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,159评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,449评论 3 374
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,136评论 2 356

推荐阅读更多精彩内容