public Class<? extends T> buildProxyClass() throws IOException {
    ClassLoader requestedClassloader;
    if (sharedClassLoader) {
      requestedClassloader = baseClass.getClassLoader();
    } else {
      requestedClassloader = parentClassLoader;
    }

    // try the cache to see if we've generated this one before
    // we only populate the map with matching types
    ProxiedClass<T> cacheKey =
        new ProxiedClass<>(baseClass, interfaces, requestedClassloader, sharedClassLoader);
    @SuppressWarnings("unchecked")
    Class<? extends T> proxyClass = (Class) generatedProxyClasses.get(cacheKey);
    if (proxyClass != null) {
      return proxyClass; // cache hit!
    }

    // the cache missed; generate the class
    DexMaker dexMaker = new DexMaker();
    String generatedName = getMethodNameForProxyOf(baseClass, interfaces);
    TypeId<? extends T> generatedType = TypeId.get("L" + generatedName + ";");
    TypeId<T> superType = TypeId.get(baseClass);
    generateConstructorsAndFields(dexMaker, generatedType, superType, baseClass);

    Method[] methodsToProxy;
    if (methods == null) {
      methodsToProxy = getMethodsToProxyRecursive();
    } else {
      methodsToProxy = methods;
    }

    // Sort the results array so that they are in a deterministic fashion.
    //
    // We use the same parameters to sort as used in {@link MethodId#hashCode}. This is needed
    // as e.g. making a method "public" instead of "protected" should not change the id's of the
    // methods. If the id's would change the classes loaded from the cache would be incorrect.
    Arrays.sort(
        methodsToProxy,
        new Comparator<Method>() {
          @Override
          public int compare(Method method1, Method method2) {
            String m1Signature =
                method1.getDeclaringClass()
                    + method1.getName()
                    + Arrays.toString(method1.getParameterTypes())
                    + method1.getReturnType();
            String m2Signature =
                method2.getDeclaringClass()
                    + method2.getName()
                    + Arrays.toString(method2.getParameterTypes())
                    + method2.getReturnType();

            return m1Signature.compareTo(m2Signature);
          }
        });

    generateCodeForAllMethods(dexMaker, generatedType, methodsToProxy, superType);
    dexMaker.declare(
        generatedType, generatedName + ".generated", PUBLIC, superType, getInterfacesAsTypeIds());
    if (sharedClassLoader) {
      dexMaker.setSharedClassLoader(requestedClassloader);
    }
    if (markTrusted) {
      // The proxied class might have blacklisted methods. Blacklisting methods (and fields)
      // is a new feature of Android P:
      //
      // https://android-developers.googleblog.com/2018/02/
      // improving-stability-by-reducing-usage.html
      //
      // The newly generated class might not be allowed to call methods of the proxied class
      // if it is not trusted. As it is not clear which classes have blacklisted methods, mark
      // all generated classes as trusted.
      dexMaker.markAsTrusted();
    }
    ClassLoader classLoader;
    if (sharedClassLoader) {
      classLoader = dexMaker.generateAndLoad(null, dexCache);
    } else {
      classLoader = dexMaker.generateAndLoad(parentClassLoader, dexCache);
    }
    try {
      proxyClass = loadClass(classLoader, generatedName);
    } catch (IllegalAccessError e) {
      // Thrown when the base class is not accessible.
      throw new UnsupportedOperationException("cannot proxy inaccessible class " + baseClass, e);
    } catch (ClassNotFoundException e) {
      // Should not be thrown, we're sure to have generated this class.
      throw new AssertionError(e);
    }
    setMethodsStaticField(proxyClass, methodsToProxy);
    generatedProxyClasses.put(cacheKey, proxyClass);
    return proxyClass;
  }
Generate a proxy class. Note that new instances of this class will not automatically have an an
invocation handler, even if {@link #handler(InvocationHandler)} was called. The handler must be
set on each instance after it is created, using {@link #setInvocationHandler(Object,
InvocationHandler)}.
android/android_framework/dex-maker/src/main/java/com/android/dx/stock/ProxyBuilder.java