ObjectInputStream.java revision 2543351c360bdfe0046e819dedb069f3724d703a
1/*
2 *  Licensed to the Apache Software Foundation (ASF) under one or more
3 *  contributor license agreements.  See the NOTICE file distributed with
4 *  this work for additional information regarding copyright ownership.
5 *  The ASF licenses this file to You under the Apache License, Version 2.0
6 *  (the "License"); you may not use this file except in compliance with
7 *  the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 */
17
18package java.io;
19
20// BEGIN android-note
21// Harmony uses ObjectAccessors to access fields through JNI. Android has not
22// yet migrated that API. As a consequence, there's a lot of changes here...
23// END android-note
24
25import dalvik.system.VMStack;
26import java.io.EmulatedFields.ObjectSlot;
27import java.lang.reflect.Array;
28import java.lang.reflect.Constructor;
29import java.lang.reflect.InvocationTargetException;
30import java.lang.reflect.Method;
31import java.lang.reflect.Modifier;
32import java.lang.reflect.Proxy;
33import java.security.AccessController;
34import java.security.PrivilegedAction;
35import java.util.ArrayList;
36import java.util.HashMap;
37import java.util.Iterator;
38import org.apache.harmony.luni.util.PriviAction;
39
40/**
41 * A specialized {@link InputStream} that is able to read (deserialize) Java
42 * objects as well as primitive data types (int, byte, char etc.). The data has
43 * typically been saved using an ObjectOutputStream.
44 *
45 * @see ObjectOutputStream
46 * @see ObjectInput
47 * @see Serializable
48 * @see Externalizable
49 */
50public class ObjectInputStream extends InputStream implements ObjectInput,
51        ObjectStreamConstants {
52
53    // BEGIN android-note
54    // this is non-static to avoid sync contention. Would static be faster?
55    // END android-note
56    private InputStream emptyStream = new ByteArrayInputStream(
57            new byte[0]);
58
59    // To put into objectsRead when reading unsharedObject
60    private static final Object UNSHARED_OBJ = new Object(); // $NON-LOCK-1$
61
62    // If the receiver has already read & not consumed a TC code
63    private boolean hasPushbackTC;
64
65    // Push back TC code if the variable above is true
66    private byte pushbackTC;
67
68    // How many nested levels to readObject. When we reach 0 we have to validate
69    // the graph then reset it
70    private int nestedLevels;
71
72    // All objects are assigned an ID (integer handle)
73    private int nextHandle;
74
75    // Where we read from
76    private DataInputStream input;
77
78    // Where we read primitive types from
79    private DataInputStream primitiveTypes;
80
81    // Where we keep primitive type data
82    private InputStream primitiveData = emptyStream;
83
84    // Resolve object is a mechanism for replacement
85    private boolean enableResolve;
86
87    // Table mapping Integer (handle) -> Object
88    private HashMap<Integer, Object> objectsRead;
89
90    // Used by defaultReadObject
91    private Object currentObject;
92
93    // Used by defaultReadObject
94    private ObjectStreamClass currentClass;
95
96    // All validations to be executed when the complete graph is read. See inner
97    // type below.
98    private InputValidationDesc[] validations;
99
100    // Allows the receiver to decide if it needs to call readObjectOverride
101    private boolean subclassOverridingImplementation;
102
103    // Original caller's class loader, used to perform class lookups
104    private ClassLoader callerClassLoader;
105
106    // false when reading missing fields
107    private boolean mustResolve = true;
108
109    // Handle for the current class descriptor
110    private Integer descriptorHandle;
111
112    private static final HashMap<String, Class<?>> PRIMITIVE_CLASSES =
113        new HashMap<String, Class<?>>();
114
115    static {
116        PRIMITIVE_CLASSES.put("byte", byte.class);
117        PRIMITIVE_CLASSES.put("short", short.class);
118        PRIMITIVE_CLASSES.put("int", int.class);
119        PRIMITIVE_CLASSES.put("long", long.class);
120        PRIMITIVE_CLASSES.put("boolean", boolean.class);
121        PRIMITIVE_CLASSES.put("char", char.class);
122        PRIMITIVE_CLASSES.put("float", float.class);
123        PRIMITIVE_CLASSES.put("double", double.class);
124    }
125
126    // BEGIN android-removed
127    // private ObjectAccessor accessor = AccessorFactory.getObjectAccessor();
128    // END android-removed
129
130    // Internal type used to keep track of validators & corresponding priority
131    static class InputValidationDesc {
132        ObjectInputValidation validator;
133
134        int priority;
135    }
136
137    /**
138     * GetField is an inner class that provides access to the persistent fields
139     * read from the source stream.
140     */
141    public abstract static class GetField {
142        /**
143         * Gets the ObjectStreamClass that describes a field.
144         *
145         * @return the descriptor class for a serialized field.
146         */
147        public abstract ObjectStreamClass getObjectStreamClass();
148
149        /**
150         * Indicates if the field identified by {@code name} is defaulted. This
151         * means that it has no value in this stream.
152         *
153         * @param name
154         *            the name of the field to check.
155         * @return {@code true} if the field is defaulted, {@code false}
156         *         otherwise.
157         * @throws IllegalArgumentException
158         *             if {@code name} does not identify a serializable field.
159         * @throws IOException
160         *             if an error occurs while reading from the source input
161         *             stream.
162         */
163        public abstract boolean defaulted(String name) throws IOException,
164                IllegalArgumentException;
165
166        /**
167         * Gets the value of the boolean field identified by {@code name} from
168         * the persistent field.
169         *
170         * @param name
171         *            the name of the field to get.
172         * @param defaultValue
173         *            the default value that is used if the field does not have
174         *            a value when read from the source stream.
175         * @return the value of the field identified by {@code name}.
176         * @throws IOException
177         *             if an error occurs while reading from the source input
178         *             stream.
179         * @throws IllegalArgumentException
180         *             if the type of the field identified by {@code name} is
181         *             not {@code boolean}.
182         */
183        public abstract boolean get(String name, boolean defaultValue)
184                throws IOException, IllegalArgumentException;
185
186        /**
187         * Gets the value of the character field identified by {@code name} from
188         * the persistent field.
189         *
190         * @param name
191         *            the name of the field to get.
192         * @param defaultValue
193         *            the default value that is used if the field does not have
194         *            a value when read from the source stream.
195         * @return the value of the field identified by {@code name}.
196         * @throws IOException
197         *             if an error occurs while reading from the source input
198         *             stream.
199         * @throws IllegalArgumentException
200         *             if the type of the field identified by {@code name} is
201         *             not {@code char}.
202         */
203        public abstract char get(String name, char defaultValue)
204                throws IOException, IllegalArgumentException;
205
206        /**
207         * Gets the value of the byte field identified by {@code name} from the
208         * persistent field.
209         *
210         * @param name
211         *            the name of the field to get.
212         * @param defaultValue
213         *            the default value that is used if the field does not have
214         *            a value when read from the source stream.
215         * @return the value of the field identified by {@code name}.
216         * @throws IOException
217         *             if an error occurs while reading from the source input
218         *             stream.
219         * @throws IllegalArgumentException
220         *             if the type of the field identified by {@code name} is
221         *             not {@code byte}.
222         */
223        public abstract byte get(String name, byte defaultValue)
224                throws IOException, IllegalArgumentException;
225
226        /**
227         * Gets the value of the short field identified by {@code name} from the
228         * persistent field.
229         *
230         * @param name
231         *            the name of the field to get.
232         * @param defaultValue
233         *            the default value that is used if the field does not have
234         *            a value when read from the source stream.
235         * @return the value of the field identified by {@code name}.
236         * @throws IOException
237         *             if an error occurs while reading from the source input
238         *             stream.
239         * @throws IllegalArgumentException
240         *             if the type of the field identified by {@code name} is
241         *             not {@code short}.
242         */
243        public abstract short get(String name, short defaultValue)
244                throws IOException, IllegalArgumentException;
245
246        /**
247         * Gets the value of the integer field identified by {@code name} from
248         * the persistent field.
249         *
250         * @param name
251         *            the name of the field to get.
252         * @param defaultValue
253         *            the default value that is used if the field does not have
254         *            a value when read from the source stream.
255         * @return the value of the field identified by {@code name}.
256         * @throws IOException
257         *             if an error occurs while reading from the source input
258         *             stream.
259         * @throws IllegalArgumentException
260         *             if the type of the field identified by {@code name} is
261         *             not {@code int}.
262         */
263        public abstract int get(String name, int defaultValue)
264                throws IOException, IllegalArgumentException;
265
266        /**
267         * Gets the value of the long field identified by {@code name} from the
268         * persistent field.
269         *
270         * @param name
271         *            the name of the field to get.
272         * @param defaultValue
273         *            the default value that is used if the field does not have
274         *            a value when read from the source stream.
275         * @return the value of the field identified by {@code name}.
276         * @throws IOException
277         *             if an error occurs while reading from the source input
278         *             stream.
279         * @throws IllegalArgumentException
280         *             if the type of the field identified by {@code name} is
281         *             not {@code long}.
282         */
283        public abstract long get(String name, long defaultValue)
284                throws IOException, IllegalArgumentException;
285
286        /**
287         * Gets the value of the float field identified by {@code name} from the
288         * persistent field.
289         *
290         * @param name
291         *            the name of the field to get.
292         * @param defaultValue
293         *            the default value that is used if the field does not have
294         *            a value when read from the source stream.
295         * @return the value of the field identified by {@code name}.
296         * @throws IOException
297         *             if an error occurs while reading from the source input
298         *             stream.
299         * @throws IllegalArgumentException
300         *             if the type of the field identified by {@code float} is
301         *             not {@code char}.
302         */
303        public abstract float get(String name, float defaultValue)
304                throws IOException, IllegalArgumentException;
305
306        /**
307         * Gets the value of the double field identified by {@code name} from
308         * the persistent field.
309         *
310         * @param name
311         *            the name of the field to get.
312         * @param defaultValue
313         *            the default value that is used if the field does not have
314         *            a value when read from the source stream.
315         * @return the value of the field identified by {@code name}.
316         * @throws IOException
317         *             if an error occurs while reading from the source input
318         *             stream.
319         * @throws IllegalArgumentException
320         *             if the type of the field identified by {@code name} is
321         *             not {@code double}.
322         */
323        public abstract double get(String name, double defaultValue)
324                throws IOException, IllegalArgumentException;
325
326        /**
327         * Gets the value of the object field identified by {@code name} from
328         * the persistent field.
329         *
330         * @param name
331         *            the name of the field to get.
332         * @param defaultValue
333         *            the default value that is used if the field does not have
334         *            a value when read from the source stream.
335         * @return the value of the field identified by {@code name}.
336         * @throws IOException
337         *             if an error occurs while reading from the source input
338         *             stream.
339         * @throws IllegalArgumentException
340         *             if the type of the field identified by {@code name} is
341         *             not {@code Object}.
342         */
343        public abstract Object get(String name, Object defaultValue)
344                throws IOException, IllegalArgumentException;
345    }
346
347    /**
348     * Constructs a new ObjectInputStream. This default constructor can be used
349     * by subclasses that do not want to use the public constructor if it
350     * allocates unneeded data.
351     *
352     * @throws IOException
353     *             if an error occurs when creating this stream.
354     * @throws SecurityException
355     *             if a security manager is installed and it denies subclassing
356     *             this class.
357     * @see SecurityManager#checkPermission(java.security.Permission)
358     */
359    protected ObjectInputStream() throws IOException, SecurityException {
360        super();
361        SecurityManager currentManager = System.getSecurityManager();
362        if (currentManager != null) {
363            currentManager.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
364        }
365        // WARNING - we should throw IOException if not called from a subclass
366        // according to the JavaDoc. Add the test.
367        this.subclassOverridingImplementation = true;
368    }
369
370    /**
371     * Constructs a new ObjectInputStream that reads from the InputStream
372     * {@code input}.
373     *
374     * @param input
375     *            the non-null source InputStream to filter reads on.
376     * @throws IOException
377     *             if an error occurs while reading the stream header.
378     * @throws StreamCorruptedException
379     *             if the source stream does not contain serialized objects that
380     *             can be read.
381     * @throws SecurityException
382     *             if a security manager is installed and it denies subclassing
383     *             this class.
384     */
385    public ObjectInputStream(InputStream input)
386            throws StreamCorruptedException, IOException {
387        final Class<?> implementationClass = getClass();
388        final Class<?> thisClass = ObjectInputStream.class;
389        SecurityManager sm = System.getSecurityManager();
390        if (sm != null && implementationClass != thisClass) {
391            boolean mustCheck = AccessController
392                    .doPrivileged(new PrivilegedAction<Boolean>() {
393                        public Boolean run() {
394                            try {
395                                Method method = implementationClass
396                                        .getMethod(
397                                                "readFields",
398                                                ObjectStreamClass.EMPTY_CONSTRUCTOR_PARAM_TYPES);
399                                if (method.getDeclaringClass() != thisClass) {
400                                    return Boolean.TRUE;
401                                }
402                            } catch (NoSuchMethodException ignored) {
403                            }
404                            try {
405                                Method method = implementationClass
406                                        .getMethod(
407                                                "readUnshared",
408                                                ObjectStreamClass.EMPTY_CONSTRUCTOR_PARAM_TYPES);
409                                if (method.getDeclaringClass() != thisClass) {
410                                    return Boolean.TRUE;
411                                }
412                            } catch (NoSuchMethodException ignored) {
413                            }
414                            return Boolean.FALSE;
415                        }
416                    });
417            if (mustCheck) {
418                sm
419                        .checkPermission(ObjectStreamConstants.SUBCLASS_IMPLEMENTATION_PERMISSION);
420            }
421        }
422        this.input = (input instanceof DataInputStream) ? (DataInputStream) input
423                : new DataInputStream(input);
424        primitiveTypes = new DataInputStream(this);
425        enableResolve = false;
426        this.subclassOverridingImplementation = false;
427        resetState();
428        nestedLevels = 0;
429        // So read...() methods can be used by
430        // subclasses during readStreamHeader()
431        primitiveData = this.input;
432        // Has to be done here according to the specification
433        readStreamHeader();
434        primitiveData = emptyStream;
435    }
436
437    @Override
438    public int available() throws IOException {
439        // returns 0 if next data is an object, or N if reading primitive types
440        checkReadPrimitiveTypes();
441        return primitiveData.available();
442    }
443
444    /**
445     * Checks to if it is ok to read primitive types from this stream at
446     * this point. One is not supposed to read primitive types when about to
447     * read an object, for example, so an exception has to be thrown.
448     *
449     * @throws IOException
450     *             If any IO problem occurred when trying to read primitive type
451     *             or if it is illegal to read primitive types
452     */
453    private void checkReadPrimitiveTypes() throws IOException {
454        // If we still have primitive data, it is ok to read primitive data
455        if (primitiveData == input || primitiveData.available() > 0) {
456            return;
457        }
458
459        // If we got here either we had no Stream previously created or
460        // we no longer have data in that one, so get more bytes
461        do {
462            int next = 0;
463            if (hasPushbackTC) {
464                hasPushbackTC = false;
465            } else {
466                next = input.read();
467                pushbackTC = (byte) next;
468            }
469            switch (pushbackTC) {
470                case TC_BLOCKDATA:
471                    primitiveData = new ByteArrayInputStream(readBlockData());
472                    return;
473                case TC_BLOCKDATALONG:
474                    primitiveData = new ByteArrayInputStream(
475                            readBlockDataLong());
476                    return;
477                case TC_RESET:
478                    resetState();
479                    break;
480                default:
481                    if (next != -1) {
482                        pushbackTC();
483                    }
484                    return;
485            }
486            // Only TC_RESET falls through
487        } while (true);
488    }
489
490    /**
491     * Closes this stream. This implementation closes the source stream.
492     *
493     * @throws IOException
494     *             if an error occurs while closing this stream.
495     */
496    @Override
497    public void close() throws IOException {
498        input.close();
499    }
500
501    /**
502     * Default method to read objects from this stream. Serializable fields
503     * defined in the object's class and superclasses are read from the source
504     * stream.
505     *
506     * @throws ClassNotFoundException
507     *             if the object's class cannot be found.
508     * @throws IOException
509     *             if an I/O error occurs while reading the object data.
510     * @throws NotActiveException
511     *             if this method is not called from {@code readObject()}.
512     * @see ObjectOutputStream#defaultWriteObject
513     */
514    public void defaultReadObject() throws IOException, ClassNotFoundException,
515            NotActiveException {
516        // We can't be called from just anywhere. There are rules.
517        if (currentObject != null || !mustResolve) {
518            readFieldValues(currentObject, currentClass);
519        } else {
520            throw new NotActiveException();
521        }
522    }
523
524    /**
525     * Enables object replacement for this stream. By default this is not
526     * enabled. Only trusted subclasses (loaded with system class loader) are
527     * allowed to change this status.
528     *
529     * @param enable
530     *            {@code true} to enable object replacement; {@code false} to
531     *            disable it.
532     * @return the previous setting.
533     * @throws SecurityException
534     *             if a security manager is installed and it denies enabling
535     *             object replacement for this stream.
536     * @see #resolveObject
537     * @see ObjectOutputStream#enableReplaceObject
538     */
539    protected boolean enableResolveObject(boolean enable)
540            throws SecurityException {
541        if (enable) {
542            // The Stream has to be trusted for this feature to be enabled.
543            // trusted means the stream's class loader has to be null
544            SecurityManager currentManager = System.getSecurityManager();
545            if (currentManager != null) {
546                currentManager.checkPermission(SUBSTITUTION_PERMISSION);
547            }
548        }
549        boolean originalValue = enableResolve;
550        enableResolve = enable;
551        return originalValue;
552    }
553
554    /**
555     * Checks if two classes belong to the same package.
556     *
557     * @param c1
558     *            one of the classes to test.
559     * @param c2
560     *            the other class to test.
561     * @return {@code true} if the two classes belong to the same package,
562     *         {@code false} otherwise.
563     */
564    private boolean inSamePackage(Class<?> c1, Class<?> c2) {
565        String nameC1 = c1.getName();
566        String nameC2 = c2.getName();
567        int indexDotC1 = nameC1.lastIndexOf('.');
568        int indexDotC2 = nameC2.lastIndexOf('.');
569        if (indexDotC1 != indexDotC2) {
570            return false; // cannot be in the same package if indices are not
571        }
572        // the same
573        if (indexDotC1 < 0) {
574            return true; // both of them are in default package
575        }
576        return nameC1.substring(0, indexDotC1).equals(
577                nameC2.substring(0, indexDotC2));
578    }
579
580    // BEGIN android-added
581    /**
582     * Create and return a new instance of class {@code instantiationClass}
583     * but running the constructor defined in class
584     * {@code constructorClass} (same as {@code instantiationClass}
585     * or a superclass).
586     *
587     * Has to be native to avoid visibility rules and to be able to have
588     * {@code instantiationClass} not the same as
589     * {@code constructorClass} (no such API in java.lang.reflect).
590     *
591     * @param instantiationClass
592     *            The new object will be an instance of this class
593     * @param constructorClass
594     *            The empty constructor to run will be in this class
595     * @return the object created from {@code instantiationClass}
596     */
597    private static native Object newInstance(Class<?> instantiationClass,
598            Class<?> constructorClass);
599    // END android-added
600
601    /**
602     * Return the next {@code int} handle to be used to indicate cyclic
603     * references being loaded from the stream.
604     *
605     * @return the next handle to represent the next cyclic reference
606     */
607    private Integer nextHandle() {
608        return nextHandle++;
609    }
610
611    /**
612     * Return the next token code (TC) from the receiver, which indicates what
613     * kind of object follows
614     *
615     * @return the next TC from the receiver
616     *
617     * @throws IOException
618     *             If an IO error occurs
619     *
620     * @see ObjectStreamConstants
621     */
622    private byte nextTC() throws IOException {
623        if (hasPushbackTC) {
624            hasPushbackTC = false; // We are consuming it
625        } else {
626            // Just in case a later call decides to really push it back,
627            // we don't require the caller to pass it as parameter
628            pushbackTC = input.readByte();
629        }
630        return pushbackTC;
631    }
632
633    /**
634     * Pushes back the last TC code read
635     */
636    private void pushbackTC() {
637        hasPushbackTC = true;
638    }
639
640    /**
641     * Reads a single byte from the source stream and returns it as an integer
642     * in the range from 0 to 255. Returns -1 if the end of the source stream
643     * has been reached. Blocks if no input is available.
644     *
645     * @return the byte read or -1 if the end of the source stream has been
646     *         reached.
647     * @throws IOException
648     *             if an error occurs while reading from this stream.
649     */
650    @Override
651    public int read() throws IOException {
652        checkReadPrimitiveTypes();
653        return primitiveData.read();
654    }
655
656    /**
657     * Reads at most {@code length} bytes from the source stream and stores them
658     * in byte array {@code buffer} starting at offset {@code count}. Blocks
659     * until {@code count} bytes have been read, the end of the source stream is
660     * detected or an exception is thrown.
661     *
662     * @param buffer
663     *            the array in which to store the bytes read.
664     * @param offset
665     *            the initial position in {@code buffer} to store the bytes
666     *            read from the source stream.
667     * @param length
668     *            the maximum number of bytes to store in {@code buffer}.
669     * @return the number of bytes read or -1 if the end of the source input
670     *         stream has been reached.
671     * @throws IndexOutOfBoundsException
672     *             if {@code offset < 0} or {@code length < 0}, or if
673     *             {@code offset + length} is greater than the length of
674     *             {@code buffer}.
675     * @throws IOException
676     *             if an error occurs while reading from this stream.
677     * @throws NullPointerException
678     *             if {@code buffer} is {@code null}.
679     */
680    @Override
681    public int read(byte[] buffer, int offset, int length) throws IOException {
682        // Force buffer null check first!
683        if (offset > buffer.length || offset < 0) {
684            throw new ArrayIndexOutOfBoundsException("Offset out of bounds: " + offset);
685        }
686        if (length < 0 || length > buffer.length - offset) {
687            throw new ArrayIndexOutOfBoundsException("Length out of bounds: " + length);
688        }
689        if (length == 0) {
690            return 0;
691        }
692        checkReadPrimitiveTypes();
693        return primitiveData.read(buffer, offset, length);
694    }
695
696    /**
697     * Reads and returns an array of raw bytes with primitive data. The array
698     * will have up to 255 bytes. The primitive data will be in the format
699     * described by {@code DataOutputStream}.
700     *
701     * @return The primitive data read, as raw bytes
702     *
703     * @throws IOException
704     *             If an IO exception happened when reading the primitive data.
705     */
706    private byte[] readBlockData() throws IOException {
707        byte[] result = new byte[input.readByte() & 0xff];
708        input.readFully(result);
709        return result;
710    }
711
712    /**
713     * Reads and returns an array of raw bytes with primitive data. The array
714     * will have more than 255 bytes. The primitive data will be in the format
715     * described by {@code DataOutputStream}.
716     *
717     * @return The primitive data read, as raw bytes
718     *
719     * @throws IOException
720     *             If an IO exception happened when reading the primitive data.
721     */
722    private byte[] readBlockDataLong() throws IOException {
723        byte[] result = new byte[input.readInt()];
724        input.readFully(result);
725        return result;
726    }
727
728    /**
729     * Reads a boolean from the source stream.
730     *
731     * @return the boolean value read from the source stream.
732     * @throws EOFException
733     *             if the end of the input is reached before the read
734     *             request can be satisfied.
735     * @throws IOException
736     *             if an error occurs while reading from the source stream.
737     */
738    public boolean readBoolean() throws IOException {
739        return primitiveTypes.readBoolean();
740    }
741
742    /**
743     * Reads a byte (8 bit) from the source stream.
744     *
745     * @return the byte value read from the source stream.
746     * @throws EOFException
747     *             if the end of the input is reached before the read
748     *             request can be satisfied.
749     * @throws IOException
750     *             if an error occurs while reading from the source stream.
751     */
752    public byte readByte() throws IOException {
753        return primitiveTypes.readByte();
754    }
755
756    /**
757     * Reads a character (16 bit) from the source stream.
758     *
759     * @return the char value read from the source stream.
760     * @throws EOFException
761     *             if the end of the input is reached before the read
762     *             request can be satisfied.
763     * @throws IOException
764     *             if an error occurs while reading from the source stream.
765     */
766    public char readChar() throws IOException {
767        return primitiveTypes.readChar();
768    }
769
770    /**
771     * Reads and discards block data and objects until TC_ENDBLOCKDATA is found.
772     *
773     * @throws IOException
774     *             If an IO exception happened when reading the optional class
775     *             annotation.
776     * @throws ClassNotFoundException
777     *             If the class corresponding to the class descriptor could not
778     *             be found.
779     */
780    private void discardData() throws ClassNotFoundException, IOException {
781        primitiveData = emptyStream;
782        boolean resolve = mustResolve;
783        mustResolve = false;
784        do {
785            byte tc = nextTC();
786            if (tc == TC_ENDBLOCKDATA) {
787                mustResolve = resolve;
788                return; // End of annotation
789            }
790            readContent(tc);
791        } while (true);
792    }
793
794    /**
795     * Reads a class descriptor (an {@code ObjectStreamClass}) from the
796     * stream.
797     *
798     * @return the class descriptor read from the stream
799     *
800     * @throws IOException
801     *             If an IO exception happened when reading the class
802     *             descriptor.
803     * @throws ClassNotFoundException
804     *             If the class corresponding to the class descriptor could not
805     *             be found.
806     */
807    private ObjectStreamClass readClassDesc() throws ClassNotFoundException, IOException {
808        byte tc = nextTC();
809        switch (tc) {
810            case TC_CLASSDESC:
811                return readNewClassDesc(false);
812            case TC_PROXYCLASSDESC:
813                Class<?> proxyClass = readNewProxyClassDesc();
814                ObjectStreamClass streamClass = ObjectStreamClass
815                        .lookup(proxyClass);
816                streamClass.setLoadFields(new ObjectStreamField[0]);
817                registerObjectRead(streamClass, nextHandle(), false);
818                checkedSetSuperClassDesc(streamClass, readClassDesc());
819                return streamClass;
820            case TC_REFERENCE:
821                return (ObjectStreamClass) readCyclicReference();
822            case TC_NULL:
823                return null;
824            default:
825                throw corruptStream(tc);
826        }
827    }
828
829    private StreamCorruptedException corruptStream(byte tc) throws StreamCorruptedException {
830        throw new StreamCorruptedException("Wrong format: " + Integer.toHexString(tc & 0xff));
831    }
832
833    /**
834     * Reads the content of the receiver based on the previously read token
835     * {@code tc}.
836     *
837     * @param tc
838     *            The token code for the next item in the stream
839     * @return the object read from the stream
840     *
841     * @throws IOException
842     *             If an IO exception happened when reading the class
843     *             descriptor.
844     * @throws ClassNotFoundException
845     *             If the class corresponding to the object being read could not
846     *             be found.
847     */
848    private Object readContent(byte tc) throws ClassNotFoundException,
849            IOException {
850        switch (tc) {
851            case TC_BLOCKDATA:
852                return readBlockData();
853            case TC_BLOCKDATALONG:
854                return readBlockDataLong();
855            case TC_CLASS:
856                return readNewClass(false);
857            case TC_CLASSDESC:
858                return readNewClassDesc(false);
859            case TC_ARRAY:
860                return readNewArray(false);
861            case TC_OBJECT:
862                return readNewObject(false);
863            case TC_STRING:
864                return readNewString(false);
865            case TC_LONGSTRING:
866                return readNewLongString(false);
867            case TC_REFERENCE:
868                return readCyclicReference();
869            case TC_NULL:
870                return null;
871            case TC_EXCEPTION:
872                Exception exc = readException();
873                throw new WriteAbortedException("Read an exception", exc);
874            case TC_RESET:
875                resetState();
876                return null;
877            default:
878                throw corruptStream(tc);
879        }
880    }
881
882    /**
883     * Reads the content of the receiver based on the previously read token
884     * {@code tc}. Primitive data content is considered an error.
885     *
886     * @param unshared
887     *            read the object unshared
888     * @return the object read from the stream
889     *
890     * @throws IOException
891     *             If an IO exception happened when reading the class
892     *             descriptor.
893     * @throws ClassNotFoundException
894     *             If the class corresponding to the object being read could not
895     *             be found.
896     */
897    private Object readNonPrimitiveContent(boolean unshared)
898            throws ClassNotFoundException, IOException {
899        checkReadPrimitiveTypes();
900        if (primitiveData.available() > 0) {
901            OptionalDataException e = new OptionalDataException();
902            e.length = primitiveData.available();
903            throw e;
904        }
905
906        do {
907            byte tc = nextTC();
908            switch (tc) {
909                case TC_CLASS:
910                    return readNewClass(unshared);
911                case TC_CLASSDESC:
912                    return readNewClassDesc(unshared);
913                case TC_ARRAY:
914                    return readNewArray(unshared);
915                case TC_OBJECT:
916                    return readNewObject(unshared);
917                case TC_STRING:
918                    return readNewString(unshared);
919                case TC_LONGSTRING:
920                    return readNewLongString(unshared);
921                case TC_ENUM:
922                    return readEnum(unshared);
923                case TC_REFERENCE:
924                    if (unshared) {
925                        readNewHandle();
926                        throw new InvalidObjectException("Unshared read of back reference");
927                    }
928                    return readCyclicReference();
929                case TC_NULL:
930                    return null;
931                case TC_EXCEPTION:
932                    Exception exc = readException();
933                    throw new WriteAbortedException("Read an exception", exc);
934                case TC_RESET:
935                    resetState();
936                    break;
937                case TC_ENDBLOCKDATA: // Can occur reading class annotation
938                    pushbackTC();
939                    OptionalDataException e = new OptionalDataException();
940                    e.eof = true;
941                    throw e;
942                default:
943                    throw corruptStream(tc);
944            }
945            // Only TC_RESET falls through
946        } while (true);
947    }
948
949    /**
950     * Reads the next item from the stream assuming it is a cyclic reference to
951     * an object previously read. Return the actual object previously read.
952     *
953     * @return the object previously read from the stream
954     *
955     * @throws IOException
956     *             If an IO exception happened when reading the class
957     *             descriptor.
958     * @throws InvalidObjectException
959     *             If the cyclic reference is not valid.
960     */
961    private Object readCyclicReference() throws InvalidObjectException,
962            IOException {
963        return registeredObjectRead(readNewHandle());
964    }
965
966    /**
967     * Reads a double (64 bit) from the source stream.
968     *
969     * @return the double value read from the source stream.
970     * @throws EOFException
971     *             if the end of the input is reached before the read
972     *             request can be satisfied.
973     * @throws IOException
974     *             if an error occurs while reading from the source stream.
975     */
976    public double readDouble() throws IOException {
977        return primitiveTypes.readDouble();
978    }
979
980    /**
981     * Read the next item assuming it is an exception. The exception is not a
982     * regular instance in the object graph, but the exception instance that
983     * happened (if any) when dumping the original object graph. The set of seen
984     * objects will be reset just before and just after loading this exception
985     * object.
986     * <p>
987     * When exceptions are found normally in the object graph, they are loaded
988     * as a regular object, and not by this method. In that case, the set of
989     * "known objects" is not reset.
990     *
991     * @return the exception read
992     *
993     * @throws IOException
994     *             If an IO exception happened when reading the exception
995     *             object.
996     * @throws ClassNotFoundException
997     *             If a class could not be found when reading the object graph
998     *             for the exception
999     * @throws OptionalDataException
1000     *             If optional data could not be found when reading the
1001     *             exception graph
1002     * @throws WriteAbortedException
1003     *             If another exception was caused when dumping this exception
1004     */
1005    private Exception readException() throws WriteAbortedException,
1006            OptionalDataException, ClassNotFoundException, IOException {
1007
1008        resetSeenObjects();
1009
1010        // Now we read the Throwable object that was saved
1011        // WARNING - the grammar says it is a Throwable, but the
1012        // WriteAbortedException constructor takes an Exception. So, we read an
1013        // Exception from the stream
1014        Exception exc = (Exception) readObject();
1015
1016        // We reset the receiver's state (the grammar has "reset" in normal
1017        // font)
1018        resetSeenObjects();
1019        return exc;
1020    }
1021
1022    /**
1023     * Reads a collection of field descriptors (name, type name, etc) for the
1024     * class descriptor {@code cDesc} (an {@code ObjectStreamClass})
1025     *
1026     * @param cDesc
1027     *            The class descriptor (an {@code ObjectStreamClass})
1028     *            for which to write field information
1029     *
1030     * @throws IOException
1031     *             If an IO exception happened when reading the field
1032     *             descriptors.
1033     * @throws ClassNotFoundException
1034     *             If a class for one of the field types could not be found
1035     *
1036     * @see #readObject()
1037     */
1038    private void readFieldDescriptors(ObjectStreamClass cDesc)
1039            throws ClassNotFoundException, IOException {
1040        short numFields = input.readShort();
1041        ObjectStreamField[] fields = new ObjectStreamField[numFields];
1042
1043        // We set it now, but each element will be inserted in the array further
1044        // down
1045        cDesc.setLoadFields(fields);
1046
1047        // Check ObjectOutputStream.writeFieldDescriptors
1048        for (short i = 0; i < numFields; i++) {
1049            char typecode = (char) input.readByte();
1050            String fieldName = input.readUTF();
1051            boolean isPrimType = ObjectStreamClass.isPrimitiveType(typecode);
1052            String classSig;
1053            if (isPrimType) {
1054                classSig = String.valueOf(typecode);
1055            } else {
1056                // The spec says it is a UTF, but experience shows they dump
1057                // this String using writeObject (unlike the field name, which
1058                // is saved with writeUTF).
1059                // And if resolveObject is enabled, the classSig may be modified
1060                // so that the original class descriptor cannot be read
1061                // properly, so it is disabled.
1062                boolean old = enableResolve;
1063                try {
1064                    enableResolve = false;
1065                    classSig = (String) readObject();
1066                } finally {
1067                    enableResolve = old;
1068                }
1069            }
1070
1071            classSig = formatClassSig(classSig);
1072            ObjectStreamField f = new ObjectStreamField(classSig, fieldName);
1073            fields[i] = f;
1074        }
1075    }
1076
1077    /*
1078     * Format the class signature for ObjectStreamField, for example,
1079     * "[L[Ljava.lang.String;;" is converted to "[Ljava.lang.String;"
1080     */
1081    private static String formatClassSig(String classSig) {
1082        int start = 0;
1083        int end = classSig.length();
1084
1085        if (end <= 0) {
1086            return classSig;
1087        }
1088
1089        while (classSig.startsWith("[L", start)
1090                && classSig.charAt(end - 1) == ';') {
1091            start += 2;
1092            end--;
1093        }
1094
1095        if (start > 0) {
1096            start -= 2;
1097            end++;
1098            return classSig.substring(start, end);
1099        }
1100        return classSig;
1101    }
1102
1103    /**
1104     * Reads the persistent fields of the object that is currently being read
1105     * from the source stream. The values read are stored in a GetField object
1106     * that provides access to the persistent fields. This GetField object is
1107     * then returned.
1108     *
1109     * @return the GetField object from which persistent fields can be accessed
1110     *         by name.
1111     * @throws ClassNotFoundException
1112     *             if the class of an object being deserialized can not be
1113     *             found.
1114     * @throws IOException
1115     *             if an error occurs while reading from this stream.
1116     * @throws NotActiveException
1117     *             if this stream is currently not reading an object.
1118     */
1119    public GetField readFields() throws IOException, ClassNotFoundException,
1120            NotActiveException {
1121        // We can't be called from just anywhere. There are rules.
1122        if (currentObject == null) {
1123            throw new NotActiveException();
1124        }
1125        EmulatedFieldsForLoading result = new EmulatedFieldsForLoading(
1126                currentClass);
1127        readFieldValues(result);
1128        return result;
1129    }
1130
1131    /**
1132     * Reads a collection of field values for the emulated fields
1133     * {@code emulatedFields}
1134     *
1135     * @param emulatedFields
1136     *            an {@code EmulatedFieldsForLoading}, concrete subclass
1137     *            of {@code GetField}
1138     *
1139     * @throws IOException
1140     *             If an IO exception happened when reading the field values.
1141     * @throws InvalidClassException
1142     *             If an incompatible type is being assigned to an emulated
1143     *             field.
1144     * @throws OptionalDataException
1145     *             If optional data could not be found when reading the
1146     *             exception graph
1147     *
1148     * @see #readFields
1149     * @see #readObject()
1150     */
1151    private void readFieldValues(EmulatedFieldsForLoading emulatedFields)
1152            throws OptionalDataException, InvalidClassException, IOException {
1153        EmulatedFields.ObjectSlot[] slots = emulatedFields.emulatedFields()
1154                .slots();
1155        for (ObjectSlot element : slots) {
1156            element.defaulted = false;
1157            Class<?> type = element.field.getType();
1158            if (type == Integer.TYPE) {
1159                element.fieldValue = input.readInt();
1160            } else if (type == Byte.TYPE) {
1161                element.fieldValue = input.readByte();
1162            } else if (type == Character.TYPE) {
1163                element.fieldValue = input.readChar();
1164            } else if (type == Short.TYPE) {
1165                element.fieldValue = input.readShort();
1166            } else if (type == Boolean.TYPE) {
1167                element.fieldValue = input.readBoolean();
1168            } else if (type == Long.TYPE) {
1169                element.fieldValue = input.readLong();
1170            } else if (type == Float.TYPE) {
1171                element.fieldValue = input.readFloat();
1172            } else if (type == Double.TYPE) {
1173                element.fieldValue = input.readDouble();
1174            } else {
1175                // Either array or Object
1176                try {
1177                    element.fieldValue = readObject();
1178                } catch (ClassNotFoundException cnf) {
1179                    // WARNING- Not sure this is the right thing to do. Write
1180                    // test case.
1181                    throw new InvalidClassException(cnf.toString());
1182                }
1183            }
1184        }
1185    }
1186
1187    /**
1188     * Reads a collection of field values for the class descriptor
1189     * {@code classDesc} (an {@code ObjectStreamClass}). The
1190     * values will be used to set instance fields in object {@code obj}.
1191     * This is the default mechanism, when emulated fields (an
1192     * {@code GetField}) are not used. Actual values to load are stored
1193     * directly into the object {@code obj}.
1194     *
1195     * @param obj
1196     *            Instance in which the fields will be set.
1197     * @param classDesc
1198     *            A class descriptor (an {@code ObjectStreamClass})
1199     *            defining which fields should be loaded.
1200     *
1201     * @throws IOException
1202     *             If an IO exception happened when reading the field values.
1203     * @throws InvalidClassException
1204     *             If an incompatible type is being assigned to an emulated
1205     *             field.
1206     * @throws OptionalDataException
1207     *             If optional data could not be found when reading the
1208     *             exception graph
1209     * @throws ClassNotFoundException
1210     *             If a class of an object being de-serialized can not be found
1211     *
1212     * @see #readFields
1213     * @see #readObject()
1214     */
1215    private void readFieldValues(Object obj, ObjectStreamClass classDesc)
1216            throws OptionalDataException, ClassNotFoundException, IOException {
1217        // Now we must read all fields and assign them to the receiver
1218        ObjectStreamField[] fields = classDesc.getLoadFields();
1219        fields = (null == fields ? new ObjectStreamField[] {} : fields);
1220        Class<?> declaringClass = classDesc.forClass();
1221        if (declaringClass == null && mustResolve) {
1222            throw new ClassNotFoundException(classDesc.getName());
1223        }
1224
1225        for (ObjectStreamField fieldDesc : fields) {
1226
1227            // BEGIN android-removed
1228            // // get associated Field
1229            // long fieldID = fieldDesc.getFieldID(accessor, declaringClass);
1230            // END android-removed
1231
1232            // Code duplication starts, just because Java is typed
1233            if (fieldDesc.isPrimitive()) {
1234                try {
1235                    // BEGIN android-changed
1236                    switch (fieldDesc.getTypeCode()) {
1237                        case 'B':
1238                            setFieldByte(obj, declaringClass, fieldDesc.getName(),
1239                                    input.readByte());
1240                            break;
1241                        case 'C':
1242                            setFieldChar(obj, declaringClass, fieldDesc.getName(),
1243                                    input.readChar());
1244                            break;
1245                        case 'D':
1246                            setFieldDouble(obj, declaringClass, fieldDesc.getName(),
1247                                    input.readDouble());
1248                            break;
1249                        case 'F':
1250                            setFieldFloat(obj, declaringClass, fieldDesc.getName(),
1251                                    input.readFloat());
1252                            break;
1253                        case 'I':
1254                            setFieldInt(obj, declaringClass, fieldDesc.getName(),
1255                                    input.readInt());
1256                            break;
1257                        case 'J':
1258                            setFieldLong(obj, declaringClass, fieldDesc.getName(),
1259                                    input.readLong());
1260                            break;
1261                        case 'S':
1262                            setFieldShort(obj, declaringClass, fieldDesc.getName(),
1263                                    input.readShort());
1264                            break;
1265                        case 'Z':
1266                            setFieldBool(obj, declaringClass, fieldDesc.getName(),
1267                                    input.readBoolean());
1268                            break;
1269                        default:
1270                            throw new StreamCorruptedException("Invalid typecode: " +
1271                                    fieldDesc.getTypeCode());
1272                    }
1273                    // END android-changed
1274                } catch (NoSuchFieldError ignored) {
1275                }
1276            } else {
1277                // Object type (array included).
1278                String fieldName = fieldDesc.getName();
1279                boolean setBack = false;
1280                // BEGIN android-added
1281                ObjectStreamField field = classDesc.getField(fieldName);
1282                // END android-added
1283                if (mustResolve && fieldDesc == null) {
1284                    setBack = true;
1285                    mustResolve = false;
1286                }
1287                Object toSet;
1288                if (fieldDesc != null && fieldDesc.isUnshared()) {
1289                    toSet = readUnshared();
1290                } else {
1291                    toSet = readObject();
1292                }
1293                if (setBack) {
1294                    mustResolve = true;
1295                }
1296                if (fieldDesc != null) {
1297                    if (toSet != null) {
1298                        // BEGIN android-changed
1299                        // Get the field type from the local field rather than
1300                        // from the stream's supplied data. That's the field
1301                        // we'll be setting, so that's the one that needs to be
1302                        // validated.
1303                        Class<?> fieldType = field.getTypeInternal();
1304                        // END android-added
1305                        Class<?> valueType = toSet.getClass();
1306                        if (!fieldType.isAssignableFrom(valueType)) {
1307                            throw new ClassCastException(classDesc.getName() + "." + fieldName +
1308                                    " - " + fieldType + " not compatible with " + valueType);
1309                        }
1310                        try {
1311                            // BEGIN android-changed
1312                            setFieldObject(obj, declaringClass, fieldName, field.getTypeString(),
1313                                    toSet);
1314                            // END android-changed
1315                        } catch (NoSuchFieldError e) {
1316                            // Ignored
1317                        }
1318                    }
1319                }
1320            }
1321        }
1322    }
1323
1324    /**
1325     * Reads a float (32 bit) from the source stream.
1326     *
1327     * @return the float value read from the source stream.
1328     * @throws EOFException
1329     *             if the end of the input is reached before the read
1330     *             request can be satisfied.
1331     * @throws IOException
1332     *             if an error occurs while reading from the source stream.
1333     */
1334    public float readFloat() throws IOException {
1335        return primitiveTypes.readFloat();
1336    }
1337
1338    /**
1339     * Reads bytes from the source stream into the byte array {@code buffer}.
1340     * This method will block until {@code buffer.length} bytes have been read.
1341     *
1342     * @param buffer
1343     *            the array in which to store the bytes read.
1344     * @throws EOFException
1345     *             if the end of the input is reached before the read
1346     *             request can be satisfied.
1347     * @throws IOException
1348     *             if an error occurs while reading from the source stream.
1349     */
1350    public void readFully(byte[] buffer) throws IOException {
1351        primitiveTypes.readFully(buffer);
1352    }
1353
1354    /**
1355     * Reads bytes from the source stream into the byte array {@code buffer}.
1356     * This method will block until {@code length} number of bytes have been
1357     * read.
1358     *
1359     * @param buffer
1360     *            the byte array in which to store the bytes read.
1361     * @param offset
1362     *            the initial position in {@code buffer} to store the bytes
1363     *            read from the source stream.
1364     * @param length
1365     *            the maximum number of bytes to store in {@code buffer}.
1366     * @throws EOFException
1367     *             if the end of the input is reached before the read
1368     *             request can be satisfied.
1369     * @throws IOException
1370     *             if an error occurs while reading from the source stream.
1371     */
1372    public void readFully(byte[] buffer, int offset, int length)
1373            throws IOException {
1374        primitiveTypes.readFully(buffer, offset, length);
1375    }
1376
1377    /**
1378     * Walks the hierarchy of classes described by class descriptor
1379     * {@code classDesc} and reads the field values corresponding to
1380     * fields declared by the corresponding class descriptor. The instance to
1381     * store field values into is {@code object}. If the class
1382     * (corresponding to class descriptor {@code classDesc}) defines
1383     * private instance method {@code readObject} it will be used to load
1384     * field values.
1385     *
1386     * @param object
1387     *            Instance into which stored field values loaded.
1388     * @param classDesc
1389     *            A class descriptor (an {@code ObjectStreamClass})
1390     *            defining which fields should be loaded.
1391     *
1392     * @throws IOException
1393     *             If an IO exception happened when reading the field values in
1394     *             the hierarchy.
1395     * @throws ClassNotFoundException
1396     *             If a class for one of the field types could not be found
1397     * @throws NotActiveException
1398     *             If {@code defaultReadObject} is called from the wrong
1399     *             context.
1400     *
1401     * @see #defaultReadObject
1402     * @see #readObject()
1403     */
1404    private void readHierarchy(Object object, ObjectStreamClass classDesc)
1405            throws IOException, ClassNotFoundException, NotActiveException {
1406        // We can't be called from just anywhere. There are rules.
1407        if (object == null && mustResolve) {
1408            throw new NotActiveException();
1409        }
1410
1411        ArrayList<ObjectStreamClass> streamClassList = new ArrayList<ObjectStreamClass>(
1412                32);
1413        ObjectStreamClass nextStreamClass = classDesc;
1414        while (nextStreamClass != null) {
1415            streamClassList.add(0, nextStreamClass);
1416            nextStreamClass = nextStreamClass.getSuperclass();
1417        }
1418        if (object == null) {
1419            for (ObjectStreamClass objectStreamClass : streamClassList) {
1420                readObjectForClass(null, objectStreamClass);
1421            }
1422        } else {
1423            ArrayList<Class<?>> classList = new ArrayList<Class<?>>(32);
1424            Class<?> nextClass = object.getClass();
1425            while (nextClass != null) {
1426                Class<?> testClass = nextClass.getSuperclass();
1427                if (testClass != null) {
1428                    classList.add(0, nextClass);
1429                }
1430                nextClass = testClass;
1431            }
1432            int lastIndex = 0;
1433            for (Class<?> superclass : classList) {
1434                int index = findStreamSuperclass(superclass, streamClassList, lastIndex);
1435                if (index == -1) {
1436                    readObjectNoData(object, superclass,
1437                            ObjectStreamClass.lookupStreamClass(superclass));
1438                } else {
1439                    for (int j = lastIndex; j <= index; j++) {
1440                        readObjectForClass(object, streamClassList.get(j));
1441                    }
1442                    lastIndex = index + 1;
1443                }
1444            }
1445        }
1446    }
1447
1448    private int findStreamSuperclass(Class<?> cl,
1449            ArrayList<ObjectStreamClass> classList, int lastIndex) {
1450        ObjectStreamClass objCl;
1451        String forName;
1452
1453        for (int i = lastIndex; i < classList.size(); i++) {
1454            objCl = classList.get(i);
1455            forName = objCl.forClass().getName();
1456
1457            if (objCl.getName().equals(forName)) {
1458                if (cl.getName().equals(objCl.getName())) {
1459                    return i;
1460                }
1461            } else {
1462                // there was a class replacement
1463                if (cl.getName().equals(forName)) {
1464                    return i;
1465                }
1466            }
1467        }
1468        return -1;
1469    }
1470
1471    private void readObjectNoData(Object object, Class<?> cl, ObjectStreamClass classDesc)
1472            throws ObjectStreamException {
1473        if (!classDesc.isSerializable()) {
1474            return;
1475        }
1476        if (classDesc.hasMethodReadObjectNoData()){
1477            final Method readMethod = classDesc.getMethodReadObjectNoData();
1478            try {
1479                readMethod.invoke(object);
1480            } catch (InvocationTargetException e) {
1481                Throwable ex = e.getTargetException();
1482                if (ex instanceof RuntimeException) {
1483                    throw (RuntimeException) ex;
1484                } else if (ex instanceof Error) {
1485                    throw (Error) ex;
1486                }
1487                throw (ObjectStreamException) ex;
1488            } catch (IllegalAccessException e) {
1489                throw new RuntimeException(e.toString());
1490            }
1491        }
1492
1493    }
1494
1495    private void readObjectForClass(Object object, ObjectStreamClass classDesc)
1496            throws IOException, ClassNotFoundException, NotActiveException {
1497        // Have to do this before calling defaultReadObject or anything that
1498        // calls defaultReadObject
1499        currentObject = object;
1500        currentClass = classDesc;
1501
1502        boolean hadWriteMethod = (classDesc.getFlags() & SC_WRITE_METHOD) > 0;
1503        Class<?> targetClass = classDesc.forClass();
1504
1505        final Method readMethod;
1506        if (targetClass == null || !mustResolve) {
1507            readMethod = null;
1508        } else {
1509            readMethod = classDesc.getMethodReadObject();
1510        }
1511        try {
1512            if (readMethod != null) {
1513                // We have to be able to fetch its value, even if it is private
1514                AccessController.doPrivileged(new PriviAction<Object>(
1515                        readMethod));
1516                try {
1517                    readMethod.invoke(object, this);
1518                } catch (InvocationTargetException e) {
1519                    Throwable ex = e.getTargetException();
1520                    if (ex instanceof ClassNotFoundException) {
1521                        throw (ClassNotFoundException) ex;
1522                    } else if (ex instanceof RuntimeException) {
1523                        throw (RuntimeException) ex;
1524                    } else if (ex instanceof Error) {
1525                        throw (Error) ex;
1526                    }
1527                    throw (IOException) ex;
1528                } catch (IllegalAccessException e) {
1529                    throw new RuntimeException(e.toString());
1530                }
1531            } else {
1532                defaultReadObject();
1533            }
1534            if (hadWriteMethod) {
1535                discardData();
1536            }
1537        } finally {
1538            // Cleanup, needs to run always so that we can later detect invalid
1539            // calls to defaultReadObject
1540            currentObject = null; // We did not set this, so we do not need to
1541            // clean it
1542            currentClass = null;
1543        }
1544    }
1545
1546    /**
1547     * Reads an integer (32 bit) from the source stream.
1548     *
1549     * @return the integer value read from the source stream.
1550     * @throws EOFException
1551     *             if the end of the input is reached before the read
1552     *             request can be satisfied.
1553     * @throws IOException
1554     *             if an error occurs while reading from the source stream.
1555     */
1556    public int readInt() throws IOException {
1557        return primitiveTypes.readInt();
1558    }
1559
1560    /**
1561     * Reads the next line from the source stream. Lines are terminated by
1562     * {@code '\r'}, {@code '\n'}, {@code "\r\n"} or an {@code EOF}.
1563     *
1564     * @return the string read from the source stream.
1565     * @throws IOException
1566     *             if an error occurs while reading from the source stream.
1567     * @deprecated Use {@link BufferedReader}
1568     */
1569    @Deprecated
1570    public String readLine() throws IOException {
1571        return primitiveTypes.readLine();
1572    }
1573
1574    /**
1575     * Reads a long (64 bit) from the source stream.
1576     *
1577     * @return the long value read from the source stream.
1578     * @throws EOFException
1579     *             if the end of the input is reached before the read
1580     *             request can be satisfied.
1581     * @throws IOException
1582     *             if an error occurs while reading from the source stream.
1583     */
1584    public long readLong() throws IOException {
1585        return primitiveTypes.readLong();
1586    }
1587
1588    /**
1589     * Read a new array from the receiver. It is assumed the array has not been
1590     * read yet (not a cyclic reference). Return the array read.
1591     *
1592     * @param unshared
1593     *            read the object unshared
1594     * @return the array read
1595     *
1596     * @throws IOException
1597     *             If an IO exception happened when reading the array.
1598     * @throws ClassNotFoundException
1599     *             If a class for one of the objects could not be found
1600     * @throws OptionalDataException
1601     *             If optional data could not be found when reading the array.
1602     */
1603    private Object readNewArray(boolean unshared) throws OptionalDataException,
1604            ClassNotFoundException, IOException {
1605        ObjectStreamClass classDesc = readClassDesc();
1606
1607        if (classDesc == null) {
1608            throw missingClassDescriptor();
1609        }
1610
1611        Integer newHandle = nextHandle();
1612
1613        // Array size
1614        int size = input.readInt();
1615        Class<?> arrayClass = classDesc.forClass();
1616        Class<?> componentType = arrayClass.getComponentType();
1617        Object result = Array.newInstance(componentType, size);
1618
1619        registerObjectRead(result, newHandle, unshared);
1620
1621        // Now we have code duplication just because Java is typed. We have to
1622        // read N elements and assign to array positions, but we must typecast
1623        // the array first, and also call different methods depending on the
1624        // elements.
1625        if (componentType.isPrimitive()) {
1626            if (componentType == Integer.TYPE) {
1627                int[] intArray = (int[]) result;
1628                for (int i = 0; i < size; i++) {
1629                    intArray[i] = input.readInt();
1630                }
1631            } else if (componentType == Byte.TYPE) {
1632                byte[] byteArray = (byte[]) result;
1633                input.readFully(byteArray, 0, size);
1634            } else if (componentType == Character.TYPE) {
1635                char[] charArray = (char[]) result;
1636                for (int i = 0; i < size; i++) {
1637                    charArray[i] = input.readChar();
1638                }
1639            } else if (componentType == Short.TYPE) {
1640                short[] shortArray = (short[]) result;
1641                for (int i = 0; i < size; i++) {
1642                    shortArray[i] = input.readShort();
1643                }
1644            } else if (componentType == Boolean.TYPE) {
1645                boolean[] booleanArray = (boolean[]) result;
1646                for (int i = 0; i < size; i++) {
1647                    booleanArray[i] = input.readBoolean();
1648                }
1649            } else if (componentType == Long.TYPE) {
1650                long[] longArray = (long[]) result;
1651                for (int i = 0; i < size; i++) {
1652                    longArray[i] = input.readLong();
1653                }
1654            } else if (componentType == Float.TYPE) {
1655                float[] floatArray = (float[]) result;
1656                for (int i = 0; i < size; i++) {
1657                    floatArray[i] = input.readFloat();
1658                }
1659            } else if (componentType == Double.TYPE) {
1660                double[] doubleArray = (double[]) result;
1661                for (int i = 0; i < size; i++) {
1662                    doubleArray[i] = input.readDouble();
1663                }
1664            } else {
1665                throw new ClassNotFoundException("Wrong base type in " + classDesc.getName());
1666            }
1667        } else {
1668            // Array of Objects
1669            Object[] objectArray = (Object[]) result;
1670            for (int i = 0; i < size; i++) {
1671                // TODO: This place is the opportunity for enhancement
1672                //      We can implement writing elements through fast-path,
1673                //      without setting up the context (see readObject()) for
1674                //      each element with public API
1675                objectArray[i] = readObject();
1676            }
1677        }
1678        if (enableResolve) {
1679            result = resolveObject(result);
1680            registerObjectRead(result, newHandle, false);
1681        }
1682        return result;
1683    }
1684
1685    /**
1686     * Reads a new class from the receiver. It is assumed the class has not been
1687     * read yet (not a cyclic reference). Return the class read.
1688     *
1689     * @param unshared
1690     *            read the object unshared
1691     * @return The {@code java.lang.Class} read from the stream.
1692     *
1693     * @throws IOException
1694     *             If an IO exception happened when reading the class.
1695     * @throws ClassNotFoundException
1696     *             If a class for one of the objects could not be found
1697     */
1698    private Class<?> readNewClass(boolean unshared) throws ClassNotFoundException, IOException {
1699        ObjectStreamClass classDesc = readClassDesc();
1700        if (classDesc == null) {
1701            throw missingClassDescriptor();
1702        }
1703        Class<?> localClass = classDesc.forClass();
1704        if (localClass != null) {
1705            registerObjectRead(localClass, nextHandle(), unshared);
1706        }
1707        return localClass;
1708    }
1709
1710    /*
1711     * read class type for Enum, note there's difference between enum and normal
1712     * classes
1713     */
1714    private ObjectStreamClass readEnumDesc() throws IOException,
1715            ClassNotFoundException {
1716        byte tc = nextTC();
1717        switch (tc) {
1718            case TC_CLASSDESC:
1719                return readEnumDescInternal();
1720            case TC_REFERENCE:
1721                return (ObjectStreamClass) readCyclicReference();
1722            case TC_NULL:
1723                return null;
1724            default:
1725                throw corruptStream(tc);
1726        }
1727    }
1728
1729    private ObjectStreamClass readEnumDescInternal() throws IOException,
1730            ClassNotFoundException {
1731        ObjectStreamClass classDesc;
1732        primitiveData = input;
1733        Integer oldHandle = descriptorHandle;
1734        descriptorHandle = nextHandle();
1735        classDesc = readClassDescriptor();
1736        registerObjectRead(classDesc, descriptorHandle, false);
1737        descriptorHandle = oldHandle;
1738        primitiveData = emptyStream;
1739        classDesc.setClass(resolveClass(classDesc));
1740        // Consume unread class annotation data and TC_ENDBLOCKDATA
1741        discardData();
1742        ObjectStreamClass superClass = readClassDesc();
1743        checkedSetSuperClassDesc(classDesc, superClass);
1744        // Check SUIDs, note all SUID for Enum is 0L
1745        if (0L != classDesc.getSerialVersionUID() || 0L != superClass.getSerialVersionUID()) {
1746            throw new InvalidClassException(superClass.getName(),
1747                    "Incompatible class (SUID): " + superClass + " but expected " + superClass);
1748        }
1749        byte tc = nextTC();
1750        // discard TC_ENDBLOCKDATA after classDesc if any
1751        if (tc == TC_ENDBLOCKDATA) {
1752            // read next parent class. For enum, it may be null
1753            superClass.setSuperclass(readClassDesc());
1754        } else {
1755            // not TC_ENDBLOCKDATA, push back for next read
1756            pushbackTC();
1757        }
1758        return classDesc;
1759    }
1760
1761    @SuppressWarnings("unchecked")// For the Enum.valueOf call
1762    private Object readEnum(boolean unshared) throws OptionalDataException,
1763            ClassNotFoundException, IOException {
1764        // read classdesc for Enum first
1765        ObjectStreamClass classDesc = readEnumDesc();
1766        Integer newHandle = nextHandle();
1767        // read name after class desc
1768        String name;
1769        byte tc = nextTC();
1770        switch (tc) {
1771            case TC_REFERENCE:
1772                if (unshared) {
1773                    readNewHandle();
1774                    throw new InvalidObjectException("Unshared read of back reference");
1775                }
1776                name = (String) readCyclicReference();
1777                break;
1778            case TC_STRING:
1779                name = (String) readNewString(unshared);
1780                break;
1781            default:
1782                throw corruptStream(tc);
1783        }
1784
1785        Enum<?> result = Enum.valueOf((Class) classDesc.forClass(), name);
1786        registerObjectRead(result, newHandle, unshared);
1787
1788        return result;
1789    }
1790
1791    /**
1792     * Reads a new class descriptor from the receiver. It is assumed the class
1793     * descriptor has not been read yet (not a cyclic reference). Return the
1794     * class descriptor read.
1795     *
1796     * @param unshared
1797     *            read the object unshared
1798     * @return The {@code ObjectStreamClass} read from the stream.
1799     *
1800     * @throws IOException
1801     *             If an IO exception happened when reading the class
1802     *             descriptor.
1803     * @throws ClassNotFoundException
1804     *             If a class for one of the objects could not be found
1805     */
1806    private ObjectStreamClass readNewClassDesc(boolean unshared)
1807            throws ClassNotFoundException, IOException {
1808        // So read...() methods can be used by
1809        // subclasses during readClassDescriptor()
1810        primitiveData = input;
1811        Integer oldHandle = descriptorHandle;
1812        descriptorHandle = nextHandle();
1813        ObjectStreamClass newClassDesc = readClassDescriptor();
1814        registerObjectRead(newClassDesc, descriptorHandle, unshared);
1815        descriptorHandle = oldHandle;
1816        primitiveData = emptyStream;
1817
1818        // We need to map classDesc to class.
1819        try {
1820            newClassDesc.setClass(resolveClass(newClassDesc));
1821            // Check SUIDs & base name of the class
1822            verifyAndInit(newClassDesc);
1823        } catch (ClassNotFoundException e) {
1824            if (mustResolve) {
1825                throw e;
1826                // Just continue, the class may not be required
1827            }
1828        }
1829
1830        // Resolve the field signatures using the class loader of the
1831        // resolved class
1832        ObjectStreamField[] fields = newClassDesc.getLoadFields();
1833        fields = (null == fields ? new ObjectStreamField[] {} : fields);
1834        ClassLoader loader = newClassDesc.forClass() == null ? callerClassLoader
1835                : newClassDesc.forClass().getClassLoader();
1836        for (ObjectStreamField element : fields) {
1837            element.resolve(loader);
1838        }
1839
1840        // Consume unread class annotation data and TC_ENDBLOCKDATA
1841        discardData();
1842        checkedSetSuperClassDesc(newClassDesc, readClassDesc());
1843        return newClassDesc;
1844    }
1845
1846    /**
1847     * Reads a new proxy class descriptor from the receiver. It is assumed the
1848     * proxy class descriptor has not been read yet (not a cyclic reference).
1849     * Return the proxy class descriptor read.
1850     *
1851     * @return The {@code Class} read from the stream.
1852     *
1853     * @throws IOException
1854     *             If an IO exception happened when reading the class
1855     *             descriptor.
1856     * @throws ClassNotFoundException
1857     *             If a class for one of the objects could not be found
1858     */
1859    private Class<?> readNewProxyClassDesc() throws ClassNotFoundException,
1860            IOException {
1861        int count = input.readInt();
1862        String[] interfaceNames = new String[count];
1863        for (int i = 0; i < count; i++) {
1864            interfaceNames[i] = input.readUTF();
1865        }
1866        Class<?> proxy = resolveProxyClass(interfaceNames);
1867        // Consume unread class annotation data and TC_ENDBLOCKDATA
1868        discardData();
1869        return proxy;
1870    }
1871
1872    /**
1873     * Reads a class descriptor from the source stream.
1874     *
1875     * @return the class descriptor read from the source stream.
1876     * @throws ClassNotFoundException
1877     *             if a class for one of the objects cannot be found.
1878     * @throws IOException
1879     *             if an error occurs while reading from the source stream.
1880     */
1881    protected ObjectStreamClass readClassDescriptor() throws IOException, ClassNotFoundException {
1882        ObjectStreamClass newClassDesc = new ObjectStreamClass();
1883        String name = input.readUTF();
1884        if (name.length() == 0) {
1885            throw new IOException("The stream is corrupted");
1886        }
1887        newClassDesc.setName(name);
1888        newClassDesc.setSerialVersionUID(input.readLong());
1889        newClassDesc.setFlags(input.readByte());
1890
1891        /*
1892         * We must register the class descriptor before reading field
1893         * descriptors. If called outside of readObject, the descriptorHandle
1894         * might be null.
1895         */
1896        descriptorHandle = (null == descriptorHandle ? nextHandle() : descriptorHandle);
1897        registerObjectRead(newClassDesc, descriptorHandle, false);
1898
1899        readFieldDescriptors(newClassDesc);
1900        return newClassDesc;
1901    }
1902
1903    /**
1904     * Creates the proxy class that implements the interfaces specified in
1905     * {@code interfaceNames}.
1906     *
1907     * @param interfaceNames
1908     *            the interfaces used to create the proxy class.
1909     * @return the proxy class.
1910     * @throws ClassNotFoundException
1911     *             if the proxy class or any of the specified interfaces cannot
1912     *             be created.
1913     * @throws IOException
1914     *             if an error occurs while reading from the source stream.
1915     * @see ObjectOutputStream#annotateProxyClass(Class)
1916     */
1917    protected Class<?> resolveProxyClass(String[] interfaceNames)
1918            throws IOException, ClassNotFoundException {
1919        // TODO: This method is opportunity for performance enhancement
1920        //       We can cache the classloader and recently used interfaces.
1921        // BEGIN android-changed
1922        // ClassLoader loader = VM.getNonBootstrapClassLoader();
1923        ClassLoader loader = ClassLoader.getSystemClassLoader();
1924        // END android-changed
1925        Class<?>[] interfaces = new Class<?>[interfaceNames.length];
1926        for (int i = 0; i < interfaceNames.length; i++) {
1927            interfaces[i] = Class.forName(interfaceNames[i], false, loader);
1928        }
1929        try {
1930            return Proxy.getProxyClass(loader, interfaces);
1931        } catch (IllegalArgumentException e) {
1932            throw new ClassNotFoundException(e.toString(), e);
1933        }
1934    }
1935
1936    /**
1937     * Write a new handle describing a cyclic reference from the stream.
1938     *
1939     * @return the handle read
1940     *
1941     * @throws IOException
1942     *             If an IO exception happened when reading the handle
1943     */
1944    private int readNewHandle() throws IOException {
1945        return input.readInt();
1946    }
1947
1948    private Class<?> resolveConstructorClass(Class<?> objectClass, boolean wasSerializable, boolean wasExternalizable)
1949        throws OptionalDataException, ClassNotFoundException, IOException {
1950
1951            // The class of the instance may not be the same as the class of the
1952            // constructor to run
1953            // This is the constructor to run if Externalizable
1954            Class<?> constructorClass = objectClass;
1955
1956            // WARNING - What if the object is serializable and externalizable ?
1957            // Is that possible ?
1958            if (wasSerializable) {
1959                // Now we must run the constructor of the class just above the
1960                // one that implements Serializable so that slots that were not
1961                // dumped can be initialized properly
1962                while (constructorClass != null
1963                        && ObjectStreamClass.isSerializable(constructorClass)) {
1964                    constructorClass = constructorClass.getSuperclass();
1965                }
1966            }
1967
1968            // Fetch the empty constructor, or null if none.
1969            Constructor<?> constructor = null;
1970            if (constructorClass != null) {
1971                try {
1972                    constructor = constructorClass
1973                            .getDeclaredConstructor(ObjectStreamClass.EMPTY_CONSTRUCTOR_PARAM_TYPES);
1974                } catch (NoSuchMethodException nsmEx) {
1975                    // Ignored
1976                }
1977            }
1978
1979            // Has to have an empty constructor
1980            if (constructor == null) {
1981                String className = constructorClass != null ? constructorClass.getName() : null;
1982                throw new InvalidClassException(className, "IllegalAccessException");
1983            }
1984
1985            int constructorModifiers = constructor.getModifiers();
1986
1987            // Now we must check if the empty constructor is visible to the
1988            // instantiation class
1989            if (Modifier.isPrivate(constructorModifiers)
1990                    || (wasExternalizable && !Modifier.isPublic(constructorModifiers))) {
1991                throw new InvalidClassException(constructorClass.getName(),
1992                        "IllegalAccessException");
1993            }
1994
1995            // We know we are testing from a subclass, so the only other case
1996            // where the visibility is not allowed is when the constructor has
1997            // default visibility and the instantiation class is in a different
1998            // package than the constructor class
1999            if (!Modifier.isPublic(constructorModifiers)
2000                    && !Modifier.isProtected(constructorModifiers)) {
2001                // Not public, not private and not protected...means default
2002                // visibility. Check if same package
2003                if (!inSamePackage(constructorClass, objectClass)) {
2004                    throw new InvalidClassException(constructorClass.getName(),
2005                            "IllegalAccessException");
2006                }
2007            }
2008
2009            return constructorClass;
2010    }
2011
2012    /**
2013     * Read a new object from the stream. It is assumed the object has not been
2014     * loaded yet (not a cyclic reference). Return the object read.
2015     *
2016     * If the object implements <code>Externalizable</code> its
2017     * <code>readExternal</code> is called. Otherwise, all fields described by
2018     * the class hierarchy are loaded. Each class can define how its declared
2019     * instance fields are loaded by defining a private method
2020     * <code>readObject</code>
2021     *
2022     * @param unshared
2023     *            read the object unshared
2024     * @return the object read
2025     *
2026     * @throws IOException
2027     *             If an IO exception happened when reading the object.
2028     * @throws OptionalDataException
2029     *             If optional data could not be found when reading the object
2030     *             graph
2031     * @throws ClassNotFoundException
2032     *             If a class for one of the objects could not be found
2033     */
2034    private Object readNewObject(boolean unshared)
2035            throws OptionalDataException, ClassNotFoundException, IOException {
2036        ObjectStreamClass classDesc = readClassDesc();
2037
2038        if (classDesc == null) {
2039            throw missingClassDescriptor();
2040        }
2041
2042        Integer newHandle = nextHandle();
2043
2044        // Note that these values come from the Stream, and in fact it could be
2045        // that the classes have been changed so that the info below now
2046        // conflicts with the newer class
2047        boolean wasExternalizable = (classDesc.getFlags() & SC_EXTERNALIZABLE) > 0;
2048        boolean wasSerializable = (classDesc.getFlags() & SC_SERIALIZABLE) > 0;
2049
2050
2051        // Maybe we should cache the values above in classDesc ? It may be the
2052        // case that when reading classDesc we may need to read more stuff
2053        // depending on the values above
2054        Class<?> objectClass = classDesc.forClass();
2055
2056        Object result, registeredResult = null;
2057        if (objectClass != null) {
2058
2059            // BEGIN android-changed
2060            // long constructor = classDesc.getConstructor();
2061            // if (constructor == ObjectStreamClass.CONSTRUCTOR_IS_NOT_RESOLVED) {
2062            //     constructor = accessor.getMethodID(resolveConstructorClass(objectClass, wasSerializable, wasExternalizable), null, new Class[0]);
2063            //     classDesc.setConstructor(constructor);
2064            // }
2065            Class constructorClass = resolveConstructorClass(objectClass, wasSerializable, wasExternalizable);
2066            // END android-changed
2067
2068            // Now we know which class to instantiate and which constructor to
2069            // run. We are allowed to run the constructor.
2070            // BEGIN android-changed
2071            // result = accessor.newInstance(objectClass, constructor, null);
2072            result = newInstance(objectClass, constructorClass);
2073            // END android-changed
2074            registerObjectRead(result, newHandle, unshared);
2075
2076            registeredResult = result;
2077        } else {
2078            result = null;
2079        }
2080
2081        try {
2082            // This is how we know what to do in defaultReadObject. And it is
2083            // also used by defaultReadObject to check if it was called from an
2084            // invalid place. It also allows readExternal to call
2085            // defaultReadObject and have it work.
2086            currentObject = result;
2087            currentClass = classDesc;
2088
2089            // If Externalizable, just let the object read itself
2090            if (wasExternalizable) {
2091                boolean blockData = (classDesc.getFlags() & SC_BLOCK_DATA) > 0;
2092                if (!blockData) {
2093                    primitiveData = input;
2094                }
2095                if (mustResolve) {
2096                    Externalizable extern = (Externalizable) result;
2097                    extern.readExternal(this);
2098                }
2099                if (blockData) {
2100                    // Similar to readHierarchy. Anything not read by
2101                    // readExternal has to be consumed here
2102                    discardData();
2103                } else {
2104                    primitiveData = emptyStream;
2105                }
2106            } else {
2107                // If we got here, it is Serializable but not Externalizable.
2108                // Walk the hierarchy reading each class' slots
2109                readHierarchy(result, classDesc);
2110            }
2111        } finally {
2112            // Cleanup, needs to run always so that we can later detect invalid
2113            // calls to defaultReadObject
2114            currentObject = null;
2115            currentClass = null;
2116        }
2117
2118        if (objectClass != null) {
2119
2120            if (classDesc.hasMethodReadResolve()){
2121                Method methodReadResolve = classDesc.getMethodReadResolve();
2122                try {
2123                    result = methodReadResolve.invoke(result, (Object[]) null);
2124                } catch (IllegalAccessException ignored) {
2125                } catch (InvocationTargetException ite) {
2126                    Throwable target = ite.getTargetException();
2127                    if (target instanceof ObjectStreamException) {
2128                        throw (ObjectStreamException) target;
2129                    } else if (target instanceof Error) {
2130                        throw (Error) target;
2131                    } else {
2132                        throw (RuntimeException) target;
2133                    }
2134                }
2135
2136            }
2137        }
2138        // We get here either if class-based replacement was not needed or if it
2139        // was needed but produced the same object or if it could not be
2140        // computed.
2141
2142        // The object to return is the one we instantiated or a replacement for
2143        // it
2144        if (result != null && enableResolve) {
2145            result = resolveObject(result);
2146        }
2147        if (registeredResult != result) {
2148            registerObjectRead(result, newHandle, unshared);
2149        }
2150        return result;
2151    }
2152
2153    private InvalidClassException missingClassDescriptor() throws InvalidClassException {
2154        throw new InvalidClassException("Read null attempting to read class descriptor for object");
2155    }
2156
2157    /**
2158     * Read a string encoded in {@link DataInput modified UTF-8} from the
2159     * receiver. Return the string read.
2160     *
2161     * @param unshared
2162     *            read the object unshared
2163     * @return the string just read.
2164     * @throws IOException
2165     *             If an IO exception happened when reading the String.
2166     */
2167    private Object readNewString(boolean unshared) throws IOException {
2168        Object result = input.readUTF();
2169        if (enableResolve) {
2170            result = resolveObject(result);
2171        }
2172        registerObjectRead(result, nextHandle(), unshared);
2173
2174        return result;
2175    }
2176
2177    /**
2178     * Read a new String in UTF format from the receiver. Return the string
2179     * read.
2180     *
2181     * @param unshared
2182     *            read the object unshared
2183     * @return the string just read.
2184     *
2185     * @throws IOException
2186     *             If an IO exception happened when reading the String.
2187     */
2188    private Object readNewLongString(boolean unshared) throws IOException {
2189        long length = input.readLong();
2190        Object result = input.decodeUTF((int) length);
2191        if (enableResolve) {
2192            result = resolveObject(result);
2193        }
2194        registerObjectRead(result, nextHandle(), unshared);
2195
2196        return result;
2197    }
2198
2199    /**
2200     * Reads the next object from the source stream.
2201     *
2202     * @return the object read from the source stream.
2203     * @throws ClassNotFoundException
2204     *             if the class of one of the objects in the object graph cannot
2205     *             be found.
2206     * @throws IOException
2207     *             if an error occurs while reading from the source stream.
2208     * @throws OptionalDataException
2209     *             if primitive data types were found instead of an object.
2210     * @see ObjectOutputStream#writeObject(Object)
2211     */
2212    public final Object readObject() throws OptionalDataException,
2213            ClassNotFoundException, IOException {
2214        return readObject(false);
2215    }
2216
2217    /**
2218     * Reads the next unshared object from the source stream.
2219     *
2220     * @return the new object read.
2221     * @throws ClassNotFoundException
2222     *             if the class of one of the objects in the object graph cannot
2223     *             be found.
2224     * @throws IOException
2225     *             if an error occurs while reading from the source stream.
2226     * @see ObjectOutputStream#writeUnshared
2227     */
2228    public Object readUnshared() throws IOException, ClassNotFoundException {
2229        return readObject(true);
2230    }
2231
2232    private Object readObject(boolean unshared) throws OptionalDataException,
2233            ClassNotFoundException, IOException {
2234        boolean restoreInput = (primitiveData == input);
2235        if (restoreInput) {
2236            primitiveData = emptyStream;
2237        }
2238
2239        // This is the spec'ed behavior in JDK 1.2. Very bizarre way to allow
2240        // behavior overriding.
2241        if (subclassOverridingImplementation && !unshared) {
2242            return readObjectOverride();
2243        }
2244
2245        // If we still had primitive types to read, should we discard them
2246        // (reset the primitiveTypes stream) or leave as is, so that attempts to
2247        // read primitive types won't read 'past data' ???
2248        Object result;
2249        try {
2250            // We need this so we can tell when we are returning to the
2251            // original/outside caller
2252            if (++nestedLevels == 1) {
2253                // Remember the caller's class loader
2254                // BEGIN android-changed
2255                callerClassLoader = getClosestUserClassLoader();
2256                // END android-changed
2257            }
2258
2259            result = readNonPrimitiveContent(unshared);
2260            if (restoreInput) {
2261                primitiveData = input;
2262            }
2263        } finally {
2264            // We need this so we can tell when we are returning to the
2265            // original/outside caller
2266            if (--nestedLevels == 0) {
2267                // We are going to return to the original caller, perform
2268                // cleanups.
2269                // No more need to remember the caller's class loader
2270                callerClassLoader = null;
2271            }
2272        }
2273
2274        // Done reading this object. Is it time to return to the original
2275        // caller? If so we need to perform validations first.
2276        if (nestedLevels == 0 && validations != null) {
2277            // We are going to return to the original caller. If validation is
2278            // enabled we need to run them now and then cleanup the validation
2279            // collection
2280            try {
2281                for (InputValidationDesc element : validations) {
2282                    element.validator.validateObject();
2283                }
2284            } finally {
2285                // Validations have to be renewed, since they are only called
2286                // from readObject
2287                validations = null;
2288            }
2289        }
2290        return result;
2291    }
2292
2293    // BEGIN android-added
2294    private static final ClassLoader bootstrapLoader
2295            = Object.class.getClassLoader();
2296    private static final ClassLoader systemLoader
2297            = ClassLoader.getSystemClassLoader();
2298
2299    /**
2300     * Searches up the call stack to find the closest user-defined class loader.
2301     *
2302     * @return a user-defined class loader or null if one isn't found
2303     */
2304    private static ClassLoader getClosestUserClassLoader() {
2305        Class<?>[] stackClasses = VMStack.getClasses(-1, false);
2306        for (Class<?> stackClass : stackClasses) {
2307            ClassLoader loader = stackClass.getClassLoader();
2308            if (loader != null && loader != bootstrapLoader
2309                    && loader != systemLoader) {
2310                return loader;
2311            }
2312        }
2313        return null;
2314    }
2315    // END android-added
2316
2317    /**
2318     * Method to be overridden by subclasses to read the next object from the
2319     * source stream.
2320     *
2321     * @return the object read from the source stream.
2322     * @throws ClassNotFoundException
2323     *             if the class of one of the objects in the object graph cannot
2324     *             be found.
2325     * @throws IOException
2326     *             if an error occurs while reading from the source stream.
2327     * @throws OptionalDataException
2328     *             if primitive data types were found instead of an object.
2329     * @see ObjectOutputStream#writeObjectOverride
2330     */
2331    protected Object readObjectOverride() throws OptionalDataException,
2332            ClassNotFoundException, IOException {
2333        if (input == null) {
2334            return null;
2335        }
2336        // Subclasses must override.
2337        throw new IOException();
2338    }
2339
2340    /**
2341     * Reads a short (16 bit) from the source stream.
2342     *
2343     * @return the short value read from the source stream.
2344     * @throws IOException
2345     *             if an error occurs while reading from the source stream.
2346     */
2347    public short readShort() throws IOException {
2348        return primitiveTypes.readShort();
2349    }
2350
2351    /**
2352     * Reads and validates the ObjectInputStream header from the source stream.
2353     *
2354     * @throws IOException
2355     *             if an error occurs while reading from the source stream.
2356     * @throws StreamCorruptedException
2357     *             if the source stream does not contain readable serialized
2358     *             objects.
2359     */
2360    protected void readStreamHeader() throws IOException,
2361            StreamCorruptedException {
2362        if (input.readShort() == STREAM_MAGIC
2363                && input.readShort() == STREAM_VERSION) {
2364            return;
2365        }
2366        throw new StreamCorruptedException();
2367    }
2368
2369    /**
2370     * Reads an unsigned byte (8 bit) from the source stream.
2371     *
2372     * @return the unsigned byte value read from the source stream packaged in
2373     *         an integer.
2374     * @throws EOFException
2375     *             if the end of the input is reached before the read
2376     *             request can be satisfied.
2377     * @throws IOException
2378     *             if an error occurs while reading from the source stream.
2379     */
2380    public int readUnsignedByte() throws IOException {
2381        return primitiveTypes.readUnsignedByte();
2382    }
2383
2384    /**
2385     * Reads an unsigned short (16 bit) from the source stream.
2386     *
2387     * @return the unsigned short value read from the source stream packaged in
2388     *         an integer.
2389     * @throws EOFException
2390     *             if the end of the input is reached before the read
2391     *             request can be satisfied.
2392     * @throws IOException
2393     *             if an error occurs while reading from the source stream.
2394     */
2395    public int readUnsignedShort() throws IOException {
2396        return primitiveTypes.readUnsignedShort();
2397    }
2398
2399    /**
2400     * Reads a string encoded in {@link DataInput modified UTF-8} from the
2401     * source stream.
2402     *
2403     * @return the string encoded in {@link DataInput modified UTF-8} read from
2404     *         the source stream.
2405     * @throws EOFException
2406     *             if the end of the input is reached before the read
2407     *             request can be satisfied.
2408     * @throws IOException
2409     *             if an error occurs while reading from the source stream.
2410     */
2411    public String readUTF() throws IOException {
2412        return primitiveTypes.readUTF();
2413    }
2414
2415    /**
2416     * Return the object previously read tagged with handle {@code handle}.
2417     *
2418     * @param handle
2419     *            The handle that this object was assigned when it was read.
2420     * @return the object previously read.
2421     *
2422     * @throws InvalidObjectException
2423     *             If there is no previously read object with this handle
2424     */
2425    private Object registeredObjectRead(Integer handle) throws InvalidObjectException {
2426        Object res = objectsRead.get(handle);
2427        if (res == UNSHARED_OBJ) {
2428            throw new InvalidObjectException("Cannot read back reference to unshared object");
2429        }
2430        return res;
2431    }
2432
2433    /**
2434     * Assume object {@code obj} has been read, and assign a handle to
2435     * it, {@code handle}.
2436     *
2437     * @param obj
2438     *            Non-null object being loaded.
2439     * @param handle
2440     *            An Integer, the handle to this object
2441     * @param unshared
2442     *            Boolean, indicates that caller is reading in unshared mode
2443     *
2444     * @see #nextHandle
2445     */
2446    private void registerObjectRead(Object obj, Integer handle, boolean unshared) {
2447        objectsRead.put(handle, unshared ? UNSHARED_OBJ : obj);
2448    }
2449
2450    /**
2451     * Registers a callback for post-deserialization validation of objects. It
2452     * allows to perform additional consistency checks before the {@code
2453     * readObject()} method of this class returns its result to the caller. This
2454     * method can only be called from within the {@code readObject()} method of
2455     * a class that implements "special" deserialization rules. It can be called
2456     * multiple times. Validation callbacks are then done in order of decreasing
2457     * priority, defined by {@code priority}.
2458     *
2459     * @param object
2460     *            an object that can validate itself by receiving a callback.
2461     * @param priority
2462     *            the validator's priority.
2463     * @throws InvalidObjectException
2464     *             if {@code object} is {@code null}.
2465     * @throws NotActiveException
2466     *             if this stream is currently not reading objects. In that
2467     *             case, calling this method is not allowed.
2468     * @see ObjectInputValidation#validateObject()
2469     */
2470    public synchronized void registerValidation(ObjectInputValidation object,
2471            int priority) throws NotActiveException, InvalidObjectException {
2472        // Validation can only be registered when inside readObject calls
2473        Object instanceBeingRead = this.currentObject;
2474
2475        // We can't be called from just anywhere. There are rules.
2476        if (instanceBeingRead == null && nestedLevels == 0) {
2477            throw new NotActiveException();
2478        }
2479        if (object == null) {
2480            throw new InvalidObjectException("Callback object cannot be null");
2481        }
2482        // From now on it is just insertion in a SortedCollection. Since
2483        // the Java class libraries don't provide that, we have to
2484        // implement it from scratch here.
2485        InputValidationDesc desc = new InputValidationDesc();
2486        desc.validator = object;
2487        desc.priority = priority;
2488        // No need for this, validateObject does not take a parameter
2489        // desc.toValidate = instanceBeingRead;
2490        if (validations == null) {
2491            validations = new InputValidationDesc[1];
2492            validations[0] = desc;
2493        } else {
2494            int i = 0;
2495            for (; i < validations.length; i++) {
2496                InputValidationDesc validation = validations[i];
2497                // Sorted, higher priority first.
2498                if (priority >= validation.priority) {
2499                    break; // Found the index where to insert
2500                }
2501            }
2502            InputValidationDesc[] oldValidations = validations;
2503            int currentSize = oldValidations.length;
2504            validations = new InputValidationDesc[currentSize + 1];
2505            System.arraycopy(oldValidations, 0, validations, 0, i);
2506            System.arraycopy(oldValidations, i, validations, i + 1, currentSize
2507                    - i);
2508            validations[i] = desc;
2509        }
2510    }
2511
2512    /**
2513     * Reset the collection of objects already loaded by the receiver.
2514     */
2515    private void resetSeenObjects() {
2516        objectsRead = new HashMap<Integer, Object>();
2517        nextHandle = baseWireHandle;
2518        primitiveData = emptyStream;
2519    }
2520
2521    /**
2522     * Reset the receiver. The collection of objects already read by the
2523     * receiver is reset, and internal structures are also reset so that the
2524     * receiver knows it is in a fresh clean state.
2525     */
2526    private void resetState() {
2527        resetSeenObjects();
2528        hasPushbackTC = false;
2529        pushbackTC = 0;
2530        // nestedLevels = 0;
2531    }
2532
2533    /**
2534     * Loads the Java class corresponding to the class descriptor {@code
2535     * osClass} that has just been read from the source stream.
2536     *
2537     * @param osClass
2538     *            an ObjectStreamClass read from the source stream.
2539     * @return a Class corresponding to the descriptor {@code osClass}.
2540     * @throws ClassNotFoundException
2541     *             if the class for an object cannot be found.
2542     * @throws IOException
2543     *             if an I/O error occurs while creating the class.
2544     * @see ObjectOutputStream#annotateClass(Class)
2545     */
2546    protected Class<?> resolveClass(ObjectStreamClass osClass)
2547            throws IOException, ClassNotFoundException {
2548        // fastpath: obtain cached value
2549        Class<?> cls = osClass.forClass();
2550        if (null == cls) {
2551            // slowpath: resolve the class
2552            String className = osClass.getName();
2553
2554            // if it is primitive class, for example, long.class
2555            cls = PRIMITIVE_CLASSES.get(className);
2556
2557            if (null == cls) {
2558                // not primitive class
2559                // Use the first non-null ClassLoader on the stack. If null, use
2560                // the system class loader
2561                cls = Class.forName(className, true, callerClassLoader);
2562            }
2563        }
2564        return cls;
2565    }
2566
2567    /**
2568     * Allows trusted subclasses to substitute the specified original {@code
2569     * object} with a new object. Object substitution has to be activated first
2570     * with calling {@code enableResolveObject(true)}. This implementation just
2571     * returns {@code object}.
2572     *
2573     * @param object
2574     *            the original object for which a replacement may be defined.
2575     * @return the replacement object for {@code object}.
2576     * @throws IOException
2577     *             if any I/O error occurs while creating the replacement
2578     *             object.
2579     * @see #enableResolveObject
2580     * @see ObjectOutputStream#enableReplaceObject
2581     * @see ObjectOutputStream#replaceObject
2582     */
2583    protected Object resolveObject(Object object) throws IOException {
2584        // By default no object replacement. Subclasses can override
2585        return object;
2586    }
2587
2588    // BEGIN android-added
2589
2590    /*
2591     * These methods set the value of a field named fieldName of instance. The
2592     * field is declared by declaringClass. The field is the same type as the
2593     * value parameter.
2594     *
2595     * these methods could be implemented non-natively on top of
2596     * java.lang.reflect at the expense of extra object creation
2597     * (java.lang.reflect.Field). Otherwise Serialization could not fetch
2598     * private fields, except by the use of a native method like this one.
2599     *
2600     * @throws NoSuchFieldError If the field does not exist.
2601     */
2602    private static native void setFieldByte(Object instance,
2603            Class<?> declaringClass, String fieldName, byte value)
2604            throws NoSuchFieldError;
2605
2606
2607    private static native void setFieldChar(Object instance,
2608            Class<?> declaringClass, String fieldName, char value)
2609            throws NoSuchFieldError;
2610
2611
2612    private static native void setFieldDouble(Object instance,
2613            Class<?> declaringClass, String fieldName, double value)
2614            throws NoSuchFieldError;
2615
2616    private static native void setFieldFloat(Object instance,
2617            Class<?> declaringClass, String fieldName, float value)
2618            throws NoSuchFieldError;
2619
2620    private static native void setFieldInt(Object instance,
2621            Class<?> declaringClass, String fieldName, int value)
2622            throws NoSuchFieldError;
2623
2624    private static native void setFieldLong(Object instance,
2625            Class<?> declaringClass, String fieldName, long value)
2626            throws NoSuchFieldError;
2627
2628    private static native void setFieldObject(Object instance,
2629            Class<?> declaringClass, String fieldName, String fieldTypeName,
2630            Object value) throws NoSuchFieldError;
2631
2632    private static native void setFieldShort(Object instance,
2633            Class<?> declaringClass, String fieldName, short value)
2634            throws NoSuchFieldError;
2635
2636    private static native void setFieldBool(Object instance,
2637            Class<?> declaringClass, String fieldName, boolean value)
2638            throws NoSuchFieldError;
2639
2640    // END android-added
2641
2642    /**
2643     * Skips {@code length} bytes on the source stream. This method should not
2644     * be used to skip bytes at any arbitrary position, just when reading
2645     * primitive data types (int, char etc).
2646     *
2647     * @param length
2648     *            the number of bytes to skip.
2649     * @return the number of bytes actually skipped.
2650     * @throws IOException
2651     *             if an error occurs while skipping bytes on the source stream.
2652     * @throws NullPointerException
2653     *             if the source stream is {@code null}.
2654     */
2655    public int skipBytes(int length) throws IOException {
2656        // To be used with available. Ok to call if reading primitive buffer
2657        if (input == null) {
2658            throw new NullPointerException();
2659        }
2660
2661        int offset = 0;
2662        while (offset < length) {
2663            checkReadPrimitiveTypes();
2664            long skipped = primitiveData.skip(length - offset);
2665            if (skipped == 0) {
2666                return offset;
2667            }
2668            offset += (int) skipped;
2669        }
2670        return length;
2671    }
2672
2673    /**
2674     * Verify if the SUID & the base name for descriptor
2675     * <code>loadedStreamClass</code>matches
2676     * the SUID & the base name of the corresponding loaded class and
2677     * init private fields.
2678     *
2679     * @param loadedStreamClass
2680     *            An ObjectStreamClass that was loaded from the stream.
2681     *
2682     * @throws InvalidClassException
2683     *             If the SUID of the stream class does not match the VM class
2684     */
2685    private void verifyAndInit(ObjectStreamClass loadedStreamClass)
2686            throws InvalidClassException {
2687
2688        Class<?> localClass = loadedStreamClass.forClass();
2689        ObjectStreamClass localStreamClass = ObjectStreamClass
2690                .lookupStreamClass(localClass);
2691
2692        if (loadedStreamClass.getSerialVersionUID() != localStreamClass
2693                .getSerialVersionUID()) {
2694            throw new InvalidClassException(loadedStreamClass.getName(),
2695                    "Incompatible class (SUID): " + loadedStreamClass +
2696                            " but expected " + localStreamClass);
2697        }
2698
2699        String loadedClassBaseName = getBaseName(loadedStreamClass.getName());
2700        String localClassBaseName = getBaseName(localStreamClass.getName());
2701
2702        if (!loadedClassBaseName.equals(localClassBaseName)) {
2703            throw new InvalidClassException(loadedStreamClass.getName(),
2704                    String.format("Incompatible class (base name): %s but expected %s",
2705                            loadedClassBaseName, localClassBaseName));
2706        }
2707
2708        loadedStreamClass.initPrivateFields(localStreamClass);
2709    }
2710
2711    private static String getBaseName(String fullName) {
2712        int k = fullName.lastIndexOf('.');
2713
2714        if (k == -1 || k == (fullName.length() - 1)) {
2715            return fullName;
2716        }
2717        return fullName.substring(k + 1);
2718    }
2719
2720    // Avoid recursive defining.
2721    private static void checkedSetSuperClassDesc(ObjectStreamClass desc,
2722            ObjectStreamClass superDesc) throws StreamCorruptedException {
2723        if (desc.equals(superDesc)) {
2724            throw new StreamCorruptedException();
2725        }
2726        desc.setSuperclass(superDesc);
2727    }
2728}
2729