OSDN Git Service

Merge "Relax annotation visibility so runtime includes build." into nyc-dev
authorJeff Hao <jeffhao@google.com>
Sat, 28 May 2016 01:18:54 +0000 (01:18 +0000)
committerandroid-build-merger <android-build-merger@google.com>
Sat, 28 May 2016 01:18:54 +0000 (01:18 +0000)
am: aec92c397e

* commit 'aec92c397e73b74187c8d517f6cf439ba6147f4d':
  Relax annotation visibility so runtime includes build.

Change-Id: Ifbc56bc5413780813d83377818f396663f75c270

runtime/dex_file.cc
test/005-annotations/src/android/test/anno/TestAnnotations.java

index 63f3f08..88696e9 100644 (file)
@@ -1163,6 +1163,18 @@ static uint64_t ReadUnsignedLong(const uint8_t* ptr, int zwidth, bool fill_on_ri
   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());
@@ -1640,7 +1652,7 @@ const DexFile::AnnotationItem* DexFile::GetAnnotationItemFromAnnotationSet(
     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_;
@@ -1758,6 +1770,8 @@ mirror::ObjectArray<mirror::Object>* DexFile::ProcessAnnotationSet(Handle<mirror
   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;
     }
@@ -2146,7 +2160,7 @@ const DexFile::AnnotationItem* DexFile::SearchAnnotationSet(const AnnotationSetI
   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_;
index d36d43e..51254b4 100644 (file)
@@ -159,7 +159,23 @@ public class TestAnnotations {
         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...");
@@ -229,5 +245,55 @@ public class 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);
+        }
     }
 }