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