美文网首页Android进阶之路Android开发Android开发
anroid热修复方法替换遇到的几个问题

anroid热修复方法替换遇到的几个问题

作者: javalong | 来源:发表于2018-07-25 16:36 被阅读2次

    前言

    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模式下可以,正常运行后无法替换,比较奇怪,后续有发现原因,再补充。

    相关文章

      网友评论

      • wsxiaoluob:牛逼,深刻,好用,贼特么棒棒极了!

      本文标题:anroid热修复方法替换遇到的几个问题

      本文链接:https://www.haomeiwen.com/subject/yaopmftx.html