class LayoutlibClassLoader extends ClassLoader {

  @VisibleForTesting
  static void generate(@NotNull Class<?> originalBuildClass, @NotNull BiConsumer<String, byte[]> defineClass) {
    ClassLoader loader = originalBuildClass.getClassLoader();
    String originalBuildClassName = originalBuildClass.getName();
    String originalBuildBinaryClassName = toBinaryClassName(originalBuildClassName);
    Deque<String> pendingClasses = new LinkedList<>();
    pendingClasses.push(originalBuildClassName);

    Remapper remapper = new Remapper() {
      @Override
      public String map(String typeName) {
        if (typeName.startsWith(originalBuildBinaryClassName)) {
          return "android/os/Build" + StringUtil.trimStart(typeName, originalBuildBinaryClassName);
        }

        return typeName;
      }
    };

    while (!pendingClasses.isEmpty()) {
      String name = pendingClasses.pop();

      String newName = "android.os.Build" + StringUtil.trimStart(name, originalBuildClassName);
      String binaryName = toBinaryClassName(name);

      try (InputStream is = loader.getResourceAsStream(binaryName + ".class")) {
        ClassWriter writer = new ClassWriter(0);
        ClassReader reader = new ClassReader(is);
        ClassRemapper classRemapper = new ClassRemapper(writer, remapper) {
          @Override
          public void visitInnerClass(String name, String outerName, String innerName, int access) {
            if (outerName != null && outerName.startsWith(binaryName)) {
              pendingClasses.push(toClassName(name));
            }
            super.visitInnerClass(name, outerName, innerName, access);
          }
        };
        reader.accept(classRemapper, 0);
        defineClass.accept(newName, writer.toByteArray());
      }
      catch (IOException e) {
        LOG.warn("Unable to define android.os.Build", e);
      }
    }
  }

    LayoutlibClassLoader(@NotNull ClassLoader parent);

}