• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 package org.chromium.mojo.bindings;
6 
7 import org.chromium.mojo.bindings.Interface.Proxy;
8 import org.chromium.mojo.system.DataPipe;
9 import org.chromium.mojo.system.Handle;
10 import org.chromium.mojo.system.InvalidHandle;
11 import org.chromium.mojo.system.MessagePipeHandle;
12 import org.chromium.mojo.system.SharedBufferHandle;
13 import org.chromium.mojo.system.UntypedHandle;
14 
15 import java.nio.ByteOrder;
16 import java.nio.charset.Charset;
17 
18 /**
19  * A Decoder is a helper class for deserializing a mojo struct. It enables deserialization of basic
20  * types from a {@link Message} object at a given offset into it's byte buffer.
21  */
22 public class Decoder {
23 
24     /**
25      * Helper class to validate the decoded message.
26      */
27     static final class Validator {
28 
29         /**
30          * Minimal value for the next handle to deserialize.
31          */
32         private int mMinNextClaimedHandle = 0;
33         /**
34          * Minimal value of the start of the next memory to claim.
35          */
36         private long mMinNextMemory = 0;
37 
38         /**
39          * The maximal memory accessible.
40          */
41         private final long mMaxMemory;
42 
43         /**
44          * The number of handles in the message.
45          */
46         private final long mNumberOfHandles;
47 
48         /**
49          * Constructor.
50          */
Validator(long maxMemory, int numberOfHandles)51         Validator(long maxMemory, int numberOfHandles) {
52             mMaxMemory = maxMemory;
53             mNumberOfHandles = numberOfHandles;
54         }
55 
claimHandle(int handle)56         public void claimHandle(int handle) {
57             if (handle < mMinNextClaimedHandle) {
58                 throw new DeserializationException(
59                         "Trying to access handle out of order.");
60             }
61             if (handle >= mNumberOfHandles) {
62                 throw new DeserializationException("Trying to access non present handle.");
63             }
64             mMinNextClaimedHandle = handle + 1;
65         }
66 
claimMemory(long start, long end)67         public void claimMemory(long start, long end) {
68             if (start % BindingsHelper.ALIGNMENT != 0) {
69                 throw new DeserializationException("Incorrect starting alignment: " + start + ".");
70             }
71             if (start < mMinNextMemory) {
72                 throw new DeserializationException("Trying to access memory out of order.");
73             }
74             if (end < start) {
75                 throw new DeserializationException("Incorrect memory range.");
76             }
77             if (end > mMaxMemory) {
78                 throw new DeserializationException("Trying to access out of range memory.");
79             }
80             mMinNextMemory = BindingsHelper.align(end);
81         }
82     }
83 
84     /**
85      * The message to deserialize from.
86      */
87     private final Message mMessage;
88 
89     /**
90      * The base offset in the byte buffer.
91      */
92     private final int mBaseOffset;
93 
94     /**
95      * Validator for the decoded message.
96      */
97     private final Validator mValidator;
98 
99     /**
100      * Constructor.
101      *
102      * @param message The message to decode.
103      */
Decoder(Message message)104     public Decoder(Message message) {
105         this(message, new Validator(message.getData().limit(), message.getHandles().size()), 0);
106     }
107 
Decoder(Message message, Validator validator, int baseOffset)108     private Decoder(Message message, Validator validator, int baseOffset) {
109         mMessage = message;
110         mMessage.getData().order(ByteOrder.LITTLE_ENDIAN);
111         mBaseOffset = baseOffset;
112         mValidator = validator;
113     }
114 
115     /**
116      * Deserializes a {@link DataHeader} at the current position.
117      */
readDataHeader()118     public DataHeader readDataHeader() {
119         // Claim the memory for the header.
120         mValidator.claimMemory(mBaseOffset, mBaseOffset + DataHeader.HEADER_SIZE);
121         DataHeader result = readDataHeaderAtOffset(0, false);
122         // Claim the rest of the memory.
123         mValidator.claimMemory(mBaseOffset + DataHeader.HEADER_SIZE, mBaseOffset + result.size);
124         return result;
125     }
126 
127     /**
128      * Deserializes a {@link DataHeader} for an union at the given offset.
129      */
readDataHeaderForUnion(int offset)130     public DataHeader readDataHeaderForUnion(int offset) {
131         DataHeader result = readDataHeaderAtOffset(offset, true);
132         if (result.size == 0) {
133             if (result.elementsOrVersion != 0) {
134                 throw new DeserializationException(
135                         "Unexpected version tag for a null union. Expecting 0, found: "
136                         + result.elementsOrVersion);
137             }
138         } else if (result.size != BindingsHelper.UNION_SIZE) {
139             throw new DeserializationException(
140                     "Unexpected size of an union. The size must be 0 for a null union, or 16 for "
141                     + "a non-null union.");
142         }
143         return result;
144     }
145 
146     /**
147      * @returns a decoder suitable to decode an union defined as the root object of a message.
148      */
decoderForSerializedUnion()149     public Decoder decoderForSerializedUnion() {
150         mValidator.claimMemory(0, BindingsHelper.UNION_SIZE);
151         return this;
152     }
153 
154     /**
155      * Deserializes a {@link DataHeader} at the given offset.
156      */
readDataHeaderAtOffset(int offset, boolean isUnion)157     private DataHeader readDataHeaderAtOffset(int offset, boolean isUnion) {
158         int size = readInt(offset + DataHeader.SIZE_OFFSET);
159         int elementsOrVersion = readInt(offset + DataHeader.ELEMENTS_OR_VERSION_OFFSET);
160         if (size < 0) {
161             throw new DeserializationException(
162                     "Negative size. Unsigned integers are not valid for java.");
163         }
164         if (elementsOrVersion < 0 && (!isUnion || elementsOrVersion != -1)) {
165             throw new DeserializationException(
166                     "Negative elements or version. Unsigned integers are not valid for java.");
167         }
168 
169         return new DataHeader(size, elementsOrVersion);
170     }
171 
readAndValidateDataHeader(DataHeader[] versionArray)172     public DataHeader readAndValidateDataHeader(DataHeader[] versionArray) {
173         DataHeader header = readDataHeader();
174         int maxVersionIndex = versionArray.length - 1;
175         if (header.elementsOrVersion <= versionArray[maxVersionIndex].elementsOrVersion) {
176             DataHeader referenceHeader = null;
177             for (int index = maxVersionIndex; index >= 0; index--) {
178                 DataHeader dataHeader = versionArray[index];
179                 if (header.elementsOrVersion >= dataHeader.elementsOrVersion) {
180                     referenceHeader = dataHeader;
181                     break;
182                 }
183             }
184             if (referenceHeader == null || referenceHeader.size != header.size) {
185                 throw new DeserializationException(
186                         "Header doesn't correspond to any known version.");
187             }
188         } else {
189             if (header.size < versionArray[maxVersionIndex].size) {
190                 throw new DeserializationException("Message newer than the last known version"
191                         + " cannot be shorter than required by the last known version.");
192             }
193         }
194         return header;
195     }
196 
197     /**
198      * Deserializes a {@link DataHeader} at the given offset and checks if it is correct for an
199      * array where elements are pointers.
200      */
readDataHeaderForPointerArray(int expectedLength)201     public DataHeader readDataHeaderForPointerArray(int expectedLength) {
202         return readDataHeaderForArray(BindingsHelper.POINTER_SIZE, expectedLength);
203     }
204 
205     /**
206      * Deserializes a {@link DataHeader} at the given offset and checks if it is correct for an
207      * array where elements are unions.
208      */
readDataHeaderForUnionArray(int expectedLength)209     public DataHeader readDataHeaderForUnionArray(int expectedLength) {
210         return readDataHeaderForArray(BindingsHelper.UNION_SIZE, expectedLength);
211     }
212 
213     /**
214      * Deserializes a {@link DataHeader} at the given offset and checks if it is correct for a map.
215      */
readDataHeaderForMap()216     public void readDataHeaderForMap() {
217         DataHeader si = readDataHeader();
218         if (si.size != BindingsHelper.MAP_STRUCT_HEADER.size) {
219             throw new DeserializationException(
220                     "Incorrect header for map. The size is incorrect.");
221         }
222         if (si.elementsOrVersion != BindingsHelper.MAP_STRUCT_HEADER.elementsOrVersion) {
223             throw new DeserializationException(
224                     "Incorrect header for map. The version is incorrect.");
225         }
226     }
227 
228     /**
229      * Deserializes a byte at the given offset.
230      */
readByte(int offset)231     public byte readByte(int offset) {
232         validateBufferSize(offset, 1);
233         return mMessage.getData().get(mBaseOffset + offset);
234     }
235 
236     /**
237      * Deserializes a boolean at the given offset, re-using any partially read byte.
238      */
readBoolean(int offset, int bit)239     public boolean readBoolean(int offset, int bit) {
240         validateBufferSize(offset, 1);
241         return (readByte(offset) & (1 << bit)) != 0;
242     }
243 
244     /**
245      * Deserializes a short at the given offset.
246      */
readShort(int offset)247     public short readShort(int offset) {
248         validateBufferSize(offset, 2);
249         return mMessage.getData().getShort(mBaseOffset + offset);
250     }
251 
252     /**
253      * Deserializes an int at the given offset.
254      */
readInt(int offset)255     public int readInt(int offset) {
256         validateBufferSize(offset, 4);
257         return mMessage.getData().getInt(mBaseOffset + offset);
258     }
259 
260     /**
261      * Deserializes a float at the given offset.
262      */
readFloat(int offset)263     public float readFloat(int offset) {
264         validateBufferSize(offset, 4);
265         return mMessage.getData().getFloat(mBaseOffset + offset);
266     }
267 
268     /**
269      * Deserializes a long at the given offset.
270      */
readLong(int offset)271     public long readLong(int offset) {
272         validateBufferSize(offset, 8);
273         return mMessage.getData().getLong(mBaseOffset + offset);
274     }
275 
276     /**
277      * Deserializes a double at the given offset.
278      */
readDouble(int offset)279     public double readDouble(int offset) {
280         validateBufferSize(offset, 8);
281         return mMessage.getData().getDouble(mBaseOffset + offset);
282     }
283 
284     /**
285      * Deserializes a pointer at the given offset. Returns a Decoder suitable to decode the content
286      * of the pointer.
287      */
readPointer(int offset, boolean nullable)288     public Decoder readPointer(int offset, boolean nullable) {
289         int basePosition = mBaseOffset + offset;
290         long pointerOffset = readLong(offset);
291         if (pointerOffset == 0) {
292             if (!nullable) {
293                 throw new DeserializationException(
294                         "Trying to decode null pointer for a non-nullable type.");
295             }
296             return null;
297         }
298         int newPosition = (int) (basePosition + pointerOffset);
299         // The method |getDecoderAtPosition| will validate that the pointer address is valid.
300         return getDecoderAtPosition(newPosition);
301 
302     }
303 
304     /**
305      * Deserializes an array of boolean at the given offset.
306      */
readBooleans(int offset, int arrayNullability, int expectedLength)307     public boolean[] readBooleans(int offset, int arrayNullability, int expectedLength) {
308         Decoder d = readPointer(offset, BindingsHelper.isArrayNullable(arrayNullability));
309         if (d == null) {
310             return null;
311         }
312         DataHeader si = d.readDataHeaderForBooleanArray(expectedLength);
313         byte[] bytes = new byte[(si.elementsOrVersion + 7) / BindingsHelper.ALIGNMENT];
314         d.mMessage.getData().position(d.mBaseOffset + DataHeader.HEADER_SIZE);
315         d.mMessage.getData().get(bytes);
316         boolean[] result = new boolean[si.elementsOrVersion];
317         for (int i = 0; i < bytes.length; ++i) {
318             for (int j = 0; j < BindingsHelper.ALIGNMENT; ++j) {
319                 int booleanIndex = i * BindingsHelper.ALIGNMENT + j;
320                 if (booleanIndex < result.length) {
321                     result[booleanIndex] = (bytes[i] & (1 << j)) != 0;
322                 }
323             }
324         }
325         return result;
326     }
327 
328     /**
329      * Deserializes an array of bytes at the given offset.
330      */
readBytes(int offset, int arrayNullability, int expectedLength)331     public byte[] readBytes(int offset, int arrayNullability, int expectedLength) {
332         Decoder d = readPointer(offset, BindingsHelper.isArrayNullable(arrayNullability));
333         if (d == null) {
334             return null;
335         }
336         DataHeader si = d.readDataHeaderForArray(1, expectedLength);
337         byte[] result = new byte[si.elementsOrVersion];
338         d.mMessage.getData().position(d.mBaseOffset + DataHeader.HEADER_SIZE);
339         d.mMessage.getData().get(result);
340         return result;
341     }
342 
343     /**
344      * Deserializes an array of shorts at the given offset.
345      */
readShorts(int offset, int arrayNullability, int expectedLength)346     public short[] readShorts(int offset, int arrayNullability, int expectedLength) {
347         Decoder d = readPointer(offset, BindingsHelper.isArrayNullable(arrayNullability));
348         if (d == null) {
349             return null;
350         }
351         DataHeader si = d.readDataHeaderForArray(2, expectedLength);
352         short[] result = new short[si.elementsOrVersion];
353         d.mMessage.getData().position(d.mBaseOffset + DataHeader.HEADER_SIZE);
354         d.mMessage.getData().asShortBuffer().get(result);
355         return result;
356     }
357 
358     /**
359      * Deserializes an array of ints at the given offset.
360      */
readInts(int offset, int arrayNullability, int expectedLength)361     public int[] readInts(int offset, int arrayNullability, int expectedLength) {
362         Decoder d = readPointer(offset, BindingsHelper.isArrayNullable(arrayNullability));
363         if (d == null) {
364             return null;
365         }
366         DataHeader si = d.readDataHeaderForArray(4, expectedLength);
367         int[] result = new int[si.elementsOrVersion];
368         d.mMessage.getData().position(d.mBaseOffset + DataHeader.HEADER_SIZE);
369         d.mMessage.getData().asIntBuffer().get(result);
370         return result;
371     }
372 
373     /**
374      * Deserializes an array of floats at the given offset.
375      */
readFloats(int offset, int arrayNullability, int expectedLength)376     public float[] readFloats(int offset, int arrayNullability, int expectedLength) {
377         Decoder d = readPointer(offset, BindingsHelper.isArrayNullable(arrayNullability));
378         if (d == null) {
379             return null;
380         }
381         DataHeader si = d.readDataHeaderForArray(4, expectedLength);
382         float[] result = new float[si.elementsOrVersion];
383         d.mMessage.getData().position(d.mBaseOffset + DataHeader.HEADER_SIZE);
384         d.mMessage.getData().asFloatBuffer().get(result);
385         return result;
386     }
387 
388     /**
389      * Deserializes an array of longs at the given offset.
390      */
readLongs(int offset, int arrayNullability, int expectedLength)391     public long[] readLongs(int offset, int arrayNullability, int expectedLength) {
392         Decoder d = readPointer(offset, BindingsHelper.isArrayNullable(arrayNullability));
393         if (d == null) {
394             return null;
395         }
396         DataHeader si = d.readDataHeaderForArray(8, expectedLength);
397         long[] result = new long[si.elementsOrVersion];
398         d.mMessage.getData().position(d.mBaseOffset + DataHeader.HEADER_SIZE);
399         d.mMessage.getData().asLongBuffer().get(result);
400         return result;
401     }
402 
403     /**
404      * Deserializes an array of doubles at the given offset.
405      */
readDoubles(int offset, int arrayNullability, int expectedLength)406     public double[] readDoubles(int offset, int arrayNullability, int expectedLength) {
407         Decoder d = readPointer(offset, BindingsHelper.isArrayNullable(arrayNullability));
408         if (d == null) {
409             return null;
410         }
411         DataHeader si = d.readDataHeaderForArray(8, expectedLength);
412         double[] result = new double[si.elementsOrVersion];
413         d.mMessage.getData().position(d.mBaseOffset + DataHeader.HEADER_SIZE);
414         d.mMessage.getData().asDoubleBuffer().get(result);
415         return result;
416     }
417 
418     /**
419      * Deserializes an |Handle| at the given offset.
420      */
readHandle(int offset, boolean nullable)421     public Handle readHandle(int offset, boolean nullable) {
422         int index = readInt(offset);
423         if (index == -1) {
424             if (!nullable) {
425                 throw new DeserializationException(
426                         "Trying to decode an invalid handle for a non-nullable type.");
427             }
428             return InvalidHandle.INSTANCE;
429         }
430         mValidator.claimHandle(index);
431         return mMessage.getHandles().get(index);
432     }
433 
434     /**
435      * Deserializes an |UntypedHandle| at the given offset.
436      */
readUntypedHandle(int offset, boolean nullable)437     public UntypedHandle readUntypedHandle(int offset, boolean nullable) {
438         return readHandle(offset, nullable).toUntypedHandle();
439     }
440 
441     /**
442      * Deserializes a |ConsumerHandle| at the given offset.
443      */
readConsumerHandle(int offset, boolean nullable)444     public DataPipe.ConsumerHandle readConsumerHandle(int offset, boolean nullable) {
445         return readUntypedHandle(offset, nullable).toDataPipeConsumerHandle();
446     }
447 
448     /**
449      * Deserializes a |ProducerHandle| at the given offset.
450      */
readProducerHandle(int offset, boolean nullable)451     public DataPipe.ProducerHandle readProducerHandle(int offset, boolean nullable) {
452         return readUntypedHandle(offset, nullable).toDataPipeProducerHandle();
453     }
454 
455     /**
456      * Deserializes a |MessagePipeHandle| at the given offset.
457      */
readMessagePipeHandle(int offset, boolean nullable)458     public MessagePipeHandle readMessagePipeHandle(int offset, boolean nullable) {
459         return readUntypedHandle(offset, nullable).toMessagePipeHandle();
460     }
461 
462     /**
463      * Deserializes a |SharedBufferHandle| at the given offset.
464      */
readSharedBufferHandle(int offset, boolean nullable)465     public SharedBufferHandle readSharedBufferHandle(int offset, boolean nullable) {
466         return readUntypedHandle(offset, nullable).toSharedBufferHandle();
467     }
468 
469     /**
470      * Deserializes an interface at the given offset.
471      *
472      * @return a proxy to the service.
473      */
readServiceInterface(int offset, boolean nullable, Interface.Manager<?, P> manager)474     public <P extends Proxy> P readServiceInterface(int offset, boolean nullable,
475             Interface.Manager<?, P> manager) {
476         MessagePipeHandle handle = readMessagePipeHandle(offset, nullable);
477         if (!handle.isValid()) {
478             return null;
479         }
480         int version = readInt(offset + BindingsHelper.SERIALIZED_HANDLE_SIZE);
481         return manager.attachProxy(handle, version);
482     }
483 
484     /**
485      * Deserializes a |InterfaceRequest| at the given offset.
486      */
readInterfaceRequest(int offset, boolean nullable)487     public <I extends Interface> InterfaceRequest<I> readInterfaceRequest(int offset,
488             boolean nullable) {
489         MessagePipeHandle handle = readMessagePipeHandle(offset, nullable);
490         if (handle == null) {
491             return null;
492         }
493         return new InterfaceRequest<I>(handle);
494     }
495 
496     /**
497      * Deserializes an associated interface at the given offset. Not yet supported.
498      */
readAssociatedServiceInterfaceNotSupported(int offset, boolean nullable)499     public AssociatedInterfaceNotSupported readAssociatedServiceInterfaceNotSupported(int offset,
500             boolean nullable) {
501         return null;
502     }
503 
504     /**
505      * Deserializes an associated interface request at the given offset. Not yet supported.
506      */
readAssociatedInterfaceRequestNotSupported( int offset, boolean nullable)507     public AssociatedInterfaceRequestNotSupported readAssociatedInterfaceRequestNotSupported(
508             int offset, boolean nullable) {
509         return null;
510     }
511 
512     /**
513      * Deserializes a string at the given offset.
514      */
readString(int offset, boolean nullable)515     public String readString(int offset, boolean nullable) {
516         final int arrayNullability = nullable ? BindingsHelper.ARRAY_NULLABLE : 0;
517         byte[] bytes = readBytes(offset, arrayNullability, BindingsHelper.UNSPECIFIED_ARRAY_LENGTH);
518         if (bytes == null) {
519             return null;
520         }
521         return new String(bytes, Charset.forName("utf8"));
522     }
523 
524     /**
525      * Deserializes an array of |Handle| at the given offset.
526      */
readHandles(int offset, int arrayNullability, int expectedLength)527     public Handle[] readHandles(int offset, int arrayNullability, int expectedLength) {
528         Decoder d = readPointer(offset, BindingsHelper.isArrayNullable(arrayNullability));
529         if (d == null) {
530             return null;
531         }
532         DataHeader si = d.readDataHeaderForArray(4, expectedLength);
533         Handle[] result = new Handle[si.elementsOrVersion];
534         for (int i = 0; i < result.length; ++i) {
535             result[i] = d.readHandle(
536                     DataHeader.HEADER_SIZE + BindingsHelper.SERIALIZED_HANDLE_SIZE * i,
537                     BindingsHelper.isElementNullable(arrayNullability));
538         }
539         return result;
540     }
541 
542     /**
543      * Deserializes an array of |UntypedHandle| at the given offset.
544      */
readUntypedHandles( int offset, int arrayNullability, int expectedLength)545     public UntypedHandle[] readUntypedHandles(
546             int offset, int arrayNullability, int expectedLength) {
547         Decoder d = readPointer(offset, BindingsHelper.isArrayNullable(arrayNullability));
548         if (d == null) {
549             return null;
550         }
551         DataHeader si = d.readDataHeaderForArray(4, expectedLength);
552         UntypedHandle[] result = new UntypedHandle[si.elementsOrVersion];
553         for (int i = 0; i < result.length; ++i) {
554             result[i] = d.readUntypedHandle(
555                     DataHeader.HEADER_SIZE + BindingsHelper.SERIALIZED_HANDLE_SIZE * i,
556                     BindingsHelper.isElementNullable(arrayNullability));
557         }
558         return result;
559     }
560 
561     /**
562      * Deserializes an array of |ConsumerHandle| at the given offset.
563      */
readConsumerHandles( int offset, int arrayNullability, int expectedLength)564     public DataPipe.ConsumerHandle[] readConsumerHandles(
565             int offset, int arrayNullability, int expectedLength) {
566         Decoder d = readPointer(offset, BindingsHelper.isArrayNullable(arrayNullability));
567         if (d == null) {
568             return null;
569         }
570         DataHeader si = d.readDataHeaderForArray(4, expectedLength);
571         DataPipe.ConsumerHandle[] result = new DataPipe.ConsumerHandle[si.elementsOrVersion];
572         for (int i = 0; i < result.length; ++i) {
573             result[i] = d.readConsumerHandle(
574                     DataHeader.HEADER_SIZE + BindingsHelper.SERIALIZED_HANDLE_SIZE * i,
575                     BindingsHelper.isElementNullable(arrayNullability));
576         }
577         return result;
578     }
579 
580     /**
581      * Deserializes an array of |ProducerHandle| at the given offset.
582      */
readProducerHandles( int offset, int arrayNullability, int expectedLength)583     public DataPipe.ProducerHandle[] readProducerHandles(
584             int offset, int arrayNullability, int expectedLength) {
585         Decoder d = readPointer(offset, BindingsHelper.isArrayNullable(arrayNullability));
586         if (d == null) {
587             return null;
588         }
589         DataHeader si = d.readDataHeaderForArray(4, expectedLength);
590         DataPipe.ProducerHandle[] result = new DataPipe.ProducerHandle[si.elementsOrVersion];
591         for (int i = 0; i < result.length; ++i) {
592             result[i] = d.readProducerHandle(
593                     DataHeader.HEADER_SIZE + BindingsHelper.SERIALIZED_HANDLE_SIZE * i,
594                     BindingsHelper.isElementNullable(arrayNullability));
595         }
596         return result;
597 
598     }
599 
600     /**
601      * Deserializes an array of |MessagePipeHandle| at the given offset.
602      */
readMessagePipeHandles( int offset, int arrayNullability, int expectedLength)603     public MessagePipeHandle[] readMessagePipeHandles(
604             int offset, int arrayNullability, int expectedLength) {
605         Decoder d = readPointer(offset, BindingsHelper.isArrayNullable(arrayNullability));
606         if (d == null) {
607             return null;
608         }
609         DataHeader si = d.readDataHeaderForArray(4, expectedLength);
610         MessagePipeHandle[] result = new MessagePipeHandle[si.elementsOrVersion];
611         for (int i = 0; i < result.length; ++i) {
612             result[i] = d.readMessagePipeHandle(
613                     DataHeader.HEADER_SIZE + BindingsHelper.SERIALIZED_HANDLE_SIZE * i,
614                     BindingsHelper.isElementNullable(arrayNullability));
615         }
616         return result;
617 
618     }
619 
620     /**
621      * Deserializes an array of |SharedBufferHandle| at the given offset.
622      */
readSharedBufferHandles( int offset, int arrayNullability, int expectedLength)623     public SharedBufferHandle[] readSharedBufferHandles(
624             int offset, int arrayNullability, int expectedLength) {
625         Decoder d = readPointer(offset, BindingsHelper.isArrayNullable(arrayNullability));
626         if (d == null) {
627             return null;
628         }
629         DataHeader si = d.readDataHeaderForArray(4, expectedLength);
630         SharedBufferHandle[] result = new SharedBufferHandle[si.elementsOrVersion];
631         for (int i = 0; i < result.length; ++i) {
632             result[i] = d.readSharedBufferHandle(
633                     DataHeader.HEADER_SIZE + BindingsHelper.SERIALIZED_HANDLE_SIZE * i,
634                     BindingsHelper.isElementNullable(arrayNullability));
635         }
636         return result;
637 
638     }
639 
640     /**
641      * Deserializes an array of |ServiceHandle| at the given offset.
642      */
readServiceInterfaces( int offset, int arrayNullability, int expectedLength, Interface.Manager<S, P> manager)643     public <S extends Interface, P extends Proxy> S[] readServiceInterfaces(
644             int offset, int arrayNullability, int expectedLength, Interface.Manager<S, P> manager) {
645         Decoder d = readPointer(offset, BindingsHelper.isArrayNullable(arrayNullability));
646         if (d == null) {
647             return null;
648         }
649         DataHeader si =
650                 d.readDataHeaderForArray(BindingsHelper.SERIALIZED_INTERFACE_SIZE, expectedLength);
651         S[] result = manager.buildArray(si.elementsOrVersion);
652         for (int i = 0; i < result.length; ++i) {
653             // This cast is necessary because java 6 doesn't handle wildcard correctly when using
654             // Manager<S, ? extends S>
655             @SuppressWarnings("unchecked")
656             S value = (S) d.readServiceInterface(
657                     DataHeader.HEADER_SIZE + BindingsHelper.SERIALIZED_INTERFACE_SIZE * i,
658                     BindingsHelper.isElementNullable(arrayNullability), manager);
659             result[i] = value;
660         }
661         return result;
662     }
663 
664     /**
665      * Deserializes an array of |InterfaceRequest| at the given offset.
666      */
readInterfaceRequests( int offset, int arrayNullability, int expectedLength)667     public <I extends Interface> InterfaceRequest<I>[] readInterfaceRequests(
668             int offset, int arrayNullability, int expectedLength) {
669         Decoder d = readPointer(offset, BindingsHelper.isArrayNullable(arrayNullability));
670         if (d == null) {
671             return null;
672         }
673         DataHeader si = d.readDataHeaderForArray(4, expectedLength);
674         @SuppressWarnings("unchecked")
675         InterfaceRequest<I>[] result = new InterfaceRequest[si.elementsOrVersion];
676         for (int i = 0; i < result.length; ++i) {
677             result[i] = d.readInterfaceRequest(
678                     DataHeader.HEADER_SIZE + BindingsHelper.SERIALIZED_HANDLE_SIZE * i,
679                     BindingsHelper.isElementNullable(arrayNullability));
680         }
681         return result;
682     }
683 
684     /**
685      * Deserializes an array of associated interfaces at the given offset. Not yet supported.
686      */
readAssociatedServiceInterfaceNotSupporteds( int offset, int arrayNullability, int expectedLength)687     public AssociatedInterfaceNotSupported[] readAssociatedServiceInterfaceNotSupporteds(
688             int offset, int arrayNullability, int expectedLength) {
689         return null;
690     }
691 
692     /**
693      * Deserializes an array of associated interface requests at the given offset. Not yet
694      * supported.
695      */
readAssociatedInterfaceRequestNotSupporteds( int offset, int arrayNullability, int expectedLength)696     public AssociatedInterfaceRequestNotSupported[] readAssociatedInterfaceRequestNotSupporteds(
697             int offset, int arrayNullability, int expectedLength) {
698         return null;
699     }
700 
701     /**
702      * Returns a view of this decoder at the offset |offset|.
703      */
getDecoderAtPosition(int offset)704     private Decoder getDecoderAtPosition(int offset) {
705         return new Decoder(mMessage, mValidator, offset);
706     }
707 
708     /**
709      * Deserializes a {@link DataHeader} at the given offset and checks if it is correct for an
710      * array of booleans.
711      */
readDataHeaderForBooleanArray(int expectedLength)712     private DataHeader readDataHeaderForBooleanArray(int expectedLength) {
713         DataHeader dataHeader = readDataHeader();
714         if (dataHeader.size < DataHeader.HEADER_SIZE + (dataHeader.elementsOrVersion + 7) / 8) {
715             throw new DeserializationException("Array header is incorrect.");
716         }
717         if (expectedLength != BindingsHelper.UNSPECIFIED_ARRAY_LENGTH
718                 && dataHeader.elementsOrVersion != expectedLength) {
719             throw new DeserializationException("Incorrect array length. Expected: " + expectedLength
720                     + ", but got: " + dataHeader.elementsOrVersion + ".");
721         }
722         return dataHeader;
723     }
724 
725     /**
726      * Deserializes a {@link DataHeader} of an array at the given offset.
727      */
readDataHeaderForArray(long elementSize, int expectedLength)728     private DataHeader readDataHeaderForArray(long elementSize, int expectedLength) {
729         DataHeader dataHeader = readDataHeader();
730         if (dataHeader.size
731                 < (DataHeader.HEADER_SIZE + elementSize * dataHeader.elementsOrVersion)) {
732             throw new DeserializationException("Array header is incorrect.");
733         }
734         if (expectedLength != BindingsHelper.UNSPECIFIED_ARRAY_LENGTH
735                 && dataHeader.elementsOrVersion != expectedLength) {
736             throw new DeserializationException("Incorrect array length. Expected: " + expectedLength
737                     + ", but got: " + dataHeader.elementsOrVersion + ".");
738         }
739         return dataHeader;
740     }
741 
validateBufferSize(int offset, int size)742     private void validateBufferSize(int offset, int size) {
743         if (mMessage.getData().limit() < offset + size) {
744             throw new DeserializationException("Buffer is smaller than expected.");
745         }
746     }
747 }
748