frameworks_dependencies.gradle 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. import org.objectweb.asm.ClassReader
  2. import org.objectweb.asm.ClassWriter
  3. import org.objectweb.asm.Opcodes
  4. import org.objectweb.asm.tree.AnnotationNode
  5. import org.objectweb.asm.tree.ClassNode
  6. import org.objectweb.asm.tree.FieldNode
  7. import org.objectweb.asm.tree.InnerClassNode
  8. import org.objectweb.asm.tree.MethodNode
  9. import java.nio.file.Paths
  10. import java.util.jar.JarEntry
  11. import java.util.jar.JarFile
  12. import java.util.jar.JarOutputStream
  13. import java.util.zip.ZipEntry
  14. buildscript {
  15. repositories {
  16. maven { url "https://maven.aliyun.com/repository/public/" }
  17. }
  18. dependencies {
  19. classpath 'org.ow2.asm:asm-commons:9.2'
  20. }
  21. }
  22. Project frameworks = project(":Frameworks")
  23. gradle.projectsEvaluated {
  24. Task frameworksJarTask = null
  25. try {
  26. frameworksJarTask = frameworks.tasks.named("jar").get()
  27. } catch (Throwable ex) {
  28. ex.printStackTrace()
  29. }
  30. if (frameworksJarTask == null) {
  31. return
  32. }
  33. File frameworksJar = null
  34. frameworksJarTask.outputs.files.files.forEach {
  35. if (it.getName() == "Frameworks.jar") {
  36. frameworksJar = it
  37. }
  38. }
  39. if (frameworksJar == null) {
  40. return
  41. }
  42. // 获取SDK路径
  43. // android.sdkDirectory.getAbsolutePath()
  44. File sdkJar = new File(Paths.get(android.sdkDirectory.getAbsolutePath(), "platforms",
  45. "android-${sdkInt}", "android.jar").toString())
  46. File resultJar = new File(frameworksJar.getParent(), "android-${sdkInt}.jar")
  47. File tempDir = new File(frameworks.getBuildDir(), "tmp")
  48. File inputFile = new File(tempDir, System.currentTimeMillis() + ".txt")
  49. Project currentProject = project
  50. Task currentPreBuild = currentProject.tasks.named("preBuild").get()
  51. currentPreBuild.doLast {
  52. // 只有当frameworksJarTask未执行时才添加输入文件
  53. if (!frameworksJarTask.getState().executed) {
  54. if (!tempDir.exists()) {
  55. tempDir.mkdirs()
  56. }
  57. if (!inputFile.exists()) {
  58. inputFile.createNewFile()
  59. }
  60. // 为了避免UP-TO-DATE导致doLast不执行,这里随机添加一个输入文件
  61. frameworksJarTask.inputs.file(inputFile)
  62. }
  63. }
  64. frameworksJarTask.doLast {
  65. inputFile.delete()
  66. // 只有在编译当前Module时才去合并对应的jar
  67. if (currentPreBuild.getState().executed) {
  68. println("mergeJar -> $currentProject")
  69. try {
  70. if (resultJar.exists()) {
  71. resultJar.delete()
  72. }
  73. ClassMerge.mergeJar(resultJar, sdkJar, frameworksJar, "$sdkInt")
  74. } catch (Throwable ex) {
  75. ex.printStackTrace()
  76. }
  77. }
  78. }
  79. // 针对kotlin代码编译,需要加此设置才能编译通过
  80. if (project.getPlugins().findPlugin("kotlin-android") != null) {
  81. project.dependencies {
  82. compileOnly files(resultJar)
  83. }
  84. }
  85. tasks.withType(JavaCompile).configureEach {
  86. String taskName = it.name
  87. if (taskName.contains("UnitTest") || taskName.contains("AndroidTest")) {
  88. return
  89. }
  90. it.doFirst {
  91. // File androidJar = null
  92. // // android.jar在classpath中或者在bootstrapClasspath中
  93. // // TODO AndHub 规律暂时未知?
  94. // classpath.files.forEach {
  95. // if (it.getName() == "android.jar") {
  96. // androidJar = it
  97. // }
  98. // }
  99. // options.bootstrapClasspath.files.forEach {
  100. // if (it.getName() == "android.jar") {
  101. // androidJar = it
  102. // }
  103. // }
  104. //
  105. // println("classpath framework jar = ${resultJar}")
  106. //
  107. // try {
  108. // ClassMerge.mergeJar(resultJar, androidJar, frameworksJar, "$sdkInt")
  109. // } catch (Throwable ex) {
  110. // ex.printStackTrace()
  111. // }
  112. // android.jar在classpath中则需要设置classpath
  113. // android.jar在bootstrapClasspath中则需要设置bootstrapClasspath
  114. // 这里都设置一下
  115. classpath = files(resultJar, classpath)
  116. options.bootstrapClasspath = files(resultJar, options.bootstrapClasspath)
  117. }
  118. }
  119. }
  120. dependencies {
  121. compileOnly frameworks
  122. }
  123. class ClassMerge {
  124. /**
  125. * 合并jar文件中的class,规则:<br/>
  126. * 1、frameworksJar中的class如果在androidJar中能找到同类则进行合并后写入resultJar中<br/>
  127. * 2、frameworksJar中的class如果在androidJar找不到到同类则直接写入resultJar中
  128. *
  129. * @param resultJar 合并后的jar文件
  130. * @param androidJar SDK中对应版本的android.jar
  131. * @param frameworksJar Frameworks module编译出的jar文件
  132. *
  133. * @throws Exception
  134. */
  135. static void mergeJar(File resultJar, File androidJar, File frameworksJar, String sdkInt) throws Exception {
  136. // 这里只合并一次,不然在extractXxxAnnotations任务中会报错
  137. // WARN: Could not read file:
  138. // xxx/Frameworks/build/libs/android-32.jar!/android/graphics/drawable/Drawable.class;
  139. // size in bytes: 10378; file type: CLASS
  140. // java.util.zip.ZipException: zip END header not found
  141. // 可能是文件流被占用的原因
  142. if (resultJar.exists()) {
  143. return
  144. }
  145. JarOutputStream jos = new JarOutputStream(new FileOutputStream(resultJar))
  146. JarFile androidJarFile = new JarFile(androidJar)
  147. JarFile frameworksJarFile = new JarFile(frameworksJar)
  148. Enumeration<JarEntry> enumeration = frameworksJarFile.entries()
  149. while (enumeration.hasMoreElements()) {
  150. JarEntry jarEntry = enumeration.nextElement()
  151. String entryName = jarEntry.getName()
  152. // 过滤掉commons下面的class
  153. if (entryName.startsWith("commons/") || entryName.startsWith("META-INF/")) {
  154. continue
  155. }
  156. ZipEntry zipEntry = new ZipEntry(entryName)
  157. jos.putNextEntry(zipEntry)
  158. ZipEntry androidJarZip = androidJarFile.getEntry(entryName)
  159. byte[] byteCode
  160. if (androidJarZip != null && entryName.endsWith(".class")) {
  161. byte[] baseClassByte = androidJarFile.getInputStream(jarEntry).readAllBytes()
  162. byte[] copyClassByte = frameworksJarFile.getInputStream(jarEntry).readAllBytes()
  163. byteCode = mergeAndFixClass(baseClassByte, copyClassByte, sdkInt)
  164. } else {
  165. // android.jar中无此class,直接拷贝,无需合并
  166. byte[] baseClassByte = frameworksJarFile.getInputStream(jarEntry).readAllBytes()
  167. // 这里除了class还有文件夹,baseClassByte.length为0
  168. // META-INF/MANIFEST.MF
  169. if (entryName.endsWith(".class")) {
  170. byteCode = mergeAndFixClass(baseClassByte, null, sdkInt)
  171. } else {
  172. byteCode = baseClassByte
  173. }
  174. }
  175. jos.write(byteCode)
  176. jos.closeEntry()
  177. }
  178. jos.close()
  179. androidJarFile.close()
  180. frameworksJarFile.close()
  181. }
  182. private static byte[] mergeAndFixClass(byte[] baseClassByte, byte[] copyClassByte, String sdkInt) throws Exception {
  183. int api = Opcodes.ASM9
  184. int flags = ClassWriter.COMPUTE_FRAMES
  185. ClassReader baseClassReader = new ClassReader(baseClassByte)
  186. ClassNode baseClassNode = new ClassNode(api)
  187. baseClassReader.accept(baseClassNode, 0)
  188. // 需要将访问属性改为public的类
  189. Set<String> publicClass = new HashSet<>()
  190. publicClass.add("android/annotation/NonNull")
  191. publicClass.add("android/annotation/Nullable")
  192. if (publicClass.contains(baseClassNode.name)) {
  193. baseClassNode.access = baseClassNode.access | Opcodes.ACC_PUBLIC
  194. }
  195. List<MethodNode> baseClassMethods = fixMethod(baseClassNode.methods, sdkInt)
  196. List<FieldNode> baseClassFields = fixField(baseClassNode.fields, sdkInt)
  197. if (copyClassByte != null) {
  198. ClassReader copyClassReader = new ClassReader(copyClassByte)
  199. ClassNode copyClassNode = new ClassNode(api)
  200. copyClassReader.accept(copyClassNode, 0)
  201. List<MethodNode> methods = fixMethod(copyClassNode.methods, sdkInt)
  202. Formatter formatter = new Formatter(Locale.getDefault())
  203. for (MethodNode node : methods) {
  204. // 过滤掉重复方法,会什么会有重复方法?
  205. // 有些版本的android.jar中没有此方法,有些版本中有此方法,
  206. // 导致Frameworks.jar中的方法和android.jar中的方法重复
  207. if (methodExists(baseClassMethods, node)) {
  208. String access = formatter.format("0x%04x", node.access).toString()
  209. println("重复方法->[${copyClassNode.name}] $access ${node.name} ${node.desc}")
  210. } else {
  211. baseClassMethods.add(node)
  212. }
  213. }
  214. // 添加字段
  215. List<FieldNode> fields = fixField(copyClassNode.fields, sdkInt)
  216. for (FieldNode node : fields) {
  217. baseClassFields.add(node)
  218. }
  219. // 添加内部类
  220. for (InnerClassNode node : copyClassNode.innerClasses) {
  221. if (!innerClassesExists(baseClassNode.innerClasses, node)) {
  222. baseClassNode.innerClasses.add(node)
  223. }
  224. }
  225. }
  226. ClassWriter baseClassWriter = new ClassWriter(flags)
  227. baseClassNode.accept(baseClassWriter)
  228. return baseClassWriter.toByteArray()
  229. }
  230. private static boolean innerClassesExists(List<InnerClassNode> classNodes, InnerClassNode innerClass) {
  231. for (InnerClassNode node : classNodes) {
  232. if (node.name == innerClass.name) {
  233. return true
  234. }
  235. }
  236. return false
  237. }
  238. private static boolean methodExists(List<MethodNode> methods, MethodNode method) {
  239. for (MethodNode node : methods) {
  240. if (node.name == method.name && node.desc == method.desc) {
  241. return true
  242. }
  243. }
  244. return false
  245. }
  246. private static List<FieldNode> fixField(List<FieldNode> fields, String sdkInt) {
  247. for (FieldNode node : fields) {
  248. // 修改字段类型
  249. fixNodeDesc(node, node.visibleAnnotations, sdkInt)
  250. // 清除掉字段上的注解,如:
  251. // java.lang.Deprecated
  252. // RetentionPolicy.RUNTIME注解
  253. node.visibleAnnotations = Collections.emptyList()
  254. // RetentionPolicy.CLASS注解
  255. node.invisibleAnnotations = Collections.emptyList()
  256. }
  257. return fields
  258. }
  259. private static List<MethodNode> fixMethod(List<MethodNode> methods, String sdkInt) {
  260. for (MethodNode node : methods) {
  261. // 修改方法描述符
  262. fixNodeDesc(node, node.visibleAnnotations, sdkInt)
  263. int newAccess = node.access
  264. // 将将构造方法改为public
  265. if ("<init>" == node.name) {
  266. int maskFlag = newAccess & 0x000F
  267. // private、protected、默认修饰符
  268. if (maskFlag == Opcodes.ACC_PRIVATE
  269. || maskFlag == Opcodes.ACC_PROTECTED
  270. || maskFlag == 0) {
  271. newAccess = (newAccess & 0xFFF0) | Opcodes.ACC_PUBLIC
  272. }
  273. }
  274. // 去掉方法deprecated标记
  275. if ((newAccess & 0xF0000) == Opcodes.ACC_DEPRECATED) {
  276. newAccess = newAccess & 0x0FFFF
  277. }
  278. node.access = newAccess
  279. // 清除掉方法参数和返回值上的注解,如:
  280. // android.annotation.Nullable
  281. // android.annotation.NonNull
  282. // RetentionPolicy.RUNTIME注解
  283. node.visibleAnnotations = Collections.emptyList()
  284. node.visibleParameterAnnotations = Collections.emptyList()
  285. // RetentionPolicy.CLASS注解
  286. node.invisibleAnnotations = Collections.emptyList()
  287. node.invisibleParameterAnnotations = Collections.emptyList()
  288. }
  289. return methods
  290. }
  291. private static void fixNodeDesc(Object node, List<AnnotationNode> annotations, String sdkInt) {
  292. if (node == null && annotations == null && annotations.size() == 0) {
  293. return
  294. }
  295. for (AnnotationNode annotation : annotations) {
  296. String desc = annotation.desc
  297. if (desc == "Lcommons/annotations/MethodDescriptor;"
  298. || desc == "Lcommons/annotations/FieldType;") {
  299. List<Object> values = annotation.values
  300. // 注解方法和值依次排列,方法在前,值在后
  301. // MethodDescriptor [version, 31, value, (IZ)Landroid/window/TaskSnapshot;]
  302. // FieldType [version, 31, value, [Landroid/graphics/Insets;]
  303. if (values != null && values.size() == 4 && values.get(1).toString() == sdkInt) {
  304. node.desc = values.get(3)
  305. }
  306. } else if (desc == "Lcommons/annotations/MethodDescriptor\$MethodDescriptors;"
  307. || desc == "Lcommons/annotations/FieldType\$FieldTypes;") {
  308. // 注解方法和值依次排列,方法在前,值在后
  309. // annotationNode.values第一个值为value,第2个值为数组
  310. // [value, [org.objectweb.asm.tree.AnnotationNode@797081d1, org.objectweb.asm.tree.AnnotationNode@7035ba64]]
  311. for (AnnotationNode object : annotation.values.get(1)) {
  312. List<Object> values = object.values
  313. if (values != null && values.size() == 4 && values.get(1).toString() == sdkInt) {
  314. node.desc = values.get(3)
  315. }
  316. }
  317. }
  318. }
  319. }
  320. }