• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
<lambda>null2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.tools.metalava.apilevels
17 
18 import com.android.SdkConstants
19 import org.objectweb.asm.ClassReader
20 import org.objectweb.asm.Opcodes
21 import org.objectweb.asm.tree.ClassNode
22 import org.objectweb.asm.tree.FieldNode
23 import org.objectweb.asm.tree.MethodNode
24 import java.io.File
25 import java.io.FileInputStream
26 import java.util.zip.ZipInputStream
27 
28 fun Api.readAndroidJar(apiLevel: Int, jar: File) {
29     update(apiLevel)
30     readJar(apiLevel, jar)
31 }
32 
readExtensionJarnull33 fun Api.readExtensionJar(extensionVersion: Int, module: String, jar: File, nextApiLevel: Int) {
34     readJar(nextApiLevel, jar, extensionVersion, module)
35 }
36 
readJarnull37 fun Api.readJar(apiLevel: Int, jar: File, extensionVersion: Int? = null, module: String? = null) {
38     val fis = FileInputStream(jar)
39     ZipInputStream(fis).use { zis ->
40         var entry = zis.nextEntry
41         while (entry != null) {
42             if (!entry.name.endsWith(SdkConstants.DOT_CLASS)) {
43                 entry = zis.nextEntry
44                 continue
45             }
46             val bytes = zis.readBytes()
47             val reader = ClassReader(bytes)
48             val classNode = ClassNode(Opcodes.ASM5)
49             reader.accept(classNode, 0)
50 
51             val theClass = addClass(
52                 classNode.name,
53                 apiLevel,
54                 (classNode.access and Opcodes.ACC_DEPRECATED) != 0
55             )
56             extensionVersion?.let { theClass.updateExtension(extensionVersion) }
57             module?.let { theClass.updateMainlineModule(module) }
58 
59             theClass.updateHidden(
60                 apiLevel,
61                 (classNode.access and Opcodes.ACC_PUBLIC) == 0
62             )
63 
64             // super class
65             if (classNode.superName != null) {
66                 theClass.addSuperClass(classNode.superName, apiLevel)
67             }
68 
69             // interfaces
70             for (interfaceName in classNode.interfaces) {
71                 theClass.addInterface(interfaceName, apiLevel)
72             }
73 
74             // fields
75             for (field in classNode.fields) {
76                 val fieldNode = field as FieldNode
77                 if ((fieldNode.access and (Opcodes.ACC_PUBLIC or Opcodes.ACC_PROTECTED)) == 0) {
78                     continue
79                 }
80                 if (!fieldNode.name.startsWith("this\$") && fieldNode.name != "\$VALUES") {
81                     val apiField = theClass.addField(
82                         fieldNode.name,
83                         apiLevel,
84                         (fieldNode.access and Opcodes.ACC_DEPRECATED) != 0
85                     )
86                     extensionVersion?.let { apiField.updateExtension(extensionVersion) }
87                 }
88             }
89 
90             // methods
91             for (method in classNode.methods) {
92                 val methodNode = method as MethodNode
93                 if ((methodNode.access and (Opcodes.ACC_PUBLIC or Opcodes.ACC_PROTECTED)) == 0) {
94                     continue
95                 }
96                 if (methodNode.name != "<clinit>") {
97                     val apiMethod = theClass.addMethod(
98                         methodNode.name + methodNode.desc, apiLevel,
99                         (methodNode.access and Opcodes.ACC_DEPRECATED) != 0
100                     )
101                     extensionVersion?.let { apiMethod.updateExtension(extensionVersion) }
102                 }
103             }
104 
105             entry = zis.nextEntry
106         }
107     }
108 }
109