Introduce cache schema for generic Struct class.

Bug: 163492391
Test: atest android.net.util.StructTest --rerun-until-failure
Change-Id: Idffad7d3b907d8853ed7d296808a2e0e2736cbbe
diff --git a/staticlibs/device/android/net/util/Struct.java b/staticlibs/device/android/net/util/Struct.java
index 92e05aa..03f5f22 100644
--- a/staticlibs/device/android/net/util/Struct.java
+++ b/staticlibs/device/android/net/util/Struct.java
@@ -29,6 +29,7 @@
 import java.nio.BufferUnderflowException;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
+import java.util.concurrent.ConcurrentHashMap;
 
 /**
  * Define a generic class that helps to parse the structured message.
@@ -142,6 +143,7 @@
             this.field = field;
         }
     }
+    private static ConcurrentHashMap<Class, FieldInfo[]> sFieldCache = new ConcurrentHashMap();
 
     private static void checkAnnotationType(final Type type, final Class fieldType) {
         switch (type) {
@@ -300,11 +302,15 @@
                     + Struct.class.getName());
         }
 
-        final FieldInfo[] annotationFields = new FieldInfo[getAnnotationFieldCount(clazz)];
+        final FieldInfo[] cachedAnnotationFields = sFieldCache.get(clazz);
+        if (cachedAnnotationFields != null) {
+            return cachedAnnotationFields;
+        }
 
         // Since array returned from Class#getDeclaredFields doesn't guarantee the actual order
         // of field appeared in the class, that is a problem when parsing raw data read from
         // ByteBuffer. Store the fields appeared by the order() defined in the Field annotation.
+        final FieldInfo[] annotationFields = new FieldInfo[getAnnotationFieldCount(clazz)];
         for (java.lang.reflect.Field field : clazz.getDeclaredFields()) {
             if (Modifier.isStatic(field.getModifiers())) continue;
 
@@ -324,6 +330,7 @@
             }
             annotationFields[annotation.order()] = new FieldInfo(annotation, field);
         }
+        sFieldCache.putIfAbsent(clazz, annotationFields);
         return annotationFields;
     }