Frameworks: Slightly refactor Parcel code

Decrease the amount of code covered by a lock in Parcel. This allows
fetching multiple classes in parallel, with the slight downside that
these classes might be the same.

Reduces contention samples for this method in profiling by two thirds.

Test: m
Test: manual profiling
Change-Id: I96415659f6625df25800c60dd3bee1094255fcc3
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index ae743fb..fe2fbb1 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -2797,65 +2797,67 @@
             return null;
         }
         Parcelable.Creator<?> creator;
+        HashMap<String, Parcelable.Creator<?>> map;
         synchronized (mCreators) {
-            HashMap<String,Parcelable.Creator<?>> map = mCreators.get(loader);
+            map = mCreators.get(loader);
             if (map == null) {
                 map = new HashMap<>();
                 mCreators.put(loader, map);
             }
             creator = map.get(name);
-            if (creator == null) {
-                try {
-                    // If loader == null, explicitly emulate Class.forName(String) "caller
-                    // classloader" behavior.
-                    ClassLoader parcelableClassLoader =
-                            (loader == null ? getClass().getClassLoader() : loader);
-                    // Avoid initializing the Parcelable class until we know it implements
-                    // Parcelable and has the necessary CREATOR field. http://b/1171613.
-                    Class<?> parcelableClass = Class.forName(name, false /* initialize */,
-                            parcelableClassLoader);
-                    if (!Parcelable.class.isAssignableFrom(parcelableClass)) {
-                        throw new BadParcelableException("Parcelable protocol requires subclassing "
-                                + "from Parcelable on class " + name);
-                    }
-                    Field f = parcelableClass.getField("CREATOR");
-                    if ((f.getModifiers() & Modifier.STATIC) == 0) {
-                        throw new BadParcelableException("Parcelable protocol requires "
-                                + "the CREATOR object to be static on class " + name);
-                    }
-                    Class<?> creatorType = f.getType();
-                    if (!Parcelable.Creator.class.isAssignableFrom(creatorType)) {
-                        // Fail before calling Field.get(), not after, to avoid initializing
-                        // parcelableClass unnecessarily.
-                        throw new BadParcelableException("Parcelable protocol requires a "
-                                + "Parcelable.Creator object called "
-                                + "CREATOR on class " + name);
-                    }
-                    creator = (Parcelable.Creator<?>) f.get(null);
-                }
-                catch (IllegalAccessException e) {
-                    Log.e(TAG, "Illegal access when unmarshalling: " + name, e);
-                    throw new BadParcelableException(
-                            "IllegalAccessException when unmarshalling: " + name);
-                }
-                catch (ClassNotFoundException e) {
-                    Log.e(TAG, "Class not found when unmarshalling: " + name, e);
-                    throw new BadParcelableException(
-                            "ClassNotFoundException when unmarshalling: " + name);
-                }
-                catch (NoSuchFieldException e) {
-                    throw new BadParcelableException("Parcelable protocol requires a "
-                            + "Parcelable.Creator object called "
-                            + "CREATOR on class " + name);
-                }
-                if (creator == null) {
-                    throw new BadParcelableException("Parcelable protocol requires a "
-                            + "non-null Parcelable.Creator object called "
-                            + "CREATOR on class " + name);
-                }
+        }
+        if (creator != null) {
+            return creator;
+        }
 
-                map.put(name, creator);
+        try {
+            // If loader == null, explicitly emulate Class.forName(String) "caller
+            // classloader" behavior.
+            ClassLoader parcelableClassLoader =
+                    (loader == null ? getClass().getClassLoader() : loader);
+            // Avoid initializing the Parcelable class until we know it implements
+            // Parcelable and has the necessary CREATOR field. http://b/1171613.
+            Class<?> parcelableClass = Class.forName(name, false /* initialize */,
+                    parcelableClassLoader);
+            if (!Parcelable.class.isAssignableFrom(parcelableClass)) {
+                throw new BadParcelableException("Parcelable protocol requires subclassing "
+                        + "from Parcelable on class " + name);
             }
+            Field f = parcelableClass.getField("CREATOR");
+            if ((f.getModifiers() & Modifier.STATIC) == 0) {
+                throw new BadParcelableException("Parcelable protocol requires "
+                        + "the CREATOR object to be static on class " + name);
+            }
+            Class<?> creatorType = f.getType();
+            if (!Parcelable.Creator.class.isAssignableFrom(creatorType)) {
+                // Fail before calling Field.get(), not after, to avoid initializing
+                // parcelableClass unnecessarily.
+                throw new BadParcelableException("Parcelable protocol requires a "
+                        + "Parcelable.Creator object called "
+                        + "CREATOR on class " + name);
+            }
+            creator = (Parcelable.Creator<?>) f.get(null);
+        } catch (IllegalAccessException e) {
+            Log.e(TAG, "Illegal access when unmarshalling: " + name, e);
+            throw new BadParcelableException(
+                    "IllegalAccessException when unmarshalling: " + name);
+        } catch (ClassNotFoundException e) {
+            Log.e(TAG, "Class not found when unmarshalling: " + name, e);
+            throw new BadParcelableException(
+                    "ClassNotFoundException when unmarshalling: " + name);
+        } catch (NoSuchFieldException e) {
+            throw new BadParcelableException("Parcelable protocol requires a "
+                    + "Parcelable.Creator object called "
+                    + "CREATOR on class " + name);
+        }
+        if (creator == null) {
+            throw new BadParcelableException("Parcelable protocol requires a "
+                    + "non-null Parcelable.Creator object called "
+                    + "CREATOR on class " + name);
+        }
+
+        synchronized (mCreators) {
+            map.put(name, creator);
         }
 
         return creator;