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