1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This code is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License version 2 only, as
8  * published by the Free Software Foundation.  Oracle designates this
9  * particular file as subject to the "Classpath" exception as provided
10  * by Oracle in the LICENSE file that accompanied this code.
11  *
12  * This code is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15  * version 2 for more details (a copy is included in the LICENSE file that
16  * accompanied this code).
17  *
18  * You should have received a copy of the GNU General Public License version
19  * 2 along with this work; if not, write to the Free Software Foundation,
20  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
21  *
22  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
23  * or visit www.oracle.com if you need additional information or have any
24  * questions.
25  */
26 
27 package java.io;
28 
29 import java.io.ObjectStreamClass.WeakClassKey;
30 import java.lang.ref.ReferenceQueue;
31 import java.security.AccessController;
32 import java.security.PrivilegedAction;
33 import java.util.ArrayList;
34 import java.util.Arrays;
35 import java.util.List;
36 import java.util.concurrent.ConcurrentHashMap;
37 import java.util.concurrent.ConcurrentMap;
38 import static java.io.ObjectStreamClass.processQueue;
39 import java.io.SerialCallbackContext;
40 import sun.reflect.misc.ReflectUtil;
41 
42 /**
43  * An ObjectOutputStream writes primitive data types and graphs of Java objects
44  * to an OutputStream.  The objects can be read (reconstituted) using an
45  * ObjectInputStream.  Persistent storage of objects can be accomplished by
46  * using a file for the stream.  If the stream is a network socket stream, the
47  * objects can be reconstituted on another host or in another process.
48  *
49  * <p>Only objects that support the java.io.Serializable interface can be
50  * written to streams.  The class of each serializable object is encoded
51  * including the class name and signature of the class, the values of the
52  * object's fields and arrays, and the closure of any other objects referenced
53  * from the initial objects.
54  *
55  * <p>The method writeObject is used to write an object to the stream.  Any
56  * object, including Strings and arrays, is written with writeObject. Multiple
57  * objects or primitives can be written to the stream.  The objects must be
58  * read back from the corresponding ObjectInputstream with the same types and
59  * in the same order as they were written.
60  *
61  * <p>Primitive data types can also be written to the stream using the
62  * appropriate methods from DataOutput. Strings can also be written using the
63  * writeUTF method.
64  *
65  * <p>The default serialization mechanism for an object writes the class of the
66  * object, the class signature, and the values of all non-transient and
67  * non-static fields.  References to other objects (except in transient or
68  * static fields) cause those objects to be written also. Multiple references
69  * to a single object are encoded using a reference sharing mechanism so that
70  * graphs of objects can be restored to the same shape as when the original was
71  * written.
72  *
73  * <p>For example to write an object that can be read by the example in
74  * ObjectInputStream:
75  * <br>
76  * <pre>
77  *      FileOutputStream fos = new FileOutputStream("t.tmp");
78  *      ObjectOutputStream oos = new ObjectOutputStream(fos);
79  *
80  *      oos.writeInt(12345);
81  *      oos.writeObject("Today");
82  *      oos.writeObject(new Date());
83  *
84  *      oos.close();
85  * </pre>
86  *
87  * <p>Classes that require special handling during the serialization and
88  * deserialization process must implement special methods with these exact
89  * signatures:
90  * <br>
91  * <pre>
92  * private void readObject(java.io.ObjectInputStream stream)
93  *     throws IOException, ClassNotFoundException;
94  * private void writeObject(java.io.ObjectOutputStream stream)
95  *     throws IOException
96  * private void readObjectNoData()
97  *     throws ObjectStreamException;
98  * </pre>
99  *
100  * <p>The writeObject method is responsible for writing the state of the object
101  * for its particular class so that the corresponding readObject method can
102  * restore it.  The method does not need to concern itself with the state
103  * belonging to the object's superclasses or subclasses.  State is saved by
104  * writing the individual fields to the ObjectOutputStream using the
105  * writeObject method or by using the methods for primitive data types
106  * supported by DataOutput.
107  *
108  * <p>Serialization does not write out the fields of any object that does not
109  * implement the java.io.Serializable interface.  Subclasses of Objects that
110  * are not serializable can be serializable. In this case the non-serializable
111  * class must have a no-arg constructor to allow its fields to be initialized.
112  * In this case it is the responsibility of the subclass to save and restore
113  * the state of the non-serializable class. It is frequently the case that the
114  * fields of that class are accessible (public, package, or protected) or that
115  * there are get and set methods that can be used to restore the state.
116  *
117  * <p>Serialization of an object can be prevented by implementing writeObject
118  * and readObject methods that throw the NotSerializableException.  The
119  * exception will be caught by the ObjectOutputStream and abort the
120  * serialization process.
121  *
122  * <p>Implementing the Externalizable interface allows the object to assume
123  * complete control over the contents and format of the object's serialized
124  * form.  The methods of the Externalizable interface, writeExternal and
125  * readExternal, are called to save and restore the objects state.  When
126  * implemented by a class they can write and read their own state using all of
127  * the methods of ObjectOutput and ObjectInput.  It is the responsibility of
128  * the objects to handle any versioning that occurs.
129  *
130  * <p>Enum constants are serialized differently than ordinary serializable or
131  * externalizable objects.  The serialized form of an enum constant consists
132  * solely of its name; field values of the constant are not transmitted.  To
133  * serialize an enum constant, ObjectOutputStream writes the string returned by
134  * the constant's name method.  Like other serializable or externalizable
135  * objects, enum constants can function as the targets of back references
136  * appearing subsequently in the serialization stream.  The process by which
137  * enum constants are serialized cannot be customized; any class-specific
138  * writeObject and writeReplace methods defined by enum types are ignored
139  * during serialization.  Similarly, any serialPersistentFields or
140  * serialVersionUID field declarations are also ignored--all enum types have a
141  * fixed serialVersionUID of 0L.
142  *
143  * <p>Primitive data, excluding serializable fields and externalizable data, is
144  * written to the ObjectOutputStream in block-data records. A block data record
145  * is composed of a header and data. The block data header consists of a marker
146  * and the number of bytes to follow the header.  Consecutive primitive data
147  * writes are merged into one block-data record.  The blocking factor used for
148  * a block-data record will be 1024 bytes.  Each block-data record will be
149  * filled up to 1024 bytes, or be written whenever there is a termination of
150  * block-data mode.  Calls to the ObjectOutputStream methods writeObject,
151  * defaultWriteObject and writeFields initially terminate any existing
152  * block-data record.
153  *
154  * @author      Mike Warres
155  * @author      Roger Riggs
156  * @see java.io.DataOutput
157  * @see java.io.ObjectInputStream
158  * @see java.io.Serializable
159  * @see java.io.Externalizable
160  * @see <a href="../../../platform/serialization/spec/output.html">Object Serialization Specification, Section 2, Object Output Classes</a>
161  * @since       JDK1.1
162  */
163 public class ObjectOutputStream
164     extends OutputStream implements ObjectOutput, ObjectStreamConstants
165 {
166 
167     private static class Caches {
168         /** cache of subclass security audit results */
169         static final ConcurrentMap<WeakClassKey,Boolean> subclassAudits =
170             new ConcurrentHashMap<>();
171 
172         /** queue for WeakReferences to audited subclasses */
173         static final ReferenceQueue<Class<?>> subclassAuditsQueue =
174             new ReferenceQueue<>();
175     }
176 
177     /** filter stream for handling block data conversion */
178     private final BlockDataOutputStream bout;
179     /** obj -> wire handle map */
180     private final HandleTable handles;
181     /** obj -> replacement obj map */
182     private final ReplaceTable subs;
183     /** stream protocol version */
184     private int protocol = PROTOCOL_VERSION_2;
185     /** recursion depth */
186     private int depth;
187 
188     /** buffer for writing primitive field values */
189     private byte[] primVals;
190 
191     /** if true, invoke writeObjectOverride() instead of writeObject() */
192     private final boolean enableOverride;
193     /** if true, invoke replaceObject() */
194     private boolean enableReplace;
195 
196     // values below valid only during upcalls to writeObject()/writeExternal()
197     /**
198      * Context during upcalls to class-defined writeObject methods; holds
199      * object currently being serialized and descriptor for current class.
200      * Null when not during writeObject upcall.
201      */
202     private SerialCallbackContext curContext;
203     /** current PutField object */
204     private PutFieldImpl curPut;
205 
206     /** custom storage for debug trace info */
207     private final DebugTraceInfoStack debugInfoStack;
208 
209     /**
210      * value of "sun.io.serialization.extendedDebugInfo" property,
211      * as true or false for extended information about exception's place
212      */
213     // BEGIN Android-changed: Do not support extendedDebugInfo on Android.
214     /*
215     private static final boolean extendedDebugInfo =
216         java.security.AccessController.doPrivileged(
217             new sun.security.action.GetBooleanAction(
218                 "sun.io.serialization.extendedDebugInfo")).booleanValue();
219     */
220     private static final boolean extendedDebugInfo = false;
221     // END Android-changed: Do not support extendedDebugInfo on Android.
222 
223     /**
224      * Creates an ObjectOutputStream that writes to the specified OutputStream.
225      * This constructor writes the serialization stream header to the
226      * underlying stream; callers may wish to flush the stream immediately to
227      * ensure that constructors for receiving ObjectInputStreams will not block
228      * when reading the header.
229      *
230      * <p>If a security manager is installed, this constructor will check for
231      * the "enableSubclassImplementation" SerializablePermission when invoked
232      * directly or indirectly by the constructor of a subclass which overrides
233      * the ObjectOutputStream.putFields or ObjectOutputStream.writeUnshared
234      * methods.
235      *
236      * @param   out output stream to write to
237      * @throws  IOException if an I/O error occurs while writing stream header
238      * @throws  SecurityException if untrusted subclass illegally overrides
239      *          security-sensitive methods
240      * @throws  NullPointerException if <code>out</code> is <code>null</code>
241      * @since   1.4
242      * @see     ObjectOutputStream#ObjectOutputStream()
243      * @see     ObjectOutputStream#putFields()
244      * @see     ObjectInputStream#ObjectInputStream(InputStream)
245      */
ObjectOutputStream(OutputStream out)246     public ObjectOutputStream(OutputStream out) throws IOException {
247         verifySubclass();
248         bout = new BlockDataOutputStream(out);
249         handles = new HandleTable(10, (float) 3.00);
250         subs = new ReplaceTable(10, (float) 3.00);
251         enableOverride = false;
252         writeStreamHeader();
253         bout.setBlockDataMode(true);
254         if (extendedDebugInfo) {
255             debugInfoStack = new DebugTraceInfoStack();
256         } else {
257             debugInfoStack = null;
258         }
259     }
260 
261     /**
262      * Provide a way for subclasses that are completely reimplementing
263      * ObjectOutputStream to not have to allocate private data just used by
264      * this implementation of ObjectOutputStream.
265      *
266      * <p>If there is a security manager installed, this method first calls the
267      * security manager's <code>checkPermission</code> method with a
268      * <code>SerializablePermission("enableSubclassImplementation")</code>
269      * permission to ensure it's ok to enable subclassing.
270      *
271      * @throws  SecurityException if a security manager exists and its
272      *          <code>checkPermission</code> method denies enabling
273      *          subclassing.
274      * @throws  IOException if an I/O error occurs while creating this stream
275      * @see SecurityManager#checkPermission
276      * @see java.io.SerializablePermission
277      */
ObjectOutputStream()278     protected ObjectOutputStream() throws IOException, SecurityException {
279         SecurityManager sm = System.getSecurityManager();
280         if (sm != null) {
281             sm.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
282         }
283         bout = null;
284         handles = null;
285         subs = null;
286         enableOverride = true;
287         debugInfoStack = null;
288     }
289 
290     /**
291      * Specify stream protocol version to use when writing the stream.
292      *
293      * <p>This routine provides a hook to enable the current version of
294      * Serialization to write in a format that is backwards compatible to a
295      * previous version of the stream format.
296      *
297      * <p>Every effort will be made to avoid introducing additional
298      * backwards incompatibilities; however, sometimes there is no
299      * other alternative.
300      *
301      * @param   version use ProtocolVersion from java.io.ObjectStreamConstants.
302      * @throws  IllegalStateException if called after any objects
303      *          have been serialized.
304      * @throws  IllegalArgumentException if invalid version is passed in.
305      * @throws  IOException if I/O errors occur
306      * @see java.io.ObjectStreamConstants#PROTOCOL_VERSION_1
307      * @see java.io.ObjectStreamConstants#PROTOCOL_VERSION_2
308      * @since   1.2
309      */
useProtocolVersion(int version)310     public void useProtocolVersion(int version) throws IOException {
311         if (handles.size() != 0) {
312             // REMIND: implement better check for pristine stream?
313             throw new IllegalStateException("stream non-empty");
314         }
315         switch (version) {
316             case PROTOCOL_VERSION_1:
317             case PROTOCOL_VERSION_2:
318                 protocol = version;
319                 break;
320 
321             default:
322                 throw new IllegalArgumentException(
323                     "unknown version: " + version);
324         }
325     }
326 
327     /**
328      * Write the specified object to the ObjectOutputStream.  The class of the
329      * object, the signature of the class, and the values of the non-transient
330      * and non-static fields of the class and all of its supertypes are
331      * written.  Default serialization for a class can be overridden using the
332      * writeObject and the readObject methods.  Objects referenced by this
333      * object are written transitively so that a complete equivalent graph of
334      * objects can be reconstructed by an ObjectInputStream.
335      *
336      * <p>Exceptions are thrown for problems with the OutputStream and for
337      * classes that should not be serialized.  All exceptions are fatal to the
338      * OutputStream, which is left in an indeterminate state, and it is up to
339      * the caller to ignore or recover the stream state.
340      *
341      * @throws  InvalidClassException Something is wrong with a class used by
342      *          serialization.
343      * @throws  NotSerializableException Some object to be serialized does not
344      *          implement the java.io.Serializable interface.
345      * @throws  IOException Any exception thrown by the underlying
346      *          OutputStream.
347      */
writeObject(Object obj)348     public final void writeObject(Object obj) throws IOException {
349         if (enableOverride) {
350             writeObjectOverride(obj);
351             return;
352         }
353         try {
354             writeObject0(obj, false);
355         } catch (IOException ex) {
356             if (depth == 0) {
357                 // BEGIN Android-changed: Ignore secondary exceptions during writeObject().
358                 // writeFatalException(ex);
359                 try {
360                     writeFatalException(ex);
361 
362                 } catch (IOException ex2) {
363                     // If writing the exception to the output stream causes another exception there
364                     // is no need to propagate the second exception or generate a third exception,
365                     // both of which might obscure details of the root cause.
366                 }
367                 // END Android-changed: Ignore secondary exceptions during writeObject().
368             }
369             throw ex;
370         }
371     }
372 
373     /**
374      * Method used by subclasses to override the default writeObject method.
375      * This method is called by trusted subclasses of ObjectInputStream that
376      * constructed ObjectInputStream using the protected no-arg constructor.
377      * The subclass is expected to provide an override method with the modifier
378      * "final".
379      *
380      * @param   obj object to be written to the underlying stream
381      * @throws  IOException if there are I/O errors while writing to the
382      *          underlying stream
383      * @see #ObjectOutputStream()
384      * @see #writeObject(Object)
385      * @since 1.2
386      */
writeObjectOverride(Object obj)387     protected void writeObjectOverride(Object obj) throws IOException {
388         // BEGIN Android-added: Let writeObjectOverride throw IOException if !enableOverride.
389         if (!enableOverride) {
390             // Subclasses must override.
391             throw new IOException();
392         }
393         // END Android-added: Let writeObjectOverride throw IOException if !enableOverride.
394     }
395 
396     /**
397      * Writes an "unshared" object to the ObjectOutputStream.  This method is
398      * identical to writeObject, except that it always writes the given object
399      * as a new, unique object in the stream (as opposed to a back-reference
400      * pointing to a previously serialized instance).  Specifically:
401      * <ul>
402      *   <li>An object written via writeUnshared is always serialized in the
403      *       same manner as a newly appearing object (an object that has not
404      *       been written to the stream yet), regardless of whether or not the
405      *       object has been written previously.
406      *
407      *   <li>If writeObject is used to write an object that has been previously
408      *       written with writeUnshared, the previous writeUnshared operation
409      *       is treated as if it were a write of a separate object.  In other
410      *       words, ObjectOutputStream will never generate back-references to
411      *       object data written by calls to writeUnshared.
412      * </ul>
413      * While writing an object via writeUnshared does not in itself guarantee a
414      * unique reference to the object when it is deserialized, it allows a
415      * single object to be defined multiple times in a stream, so that multiple
416      * calls to readUnshared by the receiver will not conflict.  Note that the
417      * rules described above only apply to the base-level object written with
418      * writeUnshared, and not to any transitively referenced sub-objects in the
419      * object graph to be serialized.
420      *
421      * <p>ObjectOutputStream subclasses which override this method can only be
422      * constructed in security contexts possessing the
423      * "enableSubclassImplementation" SerializablePermission; any attempt to
424      * instantiate such a subclass without this permission will cause a
425      * SecurityException to be thrown.
426      *
427      * @param   obj object to write to stream
428      * @throws  NotSerializableException if an object in the graph to be
429      *          serialized does not implement the Serializable interface
430      * @throws  InvalidClassException if a problem exists with the class of an
431      *          object to be serialized
432      * @throws  IOException if an I/O error occurs during serialization
433      * @since 1.4
434      */
writeUnshared(Object obj)435     public void writeUnshared(Object obj) throws IOException {
436         try {
437             writeObject0(obj, true);
438         } catch (IOException ex) {
439             if (depth == 0) {
440                 writeFatalException(ex);
441             }
442             throw ex;
443         }
444     }
445 
446     /**
447      * Write the non-static and non-transient fields of the current class to
448      * this stream.  This may only be called from the writeObject method of the
449      * class being serialized. It will throw the NotActiveException if it is
450      * called otherwise.
451      *
452      * @throws  IOException if I/O errors occur while writing to the underlying
453      *          <code>OutputStream</code>
454      */
defaultWriteObject()455     public void defaultWriteObject() throws IOException {
456         SerialCallbackContext ctx = curContext;
457         if (ctx == null) {
458             throw new NotActiveException("not in call to writeObject");
459         }
460         Object curObj = ctx.getObj();
461         ObjectStreamClass curDesc = ctx.getDesc();
462         bout.setBlockDataMode(false);
463         defaultWriteFields(curObj, curDesc);
464         bout.setBlockDataMode(true);
465     }
466 
467     /**
468      * Retrieve the object used to buffer persistent fields to be written to
469      * the stream.  The fields will be written to the stream when writeFields
470      * method is called.
471      *
472      * @return  an instance of the class Putfield that holds the serializable
473      *          fields
474      * @throws  IOException if I/O errors occur
475      * @since 1.2
476      */
putFields()477     public ObjectOutputStream.PutField putFields() throws IOException {
478         if (curPut == null) {
479             SerialCallbackContext ctx = curContext;
480             if (ctx == null) {
481                 throw new NotActiveException("not in call to writeObject");
482             }
483             Object curObj = ctx.getObj();
484             ObjectStreamClass curDesc = ctx.getDesc();
485             curPut = new PutFieldImpl(curDesc);
486         }
487         return curPut;
488     }
489 
490     /**
491      * Write the buffered fields to the stream.
492      *
493      * @throws  IOException if I/O errors occur while writing to the underlying
494      *          stream
495      * @throws  NotActiveException Called when a classes writeObject method was
496      *          not called to write the state of the object.
497      * @since 1.2
498      */
writeFields()499     public void writeFields() throws IOException {
500         if (curPut == null) {
501             throw new NotActiveException("no current PutField object");
502         }
503         bout.setBlockDataMode(false);
504         curPut.writeFields();
505         bout.setBlockDataMode(true);
506     }
507 
508     /**
509      * Reset will disregard the state of any objects already written to the
510      * stream.  The state is reset to be the same as a new ObjectOutputStream.
511      * The current point in the stream is marked as reset so the corresponding
512      * ObjectInputStream will be reset at the same point.  Objects previously
513      * written to the stream will not be referred to as already being in the
514      * stream.  They will be written to the stream again.
515      *
516      * @throws  IOException if reset() is invoked while serializing an object.
517      */
reset()518     public void reset() throws IOException {
519         if (depth != 0) {
520             throw new IOException("stream active");
521         }
522         bout.setBlockDataMode(false);
523         bout.writeByte(TC_RESET);
524         clear();
525         bout.setBlockDataMode(true);
526     }
527 
528     /**
529      * Subclasses may implement this method to allow class data to be stored in
530      * the stream. By default this method does nothing.  The corresponding
531      * method in ObjectInputStream is resolveClass.  This method is called
532      * exactly once for each unique class in the stream.  The class name and
533      * signature will have already been written to the stream.  This method may
534      * make free use of the ObjectOutputStream to save any representation of
535      * the class it deems suitable (for example, the bytes of the class file).
536      * The resolveClass method in the corresponding subclass of
537      * ObjectInputStream must read and use any data or objects written by
538      * annotateClass.
539      *
540      * @param   cl the class to annotate custom data for
541      * @throws  IOException Any exception thrown by the underlying
542      *          OutputStream.
543      */
annotateClass(Class<?> cl)544     protected void annotateClass(Class<?> cl) throws IOException {
545     }
546 
547     /**
548      * Subclasses may implement this method to store custom data in the stream
549      * along with descriptors for dynamic proxy classes.
550      *
551      * <p>This method is called exactly once for each unique proxy class
552      * descriptor in the stream.  The default implementation of this method in
553      * <code>ObjectOutputStream</code> does nothing.
554      *
555      * <p>The corresponding method in <code>ObjectInputStream</code> is
556      * <code>resolveProxyClass</code>.  For a given subclass of
557      * <code>ObjectOutputStream</code> that overrides this method, the
558      * <code>resolveProxyClass</code> method in the corresponding subclass of
559      * <code>ObjectInputStream</code> must read any data or objects written by
560      * <code>annotateProxyClass</code>.
561      *
562      * @param   cl the proxy class to annotate custom data for
563      * @throws  IOException any exception thrown by the underlying
564      *          <code>OutputStream</code>
565      * @see ObjectInputStream#resolveProxyClass(String[])
566      * @since   1.3
567      */
annotateProxyClass(Class<?> cl)568     protected void annotateProxyClass(Class<?> cl) throws IOException {
569     }
570 
571     /**
572      * This method will allow trusted subclasses of ObjectOutputStream to
573      * substitute one object for another during serialization. Replacing
574      * objects is disabled until enableReplaceObject is called. The
575      * enableReplaceObject method checks that the stream requesting to do
576      * replacement can be trusted.  The first occurrence of each object written
577      * into the serialization stream is passed to replaceObject.  Subsequent
578      * references to the object are replaced by the object returned by the
579      * original call to replaceObject.  To ensure that the private state of
580      * objects is not unintentionally exposed, only trusted streams may use
581      * replaceObject.
582      *
583      * <p>The ObjectOutputStream.writeObject method takes a parameter of type
584      * Object (as opposed to type Serializable) to allow for cases where
585      * non-serializable objects are replaced by serializable ones.
586      *
587      * <p>When a subclass is replacing objects it must insure that either a
588      * complementary substitution must be made during deserialization or that
589      * the substituted object is compatible with every field where the
590      * reference will be stored.  Objects whose type is not a subclass of the
591      * type of the field or array element abort the serialization by raising an
592      * exception and the object is not be stored.
593      *
594      * <p>This method is called only once when each object is first
595      * encountered.  All subsequent references to the object will be redirected
596      * to the new object. This method should return the object to be
597      * substituted or the original object.
598      *
599      * <p>Null can be returned as the object to be substituted, but may cause
600      * NullReferenceException in classes that contain references to the
601      * original object since they may be expecting an object instead of
602      * null.
603      *
604      * @param   obj the object to be replaced
605      * @return  the alternate object that replaced the specified one
606      * @throws  IOException Any exception thrown by the underlying
607      *          OutputStream.
608      */
replaceObject(Object obj)609     protected Object replaceObject(Object obj) throws IOException {
610         return obj;
611     }
612 
613     /**
614      * Enable the stream to do replacement of objects in the stream.  When
615      * enabled, the replaceObject method is called for every object being
616      * serialized.
617      *
618      * <p>If <code>enable</code> is true, and there is a security manager
619      * installed, this method first calls the security manager's
620      * <code>checkPermission</code> method with a
621      * <code>SerializablePermission("enableSubstitution")</code> permission to
622      * ensure it's ok to enable the stream to do replacement of objects in the
623      * stream.
624      *
625      * @param   enable boolean parameter to enable replacement of objects
626      * @return  the previous setting before this method was invoked
627      * @throws  SecurityException if a security manager exists and its
628      *          <code>checkPermission</code> method denies enabling the stream
629      *          to do replacement of objects in the stream.
630      * @see SecurityManager#checkPermission
631      * @see java.io.SerializablePermission
632      */
enableReplaceObject(boolean enable)633     protected boolean enableReplaceObject(boolean enable)
634         throws SecurityException
635     {
636         if (enable == enableReplace) {
637             return enable;
638         }
639         if (enable) {
640             SecurityManager sm = System.getSecurityManager();
641             if (sm != null) {
642                 sm.checkPermission(SUBSTITUTION_PERMISSION);
643             }
644         }
645         enableReplace = enable;
646         return !enableReplace;
647     }
648 
649     /**
650      * The writeStreamHeader method is provided so subclasses can append or
651      * prepend their own header to the stream.  It writes the magic number and
652      * version to the stream.
653      *
654      * @throws  IOException if I/O errors occur while writing to the underlying
655      *          stream
656      */
writeStreamHeader()657     protected void writeStreamHeader() throws IOException {
658         bout.writeShort(STREAM_MAGIC);
659         bout.writeShort(STREAM_VERSION);
660     }
661 
662     /**
663      * Write the specified class descriptor to the ObjectOutputStream.  Class
664      * descriptors are used to identify the classes of objects written to the
665      * stream.  Subclasses of ObjectOutputStream may override this method to
666      * customize the way in which class descriptors are written to the
667      * serialization stream.  The corresponding method in ObjectInputStream,
668      * <code>readClassDescriptor</code>, should then be overridden to
669      * reconstitute the class descriptor from its custom stream representation.
670      * By default, this method writes class descriptors according to the format
671      * defined in the Object Serialization specification.
672      *
673      * <p>Note that this method will only be called if the ObjectOutputStream
674      * is not using the old serialization stream format (set by calling
675      * ObjectOutputStream's <code>useProtocolVersion</code> method).  If this
676      * serialization stream is using the old format
677      * (<code>PROTOCOL_VERSION_1</code>), the class descriptor will be written
678      * internally in a manner that cannot be overridden or customized.
679      *
680      * @param   desc class descriptor to write to the stream
681      * @throws  IOException If an I/O error has occurred.
682      * @see java.io.ObjectInputStream#readClassDescriptor()
683      * @see #useProtocolVersion(int)
684      * @see java.io.ObjectStreamConstants#PROTOCOL_VERSION_1
685      * @since 1.3
686      */
writeClassDescriptor(ObjectStreamClass desc)687     protected void writeClassDescriptor(ObjectStreamClass desc)
688         throws IOException
689     {
690         desc.writeNonProxy(this);
691     }
692 
693     /**
694      * Writes a byte. This method will block until the byte is actually
695      * written.
696      *
697      * @param   val the byte to be written to the stream
698      * @throws  IOException If an I/O error has occurred.
699      */
write(int val)700     public void write(int val) throws IOException {
701         bout.write(val);
702     }
703 
704     /**
705      * Writes an array of bytes. This method will block until the bytes are
706      * actually written.
707      *
708      * @param   buf the data to be written
709      * @throws  IOException If an I/O error has occurred.
710      */
write(byte[] buf)711     public void write(byte[] buf) throws IOException {
712         bout.write(buf, 0, buf.length, false);
713     }
714 
715     /**
716      * Writes a sub array of bytes.
717      *
718      * @param   buf the data to be written
719      * @param   off the start offset in the data
720      * @param   len the number of bytes that are written
721      * @throws  IOException If an I/O error has occurred.
722      */
write(byte[] buf, int off, int len)723     public void write(byte[] buf, int off, int len) throws IOException {
724         if (buf == null) {
725             throw new NullPointerException();
726         }
727         int endoff = off + len;
728         if (off < 0 || len < 0 || endoff > buf.length || endoff < 0) {
729             throw new IndexOutOfBoundsException();
730         }
731         bout.write(buf, off, len, false);
732     }
733 
734     /**
735      * Flushes the stream. This will write any buffered output bytes and flush
736      * through to the underlying stream.
737      *
738      * @throws  IOException If an I/O error has occurred.
739      */
flush()740     public void flush() throws IOException {
741         bout.flush();
742     }
743 
744     /**
745      * Drain any buffered data in ObjectOutputStream.  Similar to flush but
746      * does not propagate the flush to the underlying stream.
747      *
748      * @throws  IOException if I/O errors occur while writing to the underlying
749      *          stream
750      */
drain()751     protected void drain() throws IOException {
752         bout.drain();
753     }
754 
755     /**
756      * Closes the stream. This method must be called to release any resources
757      * associated with the stream.
758      *
759      * @throws  IOException If an I/O error has occurred.
760      */
close()761     public void close() throws IOException {
762         flush();
763         // Android-removed:  Don't clear() during close(), keep the handle table. http://b/28159133
764         // clear();
765         bout.close();
766     }
767 
768     /**
769      * Writes a boolean.
770      *
771      * @param   val the boolean to be written
772      * @throws  IOException if I/O errors occur while writing to the underlying
773      *          stream
774      */
writeBoolean(boolean val)775     public void writeBoolean(boolean val) throws IOException {
776         bout.writeBoolean(val);
777     }
778 
779     /**
780      * Writes an 8 bit byte.
781      *
782      * @param   val the byte value to be written
783      * @throws  IOException if I/O errors occur while writing to the underlying
784      *          stream
785      */
writeByte(int val)786     public void writeByte(int val) throws IOException  {
787         bout.writeByte(val);
788     }
789 
790     /**
791      * Writes a 16 bit short.
792      *
793      * @param   val the short value to be written
794      * @throws  IOException if I/O errors occur while writing to the underlying
795      *          stream
796      */
writeShort(int val)797     public void writeShort(int val)  throws IOException {
798         bout.writeShort(val);
799     }
800 
801     /**
802      * Writes a 16 bit char.
803      *
804      * @param   val the char value to be written
805      * @throws  IOException if I/O errors occur while writing to the underlying
806      *          stream
807      */
writeChar(int val)808     public void writeChar(int val)  throws IOException {
809         bout.writeChar(val);
810     }
811 
812     /**
813      * Writes a 32 bit int.
814      *
815      * @param   val the integer value to be written
816      * @throws  IOException if I/O errors occur while writing to the underlying
817      *          stream
818      */
writeInt(int val)819     public void writeInt(int val)  throws IOException {
820         bout.writeInt(val);
821     }
822 
823     /**
824      * Writes a 64 bit long.
825      *
826      * @param   val the long value to be written
827      * @throws  IOException if I/O errors occur while writing to the underlying
828      *          stream
829      */
writeLong(long val)830     public void writeLong(long val)  throws IOException {
831         bout.writeLong(val);
832     }
833 
834     /**
835      * Writes a 32 bit float.
836      *
837      * @param   val the float value to be written
838      * @throws  IOException if I/O errors occur while writing to the underlying
839      *          stream
840      */
writeFloat(float val)841     public void writeFloat(float val) throws IOException {
842         bout.writeFloat(val);
843     }
844 
845     /**
846      * Writes a 64 bit double.
847      *
848      * @param   val the double value to be written
849      * @throws  IOException if I/O errors occur while writing to the underlying
850      *          stream
851      */
writeDouble(double val)852     public void writeDouble(double val) throws IOException {
853         bout.writeDouble(val);
854     }
855 
856     /**
857      * Writes a String as a sequence of bytes.
858      *
859      * @param   str the String of bytes to be written
860      * @throws  IOException if I/O errors occur while writing to the underlying
861      *          stream
862      */
writeBytes(String str)863     public void writeBytes(String str) throws IOException {
864         bout.writeBytes(str);
865     }
866 
867     /**
868      * Writes a String as a sequence of chars.
869      *
870      * @param   str the String of chars to be written
871      * @throws  IOException if I/O errors occur while writing to the underlying
872      *          stream
873      */
writeChars(String str)874     public void writeChars(String str) throws IOException {
875         bout.writeChars(str);
876     }
877 
878     /**
879      * Primitive data write of this String in
880      * <a href="DataInput.html#modified-utf-8">modified UTF-8</a>
881      * format.  Note that there is a
882      * significant difference between writing a String into the stream as
883      * primitive data or as an Object. A String instance written by writeObject
884      * is written into the stream as a String initially. Future writeObject()
885      * calls write references to the string into the stream.
886      *
887      * @param   str the String to be written
888      * @throws  IOException if I/O errors occur while writing to the underlying
889      *          stream
890      */
writeUTF(String str)891     public void writeUTF(String str) throws IOException {
892         bout.writeUTF(str);
893     }
894 
895     /**
896      * Provide programmatic access to the persistent fields to be written
897      * to ObjectOutput.
898      *
899      * @since 1.2
900      */
901     public static abstract class PutField {
902 
903         /**
904          * Put the value of the named boolean field into the persistent field.
905          *
906          * @param  name the name of the serializable field
907          * @param  val the value to assign to the field
908          * @throws IllegalArgumentException if <code>name</code> does not
909          * match the name of a serializable field for the class whose fields
910          * are being written, or if the type of the named field is not
911          * <code>boolean</code>
912          */
put(String name, boolean val)913         public abstract void put(String name, boolean val);
914 
915         /**
916          * Put the value of the named byte field into the persistent field.
917          *
918          * @param  name the name of the serializable field
919          * @param  val the value to assign to the field
920          * @throws IllegalArgumentException if <code>name</code> does not
921          * match the name of a serializable field for the class whose fields
922          * are being written, or if the type of the named field is not
923          * <code>byte</code>
924          */
put(String name, byte val)925         public abstract void put(String name, byte val);
926 
927         /**
928          * Put the value of the named char field into the persistent field.
929          *
930          * @param  name the name of the serializable field
931          * @param  val the value to assign to the field
932          * @throws IllegalArgumentException if <code>name</code> does not
933          * match the name of a serializable field for the class whose fields
934          * are being written, or if the type of the named field is not
935          * <code>char</code>
936          */
put(String name, char val)937         public abstract void put(String name, char val);
938 
939         /**
940          * Put the value of the named short field into the persistent field.
941          *
942          * @param  name the name of the serializable field
943          * @param  val the value to assign to the field
944          * @throws IllegalArgumentException if <code>name</code> does not
945          * match the name of a serializable field for the class whose fields
946          * are being written, or if the type of the named field is not
947          * <code>short</code>
948          */
put(String name, short val)949         public abstract void put(String name, short val);
950 
951         /**
952          * Put the value of the named int field into the persistent field.
953          *
954          * @param  name the name of the serializable field
955          * @param  val the value to assign to the field
956          * @throws IllegalArgumentException if <code>name</code> does not
957          * match the name of a serializable field for the class whose fields
958          * are being written, or if the type of the named field is not
959          * <code>int</code>
960          */
put(String name, int val)961         public abstract void put(String name, int val);
962 
963         /**
964          * Put the value of the named long field into the persistent field.
965          *
966          * @param  name the name of the serializable field
967          * @param  val the value to assign to the field
968          * @throws IllegalArgumentException if <code>name</code> does not
969          * match the name of a serializable field for the class whose fields
970          * are being written, or if the type of the named field is not
971          * <code>long</code>
972          */
put(String name, long val)973         public abstract void put(String name, long val);
974 
975         /**
976          * Put the value of the named float field into the persistent field.
977          *
978          * @param  name the name of the serializable field
979          * @param  val the value to assign to the field
980          * @throws IllegalArgumentException if <code>name</code> does not
981          * match the name of a serializable field for the class whose fields
982          * are being written, or if the type of the named field is not
983          * <code>float</code>
984          */
put(String name, float val)985         public abstract void put(String name, float val);
986 
987         /**
988          * Put the value of the named double field into the persistent field.
989          *
990          * @param  name the name of the serializable field
991          * @param  val the value to assign to the field
992          * @throws IllegalArgumentException if <code>name</code> does not
993          * match the name of a serializable field for the class whose fields
994          * are being written, or if the type of the named field is not
995          * <code>double</code>
996          */
put(String name, double val)997         public abstract void put(String name, double val);
998 
999         /**
1000          * Put the value of the named Object field into the persistent field.
1001          *
1002          * @param  name the name of the serializable field
1003          * @param  val the value to assign to the field
1004          *         (which may be <code>null</code>)
1005          * @throws IllegalArgumentException if <code>name</code> does not
1006          * match the name of a serializable field for the class whose fields
1007          * are being written, or if the type of the named field is not a
1008          * reference type
1009          */
put(String name, Object val)1010         public abstract void put(String name, Object val);
1011 
1012         /**
1013          * Write the data and fields to the specified ObjectOutput stream,
1014          * which must be the same stream that produced this
1015          * <code>PutField</code> object.
1016          *
1017          * @param  out the stream to write the data and fields to
1018          * @throws IOException if I/O errors occur while writing to the
1019          *         underlying stream
1020          * @throws IllegalArgumentException if the specified stream is not
1021          *         the same stream that produced this <code>PutField</code>
1022          *         object
1023          * @deprecated This method does not write the values contained by this
1024          *         <code>PutField</code> object in a proper format, and may
1025          *         result in corruption of the serialization stream.  The
1026          *         correct way to write <code>PutField</code> data is by
1027          *         calling the {@link java.io.ObjectOutputStream#writeFields()}
1028          *         method.
1029          */
1030         @Deprecated
write(ObjectOutput out)1031         public abstract void write(ObjectOutput out) throws IOException;
1032     }
1033 
1034 
1035     /**
1036      * Returns protocol version in use.
1037      */
getProtocolVersion()1038     int getProtocolVersion() {
1039         return protocol;
1040     }
1041 
1042     /**
1043      * Writes string without allowing it to be replaced in stream.  Used by
1044      * ObjectStreamClass to write class descriptor type strings.
1045      */
writeTypeString(String str)1046     void writeTypeString(String str) throws IOException {
1047         int handle;
1048         if (str == null) {
1049             writeNull();
1050         } else if ((handle = handles.lookup(str)) != -1) {
1051             writeHandle(handle);
1052         } else {
1053             writeString(str, false);
1054         }
1055     }
1056 
1057     /**
1058      * Verifies that this (possibly subclass) instance can be constructed
1059      * without violating security constraints: the subclass must not override
1060      * security-sensitive non-final methods, or else the
1061      * "enableSubclassImplementation" SerializablePermission is checked.
1062      */
verifySubclass()1063     private void verifySubclass() {
1064         Class<?> cl = getClass();
1065         if (cl == ObjectOutputStream.class) {
1066             return;
1067         }
1068         SecurityManager sm = System.getSecurityManager();
1069         if (sm == null) {
1070             return;
1071         }
1072         processQueue(Caches.subclassAuditsQueue, Caches.subclassAudits);
1073         WeakClassKey key = new WeakClassKey(cl, Caches.subclassAuditsQueue);
1074         Boolean result = Caches.subclassAudits.get(key);
1075         if (result == null) {
1076             result = Boolean.valueOf(auditSubclass(cl));
1077             Caches.subclassAudits.putIfAbsent(key, result);
1078         }
1079         if (result.booleanValue()) {
1080             return;
1081         }
1082         sm.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
1083     }
1084 
1085     /**
1086      * Performs reflective checks on given subclass to verify that it doesn't
1087      * override security-sensitive non-final methods.  Returns true if subclass
1088      * is "safe", false otherwise.
1089      */
auditSubclass(final Class<?> subcl)1090     private static boolean auditSubclass(final Class<?> subcl) {
1091         Boolean result = AccessController.doPrivileged(
1092             new PrivilegedAction<Boolean>() {
1093                 public Boolean run() {
1094                     for (Class<?> cl = subcl;
1095                          cl != ObjectOutputStream.class;
1096                          cl = cl.getSuperclass())
1097                     {
1098                         try {
1099                             cl.getDeclaredMethod(
1100                                 "writeUnshared", new Class<?>[] { Object.class });
1101                             return Boolean.FALSE;
1102                         } catch (NoSuchMethodException ex) {
1103                         }
1104                         try {
1105                             cl.getDeclaredMethod("putFields", (Class<?>[]) null);
1106                             return Boolean.FALSE;
1107                         } catch (NoSuchMethodException ex) {
1108                         }
1109                     }
1110                     return Boolean.TRUE;
1111                 }
1112             }
1113         );
1114         return result.booleanValue();
1115     }
1116 
1117     /**
1118      * Clears internal data structures.
1119      */
clear()1120     private void clear() {
1121         subs.clear();
1122         handles.clear();
1123     }
1124 
1125     /**
1126      * Underlying writeObject/writeUnshared implementation.
1127      */
writeObject0(Object obj, boolean unshared)1128     private void writeObject0(Object obj, boolean unshared)
1129         throws IOException
1130     {
1131         boolean oldMode = bout.setBlockDataMode(false);
1132         depth++;
1133         try {
1134             // handle previously written and non-replaceable objects
1135             int h;
1136             if ((obj = subs.lookup(obj)) == null) {
1137                 writeNull();
1138                 return;
1139             } else if (!unshared && (h = handles.lookup(obj)) != -1) {
1140                 writeHandle(h);
1141                 return;
1142             // BEGIN Android-changed:  Make Class and ObjectStreamClass replaceable.
1143             /*
1144             } else if (obj instanceof Class) {
1145                 writeClass((Class) obj, unshared);
1146                 return;
1147             } else if (obj instanceof ObjectStreamClass) {
1148                 writeClassDesc((ObjectStreamClass) obj, unshared);
1149                 return;
1150             */
1151             // END Android-changed:  Make Class and ObjectStreamClass replaceable.
1152             }
1153 
1154             // check for replacement object
1155             Object orig = obj;
1156             Class<?> cl = obj.getClass();
1157             ObjectStreamClass desc;
1158 
1159             // BEGIN Android-changed: Make only one call to writeReplace.
1160             /*
1161             for (;;) {
1162                 // REMIND: skip this check for strings/arrays?
1163                 Class<?> repCl;
1164                 desc = ObjectStreamClass.lookup(cl, true);
1165                 if (!desc.hasWriteReplaceMethod() ||
1166                     (obj = desc.invokeWriteReplace(obj)) == null ||
1167                     (repCl = obj.getClass()) == cl)
1168                 {
1169                     break;
1170                 }
1171                 cl = repCl;
1172                 desc = ObjectStreamClass.lookup(cl, true);
1173                 break;
1174             }
1175             */
1176             // Do only one replace pass
1177 
1178             Class repCl;
1179             desc = ObjectStreamClass.lookup(cl, true);
1180             if (desc.hasWriteReplaceMethod() &&
1181                 (obj = desc.invokeWriteReplace(obj)) != null &&
1182                 (repCl = obj.getClass()) != cl)
1183             {
1184                 cl = repCl;
1185                 desc = ObjectStreamClass.lookup(cl, true);
1186             }
1187             // END Android-changed: Make only one call to writeReplace.
1188 
1189             if (enableReplace) {
1190                 Object rep = replaceObject(obj);
1191                 if (rep != obj && rep != null) {
1192                     cl = rep.getClass();
1193                     desc = ObjectStreamClass.lookup(cl, true);
1194                 }
1195                 obj = rep;
1196             }
1197 
1198             // if object replaced, run through original checks a second time
1199             if (obj != orig) {
1200                 subs.assign(orig, obj);
1201                 if (obj == null) {
1202                     writeNull();
1203                     return;
1204                 } else if (!unshared && (h = handles.lookup(obj)) != -1) {
1205                     writeHandle(h);
1206                     return;
1207 // BEGIN Android-changed:  Make Class and ObjectStreamClass replaceable.
1208 /*
1209                 } else if (obj instanceof Class) {
1210                     writeClass((Class) obj, unshared);
1211                     return;
1212                 } else if (obj instanceof ObjectStreamClass) {
1213                     writeClassDesc((ObjectStreamClass) obj, unshared);
1214                     return;
1215 */
1216 // END Android-changed:  Make Class and ObjectStreamClass replaceable.
1217                 }
1218             }
1219 
1220             // remaining cases
1221             // BEGIN Android-changed: Make Class and ObjectStreamClass replaceable.
1222             if (obj instanceof Class) {
1223                 writeClass((Class) obj, unshared);
1224             } else if (obj instanceof ObjectStreamClass) {
1225                 writeClassDesc((ObjectStreamClass) obj, unshared);
1226             // END Android-changed: Make Class and ObjectStreamClass replaceable.
1227             } else if (obj instanceof String) {
1228                 writeString((String) obj, unshared);
1229             } else if (cl.isArray()) {
1230                 writeArray(obj, desc, unshared);
1231             } else if (obj instanceof Enum) {
1232                 writeEnum((Enum<?>) obj, desc, unshared);
1233             } else if (obj instanceof Serializable) {
1234                 writeOrdinaryObject(obj, desc, unshared);
1235             } else {
1236                 if (extendedDebugInfo) {
1237                     throw new NotSerializableException(
1238                         cl.getName() + "\n" + debugInfoStack.toString());
1239                 } else {
1240                     throw new NotSerializableException(cl.getName());
1241                 }
1242             }
1243         } finally {
1244             depth--;
1245             bout.setBlockDataMode(oldMode);
1246         }
1247     }
1248 
1249     /**
1250      * Writes null code to stream.
1251      */
writeNull()1252     private void writeNull() throws IOException {
1253         bout.writeByte(TC_NULL);
1254     }
1255 
1256     /**
1257      * Writes given object handle to stream.
1258      */
writeHandle(int handle)1259     private void writeHandle(int handle) throws IOException {
1260         bout.writeByte(TC_REFERENCE);
1261         bout.writeInt(baseWireHandle + handle);
1262     }
1263 
1264     /**
1265      * Writes representation of given class to stream.
1266      */
writeClass(Class<?> cl, boolean unshared)1267     private void writeClass(Class<?> cl, boolean unshared) throws IOException {
1268         bout.writeByte(TC_CLASS);
1269         writeClassDesc(ObjectStreamClass.lookup(cl, true), false);
1270         handles.assign(unshared ? null : cl);
1271     }
1272 
1273     /**
1274      * Writes representation of given class descriptor to stream.
1275      */
writeClassDesc(ObjectStreamClass desc, boolean unshared)1276     private void writeClassDesc(ObjectStreamClass desc, boolean unshared)
1277         throws IOException
1278     {
1279         int handle;
1280         if (desc == null) {
1281             writeNull();
1282         } else if (!unshared && (handle = handles.lookup(desc)) != -1) {
1283             writeHandle(handle);
1284         } else if (desc.isProxy()) {
1285             writeProxyDesc(desc, unshared);
1286         } else {
1287             writeNonProxyDesc(desc, unshared);
1288         }
1289     }
1290 
isCustomSubclass()1291     private boolean isCustomSubclass() {
1292         // Return true if this class is a custom subclass of ObjectOutputStream
1293         return getClass().getClassLoader()
1294                    != ObjectOutputStream.class.getClassLoader();
1295     }
1296 
1297     /**
1298      * Writes class descriptor representing a dynamic proxy class to stream.
1299      */
writeProxyDesc(ObjectStreamClass desc, boolean unshared)1300     private void writeProxyDesc(ObjectStreamClass desc, boolean unshared)
1301         throws IOException
1302     {
1303         bout.writeByte(TC_PROXYCLASSDESC);
1304         handles.assign(unshared ? null : desc);
1305 
1306         Class<?> cl = desc.forClass();
1307         Class<?>[] ifaces = cl.getInterfaces();
1308         bout.writeInt(ifaces.length);
1309         for (int i = 0; i < ifaces.length; i++) {
1310             bout.writeUTF(ifaces[i].getName());
1311         }
1312 
1313         bout.setBlockDataMode(true);
1314         if (cl != null && isCustomSubclass()) {
1315             ReflectUtil.checkPackageAccess(cl);
1316         }
1317         annotateProxyClass(cl);
1318         bout.setBlockDataMode(false);
1319         bout.writeByte(TC_ENDBLOCKDATA);
1320 
1321         writeClassDesc(desc.getSuperDesc(), false);
1322     }
1323 
1324     /**
1325      * Writes class descriptor representing a standard (i.e., not a dynamic
1326      * proxy) class to stream.
1327      */
writeNonProxyDesc(ObjectStreamClass desc, boolean unshared)1328     private void writeNonProxyDesc(ObjectStreamClass desc, boolean unshared)
1329         throws IOException
1330     {
1331         bout.writeByte(TC_CLASSDESC);
1332         handles.assign(unshared ? null : desc);
1333 
1334         if (protocol == PROTOCOL_VERSION_1) {
1335             // do not invoke class descriptor write hook with old protocol
1336             desc.writeNonProxy(this);
1337         } else {
1338             writeClassDescriptor(desc);
1339         }
1340 
1341         Class<?> cl = desc.forClass();
1342         bout.setBlockDataMode(true);
1343         if (cl != null && isCustomSubclass()) {
1344             ReflectUtil.checkPackageAccess(cl);
1345         }
1346         annotateClass(cl);
1347         bout.setBlockDataMode(false);
1348         bout.writeByte(TC_ENDBLOCKDATA);
1349 
1350         writeClassDesc(desc.getSuperDesc(), false);
1351     }
1352 
1353     /**
1354      * Writes given string to stream, using standard or long UTF format
1355      * depending on string length.
1356      */
writeString(String str, boolean unshared)1357     private void writeString(String str, boolean unshared) throws IOException {
1358         handles.assign(unshared ? null : str);
1359         long utflen = bout.getUTFLength(str);
1360         if (utflen <= 0xFFFF) {
1361             bout.writeByte(TC_STRING);
1362             bout.writeUTF(str, utflen);
1363         } else {
1364             bout.writeByte(TC_LONGSTRING);
1365             bout.writeLongUTF(str, utflen);
1366         }
1367     }
1368 
1369     /**
1370      * Writes given array object to stream.
1371      */
writeArray(Object array, ObjectStreamClass desc, boolean unshared)1372     private void writeArray(Object array,
1373                             ObjectStreamClass desc,
1374                             boolean unshared)
1375         throws IOException
1376     {
1377         bout.writeByte(TC_ARRAY);
1378         writeClassDesc(desc, false);
1379         handles.assign(unshared ? null : array);
1380 
1381         Class<?> ccl = desc.forClass().getComponentType();
1382         if (ccl.isPrimitive()) {
1383             if (ccl == Integer.TYPE) {
1384                 int[] ia = (int[]) array;
1385                 bout.writeInt(ia.length);
1386                 bout.writeInts(ia, 0, ia.length);
1387             } else if (ccl == Byte.TYPE) {
1388                 byte[] ba = (byte[]) array;
1389                 bout.writeInt(ba.length);
1390                 bout.write(ba, 0, ba.length, true);
1391             } else if (ccl == Long.TYPE) {
1392                 long[] ja = (long[]) array;
1393                 bout.writeInt(ja.length);
1394                 bout.writeLongs(ja, 0, ja.length);
1395             } else if (ccl == Float.TYPE) {
1396                 float[] fa = (float[]) array;
1397                 bout.writeInt(fa.length);
1398                 bout.writeFloats(fa, 0, fa.length);
1399             } else if (ccl == Double.TYPE) {
1400                 double[] da = (double[]) array;
1401                 bout.writeInt(da.length);
1402                 bout.writeDoubles(da, 0, da.length);
1403             } else if (ccl == Short.TYPE) {
1404                 short[] sa = (short[]) array;
1405                 bout.writeInt(sa.length);
1406                 bout.writeShorts(sa, 0, sa.length);
1407             } else if (ccl == Character.TYPE) {
1408                 char[] ca = (char[]) array;
1409                 bout.writeInt(ca.length);
1410                 bout.writeChars(ca, 0, ca.length);
1411             } else if (ccl == Boolean.TYPE) {
1412                 boolean[] za = (boolean[]) array;
1413                 bout.writeInt(za.length);
1414                 bout.writeBooleans(za, 0, za.length);
1415             } else {
1416                 throw new InternalError();
1417             }
1418         } else {
1419             Object[] objs = (Object[]) array;
1420             int len = objs.length;
1421             bout.writeInt(len);
1422             if (extendedDebugInfo) {
1423                 debugInfoStack.push(
1424                     "array (class \"" + array.getClass().getName() +
1425                     "\", size: " + len  + ")");
1426             }
1427             try {
1428                 for (int i = 0; i < len; i++) {
1429                     if (extendedDebugInfo) {
1430                         debugInfoStack.push(
1431                             "element of array (index: " + i + ")");
1432                     }
1433                     try {
1434                         writeObject0(objs[i], false);
1435                     } finally {
1436                         if (extendedDebugInfo) {
1437                             debugInfoStack.pop();
1438                         }
1439                     }
1440                 }
1441             } finally {
1442                 if (extendedDebugInfo) {
1443                     debugInfoStack.pop();
1444                 }
1445             }
1446         }
1447     }
1448 
1449     /**
1450      * Writes given enum constant to stream.
1451      */
writeEnum(Enum<?> en, ObjectStreamClass desc, boolean unshared)1452     private void writeEnum(Enum<?> en,
1453                            ObjectStreamClass desc,
1454                            boolean unshared)
1455         throws IOException
1456     {
1457         bout.writeByte(TC_ENUM);
1458         ObjectStreamClass sdesc = desc.getSuperDesc();
1459         writeClassDesc((sdesc.forClass() == Enum.class) ? desc : sdesc, false);
1460         handles.assign(unshared ? null : en);
1461         writeString(en.name(), false);
1462     }
1463 
1464     /**
1465      * Writes representation of a "ordinary" (i.e., not a String, Class,
1466      * ObjectStreamClass, array, or enum constant) serializable object to the
1467      * stream.
1468      */
writeOrdinaryObject(Object obj, ObjectStreamClass desc, boolean unshared)1469     private void writeOrdinaryObject(Object obj,
1470                                      ObjectStreamClass desc,
1471                                      boolean unshared)
1472         throws IOException
1473     {
1474         if (extendedDebugInfo) {
1475             debugInfoStack.push(
1476                 (depth == 1 ? "root " : "") + "object (class \"" +
1477                 obj.getClass().getName() + "\", " + obj.toString() + ")");
1478         }
1479         try {
1480             desc.checkSerialize();
1481 
1482             bout.writeByte(TC_OBJECT);
1483             writeClassDesc(desc, false);
1484             handles.assign(unshared ? null : obj);
1485             if (desc.isRecord()) {
1486                 writeRecordData(obj, desc);
1487             } else if (desc.isExternalizable() && !desc.isProxy()) {
1488                 writeExternalData((Externalizable) obj);
1489             } else {
1490                 writeSerialData(obj, desc);
1491             }
1492         } finally {
1493             if (extendedDebugInfo) {
1494                 debugInfoStack.pop();
1495             }
1496         }
1497     }
1498 
1499     /**
1500      * Writes externalizable data of given object by invoking its
1501      * writeExternal() method.
1502      */
writeExternalData(Externalizable obj)1503     private void writeExternalData(Externalizable obj) throws IOException {
1504         PutFieldImpl oldPut = curPut;
1505         curPut = null;
1506 
1507         if (extendedDebugInfo) {
1508             debugInfoStack.push("writeExternal data");
1509         }
1510         SerialCallbackContext oldContext = curContext;
1511         try {
1512             curContext = null;
1513             if (protocol == PROTOCOL_VERSION_1) {
1514                 obj.writeExternal(this);
1515             } else {
1516                 bout.setBlockDataMode(true);
1517                 obj.writeExternal(this);
1518                 bout.setBlockDataMode(false);
1519                 bout.writeByte(TC_ENDBLOCKDATA);
1520             }
1521         } finally {
1522             curContext = oldContext;
1523             if (extendedDebugInfo) {
1524                 debugInfoStack.pop();
1525             }
1526         }
1527 
1528         curPut = oldPut;
1529     }
1530 
1531     /** Writes the record component values for the given record object. */
writeRecordData(Object obj, ObjectStreamClass desc)1532     private void writeRecordData(Object obj, ObjectStreamClass desc)
1533             throws IOException
1534     {
1535         assert obj.getClass().isRecord();
1536         ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout();
1537         if (slots.length != 1) {
1538             throw new InvalidClassException(
1539                     "expected a single record slot length, but found: " + slots.length);
1540         }
1541 
1542         defaultWriteFields(obj, desc);  // #### seems unnecessary to use the accessors
1543     }
1544 
1545     /**
1546      * Writes instance data for each serializable class of given object, from
1547      * superclass to subclass.
1548      */
writeSerialData(Object obj, ObjectStreamClass desc)1549     private void writeSerialData(Object obj, ObjectStreamClass desc)
1550         throws IOException
1551     {
1552         ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout();
1553         for (int i = 0; i < slots.length; i++) {
1554             ObjectStreamClass slotDesc = slots[i].desc;
1555             if (slotDesc.hasWriteObjectMethod()) {
1556                 PutFieldImpl oldPut = curPut;
1557                 curPut = null;
1558                 SerialCallbackContext oldContext = curContext;
1559 
1560                 if (extendedDebugInfo) {
1561                     debugInfoStack.push(
1562                         "custom writeObject data (class \"" +
1563                         slotDesc.getName() + "\")");
1564                 }
1565                 try {
1566                     curContext = new SerialCallbackContext(obj, slotDesc);
1567                     bout.setBlockDataMode(true);
1568                     slotDesc.invokeWriteObject(obj, this);
1569                     bout.setBlockDataMode(false);
1570                     bout.writeByte(TC_ENDBLOCKDATA);
1571                 } finally {
1572                     curContext.setUsed();
1573                     curContext = oldContext;
1574                     if (extendedDebugInfo) {
1575                         debugInfoStack.pop();
1576                     }
1577                 }
1578 
1579                 curPut = oldPut;
1580             } else {
1581                 defaultWriteFields(obj, slotDesc);
1582             }
1583         }
1584     }
1585 
1586     /**
1587      * Fetches and writes values of serializable fields of given object to
1588      * stream.  The given class descriptor specifies which field values to
1589      * write, and in which order they should be written.
1590      */
defaultWriteFields(Object obj, ObjectStreamClass desc)1591     private void defaultWriteFields(Object obj, ObjectStreamClass desc)
1592         throws IOException
1593     {
1594         Class<?> cl = desc.forClass();
1595         if (cl != null && obj != null && !cl.isInstance(obj)) {
1596             throw new ClassCastException();
1597         }
1598 
1599         desc.checkDefaultSerialize();
1600 
1601         int primDataSize = desc.getPrimDataSize();
1602         if (primVals == null || primVals.length < primDataSize) {
1603             primVals = new byte[primDataSize];
1604         }
1605         desc.getPrimFieldValues(obj, primVals);
1606         bout.write(primVals, 0, primDataSize, false);
1607 
1608         ObjectStreamField[] fields = desc.getFields(false);
1609         Object[] objVals = new Object[desc.getNumObjFields()];
1610         int numPrimFields = fields.length - objVals.length;
1611         desc.getObjFieldValues(obj, objVals);
1612         for (int i = 0; i < objVals.length; i++) {
1613             if (extendedDebugInfo) {
1614                 debugInfoStack.push(
1615                     "field (class \"" + desc.getName() + "\", name: \"" +
1616                     fields[numPrimFields + i].getName() + "\", type: \"" +
1617                     fields[numPrimFields + i].getType() + "\")");
1618             }
1619             try {
1620                 writeObject0(objVals[i],
1621                              fields[numPrimFields + i].isUnshared());
1622             } finally {
1623                 if (extendedDebugInfo) {
1624                     debugInfoStack.pop();
1625                 }
1626             }
1627         }
1628     }
1629 
1630     /**
1631      * Attempts to write to stream fatal IOException that has caused
1632      * serialization to abort.
1633      */
writeFatalException(IOException ex)1634     private void writeFatalException(IOException ex) throws IOException {
1635         /*
1636          * Note: the serialization specification states that if a second
1637          * IOException occurs while attempting to serialize the original fatal
1638          * exception to the stream, then a StreamCorruptedException should be
1639          * thrown (section 2.1).  However, due to a bug in previous
1640          * implementations of serialization, StreamCorruptedExceptions were
1641          * rarely (if ever) actually thrown--the "root" exceptions from
1642          * underlying streams were thrown instead.  This historical behavior is
1643          * followed here for consistency.
1644          */
1645         clear();
1646         boolean oldMode = bout.setBlockDataMode(false);
1647         try {
1648             bout.writeByte(TC_EXCEPTION);
1649             writeObject0(ex, false);
1650             clear();
1651         } finally {
1652             bout.setBlockDataMode(oldMode);
1653         }
1654     }
1655 
1656     /**
1657      * Converts specified span of float values into byte values.
1658      */
1659     // REMIND: remove once hotspot inlines Float.floatToIntBits
floatsToBytes(float[] src, int srcpos, byte[] dst, int dstpos, int nfloats)1660     private static native void floatsToBytes(float[] src, int srcpos,
1661                                              byte[] dst, int dstpos,
1662                                              int nfloats);
1663 
1664     /**
1665      * Converts specified span of double values into byte values.
1666      */
1667     // REMIND: remove once hotspot inlines Double.doubleToLongBits
doublesToBytes(double[] src, int srcpos, byte[] dst, int dstpos, int ndoubles)1668     private static native void doublesToBytes(double[] src, int srcpos,
1669                                               byte[] dst, int dstpos,
1670                                               int ndoubles);
1671 
1672     /**
1673      * Default PutField implementation.
1674      */
1675     private class PutFieldImpl extends PutField {
1676 
1677         /** class descriptor describing serializable fields */
1678         private final ObjectStreamClass desc;
1679         /** primitive field values */
1680         private final byte[] primVals;
1681         /** object field values */
1682         private final Object[] objVals;
1683 
1684         /**
1685          * Creates PutFieldImpl object for writing fields defined in given
1686          * class descriptor.
1687          */
PutFieldImpl(ObjectStreamClass desc)1688         PutFieldImpl(ObjectStreamClass desc) {
1689             this.desc = desc;
1690             primVals = new byte[desc.getPrimDataSize()];
1691             objVals = new Object[desc.getNumObjFields()];
1692         }
1693 
put(String name, boolean val)1694         public void put(String name, boolean val) {
1695             Bits.putBoolean(primVals, getFieldOffset(name, Boolean.TYPE), val);
1696         }
1697 
put(String name, byte val)1698         public void put(String name, byte val) {
1699             primVals[getFieldOffset(name, Byte.TYPE)] = val;
1700         }
1701 
put(String name, char val)1702         public void put(String name, char val) {
1703             Bits.putChar(primVals, getFieldOffset(name, Character.TYPE), val);
1704         }
1705 
put(String name, short val)1706         public void put(String name, short val) {
1707             Bits.putShort(primVals, getFieldOffset(name, Short.TYPE), val);
1708         }
1709 
put(String name, int val)1710         public void put(String name, int val) {
1711             Bits.putInt(primVals, getFieldOffset(name, Integer.TYPE), val);
1712         }
1713 
put(String name, float val)1714         public void put(String name, float val) {
1715             Bits.putFloat(primVals, getFieldOffset(name, Float.TYPE), val);
1716         }
1717 
put(String name, long val)1718         public void put(String name, long val) {
1719             Bits.putLong(primVals, getFieldOffset(name, Long.TYPE), val);
1720         }
1721 
put(String name, double val)1722         public void put(String name, double val) {
1723             Bits.putDouble(primVals, getFieldOffset(name, Double.TYPE), val);
1724         }
1725 
put(String name, Object val)1726         public void put(String name, Object val) {
1727             objVals[getFieldOffset(name, Object.class)] = val;
1728         }
1729 
1730         // deprecated in ObjectOutputStream.PutField
write(ObjectOutput out)1731         public void write(ObjectOutput out) throws IOException {
1732             /*
1733              * Applications should *not* use this method to write PutField
1734              * data, as it will lead to stream corruption if the PutField
1735              * object writes any primitive data (since block data mode is not
1736              * unset/set properly, as is done in OOS.writeFields()).  This
1737              * broken implementation is being retained solely for behavioral
1738              * compatibility, in order to support applications which use
1739              * OOS.PutField.write() for writing only non-primitive data.
1740              *
1741              * Serialization of unshared objects is not implemented here since
1742              * it is not necessary for backwards compatibility; also, unshared
1743              * semantics may not be supported by the given ObjectOutput
1744              * instance.  Applications which write unshared objects using the
1745              * PutField API must use OOS.writeFields().
1746              */
1747             if (ObjectOutputStream.this != out) {
1748                 throw new IllegalArgumentException("wrong stream");
1749             }
1750             out.write(primVals, 0, primVals.length);
1751 
1752             ObjectStreamField[] fields = desc.getFields(false);
1753             int numPrimFields = fields.length - objVals.length;
1754             // REMIND: warn if numPrimFields > 0?
1755             for (int i = 0; i < objVals.length; i++) {
1756                 if (fields[numPrimFields + i].isUnshared()) {
1757                     throw new IOException("cannot write unshared object");
1758                 }
1759                 out.writeObject(objVals[i]);
1760             }
1761         }
1762 
1763         /**
1764          * Writes buffered primitive data and object fields to stream.
1765          */
writeFields()1766         void writeFields() throws IOException {
1767             bout.write(primVals, 0, primVals.length, false);
1768 
1769             ObjectStreamField[] fields = desc.getFields(false);
1770             int numPrimFields = fields.length - objVals.length;
1771             for (int i = 0; i < objVals.length; i++) {
1772                 if (extendedDebugInfo) {
1773                     debugInfoStack.push(
1774                         "field (class \"" + desc.getName() + "\", name: \"" +
1775                         fields[numPrimFields + i].getName() + "\", type: \"" +
1776                         fields[numPrimFields + i].getType() + "\")");
1777                 }
1778                 try {
1779                     writeObject0(objVals[i],
1780                                  fields[numPrimFields + i].isUnshared());
1781                 } finally {
1782                     if (extendedDebugInfo) {
1783                         debugInfoStack.pop();
1784                     }
1785                 }
1786             }
1787         }
1788 
1789         /**
1790          * Returns offset of field with given name and type.  A specified type
1791          * of null matches all types, Object.class matches all non-primitive
1792          * types, and any other non-null type matches assignable types only.
1793          * Throws IllegalArgumentException if no matching field found.
1794          */
getFieldOffset(String name, Class<?> type)1795         private int getFieldOffset(String name, Class<?> type) {
1796             ObjectStreamField field = desc.getField(name, type);
1797             if (field == null) {
1798                 throw new IllegalArgumentException("no such field " + name +
1799                                                    " with type " + type);
1800             }
1801             return field.getOffset();
1802         }
1803     }
1804 
1805     /**
1806      * Buffered output stream with two modes: in default mode, outputs data in
1807      * same format as DataOutputStream; in "block data" mode, outputs data
1808      * bracketed by block data markers (see object serialization specification
1809      * for details).
1810      */
1811     private static class BlockDataOutputStream
1812         extends OutputStream implements DataOutput
1813     {
1814         /** maximum data block length */
1815         private static final int MAX_BLOCK_SIZE = 1024;
1816         /** maximum data block header length */
1817         private static final int MAX_HEADER_SIZE = 5;
1818         /** (tunable) length of char buffer (for writing strings) */
1819         private static final int CHAR_BUF_SIZE = 256;
1820 
1821         /** buffer for writing general/block data */
1822         private final byte[] buf = new byte[MAX_BLOCK_SIZE];
1823         /** buffer for writing block data headers */
1824         private final byte[] hbuf = new byte[MAX_HEADER_SIZE];
1825         /** char buffer for fast string writes */
1826         private final char[] cbuf = new char[CHAR_BUF_SIZE];
1827 
1828         /** block data mode */
1829         private boolean blkmode = false;
1830         /** current offset into buf */
1831         private int pos = 0;
1832 
1833         /** underlying output stream */
1834         private final OutputStream out;
1835         /** loopback stream (for data writes that span data blocks) */
1836         private final DataOutputStream dout;
1837 
1838         // BEGIN Android-added: Warning if writing to a closed ObjectOutputStream.
1839         /**
1840          * Indicates that this stream was closed and that a warning must be logged once if an
1841          * attempt is made to write to it and the underlying stream does not throw an exception.
1842          *
1843          * <p>This will be set back to false when a warning is logged to ensure that the log is not
1844          * flooded with warnings.
1845          *
1846          * http://b/28159133
1847          */
1848         private boolean warnOnceWhenWriting;
1849         // END Android-added: Warning if writing to a closed ObjectOutputStream.
1850 
1851         /**
1852          * Creates new BlockDataOutputStream on top of given underlying stream.
1853          * Block data mode is turned off by default.
1854          */
BlockDataOutputStream(OutputStream out)1855         BlockDataOutputStream(OutputStream out) {
1856             this.out = out;
1857             dout = new DataOutputStream(this);
1858         }
1859 
1860         /**
1861          * Sets block data mode to the given mode (true == on, false == off)
1862          * and returns the previous mode value.  If the new mode is the same as
1863          * the old mode, no action is taken.  If the new mode differs from the
1864          * old mode, any buffered data is flushed before switching to the new
1865          * mode.
1866          */
setBlockDataMode(boolean mode)1867         boolean setBlockDataMode(boolean mode) throws IOException {
1868             if (blkmode == mode) {
1869                 return blkmode;
1870             }
1871             drain();
1872             blkmode = mode;
1873             return !blkmode;
1874         }
1875 
1876         /**
1877          * Returns true if the stream is currently in block data mode, false
1878          * otherwise.
1879          */
getBlockDataMode()1880         boolean getBlockDataMode() {
1881             return blkmode;
1882         }
1883 
1884         // BEGIN Android-added: Warning about writing to closed ObjectOutputStream.
1885         /**
1886          * Warns if the stream has been closed.
1887          *
1888          * <p>This is called after data has been written to the underlying stream in order to allow
1889          * the underlying stream to detect and fail if an attempt is made to write to a closed
1890          * stream. That ensures that this will only log a warning if the underlying stream does not
1891          * so it will not log unnecessary warnings.
1892          */
warnIfClosed()1893         private void warnIfClosed() {
1894             if (warnOnceWhenWriting) {
1895                 System.logW("The app is relying on undefined behavior. Attempting to write to a"
1896                         + " closed ObjectOutputStream could produce corrupt output in a future"
1897                         + " release of Android.", new IOException("Stream Closed"));
1898                 // Set back to false so no more messages are logged unless the stream is closed
1899                 // again.
1900                 warnOnceWhenWriting = false;
1901             }
1902         }
1903         // END Android-added: Warning about writing to closed ObjectOutputStream.
1904 
1905         /* ----------------- generic output stream methods ----------------- */
1906         /*
1907          * The following methods are equivalent to their counterparts in
1908          * OutputStream, except that they partition written data into data
1909          * blocks when in block data mode.
1910          */
1911 
write(int b)1912         public void write(int b) throws IOException {
1913             if (pos >= MAX_BLOCK_SIZE) {
1914                 drain();
1915             }
1916             buf[pos++] = (byte) b;
1917         }
1918 
write(byte[] b)1919         public void write(byte[] b) throws IOException {
1920             write(b, 0, b.length, false);
1921         }
1922 
write(byte[] b, int off, int len)1923         public void write(byte[] b, int off, int len) throws IOException {
1924             write(b, off, len, false);
1925         }
1926 
flush()1927         public void flush() throws IOException {
1928             drain();
1929             out.flush();
1930         }
1931 
close()1932         public void close() throws IOException {
1933             flush();
1934             out.close();
1935             // Android-added: Warning about writing to closed ObjectOutputStream.
1936             warnOnceWhenWriting = true;
1937         }
1938 
1939         /**
1940          * Writes specified span of byte values from given array.  If copy is
1941          * true, copies the values to an intermediate buffer before writing
1942          * them to underlying stream (to avoid exposing a reference to the
1943          * original byte array).
1944          */
write(byte[] b, int off, int len, boolean copy)1945         void write(byte[] b, int off, int len, boolean copy)
1946             throws IOException
1947         {
1948             if (!(copy || blkmode)) {           // write directly
1949                 drain();
1950                 out.write(b, off, len);
1951                 // Android-added: Warning about writing to closed ObjectOutputStream.
1952                 warnIfClosed();
1953                 return;
1954             }
1955 
1956             while (len > 0) {
1957                 if (pos >= MAX_BLOCK_SIZE) {
1958                     drain();
1959                 }
1960                 if (len >= MAX_BLOCK_SIZE && !copy && pos == 0) {
1961                     // avoid unnecessary copy
1962                     writeBlockHeader(MAX_BLOCK_SIZE);
1963                     out.write(b, off, MAX_BLOCK_SIZE);
1964                     off += MAX_BLOCK_SIZE;
1965                     len -= MAX_BLOCK_SIZE;
1966                 } else {
1967                     int wlen = Math.min(len, MAX_BLOCK_SIZE - pos);
1968                     System.arraycopy(b, off, buf, pos, wlen);
1969                     pos += wlen;
1970                     off += wlen;
1971                     len -= wlen;
1972                 }
1973             }
1974             // Android-added: Warning about writing to closed ObjectOutputStream.
1975             warnIfClosed();
1976         }
1977 
1978         /**
1979          * Writes all buffered data from this stream to the underlying stream,
1980          * but does not flush underlying stream.
1981          */
drain()1982         void drain() throws IOException {
1983             if (pos == 0) {
1984                 return;
1985             }
1986             if (blkmode) {
1987                 writeBlockHeader(pos);
1988             }
1989             out.write(buf, 0, pos);
1990             pos = 0;
1991             // Android-added: Warning about writing to closed ObjectOutputStream.
1992             warnIfClosed();
1993         }
1994 
1995         /**
1996          * Writes block data header.  Data blocks shorter than 256 bytes are
1997          * prefixed with a 2-byte header; all others start with a 5-byte
1998          * header.
1999          */
writeBlockHeader(int len)2000         private void writeBlockHeader(int len) throws IOException {
2001             if (len <= 0xFF) {
2002                 hbuf[0] = TC_BLOCKDATA;
2003                 hbuf[1] = (byte) len;
2004                 out.write(hbuf, 0, 2);
2005             } else {
2006                 hbuf[0] = TC_BLOCKDATALONG;
2007                 Bits.putInt(hbuf, 1, len);
2008                 out.write(hbuf, 0, 5);
2009             }
2010             // Android-added: Warning about writing to closed ObjectOutputStream.
2011             warnIfClosed();
2012         }
2013 
2014 
2015         /* ----------------- primitive data output methods ----------------- */
2016         /*
2017          * The following methods are equivalent to their counterparts in
2018          * DataOutputStream, except that they partition written data into data
2019          * blocks when in block data mode.
2020          */
2021 
writeBoolean(boolean v)2022         public void writeBoolean(boolean v) throws IOException {
2023             if (pos >= MAX_BLOCK_SIZE) {
2024                 drain();
2025             }
2026             Bits.putBoolean(buf, pos++, v);
2027         }
2028 
writeByte(int v)2029         public void writeByte(int v) throws IOException {
2030             if (pos >= MAX_BLOCK_SIZE) {
2031                 drain();
2032             }
2033             buf[pos++] = (byte) v;
2034         }
2035 
writeChar(int v)2036         public void writeChar(int v) throws IOException {
2037             if (pos + 2 <= MAX_BLOCK_SIZE) {
2038                 Bits.putChar(buf, pos, (char) v);
2039                 pos += 2;
2040             } else {
2041                 dout.writeChar(v);
2042             }
2043         }
2044 
writeShort(int v)2045         public void writeShort(int v) throws IOException {
2046             if (pos + 2 <= MAX_BLOCK_SIZE) {
2047                 Bits.putShort(buf, pos, (short) v);
2048                 pos += 2;
2049             } else {
2050                 dout.writeShort(v);
2051             }
2052         }
2053 
writeInt(int v)2054         public void writeInt(int v) throws IOException {
2055             if (pos + 4 <= MAX_BLOCK_SIZE) {
2056                 Bits.putInt(buf, pos, v);
2057                 pos += 4;
2058             } else {
2059                 dout.writeInt(v);
2060             }
2061         }
2062 
writeFloat(float v)2063         public void writeFloat(float v) throws IOException {
2064             if (pos + 4 <= MAX_BLOCK_SIZE) {
2065                 Bits.putFloat(buf, pos, v);
2066                 pos += 4;
2067             } else {
2068                 dout.writeFloat(v);
2069             }
2070         }
2071 
writeLong(long v)2072         public void writeLong(long v) throws IOException {
2073             if (pos + 8 <= MAX_BLOCK_SIZE) {
2074                 Bits.putLong(buf, pos, v);
2075                 pos += 8;
2076             } else {
2077                 dout.writeLong(v);
2078             }
2079         }
2080 
writeDouble(double v)2081         public void writeDouble(double v) throws IOException {
2082             if (pos + 8 <= MAX_BLOCK_SIZE) {
2083                 Bits.putDouble(buf, pos, v);
2084                 pos += 8;
2085             } else {
2086                 dout.writeDouble(v);
2087             }
2088         }
2089 
writeBytes(String s)2090         public void writeBytes(String s) throws IOException {
2091             int endoff = s.length();
2092             int cpos = 0;
2093             int csize = 0;
2094             for (int off = 0; off < endoff; ) {
2095                 if (cpos >= csize) {
2096                     cpos = 0;
2097                     csize = Math.min(endoff - off, CHAR_BUF_SIZE);
2098                     s.getChars(off, off + csize, cbuf, 0);
2099                 }
2100                 if (pos >= MAX_BLOCK_SIZE) {
2101                     drain();
2102                 }
2103                 int n = Math.min(csize - cpos, MAX_BLOCK_SIZE - pos);
2104                 int stop = pos + n;
2105                 while (pos < stop) {
2106                     buf[pos++] = (byte) cbuf[cpos++];
2107                 }
2108                 off += n;
2109             }
2110         }
2111 
writeChars(String s)2112         public void writeChars(String s) throws IOException {
2113             int endoff = s.length();
2114             for (int off = 0; off < endoff; ) {
2115                 int csize = Math.min(endoff - off, CHAR_BUF_SIZE);
2116                 s.getChars(off, off + csize, cbuf, 0);
2117                 writeChars(cbuf, 0, csize);
2118                 off += csize;
2119             }
2120         }
2121 
writeUTF(String s)2122         public void writeUTF(String s) throws IOException {
2123             writeUTF(s, getUTFLength(s));
2124         }
2125 
2126 
2127         /* -------------- primitive data array output methods -------------- */
2128         /*
2129          * The following methods write out spans of primitive data values.
2130          * Though equivalent to calling the corresponding primitive write
2131          * methods repeatedly, these methods are optimized for writing groups
2132          * of primitive data values more efficiently.
2133          */
2134 
writeBooleans(boolean[] v, int off, int len)2135         void writeBooleans(boolean[] v, int off, int len) throws IOException {
2136             int endoff = off + len;
2137             while (off < endoff) {
2138                 if (pos >= MAX_BLOCK_SIZE) {
2139                     drain();
2140                 }
2141                 int stop = Math.min(endoff, off + (MAX_BLOCK_SIZE - pos));
2142                 while (off < stop) {
2143                     Bits.putBoolean(buf, pos++, v[off++]);
2144                 }
2145             }
2146         }
2147 
writeChars(char[] v, int off, int len)2148         void writeChars(char[] v, int off, int len) throws IOException {
2149             int limit = MAX_BLOCK_SIZE - 2;
2150             int endoff = off + len;
2151             while (off < endoff) {
2152                 if (pos <= limit) {
2153                     int avail = (MAX_BLOCK_SIZE - pos) >> 1;
2154                     int stop = Math.min(endoff, off + avail);
2155                     while (off < stop) {
2156                         Bits.putChar(buf, pos, v[off++]);
2157                         pos += 2;
2158                     }
2159                 } else {
2160                     dout.writeChar(v[off++]);
2161                 }
2162             }
2163         }
2164 
writeShorts(short[] v, int off, int len)2165         void writeShorts(short[] v, int off, int len) throws IOException {
2166             int limit = MAX_BLOCK_SIZE - 2;
2167             int endoff = off + len;
2168             while (off < endoff) {
2169                 if (pos <= limit) {
2170                     int avail = (MAX_BLOCK_SIZE - pos) >> 1;
2171                     int stop = Math.min(endoff, off + avail);
2172                     while (off < stop) {
2173                         Bits.putShort(buf, pos, v[off++]);
2174                         pos += 2;
2175                     }
2176                 } else {
2177                     dout.writeShort(v[off++]);
2178                 }
2179             }
2180         }
2181 
writeInts(int[] v, int off, int len)2182         void writeInts(int[] v, int off, int len) throws IOException {
2183             int limit = MAX_BLOCK_SIZE - 4;
2184             int endoff = off + len;
2185             while (off < endoff) {
2186                 if (pos <= limit) {
2187                     int avail = (MAX_BLOCK_SIZE - pos) >> 2;
2188                     int stop = Math.min(endoff, off + avail);
2189                     while (off < stop) {
2190                         Bits.putInt(buf, pos, v[off++]);
2191                         pos += 4;
2192                     }
2193                 } else {
2194                     dout.writeInt(v[off++]);
2195                 }
2196             }
2197         }
2198 
writeFloats(float[] v, int off, int len)2199         void writeFloats(float[] v, int off, int len) throws IOException {
2200             int limit = MAX_BLOCK_SIZE - 4;
2201             int endoff = off + len;
2202             while (off < endoff) {
2203                 if (pos <= limit) {
2204                     int avail = (MAX_BLOCK_SIZE - pos) >> 2;
2205                     int chunklen = Math.min(endoff - off, avail);
2206                     floatsToBytes(v, off, buf, pos, chunklen);
2207                     off += chunklen;
2208                     pos += chunklen << 2;
2209                 } else {
2210                     dout.writeFloat(v[off++]);
2211                 }
2212             }
2213         }
2214 
writeLongs(long[] v, int off, int len)2215         void writeLongs(long[] v, int off, int len) throws IOException {
2216             int limit = MAX_BLOCK_SIZE - 8;
2217             int endoff = off + len;
2218             while (off < endoff) {
2219                 if (pos <= limit) {
2220                     int avail = (MAX_BLOCK_SIZE - pos) >> 3;
2221                     int stop = Math.min(endoff, off + avail);
2222                     while (off < stop) {
2223                         Bits.putLong(buf, pos, v[off++]);
2224                         pos += 8;
2225                     }
2226                 } else {
2227                     dout.writeLong(v[off++]);
2228                 }
2229             }
2230         }
2231 
writeDoubles(double[] v, int off, int len)2232         void writeDoubles(double[] v, int off, int len) throws IOException {
2233             int limit = MAX_BLOCK_SIZE - 8;
2234             int endoff = off + len;
2235             while (off < endoff) {
2236                 if (pos <= limit) {
2237                     int avail = (MAX_BLOCK_SIZE - pos) >> 3;
2238                     int chunklen = Math.min(endoff - off, avail);
2239                     doublesToBytes(v, off, buf, pos, chunklen);
2240                     off += chunklen;
2241                     pos += chunklen << 3;
2242                 } else {
2243                     dout.writeDouble(v[off++]);
2244                 }
2245             }
2246         }
2247 
2248         /**
2249          * Returns the length in bytes of the UTF encoding of the given string.
2250          */
getUTFLength(String s)2251         long getUTFLength(String s) {
2252             int len = s.length();
2253             long utflen = 0;
2254             for (int off = 0; off < len; ) {
2255                 int csize = Math.min(len - off, CHAR_BUF_SIZE);
2256                 s.getChars(off, off + csize, cbuf, 0);
2257                 for (int cpos = 0; cpos < csize; cpos++) {
2258                     char c = cbuf[cpos];
2259                     if (c >= 0x0001 && c <= 0x007F) {
2260                         utflen++;
2261                     } else if (c > 0x07FF) {
2262                         utflen += 3;
2263                     } else {
2264                         utflen += 2;
2265                     }
2266                 }
2267                 off += csize;
2268             }
2269             return utflen;
2270         }
2271 
2272         /**
2273          * Writes the given string in UTF format.  This method is used in
2274          * situations where the UTF encoding length of the string is already
2275          * known; specifying it explicitly avoids a prescan of the string to
2276          * determine its UTF length.
2277          */
writeUTF(String s, long utflen)2278         void writeUTF(String s, long utflen) throws IOException {
2279             if (utflen > 0xFFFFL) {
2280                 throw new UTFDataFormatException();
2281             }
2282             writeShort((int) utflen);
2283             if (utflen == (long) s.length()) {
2284                 writeBytes(s);
2285             } else {
2286                 writeUTFBody(s);
2287             }
2288         }
2289 
2290         /**
2291          * Writes given string in "long" UTF format.  "Long" UTF format is
2292          * identical to standard UTF, except that it uses an 8 byte header
2293          * (instead of the standard 2 bytes) to convey the UTF encoding length.
2294          */
writeLongUTF(String s)2295         void writeLongUTF(String s) throws IOException {
2296             writeLongUTF(s, getUTFLength(s));
2297         }
2298 
2299         /**
2300          * Writes given string in "long" UTF format, where the UTF encoding
2301          * length of the string is already known.
2302          */
writeLongUTF(String s, long utflen)2303         void writeLongUTF(String s, long utflen) throws IOException {
2304             writeLong(utflen);
2305             if (utflen == (long) s.length()) {
2306                 writeBytes(s);
2307             } else {
2308                 writeUTFBody(s);
2309             }
2310         }
2311 
2312         /**
2313          * Writes the "body" (i.e., the UTF representation minus the 2-byte or
2314          * 8-byte length header) of the UTF encoding for the given string.
2315          */
writeUTFBody(String s)2316         private void writeUTFBody(String s) throws IOException {
2317             int limit = MAX_BLOCK_SIZE - 3;
2318             int len = s.length();
2319             for (int off = 0; off < len; ) {
2320                 int csize = Math.min(len - off, CHAR_BUF_SIZE);
2321                 s.getChars(off, off + csize, cbuf, 0);
2322                 for (int cpos = 0; cpos < csize; cpos++) {
2323                     char c = cbuf[cpos];
2324                     if (pos <= limit) {
2325                         if (c <= 0x007F && c != 0) {
2326                             buf[pos++] = (byte) c;
2327                         } else if (c > 0x07FF) {
2328                             buf[pos + 2] = (byte) (0x80 | ((c >> 0) & 0x3F));
2329                             buf[pos + 1] = (byte) (0x80 | ((c >> 6) & 0x3F));
2330                             buf[pos + 0] = (byte) (0xE0 | ((c >> 12) & 0x0F));
2331                             pos += 3;
2332                         } else {
2333                             buf[pos + 1] = (byte) (0x80 | ((c >> 0) & 0x3F));
2334                             buf[pos + 0] = (byte) (0xC0 | ((c >> 6) & 0x1F));
2335                             pos += 2;
2336                         }
2337                     } else {    // write one byte at a time to normalize block
2338                         if (c <= 0x007F && c != 0) {
2339                             write(c);
2340                         } else if (c > 0x07FF) {
2341                             write(0xE0 | ((c >> 12) & 0x0F));
2342                             write(0x80 | ((c >> 6) & 0x3F));
2343                             write(0x80 | ((c >> 0) & 0x3F));
2344                         } else {
2345                             write(0xC0 | ((c >> 6) & 0x1F));
2346                             write(0x80 | ((c >> 0) & 0x3F));
2347                         }
2348                     }
2349                 }
2350                 off += csize;
2351             }
2352         }
2353     }
2354 
2355     /**
2356      * Lightweight identity hash table which maps objects to integer handles,
2357      * assigned in ascending order.
2358      */
2359     private static class HandleTable {
2360 
2361         /* number of mappings in table/next available handle */
2362         private int size;
2363         /* size threshold determining when to expand hash spine */
2364         private int threshold;
2365         /* factor for computing size threshold */
2366         private final float loadFactor;
2367         /* maps hash value -> candidate handle value */
2368         private int[] spine;
2369         /* maps handle value -> next candidate handle value */
2370         private int[] next;
2371         /* maps handle value -> associated object */
2372         private Object[] objs;
2373 
2374         /**
2375          * Creates new HandleTable with given capacity and load factor.
2376          */
HandleTable(int initialCapacity, float loadFactor)2377         HandleTable(int initialCapacity, float loadFactor) {
2378             this.loadFactor = loadFactor;
2379             spine = new int[initialCapacity];
2380             next = new int[initialCapacity];
2381             objs = new Object[initialCapacity];
2382             threshold = (int) (initialCapacity * loadFactor);
2383             clear();
2384         }
2385 
2386         /**
2387          * Assigns next available handle to given object, and returns handle
2388          * value.  Handles are assigned in ascending order starting at 0.
2389          */
assign(Object obj)2390         int assign(Object obj) {
2391             if (size >= next.length) {
2392                 growEntries();
2393             }
2394             if (size >= threshold) {
2395                 growSpine();
2396             }
2397             insert(obj, size);
2398             return size++;
2399         }
2400 
2401         /**
2402          * Looks up and returns handle associated with given object, or -1 if
2403          * no mapping found.
2404          */
lookup(Object obj)2405         int lookup(Object obj) {
2406             if (size == 0) {
2407                 return -1;
2408             }
2409             int index = hash(obj) % spine.length;
2410             for (int i = spine[index]; i >= 0; i = next[i]) {
2411                 if (objs[i] == obj) {
2412                     return i;
2413                 }
2414             }
2415             return -1;
2416         }
2417 
2418         /**
2419          * Resets table to its initial (empty) state.
2420          */
clear()2421         void clear() {
2422             Arrays.fill(spine, -1);
2423             Arrays.fill(objs, 0, size, null);
2424             size = 0;
2425         }
2426 
2427         /**
2428          * Returns the number of mappings currently in table.
2429          */
size()2430         int size() {
2431             return size;
2432         }
2433 
2434         /**
2435          * Inserts mapping object -> handle mapping into table.  Assumes table
2436          * is large enough to accommodate new mapping.
2437          */
insert(Object obj, int handle)2438         private void insert(Object obj, int handle) {
2439             int index = hash(obj) % spine.length;
2440             objs[handle] = obj;
2441             next[handle] = spine[index];
2442             spine[index] = handle;
2443         }
2444 
2445         /**
2446          * Expands the hash "spine" -- equivalent to increasing the number of
2447          * buckets in a conventional hash table.
2448          */
growSpine()2449         private void growSpine() {
2450             spine = new int[(spine.length << 1) + 1];
2451             threshold = (int) (spine.length * loadFactor);
2452             Arrays.fill(spine, -1);
2453             for (int i = 0; i < size; i++) {
2454                 insert(objs[i], i);
2455             }
2456         }
2457 
2458         /**
2459          * Increases hash table capacity by lengthening entry arrays.
2460          */
growEntries()2461         private void growEntries() {
2462             int newLength = (next.length << 1) + 1;
2463             int[] newNext = new int[newLength];
2464             System.arraycopy(next, 0, newNext, 0, size);
2465             next = newNext;
2466 
2467             Object[] newObjs = new Object[newLength];
2468             System.arraycopy(objs, 0, newObjs, 0, size);
2469             objs = newObjs;
2470         }
2471 
2472         /**
2473          * Returns hash value for given object.
2474          */
hash(Object obj)2475         private int hash(Object obj) {
2476             return System.identityHashCode(obj) & 0x7FFFFFFF;
2477         }
2478     }
2479 
2480     /**
2481      * Lightweight identity hash table which maps objects to replacement
2482      * objects.
2483      */
2484     private static class ReplaceTable {
2485 
2486         /* maps object -> index */
2487         private final HandleTable htab;
2488         /* maps index -> replacement object */
2489         private Object[] reps;
2490 
2491         /**
2492          * Creates new ReplaceTable with given capacity and load factor.
2493          */
ReplaceTable(int initialCapacity, float loadFactor)2494         ReplaceTable(int initialCapacity, float loadFactor) {
2495             htab = new HandleTable(initialCapacity, loadFactor);
2496             reps = new Object[initialCapacity];
2497         }
2498 
2499         /**
2500          * Enters mapping from object to replacement object.
2501          */
assign(Object obj, Object rep)2502         void assign(Object obj, Object rep) {
2503             int index = htab.assign(obj);
2504             while (index >= reps.length) {
2505                 grow();
2506             }
2507             reps[index] = rep;
2508         }
2509 
2510         /**
2511          * Looks up and returns replacement for given object.  If no
2512          * replacement is found, returns the lookup object itself.
2513          */
lookup(Object obj)2514         Object lookup(Object obj) {
2515             int index = htab.lookup(obj);
2516             return (index >= 0) ? reps[index] : obj;
2517         }
2518 
2519         /**
2520          * Resets table to its initial (empty) state.
2521          */
clear()2522         void clear() {
2523             Arrays.fill(reps, 0, htab.size(), null);
2524             htab.clear();
2525         }
2526 
2527         /**
2528          * Returns the number of mappings currently in table.
2529          */
size()2530         int size() {
2531             return htab.size();
2532         }
2533 
2534         /**
2535          * Increases table capacity.
2536          */
grow()2537         private void grow() {
2538             Object[] newReps = new Object[(reps.length << 1) + 1];
2539             System.arraycopy(reps, 0, newReps, 0, reps.length);
2540             reps = newReps;
2541         }
2542     }
2543 
2544     /**
2545      * Stack to keep debug information about the state of the
2546      * serialization process, for embedding in exception messages.
2547      */
2548     private static class DebugTraceInfoStack {
2549         private final List<String> stack;
2550 
DebugTraceInfoStack()2551         DebugTraceInfoStack() {
2552             stack = new ArrayList<>();
2553         }
2554 
2555         /**
2556          * Removes all of the elements from enclosed list.
2557          */
clear()2558         void clear() {
2559             stack.clear();
2560         }
2561 
2562         /**
2563          * Removes the object at the top of enclosed list.
2564          */
pop()2565         void pop() {
2566             stack.remove(stack.size()-1);
2567         }
2568 
2569         /**
2570          * Pushes a String onto the top of enclosed list.
2571          */
push(String entry)2572         void push(String entry) {
2573             stack.add("\t- " + entry);
2574         }
2575 
2576         /**
2577          * Returns a string representation of this object
2578          */
toString()2579         public String toString() {
2580             StringBuilder buffer = new StringBuilder();
2581             if (!stack.isEmpty()) {
2582                 for(int i = stack.size(); i > 0; i-- ) {
2583                     buffer.append(stack.get(i-1) + ((i != 1) ? "\n" : ""));
2584                 }
2585             }
2586             return buffer.toString();
2587         }
2588     }
2589 
2590 }
2591