return val;
}
+// Checks that visibility is as expected. Includes special behavior for M and
+// before to allow runtime and build visibility when expecting runtime.
+static bool IsVisibilityCompatible(uint32_t actual, uint32_t expected) {
+ if (expected == DexFile::kDexVisibilityRuntime) {
+ int32_t sdk_version = Runtime::Current()->GetTargetSdkVersion();
+ if (sdk_version > 0 && sdk_version <= 23) {
+ return actual == DexFile::kDexVisibilityRuntime || actual == DexFile::kDexVisibilityBuild;
+ }
+ }
+ return actual == expected;
+}
+
const DexFile::AnnotationSetItem* DexFile::FindAnnotationSetForField(ArtField* field) const {
mirror::Class* klass = field->GetDeclaringClass();
const AnnotationsDirectoryItem* annotations_dir = GetAnnotationsDirectory(*klass->GetClassDef());
Handle<mirror::Class> annotation_class) const {
for (uint32_t i = 0; i < annotation_set->size_; ++i) {
const AnnotationItem* annotation_item = GetAnnotationItem(annotation_set, i);
- if (annotation_item->visibility_ != visibility) {
+ if (!IsVisibilityCompatible(annotation_item->visibility_, visibility)) {
continue;
}
const uint8_t* annotation = annotation_item->annotation_;
uint32_t dest_index = 0;
for (uint32_t i = 0; i < size; ++i) {
const AnnotationItem* annotation_item = GetAnnotationItem(annotation_set, i);
+ // Note that we do not use IsVisibilityCompatible here because older code
+ // was correct for this case.
if (annotation_item->visibility_ != visibility) {
continue;
}
const AnnotationItem* result = nullptr;
for (uint32_t i = 0; i < annotation_set->size_; ++i) {
const AnnotationItem* annotation_item = GetAnnotationItem(annotation_set, i);
- if (annotation_item->visibility_ != visibility) {
+ if (!IsVisibilityCompatible(annotation_item->visibility_, visibility)) {
continue;
}
const uint8_t* annotation = annotation_item->annotation_;
System.out.println("");
}
-
+ public static void testVisibilityCompatibility() throws Exception {
+ if (!VMRuntime.isAndroid()) {
+ return;
+ }
+ Object runtime = VMRuntime.getRuntime();
+ int currentSdkVersion = VMRuntime.getTargetSdkVersion(runtime);
+ // SDK version 23 is M.
+ int oldSdkVersion = 23;
+ VMRuntime.setTargetSdkVersion(runtime, oldSdkVersion);
+ // This annotation has CLASS retention, but is visible to the runtime in M and earlier.
+ Annotation anno = SimplyNoted.class.getAnnotation(AnnoSimpleTypeInvis.class);
+ if (anno == null) {
+ System.out.println("testVisibilityCompatibility failed: " +
+ "SimplyNoted.get(AnnoSimpleTypeInvis) should not be null");
+ }
+ VMRuntime.setTargetSdkVersion(runtime, currentSdkVersion);
+ }
public static void main(String[] args) {
System.out.println("TestAnnotations...");
} catch (NoSuchFieldError expected) {
System.out.println("Got expected NoSuchFieldError");
}
+
+ // Test if annotations marked VISIBILITY_BUILD are visible to runtime in M and earlier.
+ try {
+ testVisibilityCompatibility();
+ } catch (Exception e) {
+ System.out.println("testVisibilityCompatibility failed: " + e);
+ }
+ }
+
+ private static class VMRuntime {
+ private static Class vmRuntimeClass;
+ private static Method getRuntimeMethod;
+ private static Method getTargetSdkVersionMethod;
+ private static Method setTargetSdkVersionMethod;
+ static {
+ init();
+ }
+
+ private static void init() {
+ try {
+ vmRuntimeClass = Class.forName("dalvik.system.VMRuntime");
+ } catch (Exception e) {
+ return;
+ }
+ try {
+ getRuntimeMethod = vmRuntimeClass.getDeclaredMethod("getRuntime");
+ getTargetSdkVersionMethod =
+ vmRuntimeClass.getDeclaredMethod("getTargetSdkVersion");
+ setTargetSdkVersionMethod =
+ vmRuntimeClass.getDeclaredMethod("setTargetSdkVersion", Integer.TYPE);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public static boolean isAndroid() {
+ return vmRuntimeClass != null;
+ }
+
+ public static Object getRuntime() throws Exception {
+ return getRuntimeMethod.invoke(null);
+ }
+
+ public static int getTargetSdkVersion(Object runtime) throws Exception {
+ return (int) getTargetSdkVersionMethod.invoke(runtime);
+ }
+
+ public static void setTargetSdkVersion(Object runtime, int version) throws Exception {
+ setTargetSdkVersionMethod.invoke(runtime, version);
+ }
}
}