What is the principle of “Apply Changes” provided by Android Studio 3.5? Have an answer JVMTI, but a master did not give a code, see https://github.com/AndroidAdvanceWithGeektime/JVMTI_Sample in making the great spirit of the project, then this blog post practice

1. Let’s look at the effect first

1. First, Android P (9.0) started to support JVMTI

So try to test it on the 9.0 official simulator

2. Apply jVMTI principle to calculate object

Code address: github.com/zjw-swun/JV… Thanks again github.com/AndroidAdva… Dodola bosses

Jvmti agent: JVMti agent: jVMti agent: JVMti agent: JVMti agent: JVMti Agent This feature is available in Android Studio 3.5 with the “Apply Changes” feature, which will be available in Android P (9.0)

There is no API for calculating the size of an object, but if you are familiar with Java, you should know that the Instrument class has a getObjectSize method. To implement getObjectSize, this method is not provided until android P (9.0) supports JVMTI. The getObjectSize method can also be calculated by using www.jb51.net/article/598… H, search for the keyword getObjectSize and find the object code

jvmtiError GetObjectSize(jobject object,
            jlong* size_ptr) {
    return functions->GetObjectSize(this, object, size_ptr);
  }
Copy the code

Native -lib. CPP added support for GetObjectSize function, details can refer to git submission record, the following is a brief introduction

extern "C" JNIEXPORT jlong JNICALL tempGetObjectSize(JNIEnv *env,
                                                   jclass clazz,
                                                   jobject obj) {
}

static JNINativeMethod methods[] = {
      {"getObjectSize"."(Ljava/lang/Object;) J", reinterpret_cast<jlong *>(tempGetObjectSize)},
      {"retransformClasses"."([Ljava/lang/Class;)V", reinterpret_cast<void *>(tempRetransformClasses)}
};

JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
  JNIEnv *env;
  if(vm->GetEnv((void **) &env, JNI_VERSION_1_6) ! = JNI_OK) {return JNI_ERR;
  }
  ALOGI("==============library load====================");
  jclass clazz = env->FindClass("com/dodola/jvmtilib/JVMTIHelper");
  env->RegisterNatives(clazz, methods, sizeof(methods) / sizeof(methods[0]));
  return JNI_VERSION_1_6;
}
Copy the code

Dynamically register a {“getObjectSize”, “(Ljava/lang/Object;) in JNI_OnLoad. J”, reinterpret_cast

(tempGetObjectSize)}, then add the following statement to the JvmTINativeMethodBind function

extern "C" JNIEXPORT jlong JNICALL getObjectSize(JNIEnv *env, jclass clazz, jobject obj) {
  jlong size;
  jvmtiError result = localJvmtiEnv->GetObjectSize(obj, &size);
  ALOGI("==========getObjectSize %d=======", size);
  if(result ! = JVMTI_ERROR_NONE) { char *err;localJvmtiEnv->GetErrorName(result, &err);
      printf("Failure running GetObjectSize: %s\n", err);
      localJvmtiEnv->Deallocate(reinterpret_cast<unsigned char *>(err));
      return- 1; }return size;
}
Copy the code

Add the following statement to the JvmTINativeMethodBind function

 jmethodID methodid2 = jni_env->GetStaticMethodID(clazz, "getObjectSize"."(Ljava/lang/Object;) J");
  if (methodid2 == method) {
      *new_address_ptr = reinterpret_cast<jlong *>(&getObjectSize);
  }
Copy the code

So now we’re done loading jvmti.so and then we can call getObjectSize

Of course the JVMtiHelper. Java class forgets to add JNI Native functions

public static native long getObjectSize(Object obj);
Copy the code

Then the effect will be the same as the above illustration

3. Jvmti. H has a lot of other functions

Jvmti. H RedefineClasses and RetransformClasses are the key to implementing Apply Changes