1 /*
2  * Copyright (C) 2023 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 
17 package libcore.reflect;
18 
19 import dalvik.annotation.Signature;
20 
21 import libcore.util.EmptyArray;
22 
23 import java.lang.annotation.Annotation;
24 
25 /**
26  * Mirror of the data structure specified in {@link dalvik.annotation.Record}. But annotation type
27  * isn't allowed to have a 2D array element, but it's stored in the .dex format. This is regular
28  * class created to store the annotation elements consumed internally by libcore.
29  *
30  * Please see {@link dalvik.annotation.Record} for detailed javadoc for each element.
31  */
32 public final class RecordComponents {
33 
34     /**
35      * VISIBILITY_RUNTIME value.
36      * See https://source.android.com/docs/core/runtime/dex-format#visibility
37      */
38     private static final byte DEX_ANNOTATION_VISIBILITY_RUNTIME = 1;
39 
40     private final Class<?> declaringClass;
41 
42     private final String[] componentNames;
43     private final Class<?>[] componentTypes;
44     private final Signature[] componentSignatures;
45     private byte[][] componentAnnotationVisibilities;
46     private Annotation[][] componentAnnotations;
47 
48     /**
49      * Created an empty instance and the fields will be filled by the ART runtime.
50      */
RecordComponents(Class<?> declaringClass)51     public RecordComponents(Class<?> declaringClass) {
52         this.declaringClass = declaringClass;
53         componentNames = readElement("componentNames", String[].class);
54         componentTypes = readElement("componentTypes", Class[].class);
55         componentSignatures = readElement("componentSignatures", Signature[].class);
56     }
57 
readElement(String name, Class<T[]> array_class)58     private <T> T[] readElement(String name, Class<T[]> array_class) {
59         return declaringClass.getRecordAnnotationElement(name, array_class);
60     }
61 
getNames()62     public String[] getNames() {
63         return componentNames;
64     }
65 
getTypes()66     public Class<?>[] getTypes() {
67         return componentTypes;
68     }
69 
70     /**
71      * @return null if no signature is found.
72      */
getGenericSignature(int index)73     public String getGenericSignature(int index) {
74         Signature signature = null;
75         if (componentSignatures != null && index >= 0 && index < componentSignatures.length) {
76             signature = componentSignatures[index];
77         }
78         if (signature == null) {
79             return null;
80         }
81         StringBuilder result = new StringBuilder();
82         for (String s : signature.value()) {
83             result.append(s);
84         }
85         return result.toString();
86     }
87 
88     /**
89      * Return all annotations visible at runtime.
90      *
91      * @param index Component index
92      */
getVisibleAnnotations(int index)93     public Annotation[] getVisibleAnnotations(int index) {
94         synchronized (this) {
95             if (componentAnnotations == null) {
96                 Annotation[][] allAnnotations = readElement("componentAnnotations",
97                         Annotation[][].class);
98                 byte[][] allVisibilities = readElement("componentAnnotationVisibilities",
99                         byte[][].class);
100                 if (allAnnotations == null) {
101                     allAnnotations = new Annotation[0][];
102                 }
103                 if (allVisibilities == null) {
104                     allVisibilities = new byte[0][];
105                 }
106                 componentAnnotationVisibilities = allVisibilities;
107                 componentAnnotations = allAnnotations;
108             }
109         }
110         Annotation[][] allAnnotations = componentAnnotations;
111         byte[][] allVisibilities = componentAnnotationVisibilities;
112 
113         if (index < 0 || index >= allAnnotations.length || allAnnotations[index] == null) {
114             return EmptyArray.ANNOTATION;
115         }
116 
117         Annotation[] annotations = allAnnotations[index];
118         int size = annotations.length;
119         if (size == 0) {
120             return annotations;
121         }
122         byte[] visibilities = index < allVisibilities.length ? allVisibilities[index] : null;
123         if (visibilities == null) {
124             return EmptyArray.ANNOTATION;
125         }
126 
127         int minSize = Math.min(visibilities.length, size);
128         int visibleAnnotationsSize = 0;
129         for (int i = 0; i < minSize; i++) {
130             if (visibilities[i] == DEX_ANNOTATION_VISIBILITY_RUNTIME) {
131                 visibleAnnotationsSize++;
132             }
133         }
134 
135         // In most cases, component has no invisible annotations and return all annotations here.
136         if (visibleAnnotationsSize == size) {
137             return annotations;
138         }
139 
140         // slow path
141         Annotation[] visibleAnnotations = new Annotation[visibleAnnotationsSize];
142         int j = 0;
143         for (int i = 0; i < minSize; i++) {
144             if (visibilities[i] == DEX_ANNOTATION_VISIBILITY_RUNTIME) {
145                 visibleAnnotations[j] = annotations[i];
146                 j++;
147             }
148         }
149         return visibleAnnotations;
150     }
151 }
152