AndFixSource

核心方法addReplaceMethod(Method src, Method dest)

AndFixManager.java

fix

public synchronized void fix(String patchPath) {
   fix(new File(patchPath), mContext.getClassLoader(), null);
}
//加载补丁包中所有类所有方法,如果拥有注解methodReplace,则触发replaceMethod
public synchronized void fix(File file, ClassLoader classLoader,
      List<String> classes) {
  			final DexFile dexFile = DexFile.loadDex(file.getAbsolutePath(),
					optfile.getAbsolutePath(), Context.MODE_PRIVATE);
  
  ClassLoader patchClassLoader = new ClassLoader(classLoader) {//以当前classLoader作为parentClassLoader优先查找
				@Override
				protected Class<?> findClass(String className)
						throws ClassNotFoundException {
					Class<?> clazz = dexFile.loadClass(className, this);
					if (clazz == null
							&& className.startsWith("com.alipay.euler.andfix")) {
						return Class.forName(className);// annotation’s class
														// not found
					}
					if (clazz == null) {
						throw new ClassNotFoundException(className);
					}
					return clazz;
				}
			};
	Enumeration<String> entrys = dexFile.entries();
			Class<?> clazz = null;
			while (entrys.hasMoreElements()) {
				String entry = entrys.nextElement();
				if (classes != null && !classes.contains(entry)) {
					continue;// skip, not need fix
				}
				clazz = dexFile.loadClass(entry, patchClassLoader);
				if (clazz != null) {
					fixClass(clazz, classLoader);
				}
			}

fixClass

private void fixClass(Class<?> clazz, ClassLoader classLoader) {
   Method[] methods = clazz.getDeclaredMethods();
   MethodReplace methodReplace;
   String clz;
   String meth;
   for (Method method : methods) {
      methodReplace = method.getAnnotation(MethodReplace.class);
      if (methodReplace == null)
         continue;
      clz = methodReplace.clazz();
      meth = methodReplace.method();
      if (!isEmpty(clz) && !isEmpty(meth)) {
         replaceMethod(classLoader, clz, meth, method);
      }
   }
}

replaceMethod

/**
 * replace method
 * 
 * @param classLoader classloader
 * @param clz class
 * @param meth name of target method 
 * @param method source method
 */
private void replaceMethod(ClassLoader classLoader, String clz,
      String meth, Method method) {
   try {
      String key = clz + "@" + classLoader.toString();
      Class<?> clazz = mFixedClass.get(key);
      if (clazz == null) {// class not load
         Class<?> clzz = classLoader.loadClass(clz);
         // initialize target class
         clazz = AndFix.initTargetClass(clzz);
      }
      if (clazz != null) {// initialize class OK
         mFixedClass.put(key, clazz);
         Method src = clazz.getDeclaredMethod(meth,
               method.getParameterTypes());
         AndFix.addReplaceMethod(src, method);
      }
   } catch (Exception e) {
      Log.e(TAG, "replaceMethod", e);
   }
}

AndFix.java

addReplaceMethod

public static void addReplaceMethod(Method src, Method dest) {
   try {
      replaceMethod(src, dest);
      initFields(dest.getDeclaringClass());
   } catch (Throwable e) {
      Log.e(TAG, "addReplaceMethod", e);
   }
}

private static native void replaceMethod(Method dest, Method src);

andfix.cpp

replaceMethod

static void replaceMethod(JNIEnv* env, jclass clazz, jobject src,
      jobject dest) {
   if (isArt) {
      art_replaceMethod(env, src, dest);
   } else {
      dalvik_replaceMethod(env, src, dest);
   }
}

art_method_replace.cpp

art_replaceMethod

extern void __attribute__ ((visibility ("hidden"))) art_replaceMethod(
      JNIEnv* env, jobject src, jobject dest) {
    if (apilevel > 23) {
        replace_7_0(env, src, dest);
    } else if (apilevel > 22) {
      replace_6_0(env, src, dest);
   } else if (apilevel > 21) {
      replace_5_1(env, src, dest);
   } else if (apilevel > 19) {
      replace_5_0(env, src, dest);
    }else{
        replace_4_4(env, src, dest);
    }
}

art_method_replace_7_0.cpp

replace_7_0

void replace_7_0(JNIEnv* env, jobject src, jobject dest) {
	art::mirror::ArtMethod* smeth =
			(art::mirror::ArtMethod*) env->FromReflectedMethod(src);

	art::mirror::ArtMethod* dmeth =
			(art::mirror::ArtMethod*) env->FromReflectedMethod(dest);

//	reinterpret_cast<art::mirror::Class*>(smeth->declaring_class_)->class_loader_ =
//			reinterpret_cast<art::mirror::Class*>(dmeth->declaring_class_)->class_loader_; //for plugin classloader
	reinterpret_cast<art::mirror::Class*>(dmeth->declaring_class_)->clinit_thread_id_ =
			reinterpret_cast<art::mirror::Class*>(smeth->declaring_class_)->clinit_thread_id_;
	reinterpret_cast<art::mirror::Class*>(dmeth->declaring_class_)->status_ =
			reinterpret_cast<art::mirror::Class*>(smeth->declaring_class_)->status_ -1;
	//for reflection invoke
	reinterpret_cast<art::mirror::Class*>(dmeth->declaring_class_)->super_class_ = 0;

	smeth->declaring_class_ = dmeth->declaring_class_;
	smeth->access_flags_ = dmeth->access_flags_  | 0x0001;
	smeth->dex_code_item_offset_ = dmeth->dex_code_item_offset_;
	smeth->dex_method_index_ = dmeth->dex_method_index_;
	smeth->method_index_ = dmeth->method_index_;
	smeth->hotness_count_ = dmeth->hotness_count_;

	smeth->ptr_sized_fields_.dex_cache_resolved_methods_ =
			dmeth->ptr_sized_fields_.dex_cache_resolved_methods_;
	smeth->ptr_sized_fields_.dex_cache_resolved_types_ =
			dmeth->ptr_sized_fields_.dex_cache_resolved_types_;

	smeth->ptr_sized_fields_.entry_point_from_jni_ =
			dmeth->ptr_sized_fields_.entry_point_from_jni_;
	smeth->ptr_sized_fields_.entry_point_from_quick_compiled_code_ =
			dmeth->ptr_sized_fields_.entry_point_from_quick_compiled_code_;

	LOGD("replace_7_0: %d , %d",
			smeth->ptr_sized_fields_.entry_point_from_quick_compiled_code_,
			dmeth->ptr_sized_fields_.entry_point_from_quick_compiled_code_);

}

参考

https://github.com/alibaba/AndFix