Import Android SDK Platform P [4697573]

/google/data/ro/projects/android/fetch_artifact \
    --bid 4697573 \
    --target sdk_phone_armv7-win_sdk \
    sdk-repo-linux-sources-4697573.zip

AndroidVersion.ApiLevel has been modified to appear as 28

Change-Id: If80578c3c657366cc9cf75f8db13d46e2dd4e077
diff --git a/java/io/FileInputStream.java b/java/io/FileInputStream.java
index b44bc5a..db7ba65 100644
--- a/java/io/FileInputStream.java
+++ b/java/io/FileInputStream.java
@@ -28,6 +28,7 @@
 
 import java.nio.channels.FileChannel;
 
+import dalvik.annotation.optimization.ReachabilitySensitive;
 import dalvik.system.BlockGuard;
 import dalvik.system.CloseGuard;
 import sun.nio.ch.FileChannelImpl;
@@ -55,6 +56,8 @@
 class FileInputStream extends InputStream
 {
     /* File Descriptor - handle to the open file */
+    // Android-added: @ReachabilitySensitive
+    @ReachabilitySensitive
     private final FileDescriptor fd;
 
     /**
@@ -72,6 +75,7 @@
     private final boolean isFdOwner;
 
     // Android-added: CloseGuard support.
+    @ReachabilitySensitive
     private final CloseGuard guard = CloseGuard.get();
 
     // Android-added: Tracking of unbuffered I/O.
diff --git a/java/io/FileOutputStream.java b/java/io/FileOutputStream.java
index 79e7690..f29a741 100644
--- a/java/io/FileOutputStream.java
+++ b/java/io/FileOutputStream.java
@@ -28,6 +28,7 @@
 
 import java.nio.channels.FileChannel;
 
+import dalvik.annotation.optimization.ReachabilitySensitive;
 import dalvik.system.BlockGuard;
 import dalvik.system.CloseGuard;
 import sun.nio.ch.FileChannelImpl;
@@ -60,6 +61,8 @@
     /**
      * The system dependent file descriptor.
      */
+    // Android-added: @ReachabilitySensitive
+    @ReachabilitySensitive
     private final FileDescriptor fd;
 
     /**
@@ -82,6 +85,7 @@
     private volatile boolean closed = false;
 
     // Android-added: CloseGuard support: Log if the stream is not closed.
+    @ReachabilitySensitive
     private final CloseGuard guard = CloseGuard.get();
 
     // Android-added: Field for tracking whether the stream owns the underlying FileDescriptor.
@@ -422,6 +426,8 @@
      * @exception  IOException  if an I/O error occurs.
      * @see        java.io.FileDescriptor
      */
+     // Android-added: @ReachabilitySensitive
+     @ReachabilitySensitive
      public final FileDescriptor getFD()  throws IOException {
         if (fd != null) {
             return fd;
diff --git a/java/io/ObjectInputStream.java b/java/io/ObjectInputStream.java
index 17001c5..f722df0 100644
--- a/java/io/ObjectInputStream.java
+++ b/java/io/ObjectInputStream.java
@@ -208,7 +208,6 @@
 public class ObjectInputStream
     extends InputStream implements ObjectInput, ObjectStreamConstants
 {
-
     /** handle value representing null */
     private static final int NULL_HANDLE = -1;
 
@@ -2021,11 +2020,13 @@
             throw new InternalError();
         }
         clear();
+        // BEGIN Android-changed: Fix SerializationStressTest#test_2_writeReplace.
         IOException e = (IOException) readObject0(false);
-        // BEGIN Android-changed
+        // If we want to continue reading from same stream after fatal exception, we
+        // need to clear internal data structures.
         clear();
-        // END Android-changed
         return e;
+        // END Android-changed: Fix SerializationStressTest#test_2_writeReplace.
     }
 
     /**
@@ -2069,6 +2070,7 @@
      * corresponding modifications to the above class.
      */
     private static ClassLoader latestUserDefinedLoader() {
+        // Android-changed: Use VMStack on Android.
         return VMStack.getClosestUserClassLoader();
     }
 
diff --git a/java/io/ObjectOutputStream.java b/java/io/ObjectOutputStream.java
index 632f2d3..7c4f0ca 100644
--- a/java/io/ObjectOutputStream.java
+++ b/java/io/ObjectOutputStream.java
@@ -37,7 +37,6 @@
 import java.util.concurrent.ConcurrentMap;
 import static java.io.ObjectStreamClass.processQueue;
 import java.io.SerialCallbackContext;
-
 import sun.reflect.misc.ReflectUtil;
 
 /**
@@ -211,7 +210,15 @@
      * value of "sun.io.serialization.extendedDebugInfo" property,
      * as true or false for extended information about exception's place
      */
+    // BEGIN Android-changed: Do not support extendedDebugInfo on Android.
+    /*
+    private static final boolean extendedDebugInfo =
+        java.security.AccessController.doPrivileged(
+            new sun.security.action.GetBooleanAction(
+                "sun.io.serialization.extendedDebugInfo")).booleanValue();
+    */
     private static final boolean extendedDebugInfo = false;
+    // END Android-changed: Do not support extendedDebugInfo on Android.
 
     /**
      * Creates an ObjectOutputStream that writes to the specified OutputStream.
@@ -347,7 +354,7 @@
             writeObject0(obj, false);
         } catch (IOException ex) {
             if (depth == 0) {
-                // BEGIN Android-changed
+                // BEGIN Android-changed: Ignore secondary exceptions during writeObject().
                 // writeFatalException(ex);
                 try {
                     writeFatalException(ex);
@@ -357,7 +364,7 @@
                     // is no need to propagate the second exception or generate a third exception,
                     // both of which might obscure details of the root cause.
                 }
-                // END Android-changed
+                // END Android-changed: Ignore secondary exceptions during writeObject().
             }
             throw ex;
         }
@@ -378,12 +385,12 @@
      * @since 1.2
      */
     protected void writeObjectOverride(Object obj) throws IOException {
-        // BEGIN Android-changed
+        // BEGIN Android-added: Let writeObjectOverride throw IOException if !enableOverride.
         if (!enableOverride) {
             // Subclasses must override.
             throw new IOException();
         }
-        // END Android-changed
+        // END Android-added: Let writeObjectOverride throw IOException if !enableOverride.
     }
 
     /**
@@ -753,7 +760,7 @@
      */
     public void close() throws IOException {
         flush();
-        // http://b/28159133
+        // Android-removed:  Don't clear() during close(), keep the handle table. http://b/28159133
         // clear();
         bout.close();
     }
@@ -1132,7 +1139,7 @@
             } else if (!unshared && (h = handles.lookup(obj)) != -1) {
                 writeHandle(h);
                 return;
-            // BEGIN Android-changed
+            // BEGIN Android-changed:  Make Class and ObjectStreamClass replaceable.
             /*
             } else if (obj instanceof Class) {
                 writeClass((Class) obj, unshared);
@@ -1141,7 +1148,7 @@
                 writeClassDesc((ObjectStreamClass) obj, unshared);
                 return;
             */
-            // END Android-changed
+            // END Android-changed:  Make Class and ObjectStreamClass replaceable.
             }
 
             // check for replacement object
@@ -1149,7 +1156,7 @@
             Class<?> cl = obj.getClass();
             ObjectStreamClass desc;
 
-            // BEGIN Android-changed
+            // BEGIN Android-changed: Make only one call to writeReplace.
             /*
             for (;;) {
                 // REMIND: skip this check for strings/arrays?
@@ -1177,7 +1184,7 @@
                 cl = repCl;
                 desc = ObjectStreamClass.lookup(cl, true);
             }
-            // END Android-changed
+            // END Android-changed: Make only one call to writeReplace.
 
             if (enableReplace) {
                 Object rep = replaceObject(obj);
@@ -1197,7 +1204,7 @@
                 } else if (!unshared && (h = handles.lookup(obj)) != -1) {
                     writeHandle(h);
                     return;
-// BEGIN Android-changed
+// BEGIN Android-changed:  Make Class and ObjectStreamClass replaceable.
 /*
                 } else if (obj instanceof Class) {
                     writeClass((Class) obj, unshared);
@@ -1206,17 +1213,17 @@
                     writeClassDesc((ObjectStreamClass) obj, unshared);
                     return;
 */
-// END Android-changed
+// END Android-changed:  Make Class and ObjectStreamClass replaceable.
                 }
             }
 
             // remaining cases
-            // BEGIN Android-changed
+            // BEGIN Android-changed: Make Class and ObjectStreamClass replaceable.
             if (obj instanceof Class) {
                 writeClass((Class) obj, unshared);
             } else if (obj instanceof ObjectStreamClass) {
                 writeClassDesc((ObjectStreamClass) obj, unshared);
-            // END Android-changed
+            // END Android-changed:  Make Class and ObjectStreamClass replaceable.
             } else if (obj instanceof String) {
                 writeString((String) obj, unshared);
             } else if (cl.isArray()) {
@@ -1812,6 +1819,7 @@
         /** loopback stream (for data writes that span data blocks) */
         private final DataOutputStream dout;
 
+        // BEGIN Android-added: Warning if writing to a closed ObjectOutputStream.
         /**
          * Indicates that this stream was closed and that a warning must be logged once if an
          * attempt is made to write to it and the underlying stream does not throw an exception.
@@ -1822,6 +1830,7 @@
          * http://b/28159133
          */
         private boolean warnOnceWhenWriting;
+        // END Android-added: Warning if writing to a closed ObjectOutputStream.
 
         /**
          * Creates new BlockDataOutputStream on top of given underlying stream.
@@ -1856,6 +1865,7 @@
             return blkmode;
         }
 
+        // BEGIN Android-added: Warning about writing to closed ObjectOutputStream
         /**
          * Warns if the stream has been closed.
          *
@@ -1874,6 +1884,7 @@
                 warnOnceWhenWriting = false;
             }
         }
+        // END Android-added: Warning about writing to closed ObjectOutputStream
 
         /* ----------------- generic output stream methods ----------------- */
         /*
@@ -1905,6 +1916,7 @@
         public void close() throws IOException {
             flush();
             out.close();
+            // Android-added: Warning about writing to closed ObjectOutputStream
             warnOnceWhenWriting = true;
         }
 
@@ -1920,6 +1932,7 @@
             if (!(copy || blkmode)) {           // write directly
                 drain();
                 out.write(b, off, len);
+                // Android-added: Warning about writing to closed ObjectOutputStream
                 warnIfClosed();
                 return;
             }
@@ -1942,6 +1955,7 @@
                     len -= wlen;
                 }
             }
+            // Android-added: Warning about writing to closed ObjectOutputStream
             warnIfClosed();
         }
 
@@ -1958,6 +1972,7 @@
             }
             out.write(buf, 0, pos);
             pos = 0;
+            // Android-added: Warning about writing to closed ObjectOutputStream
             warnIfClosed();
         }
 
@@ -1976,6 +1991,7 @@
                 Bits.putInt(hbuf, 1, len);
                 out.write(hbuf, 0, 5);
             }
+            // Android-added: Warning about writing to closed ObjectOutputStream
             warnIfClosed();
         }
 
diff --git a/java/io/ObjectStreamClass.java b/java/io/ObjectStreamClass.java
index ff1cf82..b2651b8 100644
--- a/java/io/ObjectStreamClass.java
+++ b/java/io/ObjectStreamClass.java
@@ -79,7 +79,14 @@
     private static final ObjectStreamField[] serialPersistentFields =
         NO_FIELDS;
 
-    /** reflection factory for obtaining serialization constructors */
+    // BEGIN Android-removed: ReflectionFactory not used on Android.
+    /*
+    /** reflection factory for obtaining serialization constructors *
+    private static final ReflectionFactory reflFactory =
+        AccessController.doPrivileged(
+            new ReflectionFactory.GetReflectionFactoryAction());
+    */
+    // END Android-removed: ReflectionFactory not used on Android.
 
     private static class Caches {
         /** cache mapping local classes -> descriptors */
@@ -186,6 +193,21 @@
     /** superclass descriptor appearing in stream */
     private ObjectStreamClass superDesc;
 
+    /** true if, and only if, the object has been correctly initialized */
+    private boolean initialized;
+
+    // BEGIN Android-removed: Initialization not required on Android.
+    /*
+    /**
+     * Initializes native code.
+     *
+    private static native void initNative();
+    static {
+        initNative();
+    }
+    */
+    // END Android-removed: Initialization not required on Android.
+
     /**
      * Find the descriptor for a class that can be serialized.  Creates an
      * ObjectStreamClass instance if one does not exist yet for class. Null is
@@ -255,7 +277,9 @@
         if (cl == null) {
             return null;
         }
+        requireInitialized();
         if (System.getSecurityManager() != null) {
+            // Android-changed: Class loader obtained from VMStack
             if (ReflectUtil.needsPackageAccessCheck(VMStack.getCallingClassLoader(),
                   cl.getClassLoader())) {
                 ReflectUtil.checkPackageAccess(cl);
@@ -522,6 +546,7 @@
                     name, "unmatched serializable field(s) declared");
             }
         }
+        initialized = true;
     }
 
     /**
@@ -539,6 +564,14 @@
                    ObjectStreamClass superDesc)
         throws InvalidClassException
     {
+        ObjectStreamClass osc = null;
+        if (cl != null) {
+            osc = lookup(cl, true);
+            if (!osc.isProxy) {
+                throw new InvalidClassException(
+                    "cannot bind proxy descriptor to a non-proxy class");
+            }
+        }
         this.cl = cl;
         this.resolveEx = resolveEx;
         this.superDesc = superDesc;
@@ -546,21 +579,17 @@
         serializable = true;
         suid = Long.valueOf(0);
         fields = NO_FIELDS;
-
-        if (cl != null) {
-            localDesc = lookup(cl, true);
-            if (!localDesc.isProxy) {
-                throw new InvalidClassException(
-                    "cannot bind proxy descriptor to a non-proxy class");
-            }
+        if (osc != null) {
+            localDesc = osc;
             name = localDesc.name;
             externalizable = localDesc.externalizable;
-            cons = localDesc.cons;
             writeReplaceMethod = localDesc.writeReplaceMethod;
             readResolveMethod = localDesc.readResolveMethod;
             deserializeEx = localDesc.deserializeEx;
+            cons = localDesc.cons;
         }
         fieldRefl = getReflector(fields, localDesc);
+        initialized = true;
     }
 
     /**
@@ -572,11 +601,57 @@
                       ObjectStreamClass superDesc)
         throws InvalidClassException
     {
+        long suid = Long.valueOf(model.getSerialVersionUID());
+        ObjectStreamClass osc = null;
+        if (cl != null) {
+            osc = lookup(cl, true);
+            if (osc.isProxy) {
+                throw new InvalidClassException(
+                        "cannot bind non-proxy descriptor to a proxy class");
+            }
+            if (model.isEnum != osc.isEnum) {
+                throw new InvalidClassException(model.isEnum ?
+                        "cannot bind enum descriptor to a non-enum class" :
+                        "cannot bind non-enum descriptor to an enum class");
+            }
+
+            if (model.serializable == osc.serializable &&
+                    !cl.isArray() &&
+                    suid != osc.getSerialVersionUID()) {
+                throw new InvalidClassException(osc.name,
+                        "local class incompatible: " +
+                                "stream classdesc serialVersionUID = " + suid +
+                                ", local class serialVersionUID = " +
+                                osc.getSerialVersionUID());
+            }
+
+            if (!classNamesEqual(model.name, osc.name)) {
+                throw new InvalidClassException(osc.name,
+                        "local class name incompatible with stream class " +
+                                "name \"" + model.name + "\"");
+            }
+
+            if (!model.isEnum) {
+                if ((model.serializable == osc.serializable) &&
+                        (model.externalizable != osc.externalizable)) {
+                    throw new InvalidClassException(osc.name,
+                            "Serializable incompatible with Externalizable");
+                }
+
+                if ((model.serializable != osc.serializable) ||
+                        (model.externalizable != osc.externalizable) ||
+                        !(model.serializable || model.externalizable)) {
+                    deserializeEx = new ExceptionInfo(
+                            osc.name, "class invalid for deserialization");
+                }
+            }
+        }
+
         this.cl = cl;
         this.resolveEx = resolveEx;
         this.superDesc = superDesc;
         name = model.name;
-        suid = Long.valueOf(model.getSerialVersionUID());
+        this.suid = suid;
         isProxy = false;
         isEnum = model.isEnum;
         serializable = model.serializable;
@@ -587,53 +662,8 @@
         primDataSize = model.primDataSize;
         numObjFields = model.numObjFields;
 
-        if (cl != null) {
-            localDesc = lookup(cl, true);
-            if (localDesc.isProxy) {
-                throw new InvalidClassException(
-                    "cannot bind non-proxy descriptor to a proxy class");
-            }
-            if (isEnum != localDesc.isEnum) {
-                throw new InvalidClassException(isEnum ?
-                    "cannot bind enum descriptor to a non-enum class" :
-                    "cannot bind non-enum descriptor to an enum class");
-            }
-
-            if (serializable == localDesc.serializable &&
-                !cl.isArray() &&
-                suid.longValue() != localDesc.getSerialVersionUID())
-            {
-                throw new InvalidClassException(localDesc.name,
-                    "local class incompatible: " +
-                    "stream classdesc serialVersionUID = " + suid +
-                    ", local class serialVersionUID = " +
-                    localDesc.getSerialVersionUID());
-            }
-
-            if (!classNamesEqual(name, localDesc.name)) {
-                throw new InvalidClassException(localDesc.name,
-                    "local class name incompatible with stream class " +
-                    "name \"" + name + "\"");
-            }
-
-            if (!isEnum) {
-                if ((serializable == localDesc.serializable) &&
-                    (externalizable != localDesc.externalizable))
-                {
-                    throw new InvalidClassException(localDesc.name,
-                        "Serializable incompatible with Externalizable");
-                }
-
-                if ((serializable != localDesc.serializable) ||
-                    (externalizable != localDesc.externalizable) ||
-                    !(serializable || externalizable))
-                {
-                    deserializeEx = new ExceptionInfo(
-                        localDesc.name, "class invalid for deserialization");
-                }
-            }
-
-            cons = localDesc.cons;
+        if (osc != null) {
+            localDesc = osc;
             writeObjectMethod = localDesc.writeObjectMethod;
             readObjectMethod = localDesc.readObjectMethod;
             readObjectNoDataMethod = localDesc.readObjectNoDataMethod;
@@ -642,10 +672,13 @@
             if (deserializeEx == null) {
                 deserializeEx = localDesc.deserializeEx;
             }
+            cons = localDesc.cons;
         }
+
         fieldRefl = getReflector(fields, localDesc);
         // reassign to matched fields so as to reflect local unshared settings
         fields = fieldRefl.getFields();
+        initialized = true;
     }
 
     /**
@@ -748,11 +781,20 @@
     }
 
     /**
+     * Throws InternalError if not initialized.
+     */
+    private final void requireInitialized() {
+        if (!initialized)
+            throw new InternalError("Unexpected call when not initialized");
+    }
+
+    /**
      * Throws an InvalidClassException if object instances referencing this
      * class descriptor should not be allowed to deserialize.  This method does
      * not apply to deserialization of enum constants.
      */
     void checkDeserialize() throws InvalidClassException {
+        requireInitialized();
         if (deserializeEx != null) {
             throw deserializeEx.newInvalidClassException();
         }
@@ -764,6 +806,7 @@
      * not apply to serialization of enum constants.
      */
     void checkSerialize() throws InvalidClassException {
+        requireInitialized();
         if (serializeEx != null) {
             throw serializeEx.newInvalidClassException();
         }
@@ -777,6 +820,7 @@
      * does not apply to deserialization of enum constants.
      */
     void checkDefaultSerialize() throws InvalidClassException {
+        requireInitialized();
         if (defaultSerializeEx != null) {
             throw defaultSerializeEx.newInvalidClassException();
         }
@@ -788,6 +832,7 @@
      * of the subclass descriptor's bound class.
      */
     ObjectStreamClass getSuperDesc() {
+        requireInitialized();
         return superDesc;
     }
 
@@ -798,6 +843,7 @@
      * associated with this descriptor.
      */
     ObjectStreamClass getLocalDesc() {
+        requireInitialized();
         return localDesc;
     }
 
@@ -840,6 +886,7 @@
      * otherwise.
      */
     boolean isProxy() {
+        requireInitialized();
         return isProxy;
     }
 
@@ -848,6 +895,7 @@
      * otherwise.
      */
     boolean isEnum() {
+        requireInitialized();
         return isEnum;
     }
 
@@ -856,6 +904,7 @@
      * otherwise.
      */
     boolean isExternalizable() {
+        requireInitialized();
         return externalizable;
     }
 
@@ -864,6 +913,7 @@
      * otherwise.
      */
     boolean isSerializable() {
+        requireInitialized();
         return serializable;
     }
 
@@ -872,6 +922,7 @@
      * has written its data in 1.2 (block data) format, false otherwise.
      */
     boolean hasBlockExternalData() {
+        requireInitialized();
         return hasBlockExternalData;
     }
 
@@ -881,6 +932,7 @@
      * writeObject() method, false otherwise.
      */
     boolean hasWriteObjectData() {
+        requireInitialized();
         return hasWriteObjectData;
     }
 
@@ -892,6 +944,7 @@
      * accessible no-arg constructor.  Otherwise, returns false.
      */
     boolean isInstantiable() {
+        requireInitialized();
         return (cons != null);
     }
 
@@ -901,6 +954,7 @@
      * returns false.
      */
     boolean hasWriteObjectMethod() {
+        requireInitialized();
         return (writeObjectMethod != null);
     }
 
@@ -910,6 +964,7 @@
      * returns false.
      */
     boolean hasReadObjectMethod() {
+        requireInitialized();
         return (readObjectMethod != null);
     }
 
@@ -919,6 +974,7 @@
      * Otherwise, returns false.
      */
     boolean hasReadObjectNoDataMethod() {
+        requireInitialized();
         return (readObjectNoDataMethod != null);
     }
 
@@ -927,6 +983,7 @@
      * defines a conformant writeReplace method.  Otherwise, returns false.
      */
     boolean hasWriteReplaceMethod() {
+        requireInitialized();
         return (writeReplaceMethod != null);
     }
 
@@ -935,6 +992,7 @@
      * defines a conformant readResolve method.  Otherwise, returns false.
      */
     boolean hasReadResolveMethod() {
+        requireInitialized();
         return (readResolveMethod != null);
     }
 
@@ -951,6 +1009,7 @@
         throws InstantiationException, InvocationTargetException,
                UnsupportedOperationException
     {
+        requireInitialized();
         if (cons != null) {
             try {
                 return cons.newInstance();
@@ -972,6 +1031,7 @@
     void invokeWriteObject(Object obj, ObjectOutputStream out)
         throws IOException, UnsupportedOperationException
     {
+        requireInitialized();
         if (writeObjectMethod != null) {
             try {
                 writeObjectMethod.invoke(obj, new Object[]{ out });
@@ -1001,6 +1061,7 @@
         throws ClassNotFoundException, IOException,
                UnsupportedOperationException
     {
+        requireInitialized();
         if (readObjectMethod != null) {
             try {
                 readObjectMethod.invoke(obj, new Object[]{ in });
@@ -1031,6 +1092,7 @@
     void invokeReadObjectNoData(Object obj)
         throws IOException, UnsupportedOperationException
     {
+        requireInitialized();
         if (readObjectNoDataMethod != null) {
             try {
                 readObjectNoDataMethod.invoke(obj, (Object[]) null);
@@ -1059,6 +1121,7 @@
     Object invokeWriteReplace(Object obj)
         throws IOException, UnsupportedOperationException
     {
+        requireInitialized();
         if (writeReplaceMethod != null) {
             try {
                 return writeReplaceMethod.invoke(obj, (Object[]) null);
@@ -1088,6 +1151,7 @@
     Object invokeReadResolve(Object obj)
         throws IOException, UnsupportedOperationException
     {
+        requireInitialized();
         if (readResolveMethod != null) {
             try {
                 return readResolveMethod.invoke(obj, (Object[]) null);
@@ -1362,9 +1426,12 @@
             {
                 return null;
             }
+            // BEGIN Android-changed: Serialization constructor obtained differently
+            // cons = reflFactory.newConstructorForSerialization(cl, cons);
             if (cons.getDeclaringClass() != cl) {
                 cons = cons.serializationCopy(cons.getDeclaringClass(), cl);
             }
+            // END Android-changed: Serialization constructor obtained differently
             cons.setAccessible(true);
             return cons;
         } catch (NoSuchMethodException ex) {
@@ -1731,6 +1798,7 @@
                 }
             }
 
+            // Android-changed: Clinit serialization workaround b/29064453
             boolean checkSuperclass = !(VMRuntime.getRuntime().getTargetSdkVersion()
                                        <= MAX_SDK_TARGET_FOR_CLINIT_UIDGEN_WORKAROUND);
             if (hasStaticInitializer(cl, checkSuperclass)) {
@@ -1806,6 +1874,7 @@
         }
     }
 
+    // BEGIN Android-changed: Clinit serialization workaround b/29064453
     /** Max SDK target version for which we use buggy hasStaticIntializier implementation. */
     static final int MAX_SDK_TARGET_FOR_CLINIT_UIDGEN_WORKAROUND = 23;
 
@@ -1816,7 +1885,7 @@
      * will return true even if only the superclass has a static initializer method.
      */
     private native static boolean hasStaticInitializer(Class<?> cl, boolean checkSuperclass);
-
+    // END Android-changed: Clinit serialization workaround b/29064453
 
     /**
      * Class for computing and caching field/constructor/method signatures
@@ -2267,7 +2336,7 @@
         }
         return matches;
     }
-
+    // BEGIN Android-added: Keep some private API for app compat. b/28283540.
     // NOTE: The following couple of methods are left here because frameworks such as objenesis
     // use them.
     //
@@ -2305,6 +2374,7 @@
         throw new UnsupportedOperationException("ObjectStreamClass.newInstance(Class<?>, long) " +
                                                 "is not supported on SDK " + targetSdkVersion);
     }
+    // END Android-added: Keep some private API for app compat. b/28283540.
 
     /**
      * Removes from the specified map any keys that have been enqueued
diff --git a/java/io/ObjectStreamField.java b/java/io/ObjectStreamField.java
index c49bcac..957972e 100644
--- a/java/io/ObjectStreamField.java
+++ b/java/io/ObjectStreamField.java
@@ -29,7 +29,6 @@
 import sun.reflect.CallerSensitive;
 import sun.reflect.Reflection;
 import sun.reflect.misc.ReflectUtil;
-import dalvik.system.VMStack;
 
 /**
  * A description of a Serializable field from a Serializable class.  An array
@@ -163,6 +162,14 @@
      */
     @CallerSensitive
     public Class<?> getType() {
+        /* BEGIN Android-removed: Security manager is always null on Android.
+        if (System.getSecurityManager() != null) {
+             Class<?> caller = Reflection.getCallerClass();
+            if (ReflectUtil.needsPackageAccessCheck(caller.getClassLoader(), type.getClassLoader())) {
+                ReflectUtil.checkPackageAccess(type);
+            }
+        }
+        END Android-removed: Security manager is always null on Android. */
         return type;
     }
 
diff --git a/java/io/RandomAccessFile.java b/java/io/RandomAccessFile.java
index 985f8ed..a83829f 100644
--- a/java/io/RandomAccessFile.java
+++ b/java/io/RandomAccessFile.java
@@ -26,6 +26,7 @@
 
 package java.io;
 
+import dalvik.annotation.optimization.ReachabilitySensitive;
 import java.nio.channels.FileChannel;
 import sun.nio.ch.FileChannelImpl;
 import android.system.Os;
@@ -67,6 +68,7 @@
 public class RandomAccessFile implements DataOutput, DataInput, Closeable {
 
     // BEGIN Android-added: CloseGuard and some helper fields for Android changes in this file.
+    @ReachabilitySensitive
     private final CloseGuard guard = CloseGuard.get();
     private final byte[] scratch = new byte[8];
 
@@ -78,6 +80,8 @@
     private int mode;
     // END Android-added: CloseGuard and some helper fields for Android changes in this file.
 
+    // Android-added: @ReachabilitySensitive
+    @ReachabilitySensitive
     private FileDescriptor fd;
     private FileChannel channel = null;
     private boolean rw;