• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.isExternalizable() && !desc.isProxy()) {
1486                 writeExternalData((Externalizable) obj);
1487             } else {
1488                 writeSerialData(obj, desc);
1489             }
1490         } finally {
1491             if (extendedDebugInfo) {
1492                 debugInfoStack.pop();
1493             }
1494         }
1495     }
1496 
1497     /**
1498      * Writes externalizable data of given object by invoking its
1499      * writeExternal() method.
1500      */
writeExternalData(Externalizable obj)1501     private void writeExternalData(Externalizable obj) throws IOException {
1502         PutFieldImpl oldPut = curPut;
1503         curPut = null;
1504 
1505         if (extendedDebugInfo) {
1506             debugInfoStack.push("writeExternal data");
1507         }
1508         SerialCallbackContext oldContext = curContext;
1509         try {
1510             curContext = null;
1511             if (protocol == PROTOCOL_VERSION_1) {
1512                 obj.writeExternal(this);
1513             } else {
1514                 bout.setBlockDataMode(true);
1515                 obj.writeExternal(this);
1516                 bout.setBlockDataMode(false);
1517                 bout.writeByte(TC_ENDBLOCKDATA);
1518             }
1519         } finally {
1520             curContext = oldContext;
1521             if (extendedDebugInfo) {
1522                 debugInfoStack.pop();
1523             }
1524         }
1525 
1526         curPut = oldPut;
1527     }
1528 
1529     /**
1530      * Writes instance data for each serializable class of given object, from
1531      * superclass to subclass.
1532      */
writeSerialData(Object obj, ObjectStreamClass desc)1533     private void writeSerialData(Object obj, ObjectStreamClass desc)
1534         throws IOException
1535     {
1536         ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout();
1537         for (int i = 0; i < slots.length; i++) {
1538             ObjectStreamClass slotDesc = slots[i].desc;
1539             if (slotDesc.hasWriteObjectMethod()) {
1540                 PutFieldImpl oldPut = curPut;
1541                 curPut = null;
1542                 SerialCallbackContext oldContext = curContext;
1543 
1544                 if (extendedDebugInfo) {
1545                     debugInfoStack.push(
1546                         "custom writeObject data (class \"" +
1547                         slotDesc.getName() + "\")");
1548                 }
1549                 try {
1550                     curContext = new SerialCallbackContext(obj, slotDesc);
1551                     bout.setBlockDataMode(true);
1552                     slotDesc.invokeWriteObject(obj, this);
1553                     bout.setBlockDataMode(false);
1554                     bout.writeByte(TC_ENDBLOCKDATA);
1555                 } finally {
1556                     curContext.setUsed();
1557                     curContext = oldContext;
1558                     if (extendedDebugInfo) {
1559                         debugInfoStack.pop();
1560                     }
1561                 }
1562 
1563                 curPut = oldPut;
1564             } else {
1565                 defaultWriteFields(obj, slotDesc);
1566             }
1567         }
1568     }
1569 
1570     /**
1571      * Fetches and writes values of serializable fields of given object to
1572      * stream.  The given class descriptor specifies which field values to
1573      * write, and in which order they should be written.
1574      */
defaultWriteFields(Object obj, ObjectStreamClass desc)1575     private void defaultWriteFields(Object obj, ObjectStreamClass desc)
1576         throws IOException
1577     {
1578         Class<?> cl = desc.forClass();
1579         if (cl != null && obj != null && !cl.isInstance(obj)) {
1580             throw new ClassCastException();
1581         }
1582 
1583         desc.checkDefaultSerialize();
1584 
1585         int primDataSize = desc.getPrimDataSize();
1586         if (primVals == null || primVals.length < primDataSize) {
1587             primVals = new byte[primDataSize];
1588         }
1589         desc.getPrimFieldValues(obj, primVals);
1590         bout.write(primVals, 0, primDataSize, false);
1591 
1592         ObjectStreamField[] fields = desc.getFields(false);
1593         Object[] objVals = new Object[desc.getNumObjFields()];
1594         int numPrimFields = fields.length - objVals.length;
1595         desc.getObjFieldValues(obj, objVals);
1596         for (int i = 0; i < objVals.length; i++) {
1597             if (extendedDebugInfo) {
1598                 debugInfoStack.push(
1599                     "field (class \"" + desc.getName() + "\", name: \"" +
1600                     fields[numPrimFields + i].getName() + "\", type: \"" +
1601                     fields[numPrimFields + i].getType() + "\")");
1602             }
1603             try {
1604                 writeObject0(objVals[i],
1605                              fields[numPrimFields + i].isUnshared());
1606             } finally {
1607                 if (extendedDebugInfo) {
1608                     debugInfoStack.pop();
1609                 }
1610             }
1611         }
1612     }
1613 
1614     /**
1615      * Attempts to write to stream fatal IOException that has caused
1616      * serialization to abort.
1617      */
writeFatalException(IOException ex)1618     private void writeFatalException(IOException ex) throws IOException {
1619         /*
1620          * Note: the serialization specification states that if a second
1621          * IOException occurs while attempting to serialize the original fatal
1622          * exception to the stream, then a StreamCorruptedException should be
1623          * thrown (section 2.1).  However, due to a bug in previous
1624          * implementations of serialization, StreamCorruptedExceptions were
1625          * rarely (if ever) actually thrown--the "root" exceptions from
1626          * underlying streams were thrown instead.  This historical behavior is
1627          * followed here for consistency.
1628          */
1629         clear();
1630         boolean oldMode = bout.setBlockDataMode(false);
1631         try {
1632             bout.writeByte(TC_EXCEPTION);
1633             writeObject0(ex, false);
1634             clear();
1635         } finally {
1636             bout.setBlockDataMode(oldMode);
1637         }
1638     }
1639 
1640     /**
1641      * Converts specified span of float values into byte values.
1642      */
1643     // REMIND: remove once hotspot inlines Float.floatToIntBits
floatsToBytes(float[] src, int srcpos, byte[] dst, int dstpos, int nfloats)1644     private static native void floatsToBytes(float[] src, int srcpos,
1645                                              byte[] dst, int dstpos,
1646                                              int nfloats);
1647 
1648     /**
1649      * Converts specified span of double values into byte values.
1650      */
1651     // REMIND: remove once hotspot inlines Double.doubleToLongBits
doublesToBytes(double[] src, int srcpos, byte[] dst, int dstpos, int ndoubles)1652     private static native void doublesToBytes(double[] src, int srcpos,
1653                                               byte[] dst, int dstpos,
1654                                               int ndoubles);
1655 
1656     /**
1657      * Default PutField implementation.
1658      */
1659     private class PutFieldImpl extends PutField {
1660 
1661         /** class descriptor describing serializable fields */
1662         private final ObjectStreamClass desc;
1663         /** primitive field values */
1664         private final byte[] primVals;
1665         /** object field values */
1666         private final Object[] objVals;
1667 
1668         /**
1669          * Creates PutFieldImpl object for writing fields defined in given
1670          * class descriptor.
1671          */
PutFieldImpl(ObjectStreamClass desc)1672         PutFieldImpl(ObjectStreamClass desc) {
1673             this.desc = desc;
1674             primVals = new byte[desc.getPrimDataSize()];
1675             objVals = new Object[desc.getNumObjFields()];
1676         }
1677 
put(String name, boolean val)1678         public void put(String name, boolean val) {
1679             Bits.putBoolean(primVals, getFieldOffset(name, Boolean.TYPE), val);
1680         }
1681 
put(String name, byte val)1682         public void put(String name, byte val) {
1683             primVals[getFieldOffset(name, Byte.TYPE)] = val;
1684         }
1685 
put(String name, char val)1686         public void put(String name, char val) {
1687             Bits.putChar(primVals, getFieldOffset(name, Character.TYPE), val);
1688         }
1689 
put(String name, short val)1690         public void put(String name, short val) {
1691             Bits.putShort(primVals, getFieldOffset(name, Short.TYPE), val);
1692         }
1693 
put(String name, int val)1694         public void put(String name, int val) {
1695             Bits.putInt(primVals, getFieldOffset(name, Integer.TYPE), val);
1696         }
1697 
put(String name, float val)1698         public void put(String name, float val) {
1699             Bits.putFloat(primVals, getFieldOffset(name, Float.TYPE), val);
1700         }
1701 
put(String name, long val)1702         public void put(String name, long val) {
1703             Bits.putLong(primVals, getFieldOffset(name, Long.TYPE), val);
1704         }
1705 
put(String name, double val)1706         public void put(String name, double val) {
1707             Bits.putDouble(primVals, getFieldOffset(name, Double.TYPE), val);
1708         }
1709 
put(String name, Object val)1710         public void put(String name, Object val) {
1711             objVals[getFieldOffset(name, Object.class)] = val;
1712         }
1713 
1714         // deprecated in ObjectOutputStream.PutField
write(ObjectOutput out)1715         public void write(ObjectOutput out) throws IOException {
1716             /*
1717              * Applications should *not* use this method to write PutField
1718              * data, as it will lead to stream corruption if the PutField
1719              * object writes any primitive data (since block data mode is not
1720              * unset/set properly, as is done in OOS.writeFields()).  This
1721              * broken implementation is being retained solely for behavioral
1722              * compatibility, in order to support applications which use
1723              * OOS.PutField.write() for writing only non-primitive data.
1724              *
1725              * Serialization of unshared objects is not implemented here since
1726              * it is not necessary for backwards compatibility; also, unshared
1727              * semantics may not be supported by the given ObjectOutput
1728              * instance.  Applications which write unshared objects using the
1729              * PutField API must use OOS.writeFields().
1730              */
1731             if (ObjectOutputStream.this != out) {
1732                 throw new IllegalArgumentException("wrong stream");
1733             }
1734             out.write(primVals, 0, primVals.length);
1735 
1736             ObjectStreamField[] fields = desc.getFields(false);
1737             int numPrimFields = fields.length - objVals.length;
1738             // REMIND: warn if numPrimFields > 0?
1739             for (int i = 0; i < objVals.length; i++) {
1740                 if (fields[numPrimFields + i].isUnshared()) {
1741                     throw new IOException("cannot write unshared object");
1742                 }
1743                 out.writeObject(objVals[i]);
1744             }
1745         }
1746 
1747         /**
1748          * Writes buffered primitive data and object fields to stream.
1749          */
writeFields()1750         void writeFields() throws IOException {
1751             bout.write(primVals, 0, primVals.length, false);
1752 
1753             ObjectStreamField[] fields = desc.getFields(false);
1754             int numPrimFields = fields.length - objVals.length;
1755             for (int i = 0; i < objVals.length; i++) {
1756                 if (extendedDebugInfo) {
1757                     debugInfoStack.push(
1758                         "field (class \"" + desc.getName() + "\", name: \"" +
1759                         fields[numPrimFields + i].getName() + "\", type: \"" +
1760                         fields[numPrimFields + i].getType() + "\")");
1761                 }
1762                 try {
1763                     writeObject0(objVals[i],
1764                                  fields[numPrimFields + i].isUnshared());
1765                 } finally {
1766                     if (extendedDebugInfo) {
1767                         debugInfoStack.pop();
1768                     }
1769                 }
1770             }
1771         }
1772 
1773         /**
1774          * Returns offset of field with given name and type.  A specified type
1775          * of null matches all types, Object.class matches all non-primitive
1776          * types, and any other non-null type matches assignable types only.
1777          * Throws IllegalArgumentException if no matching field found.
1778          */
getFieldOffset(String name, Class<?> type)1779         private int getFieldOffset(String name, Class<?> type) {
1780             ObjectStreamField field = desc.getField(name, type);
1781             if (field == null) {
1782                 throw new IllegalArgumentException("no such field " + name +
1783                                                    " with type " + type);
1784             }
1785             return field.getOffset();
1786         }
1787     }
1788 
1789     /**
1790      * Buffered output stream with two modes: in default mode, outputs data in
1791      * same format as DataOutputStream; in "block data" mode, outputs data
1792      * bracketed by block data markers (see object serialization specification
1793      * for details).
1794      */
1795     private static class BlockDataOutputStream
1796         extends OutputStream implements DataOutput
1797     {
1798         /** maximum data block length */
1799         private static final int MAX_BLOCK_SIZE = 1024;
1800         /** maximum data block header length */
1801         private static final int MAX_HEADER_SIZE = 5;
1802         /** (tunable) length of char buffer (for writing strings) */
1803         private static final int CHAR_BUF_SIZE = 256;
1804 
1805         /** buffer for writing general/block data */
1806         private final byte[] buf = new byte[MAX_BLOCK_SIZE];
1807         /** buffer for writing block data headers */
1808         private final byte[] hbuf = new byte[MAX_HEADER_SIZE];
1809         /** char buffer for fast string writes */
1810         private final char[] cbuf = new char[CHAR_BUF_SIZE];
1811 
1812         /** block data mode */
1813         private boolean blkmode = false;
1814         /** current offset into buf */
1815         private int pos = 0;
1816 
1817         /** underlying output stream */
1818         private final OutputStream out;
1819         /** loopback stream (for data writes that span data blocks) */
1820         private final DataOutputStream dout;
1821 
1822         // BEGIN Android-added: Warning if writing to a closed ObjectOutputStream.
1823         /**
1824          * Indicates that this stream was closed and that a warning must be logged once if an
1825          * attempt is made to write to it and the underlying stream does not throw an exception.
1826          *
1827          * <p>This will be set back to false when a warning is logged to ensure that the log is not
1828          * flooded with warnings.
1829          *
1830          * http://b/28159133
1831          */
1832         private boolean warnOnceWhenWriting;
1833         // END Android-added: Warning if writing to a closed ObjectOutputStream.
1834 
1835         /**
1836          * Creates new BlockDataOutputStream on top of given underlying stream.
1837          * Block data mode is turned off by default.
1838          */
BlockDataOutputStream(OutputStream out)1839         BlockDataOutputStream(OutputStream out) {
1840             this.out = out;
1841             dout = new DataOutputStream(this);
1842         }
1843 
1844         /**
1845          * Sets block data mode to the given mode (true == on, false == off)
1846          * and returns the previous mode value.  If the new mode is the same as
1847          * the old mode, no action is taken.  If the new mode differs from the
1848          * old mode, any buffered data is flushed before switching to the new
1849          * mode.
1850          */
setBlockDataMode(boolean mode)1851         boolean setBlockDataMode(boolean mode) throws IOException {
1852             if (blkmode == mode) {
1853                 return blkmode;
1854             }
1855             drain();
1856             blkmode = mode;
1857             return !blkmode;
1858         }
1859 
1860         /**
1861          * Returns true if the stream is currently in block data mode, false
1862          * otherwise.
1863          */
getBlockDataMode()1864         boolean getBlockDataMode() {
1865             return blkmode;
1866         }
1867 
1868         // BEGIN Android-added: Warning about writing to closed ObjectOutputStream.
1869         /**
1870          * Warns if the stream has been closed.
1871          *
1872          * <p>This is called after data has been written to the underlying stream in order to allow
1873          * the underlying stream to detect and fail if an attempt is made to write to a closed
1874          * stream. That ensures that this will only log a warning if the underlying stream does not
1875          * so it will not log unnecessary warnings.
1876          */
warnIfClosed()1877         private void warnIfClosed() {
1878             if (warnOnceWhenWriting) {
1879                 System.logW("The app is relying on undefined behavior. Attempting to write to a"
1880                         + " closed ObjectOutputStream could produce corrupt output in a future"
1881                         + " release of Android.", new IOException("Stream Closed"));
1882                 // Set back to false so no more messages are logged unless the stream is closed
1883                 // again.
1884                 warnOnceWhenWriting = false;
1885             }
1886         }
1887         // END Android-added: Warning about writing to closed ObjectOutputStream.
1888 
1889         /* ----------------- generic output stream methods ----------------- */
1890         /*
1891          * The following methods are equivalent to their counterparts in
1892          * OutputStream, except that they partition written data into data
1893          * blocks when in block data mode.
1894          */
1895 
write(int b)1896         public void write(int b) throws IOException {
1897             if (pos >= MAX_BLOCK_SIZE) {
1898                 drain();
1899             }
1900             buf[pos++] = (byte) b;
1901         }
1902 
write(byte[] b)1903         public void write(byte[] b) throws IOException {
1904             write(b, 0, b.length, false);
1905         }
1906 
write(byte[] b, int off, int len)1907         public void write(byte[] b, int off, int len) throws IOException {
1908             write(b, off, len, false);
1909         }
1910 
flush()1911         public void flush() throws IOException {
1912             drain();
1913             out.flush();
1914         }
1915 
close()1916         public void close() throws IOException {
1917             flush();
1918             out.close();
1919             // Android-added: Warning about writing to closed ObjectOutputStream.
1920             warnOnceWhenWriting = true;
1921         }
1922 
1923         /**
1924          * Writes specified span of byte values from given array.  If copy is
1925          * true, copies the values to an intermediate buffer before writing
1926          * them to underlying stream (to avoid exposing a reference to the
1927          * original byte array).
1928          */
write(byte[] b, int off, int len, boolean copy)1929         void write(byte[] b, int off, int len, boolean copy)
1930             throws IOException
1931         {
1932             if (!(copy || blkmode)) {           // write directly
1933                 drain();
1934                 out.write(b, off, len);
1935                 // Android-added: Warning about writing to closed ObjectOutputStream.
1936                 warnIfClosed();
1937                 return;
1938             }
1939 
1940             while (len > 0) {
1941                 if (pos >= MAX_BLOCK_SIZE) {
1942                     drain();
1943                 }
1944                 if (len >= MAX_BLOCK_SIZE && !copy && pos == 0) {
1945                     // avoid unnecessary copy
1946                     writeBlockHeader(MAX_BLOCK_SIZE);
1947                     out.write(b, off, MAX_BLOCK_SIZE);
1948                     off += MAX_BLOCK_SIZE;
1949                     len -= MAX_BLOCK_SIZE;
1950                 } else {
1951                     int wlen = Math.min(len, MAX_BLOCK_SIZE - pos);
1952                     System.arraycopy(b, off, buf, pos, wlen);
1953                     pos += wlen;
1954                     off += wlen;
1955                     len -= wlen;
1956                 }
1957             }
1958             // Android-added: Warning about writing to closed ObjectOutputStream.
1959             warnIfClosed();
1960         }
1961 
1962         /**
1963          * Writes all buffered data from this stream to the underlying stream,
1964          * but does not flush underlying stream.
1965          */
drain()1966         void drain() throws IOException {
1967             if (pos == 0) {
1968                 return;
1969             }
1970             if (blkmode) {
1971                 writeBlockHeader(pos);
1972             }
1973             out.write(buf, 0, pos);
1974             pos = 0;
1975             // Android-added: Warning about writing to closed ObjectOutputStream.
1976             warnIfClosed();
1977         }
1978 
1979         /**
1980          * Writes block data header.  Data blocks shorter than 256 bytes are
1981          * prefixed with a 2-byte header; all others start with a 5-byte
1982          * header.
1983          */
writeBlockHeader(int len)1984         private void writeBlockHeader(int len) throws IOException {
1985             if (len <= 0xFF) {
1986                 hbuf[0] = TC_BLOCKDATA;
1987                 hbuf[1] = (byte) len;
1988                 out.write(hbuf, 0, 2);
1989             } else {
1990                 hbuf[0] = TC_BLOCKDATALONG;
1991                 Bits.putInt(hbuf, 1, len);
1992                 out.write(hbuf, 0, 5);
1993             }
1994             // Android-added: Warning about writing to closed ObjectOutputStream.
1995             warnIfClosed();
1996         }
1997 
1998 
1999         /* ----------------- primitive data output methods ----------------- */
2000         /*
2001          * The following methods are equivalent to their counterparts in
2002          * DataOutputStream, except that they partition written data into data
2003          * blocks when in block data mode.
2004          */
2005 
writeBoolean(boolean v)2006         public void writeBoolean(boolean v) throws IOException {
2007             if (pos >= MAX_BLOCK_SIZE) {
2008                 drain();
2009             }
2010             Bits.putBoolean(buf, pos++, v);
2011         }
2012 
writeByte(int v)2013         public void writeByte(int v) throws IOException {
2014             if (pos >= MAX_BLOCK_SIZE) {
2015                 drain();
2016             }
2017             buf[pos++] = (byte) v;
2018         }
2019 
writeChar(int v)2020         public void writeChar(int v) throws IOException {
2021             if (pos + 2 <= MAX_BLOCK_SIZE) {
2022                 Bits.putChar(buf, pos, (char) v);
2023                 pos += 2;
2024             } else {
2025                 dout.writeChar(v);
2026             }
2027         }
2028 
writeShort(int v)2029         public void writeShort(int v) throws IOException {
2030             if (pos + 2 <= MAX_BLOCK_SIZE) {
2031                 Bits.putShort(buf, pos, (short) v);
2032                 pos += 2;
2033             } else {
2034                 dout.writeShort(v);
2035             }
2036         }
2037 
writeInt(int v)2038         public void writeInt(int v) throws IOException {
2039             if (pos + 4 <= MAX_BLOCK_SIZE) {
2040                 Bits.putInt(buf, pos, v);
2041                 pos += 4;
2042             } else {
2043                 dout.writeInt(v);
2044             }
2045         }
2046 
writeFloat(float v)2047         public void writeFloat(float v) throws IOException {
2048             if (pos + 4 <= MAX_BLOCK_SIZE) {
2049                 Bits.putFloat(buf, pos, v);
2050                 pos += 4;
2051             } else {
2052                 dout.writeFloat(v);
2053             }
2054         }
2055 
writeLong(long v)2056         public void writeLong(long v) throws IOException {
2057             if (pos + 8 <= MAX_BLOCK_SIZE) {
2058                 Bits.putLong(buf, pos, v);
2059                 pos += 8;
2060             } else {
2061                 dout.writeLong(v);
2062             }
2063         }
2064 
writeDouble(double v)2065         public void writeDouble(double v) throws IOException {
2066             if (pos + 8 <= MAX_BLOCK_SIZE) {
2067                 Bits.putDouble(buf, pos, v);
2068                 pos += 8;
2069             } else {
2070                 dout.writeDouble(v);
2071             }
2072         }
2073 
writeBytes(String s)2074         public void writeBytes(String s) throws IOException {
2075             int endoff = s.length();
2076             int cpos = 0;
2077             int csize = 0;
2078             for (int off = 0; off < endoff; ) {
2079                 if (cpos >= csize) {
2080                     cpos = 0;
2081                     csize = Math.min(endoff - off, CHAR_BUF_SIZE);
2082                     s.getChars(off, off + csize, cbuf, 0);
2083                 }
2084                 if (pos >= MAX_BLOCK_SIZE) {
2085                     drain();
2086                 }
2087                 int n = Math.min(csize - cpos, MAX_BLOCK_SIZE - pos);
2088                 int stop = pos + n;
2089                 while (pos < stop) {
2090                     buf[pos++] = (byte) cbuf[cpos++];
2091                 }
2092                 off += n;
2093             }
2094         }
2095 
writeChars(String s)2096         public void writeChars(String s) throws IOException {
2097             int endoff = s.length();
2098             for (int off = 0; off < endoff; ) {
2099                 int csize = Math.min(endoff - off, CHAR_BUF_SIZE);
2100                 s.getChars(off, off + csize, cbuf, 0);
2101                 writeChars(cbuf, 0, csize);
2102                 off += csize;
2103             }
2104         }
2105 
writeUTF(String s)2106         public void writeUTF(String s) throws IOException {
2107             writeUTF(s, getUTFLength(s));
2108         }
2109 
2110 
2111         /* -------------- primitive data array output methods -------------- */
2112         /*
2113          * The following methods write out spans of primitive data values.
2114          * Though equivalent to calling the corresponding primitive write
2115          * methods repeatedly, these methods are optimized for writing groups
2116          * of primitive data values more efficiently.
2117          */
2118 
writeBooleans(boolean[] v, int off, int len)2119         void writeBooleans(boolean[] v, int off, int len) throws IOException {
2120             int endoff = off + len;
2121             while (off < endoff) {
2122                 if (pos >= MAX_BLOCK_SIZE) {
2123                     drain();
2124                 }
2125                 int stop = Math.min(endoff, off + (MAX_BLOCK_SIZE - pos));
2126                 while (off < stop) {
2127                     Bits.putBoolean(buf, pos++, v[off++]);
2128                 }
2129             }
2130         }
2131 
writeChars(char[] v, int off, int len)2132         void writeChars(char[] v, int off, int len) throws IOException {
2133             int limit = MAX_BLOCK_SIZE - 2;
2134             int endoff = off + len;
2135             while (off < endoff) {
2136                 if (pos <= limit) {
2137                     int avail = (MAX_BLOCK_SIZE - pos) >> 1;
2138                     int stop = Math.min(endoff, off + avail);
2139                     while (off < stop) {
2140                         Bits.putChar(buf, pos, v[off++]);
2141                         pos += 2;
2142                     }
2143                 } else {
2144                     dout.writeChar(v[off++]);
2145                 }
2146             }
2147         }
2148 
writeShorts(short[] v, int off, int len)2149         void writeShorts(short[] v, int off, int len) throws IOException {
2150             int limit = MAX_BLOCK_SIZE - 2;
2151             int endoff = off + len;
2152             while (off < endoff) {
2153                 if (pos <= limit) {
2154                     int avail = (MAX_BLOCK_SIZE - pos) >> 1;
2155                     int stop = Math.min(endoff, off + avail);
2156                     while (off < stop) {
2157                         Bits.putShort(buf, pos, v[off++]);
2158                         pos += 2;
2159                     }
2160                 } else {
2161                     dout.writeShort(v[off++]);
2162                 }
2163             }
2164         }
2165 
writeInts(int[] v, int off, int len)2166         void writeInts(int[] v, int off, int len) throws IOException {
2167             int limit = MAX_BLOCK_SIZE - 4;
2168             int endoff = off + len;
2169             while (off < endoff) {
2170                 if (pos <= limit) {
2171                     int avail = (MAX_BLOCK_SIZE - pos) >> 2;
2172                     int stop = Math.min(endoff, off + avail);
2173                     while (off < stop) {
2174                         Bits.putInt(buf, pos, v[off++]);
2175                         pos += 4;
2176                     }
2177                 } else {
2178                     dout.writeInt(v[off++]);
2179                 }
2180             }
2181         }
2182 
writeFloats(float[] v, int off, int len)2183         void writeFloats(float[] v, int off, int len) throws IOException {
2184             int limit = MAX_BLOCK_SIZE - 4;
2185             int endoff = off + len;
2186             while (off < endoff) {
2187                 if (pos <= limit) {
2188                     int avail = (MAX_BLOCK_SIZE - pos) >> 2;
2189                     int chunklen = Math.min(endoff - off, avail);
2190                     floatsToBytes(v, off, buf, pos, chunklen);
2191                     off += chunklen;
2192                     pos += chunklen << 2;
2193                 } else {
2194                     dout.writeFloat(v[off++]);
2195                 }
2196             }
2197         }
2198 
writeLongs(long[] v, int off, int len)2199         void writeLongs(long[] v, int off, int len) throws IOException {
2200             int limit = MAX_BLOCK_SIZE - 8;
2201             int endoff = off + len;
2202             while (off < endoff) {
2203                 if (pos <= limit) {
2204                     int avail = (MAX_BLOCK_SIZE - pos) >> 3;
2205                     int stop = Math.min(endoff, off + avail);
2206                     while (off < stop) {
2207                         Bits.putLong(buf, pos, v[off++]);
2208                         pos += 8;
2209                     }
2210                 } else {
2211                     dout.writeLong(v[off++]);
2212                 }
2213             }
2214         }
2215 
writeDoubles(double[] v, int off, int len)2216         void writeDoubles(double[] v, int off, int len) throws IOException {
2217             int limit = MAX_BLOCK_SIZE - 8;
2218             int endoff = off + len;
2219             while (off < endoff) {
2220                 if (pos <= limit) {
2221                     int avail = (MAX_BLOCK_SIZE - pos) >> 3;
2222                     int chunklen = Math.min(endoff - off, avail);
2223                     doublesToBytes(v, off, buf, pos, chunklen);
2224                     off += chunklen;
2225                     pos += chunklen << 3;
2226                 } else {
2227                     dout.writeDouble(v[off++]);
2228                 }
2229             }
2230         }
2231 
2232         /**
2233          * Returns the length in bytes of the UTF encoding of the given string.
2234          */
getUTFLength(String s)2235         long getUTFLength(String s) {
2236             int len = s.length();
2237             long utflen = 0;
2238             for (int off = 0; off < len; ) {
2239                 int csize = Math.min(len - off, CHAR_BUF_SIZE);
2240                 s.getChars(off, off + csize, cbuf, 0);
2241                 for (int cpos = 0; cpos < csize; cpos++) {
2242                     char c = cbuf[cpos];
2243                     if (c >= 0x0001 && c <= 0x007F) {
2244                         utflen++;
2245                     } else if (c > 0x07FF) {
2246                         utflen += 3;
2247                     } else {
2248                         utflen += 2;
2249                     }
2250                 }
2251                 off += csize;
2252             }
2253             return utflen;
2254         }
2255 
2256         /**
2257          * Writes the given string in UTF format.  This method is used in
2258          * situations where the UTF encoding length of the string is already
2259          * known; specifying it explicitly avoids a prescan of the string to
2260          * determine its UTF length.
2261          */
writeUTF(String s, long utflen)2262         void writeUTF(String s, long utflen) throws IOException {
2263             if (utflen > 0xFFFFL) {
2264                 throw new UTFDataFormatException();
2265             }
2266             writeShort((int) utflen);
2267             if (utflen == (long) s.length()) {
2268                 writeBytes(s);
2269             } else {
2270                 writeUTFBody(s);
2271             }
2272         }
2273 
2274         /**
2275          * Writes given string in "long" UTF format.  "Long" UTF format is
2276          * identical to standard UTF, except that it uses an 8 byte header
2277          * (instead of the standard 2 bytes) to convey the UTF encoding length.
2278          */
writeLongUTF(String s)2279         void writeLongUTF(String s) throws IOException {
2280             writeLongUTF(s, getUTFLength(s));
2281         }
2282 
2283         /**
2284          * Writes given string in "long" UTF format, where the UTF encoding
2285          * length of the string is already known.
2286          */
writeLongUTF(String s, long utflen)2287         void writeLongUTF(String s, long utflen) throws IOException {
2288             writeLong(utflen);
2289             if (utflen == (long) s.length()) {
2290                 writeBytes(s);
2291             } else {
2292                 writeUTFBody(s);
2293             }
2294         }
2295 
2296         /**
2297          * Writes the "body" (i.e., the UTF representation minus the 2-byte or
2298          * 8-byte length header) of the UTF encoding for the given string.
2299          */
writeUTFBody(String s)2300         private void writeUTFBody(String s) throws IOException {
2301             int limit = MAX_BLOCK_SIZE - 3;
2302             int len = s.length();
2303             for (int off = 0; off < len; ) {
2304                 int csize = Math.min(len - off, CHAR_BUF_SIZE);
2305                 s.getChars(off, off + csize, cbuf, 0);
2306                 for (int cpos = 0; cpos < csize; cpos++) {
2307                     char c = cbuf[cpos];
2308                     if (pos <= limit) {
2309                         if (c <= 0x007F && c != 0) {
2310                             buf[pos++] = (byte) c;
2311                         } else if (c > 0x07FF) {
2312                             buf[pos + 2] = (byte) (0x80 | ((c >> 0) & 0x3F));
2313                             buf[pos + 1] = (byte) (0x80 | ((c >> 6) & 0x3F));
2314                             buf[pos + 0] = (byte) (0xE0 | ((c >> 12) & 0x0F));
2315                             pos += 3;
2316                         } else {
2317                             buf[pos + 1] = (byte) (0x80 | ((c >> 0) & 0x3F));
2318                             buf[pos + 0] = (byte) (0xC0 | ((c >> 6) & 0x1F));
2319                             pos += 2;
2320                         }
2321                     } else {    // write one byte at a time to normalize block
2322                         if (c <= 0x007F && c != 0) {
2323                             write(c);
2324                         } else if (c > 0x07FF) {
2325                             write(0xE0 | ((c >> 12) & 0x0F));
2326                             write(0x80 | ((c >> 6) & 0x3F));
2327                             write(0x80 | ((c >> 0) & 0x3F));
2328                         } else {
2329                             write(0xC0 | ((c >> 6) & 0x1F));
2330                             write(0x80 | ((c >> 0) & 0x3F));
2331                         }
2332                     }
2333                 }
2334                 off += csize;
2335             }
2336         }
2337     }
2338 
2339     /**
2340      * Lightweight identity hash table which maps objects to integer handles,
2341      * assigned in ascending order.
2342      */
2343     private static class HandleTable {
2344 
2345         /* number of mappings in table/next available handle */
2346         private int size;
2347         /* size threshold determining when to expand hash spine */
2348         private int threshold;
2349         /* factor for computing size threshold */
2350         private final float loadFactor;
2351         /* maps hash value -> candidate handle value */
2352         private int[] spine;
2353         /* maps handle value -> next candidate handle value */
2354         private int[] next;
2355         /* maps handle value -> associated object */
2356         private Object[] objs;
2357 
2358         /**
2359          * Creates new HandleTable with given capacity and load factor.
2360          */
HandleTable(int initialCapacity, float loadFactor)2361         HandleTable(int initialCapacity, float loadFactor) {
2362             this.loadFactor = loadFactor;
2363             spine = new int[initialCapacity];
2364             next = new int[initialCapacity];
2365             objs = new Object[initialCapacity];
2366             threshold = (int) (initialCapacity * loadFactor);
2367             clear();
2368         }
2369 
2370         /**
2371          * Assigns next available handle to given object, and returns handle
2372          * value.  Handles are assigned in ascending order starting at 0.
2373          */
assign(Object obj)2374         int assign(Object obj) {
2375             if (size >= next.length) {
2376                 growEntries();
2377             }
2378             if (size >= threshold) {
2379                 growSpine();
2380             }
2381             insert(obj, size);
2382             return size++;
2383         }
2384 
2385         /**
2386          * Looks up and returns handle associated with given object, or -1 if
2387          * no mapping found.
2388          */
lookup(Object obj)2389         int lookup(Object obj) {
2390             if (size == 0) {
2391                 return -1;
2392             }
2393             int index = hash(obj) % spine.length;
2394             for (int i = spine[index]; i >= 0; i = next[i]) {
2395                 if (objs[i] == obj) {
2396                     return i;
2397                 }
2398             }
2399             return -1;
2400         }
2401 
2402         /**
2403          * Resets table to its initial (empty) state.
2404          */
clear()2405         void clear() {
2406             Arrays.fill(spine, -1);
2407             Arrays.fill(objs, 0, size, null);
2408             size = 0;
2409         }
2410 
2411         /**
2412          * Returns the number of mappings currently in table.
2413          */
size()2414         int size() {
2415             return size;
2416         }
2417 
2418         /**
2419          * Inserts mapping object -> handle mapping into table.  Assumes table
2420          * is large enough to accommodate new mapping.
2421          */
insert(Object obj, int handle)2422         private void insert(Object obj, int handle) {
2423             int index = hash(obj) % spine.length;
2424             objs[handle] = obj;
2425             next[handle] = spine[index];
2426             spine[index] = handle;
2427         }
2428 
2429         /**
2430          * Expands the hash "spine" -- equivalent to increasing the number of
2431          * buckets in a conventional hash table.
2432          */
growSpine()2433         private void growSpine() {
2434             spine = new int[(spine.length << 1) + 1];
2435             threshold = (int) (spine.length * loadFactor);
2436             Arrays.fill(spine, -1);
2437             for (int i = 0; i < size; i++) {
2438                 insert(objs[i], i);
2439             }
2440         }
2441 
2442         /**
2443          * Increases hash table capacity by lengthening entry arrays.
2444          */
growEntries()2445         private void growEntries() {
2446             int newLength = (next.length << 1) + 1;
2447             int[] newNext = new int[newLength];
2448             System.arraycopy(next, 0, newNext, 0, size);
2449             next = newNext;
2450 
2451             Object[] newObjs = new Object[newLength];
2452             System.arraycopy(objs, 0, newObjs, 0, size);
2453             objs = newObjs;
2454         }
2455 
2456         /**
2457          * Returns hash value for given object.
2458          */
hash(Object obj)2459         private int hash(Object obj) {
2460             return System.identityHashCode(obj) & 0x7FFFFFFF;
2461         }
2462     }
2463 
2464     /**
2465      * Lightweight identity hash table which maps objects to replacement
2466      * objects.
2467      */
2468     private static class ReplaceTable {
2469 
2470         /* maps object -> index */
2471         private final HandleTable htab;
2472         /* maps index -> replacement object */
2473         private Object[] reps;
2474 
2475         /**
2476          * Creates new ReplaceTable with given capacity and load factor.
2477          */
ReplaceTable(int initialCapacity, float loadFactor)2478         ReplaceTable(int initialCapacity, float loadFactor) {
2479             htab = new HandleTable(initialCapacity, loadFactor);
2480             reps = new Object[initialCapacity];
2481         }
2482 
2483         /**
2484          * Enters mapping from object to replacement object.
2485          */
assign(Object obj, Object rep)2486         void assign(Object obj, Object rep) {
2487             int index = htab.assign(obj);
2488             while (index >= reps.length) {
2489                 grow();
2490             }
2491             reps[index] = rep;
2492         }
2493 
2494         /**
2495          * Looks up and returns replacement for given object.  If no
2496          * replacement is found, returns the lookup object itself.
2497          */
lookup(Object obj)2498         Object lookup(Object obj) {
2499             int index = htab.lookup(obj);
2500             return (index >= 0) ? reps[index] : obj;
2501         }
2502 
2503         /**
2504          * Resets table to its initial (empty) state.
2505          */
clear()2506         void clear() {
2507             Arrays.fill(reps, 0, htab.size(), null);
2508             htab.clear();
2509         }
2510 
2511         /**
2512          * Returns the number of mappings currently in table.
2513          */
size()2514         int size() {
2515             return htab.size();
2516         }
2517 
2518         /**
2519          * Increases table capacity.
2520          */
grow()2521         private void grow() {
2522             Object[] newReps = new Object[(reps.length << 1) + 1];
2523             System.arraycopy(reps, 0, newReps, 0, reps.length);
2524             reps = newReps;
2525         }
2526     }
2527 
2528     /**
2529      * Stack to keep debug information about the state of the
2530      * serialization process, for embedding in exception messages.
2531      */
2532     private static class DebugTraceInfoStack {
2533         private final List<String> stack;
2534 
DebugTraceInfoStack()2535         DebugTraceInfoStack() {
2536             stack = new ArrayList<>();
2537         }
2538 
2539         /**
2540          * Removes all of the elements from enclosed list.
2541          */
clear()2542         void clear() {
2543             stack.clear();
2544         }
2545 
2546         /**
2547          * Removes the object at the top of enclosed list.
2548          */
pop()2549         void pop() {
2550             stack.remove(stack.size()-1);
2551         }
2552 
2553         /**
2554          * Pushes a String onto the top of enclosed list.
2555          */
push(String entry)2556         void push(String entry) {
2557             stack.add("\t- " + entry);
2558         }
2559 
2560         /**
2561          * Returns a string representation of this object
2562          */
toString()2563         public String toString() {
2564             StringBuilder buffer = new StringBuilder();
2565             if (!stack.isEmpty()) {
2566                 for(int i = stack.size(); i > 0; i-- ) {
2567                     buffer.append(stack.get(i-1) + ((i != 1) ? "\n" : ""));
2568                 }
2569             }
2570             return buffer.toString();
2571         }
2572     }
2573 
2574 }
2575