blob: efe473be9337c7ed8d377ec4bd908e965eebfa02 [file] [log] [blame]
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package libcore.reflect;
import dalvik.annotation.Signature;
import libcore.util.EmptyArray;
import java.lang.annotation.Annotation;
/**
* Mirror of the data structure specified in {@link dalvik.annotation.Record}. But annotation type
* isn't allowed to have a 2D array element, but it's stored in the .dex format. This is regular
* class created to store the annotation elements consumed internally by libcore.
*
* Please see {@link dalvik.annotation.Record} for detailed javadoc for each element.
*/
public final class RecordComponents {
/**
* VISIBILITY_RUNTIME value.
* See https://source.android.com/docs/core/runtime/dex-format#visibility
*/
private static final byte DEX_ANNOTATION_VISIBILITY_RUNTIME = 1;
private final Class<?> declaringClass;
private final String[] componentNames;
private final Class<?>[] componentTypes;
private final Signature[] componentSignatures;
private byte[][] componentAnnotationVisibilities;
private Annotation[][] componentAnnotations;
/**
* Created an empty instance and the fields will be filled by the ART runtime.
*/
public RecordComponents(Class<?> declaringClass) {
this.declaringClass = declaringClass;
componentNames = readElement("componentNames", String[].class);
componentTypes = readElement("componentTypes", Class[].class);
componentSignatures = readElement("componentSignatures", Signature[].class);
}
private <T> T[] readElement(String name, Class<T[]> array_class) {
return declaringClass.getRecordAnnotationElement(name, array_class);
}
public String[] getNames() {
return componentNames;
}
public Class<?>[] getTypes() {
return componentTypes;
}
/**
* @return null if no signature is found.
*/
public String getGenericSignature(int index) {
Signature signature = null;
if (componentSignatures != null && index >= 0 && index < componentSignatures.length) {
signature = componentSignatures[index];
}
if (signature == null) {
return null;
}
StringBuilder result = new StringBuilder();
for (String s : signature.value()) {
result.append(s);
}
return result.toString();
}
/**
* Return all annotations visible at runtime.
*
* @param index Component index
*/
public Annotation[] getVisibleAnnotations(int index) {
synchronized (this) {
if (componentAnnotations == null) {
Annotation[][] allAnnotations = readElement("componentAnnotations",
Annotation[][].class);
byte[][] allVisibilities = readElement("componentAnnotationVisibilities",
byte[][].class);
if (allAnnotations == null) {
allAnnotations = new Annotation[0][];
}
if (allVisibilities == null) {
allVisibilities = new byte[0][];
}
componentAnnotationVisibilities = allVisibilities;
componentAnnotations = allAnnotations;
}
}
Annotation[][] allAnnotations = componentAnnotations;
byte[][] allVisibilities = componentAnnotationVisibilities;
if (index < 0 || index >= allAnnotations.length || allAnnotations[index] == null) {
return EmptyArray.ANNOTATION;
}
Annotation[] annotations = allAnnotations[index];
int size = annotations.length;
if (size == 0) {
return annotations;
}
byte[] visibilities = index < allVisibilities.length ? allVisibilities[index] : null;
if (visibilities == null) {
return EmptyArray.ANNOTATION;
}
int minSize = Math.min(visibilities.length, size);
int visibleAnnotationsSize = 0;
for (int i = 0; i < minSize; i++) {
if (visibilities[i] == DEX_ANNOTATION_VISIBILITY_RUNTIME) {
visibleAnnotationsSize++;
}
}
// In most cases, component has no invisible annotations and return all annotations here.
if (visibleAnnotationsSize == size) {
return annotations;
}
// slow path
Annotation[] visibleAnnotations = new Annotation[visibleAnnotationsSize];
int j = 0;
for (int i = 0; i < minSize; i++) {
if (visibilities[i] == DEX_ANNOTATION_VISIBILITY_RUNTIME) {
visibleAnnotations[j] = annotations[i];
j++;
}
}
return visibleAnnotations;
}
}