IOMX.cpp revision df712ea86e6350f7005a02ab0e1c60c28a343ed0
1/*
2 * Copyright (c) 2009 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//#define LOG_NDEBUG 0
18#define LOG_TAG "IOMX"
19#include <utils/Log.h>
20
21#include <binder/IMemory.h>
22#include <binder/Parcel.h>
23#include <media/IOMX.h>
24#include <media/stagefright/foundation/ADebug.h>
25
26namespace android {
27
28enum {
29    CONNECT = IBinder::FIRST_CALL_TRANSACTION,
30    LIVES_LOCALLY,
31    LIST_NODES,
32    ALLOCATE_NODE,
33    FREE_NODE,
34    SEND_COMMAND,
35    GET_PARAMETER,
36    SET_PARAMETER,
37    GET_CONFIG,
38    SET_CONFIG,
39    GET_STATE,
40    ENABLE_GRAPHIC_BUFFERS,
41    USE_BUFFER,
42    USE_GRAPHIC_BUFFER,
43    STORE_META_DATA_IN_BUFFERS,
44    ALLOC_BUFFER,
45    ALLOC_BUFFER_WITH_BACKUP,
46    FREE_BUFFER,
47    FILL_BUFFER,
48    EMPTY_BUFFER,
49    GET_EXTENSION_INDEX,
50    OBSERVER_ON_MSG,
51    GET_GRAPHIC_BUFFER_USAGE,
52};
53
54class BpOMX : public BpInterface<IOMX> {
55public:
56    BpOMX(const sp<IBinder> &impl)
57        : BpInterface<IOMX>(impl) {
58    }
59
60    virtual bool livesLocally(node_id node, pid_t pid) {
61        Parcel data, reply;
62        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
63        data.writeIntPtr((intptr_t)node);
64        data.writeInt32(pid);
65        remote()->transact(LIVES_LOCALLY, data, &reply);
66
67        return reply.readInt32() != 0;
68    }
69
70    virtual status_t listNodes(List<ComponentInfo> *list) {
71        list->clear();
72
73        Parcel data, reply;
74        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
75        remote()->transact(LIST_NODES, data, &reply);
76
77        int32_t n = reply.readInt32();
78        for (int32_t i = 0; i < n; ++i) {
79            list->push_back(ComponentInfo());
80            ComponentInfo &info = *--list->end();
81
82            info.mName = reply.readString8();
83            int32_t numRoles = reply.readInt32();
84            for (int32_t j = 0; j < numRoles; ++j) {
85                info.mRoles.push_back(reply.readString8());
86            }
87        }
88
89        return OK;
90    }
91
92    virtual status_t allocateNode(
93            const char *name, const sp<IOMXObserver> &observer, node_id *node) {
94        Parcel data, reply;
95        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
96        data.writeCString(name);
97        data.writeStrongBinder(observer->asBinder());
98        remote()->transact(ALLOCATE_NODE, data, &reply);
99
100        status_t err = reply.readInt32();
101        if (err == OK) {
102            *node = (void*)reply.readIntPtr();
103        } else {
104            *node = 0;
105        }
106
107        return err;
108    }
109
110    virtual status_t freeNode(node_id node) {
111        Parcel data, reply;
112        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
113        data.writeIntPtr((intptr_t)node);
114        remote()->transact(FREE_NODE, data, &reply);
115
116        return reply.readInt32();
117    }
118
119    virtual status_t sendCommand(
120            node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param) {
121        Parcel data, reply;
122        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
123        data.writeIntPtr((intptr_t)node);
124        data.writeInt32(cmd);
125        data.writeInt32(param);
126        remote()->transact(SEND_COMMAND, data, &reply);
127
128        return reply.readInt32();
129    }
130
131    virtual status_t getParameter(
132            node_id node, OMX_INDEXTYPE index,
133            void *params, size_t size) {
134        Parcel data, reply;
135        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
136        data.writeIntPtr((intptr_t)node);
137        data.writeInt32(index);
138        data.writeInt32(size);
139        data.write(params, size);
140        remote()->transact(GET_PARAMETER, data, &reply);
141
142        status_t err = reply.readInt32();
143        if (err != OK) {
144            return err;
145        }
146
147        reply.read(params, size);
148
149        return OK;
150    }
151
152    virtual status_t setParameter(
153            node_id node, OMX_INDEXTYPE index,
154            const void *params, size_t size) {
155        Parcel data, reply;
156        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
157        data.writeIntPtr((intptr_t)node);
158        data.writeInt32(index);
159        data.writeInt32(size);
160        data.write(params, size);
161        remote()->transact(SET_PARAMETER, data, &reply);
162
163        return reply.readInt32();
164    }
165
166    virtual status_t getConfig(
167            node_id node, OMX_INDEXTYPE index,
168            void *params, size_t size) {
169        Parcel data, reply;
170        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
171        data.writeIntPtr((intptr_t)node);
172        data.writeInt32(index);
173        data.writeInt32(size);
174        data.write(params, size);
175        remote()->transact(GET_CONFIG, data, &reply);
176
177        status_t err = reply.readInt32();
178        if (err != OK) {
179            return err;
180        }
181
182        reply.read(params, size);
183
184        return OK;
185    }
186
187    virtual status_t setConfig(
188            node_id node, OMX_INDEXTYPE index,
189            const void *params, size_t size) {
190        Parcel data, reply;
191        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
192        data.writeIntPtr((intptr_t)node);
193        data.writeInt32(index);
194        data.writeInt32(size);
195        data.write(params, size);
196        remote()->transact(SET_CONFIG, data, &reply);
197
198        return reply.readInt32();
199    }
200
201    virtual status_t getState(
202            node_id node, OMX_STATETYPE* state) {
203        Parcel data, reply;
204        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
205        data.writeIntPtr((intptr_t)node);
206        remote()->transact(GET_STATE, data, &reply);
207
208        *state = static_cast<OMX_STATETYPE>(reply.readInt32());
209        return reply.readInt32();
210    }
211
212    virtual status_t enableGraphicBuffers(
213            node_id node, OMX_U32 port_index, OMX_BOOL enable) {
214        Parcel data, reply;
215        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
216        data.writeIntPtr((intptr_t)node);
217        data.writeInt32(port_index);
218        data.writeInt32((uint32_t)enable);
219        remote()->transact(ENABLE_GRAPHIC_BUFFERS, data, &reply);
220
221        status_t err = reply.readInt32();
222        return err;
223    }
224
225    virtual status_t getGraphicBufferUsage(
226            node_id node, OMX_U32 port_index, OMX_U32* usage) {
227        Parcel data, reply;
228        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
229        data.writeIntPtr((intptr_t)node);
230        data.writeInt32(port_index);
231        remote()->transact(GET_GRAPHIC_BUFFER_USAGE, data, &reply);
232
233        status_t err = reply.readInt32();
234        *usage = reply.readInt32();
235        return err;
236    }
237
238    virtual status_t useBuffer(
239            node_id node, OMX_U32 port_index, const sp<IMemory> &params,
240            buffer_id *buffer) {
241        Parcel data, reply;
242        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
243        data.writeIntPtr((intptr_t)node);
244        data.writeInt32(port_index);
245        data.writeStrongBinder(params->asBinder());
246        remote()->transact(USE_BUFFER, data, &reply);
247
248        status_t err = reply.readInt32();
249        if (err != OK) {
250            *buffer = 0;
251
252            return err;
253        }
254
255        *buffer = (void*)reply.readIntPtr();
256
257        return err;
258    }
259
260
261    virtual status_t useGraphicBuffer(
262            node_id node, OMX_U32 port_index,
263            const sp<GraphicBuffer> &graphicBuffer, buffer_id *buffer) {
264        Parcel data, reply;
265        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
266        data.writeIntPtr((intptr_t)node);
267        data.writeInt32(port_index);
268        data.write(*graphicBuffer);
269        remote()->transact(USE_GRAPHIC_BUFFER, data, &reply);
270
271        status_t err = reply.readInt32();
272        if (err != OK) {
273            *buffer = 0;
274
275            return err;
276        }
277
278        *buffer = (void*)reply.readIntPtr();
279
280        return err;
281    }
282
283    virtual status_t storeMetaDataInBuffers(
284            node_id node, OMX_U32 port_index, OMX_BOOL enable) {
285        Parcel data, reply;
286        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
287        data.writeIntPtr((intptr_t)node);
288        data.writeInt32(port_index);
289        data.writeInt32((uint32_t)enable);
290        remote()->transact(STORE_META_DATA_IN_BUFFERS, data, &reply);
291
292        status_t err = reply.readInt32();
293        return err;
294    }
295
296    virtual status_t allocateBuffer(
297            node_id node, OMX_U32 port_index, size_t size,
298            buffer_id *buffer, void **buffer_data) {
299        Parcel data, reply;
300        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
301        data.writeIntPtr((intptr_t)node);
302        data.writeInt32(port_index);
303        data.writeInt32(size);
304        remote()->transact(ALLOC_BUFFER, data, &reply);
305
306        status_t err = reply.readInt32();
307        if (err != OK) {
308            *buffer = 0;
309
310            return err;
311        }
312
313        *buffer = (void *)reply.readIntPtr();
314        *buffer_data = (void *)reply.readIntPtr();
315
316        return err;
317    }
318
319    virtual status_t allocateBufferWithBackup(
320            node_id node, OMX_U32 port_index, const sp<IMemory> &params,
321            buffer_id *buffer) {
322        Parcel data, reply;
323        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
324        data.writeIntPtr((intptr_t)node);
325        data.writeInt32(port_index);
326        data.writeStrongBinder(params->asBinder());
327        remote()->transact(ALLOC_BUFFER_WITH_BACKUP, data, &reply);
328
329        status_t err = reply.readInt32();
330        if (err != OK) {
331            *buffer = 0;
332
333            return err;
334        }
335
336        *buffer = (void*)reply.readIntPtr();
337
338        return err;
339    }
340
341    virtual status_t freeBuffer(
342            node_id node, OMX_U32 port_index, buffer_id buffer) {
343        Parcel data, reply;
344        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
345        data.writeIntPtr((intptr_t)node);
346        data.writeInt32(port_index);
347        data.writeIntPtr((intptr_t)buffer);
348        remote()->transact(FREE_BUFFER, data, &reply);
349
350        return reply.readInt32();
351    }
352
353    virtual status_t fillBuffer(node_id node, buffer_id buffer) {
354        Parcel data, reply;
355        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
356        data.writeIntPtr((intptr_t)node);
357        data.writeIntPtr((intptr_t)buffer);
358        remote()->transact(FILL_BUFFER, data, &reply);
359
360        return reply.readInt32();
361    }
362
363    virtual status_t emptyBuffer(
364            node_id node,
365            buffer_id buffer,
366            OMX_U32 range_offset, OMX_U32 range_length,
367            OMX_U32 flags, OMX_TICKS timestamp) {
368        Parcel data, reply;
369        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
370        data.writeIntPtr((intptr_t)node);
371        data.writeIntPtr((intptr_t)buffer);
372        data.writeInt32(range_offset);
373        data.writeInt32(range_length);
374        data.writeInt32(flags);
375        data.writeInt64(timestamp);
376        remote()->transact(EMPTY_BUFFER, data, &reply);
377
378        return reply.readInt32();
379    }
380
381    virtual status_t getExtensionIndex(
382            node_id node,
383            const char *parameter_name,
384            OMX_INDEXTYPE *index) {
385        Parcel data, reply;
386        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
387        data.writeIntPtr((intptr_t)node);
388        data.writeCString(parameter_name);
389
390        remote()->transact(GET_EXTENSION_INDEX, data, &reply);
391
392        status_t err = reply.readInt32();
393        if (err == OK) {
394            *index = static_cast<OMX_INDEXTYPE>(reply.readInt32());
395        } else {
396            *index = OMX_IndexComponentStartUnused;
397        }
398
399        return err;
400    }
401};
402
403IMPLEMENT_META_INTERFACE(OMX, "android.hardware.IOMX");
404
405////////////////////////////////////////////////////////////////////////////////
406
407#define CHECK_INTERFACE(interface, data, reply) \
408        do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
409            ALOGW("Call incorrectly routed to " #interface); \
410            return PERMISSION_DENIED; \
411        } } while (0)
412
413status_t BnOMX::onTransact(
414    uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) {
415    switch (code) {
416        case LIVES_LOCALLY:
417        {
418            CHECK_INTERFACE(IOMX, data, reply);
419            node_id node = (void *)data.readIntPtr();
420            pid_t pid = (pid_t)data.readInt32();
421            reply->writeInt32(livesLocally(node, pid));
422
423            return OK;
424        }
425
426        case LIST_NODES:
427        {
428            CHECK_INTERFACE(IOMX, data, reply);
429
430            List<ComponentInfo> list;
431            listNodes(&list);
432
433            reply->writeInt32(list.size());
434            for (List<ComponentInfo>::iterator it = list.begin();
435                 it != list.end(); ++it) {
436                ComponentInfo &cur = *it;
437
438                reply->writeString8(cur.mName);
439                reply->writeInt32(cur.mRoles.size());
440                for (List<String8>::iterator role_it = cur.mRoles.begin();
441                     role_it != cur.mRoles.end(); ++role_it) {
442                    reply->writeString8(*role_it);
443                }
444            }
445
446            return NO_ERROR;
447        }
448
449        case ALLOCATE_NODE:
450        {
451            CHECK_INTERFACE(IOMX, data, reply);
452
453            const char *name = data.readCString();
454
455            sp<IOMXObserver> observer =
456                interface_cast<IOMXObserver>(data.readStrongBinder());
457
458            node_id node;
459
460            status_t err = allocateNode(name, observer, &node);
461            reply->writeInt32(err);
462            if (err == OK) {
463                reply->writeIntPtr((intptr_t)node);
464            }
465
466            return NO_ERROR;
467        }
468
469        case FREE_NODE:
470        {
471            CHECK_INTERFACE(IOMX, data, reply);
472
473            node_id node = (void*)data.readIntPtr();
474
475            reply->writeInt32(freeNode(node));
476
477            return NO_ERROR;
478        }
479
480        case SEND_COMMAND:
481        {
482            CHECK_INTERFACE(IOMX, data, reply);
483
484            node_id node = (void*)data.readIntPtr();
485
486            OMX_COMMANDTYPE cmd =
487                static_cast<OMX_COMMANDTYPE>(data.readInt32());
488
489            OMX_S32 param = data.readInt32();
490            reply->writeInt32(sendCommand(node, cmd, param));
491
492            return NO_ERROR;
493        }
494
495        case GET_PARAMETER:
496        case SET_PARAMETER:
497        case GET_CONFIG:
498        case SET_CONFIG:
499        {
500            CHECK_INTERFACE(IOMX, data, reply);
501
502            node_id node = (void*)data.readIntPtr();
503            OMX_INDEXTYPE index = static_cast<OMX_INDEXTYPE>(data.readInt32());
504
505            size_t size = data.readInt32();
506
507            void *params = malloc(size);
508            data.read(params, size);
509
510            status_t err;
511            switch (code) {
512                case GET_PARAMETER:
513                    err = getParameter(node, index, params, size);
514                    break;
515                case SET_PARAMETER:
516                    err = setParameter(node, index, params, size);
517                    break;
518                case GET_CONFIG:
519                    err = getConfig(node, index, params, size);
520                    break;
521                case SET_CONFIG:
522                    err = setConfig(node, index, params, size);
523                    break;
524                default:
525                    TRESPASS();
526            }
527
528            reply->writeInt32(err);
529
530            if ((code == GET_PARAMETER || code == GET_CONFIG) && err == OK) {
531                reply->write(params, size);
532            }
533
534            free(params);
535            params = NULL;
536
537            return NO_ERROR;
538        }
539
540        case GET_STATE:
541        {
542            CHECK_INTERFACE(IOMX, data, reply);
543
544            node_id node = (void*)data.readIntPtr();
545            OMX_STATETYPE state = OMX_StateInvalid;
546
547            status_t err = getState(node, &state);
548            reply->writeInt32(state);
549            reply->writeInt32(err);
550
551            return NO_ERROR;
552        }
553
554        case ENABLE_GRAPHIC_BUFFERS:
555        {
556            CHECK_INTERFACE(IOMX, data, reply);
557
558            node_id node = (void*)data.readIntPtr();
559            OMX_U32 port_index = data.readInt32();
560            OMX_BOOL enable = (OMX_BOOL)data.readInt32();
561
562            status_t err = enableGraphicBuffers(node, port_index, enable);
563            reply->writeInt32(err);
564
565            return NO_ERROR;
566        }
567
568        case GET_GRAPHIC_BUFFER_USAGE:
569        {
570            CHECK_INTERFACE(IOMX, data, reply);
571
572            node_id node = (void*)data.readIntPtr();
573            OMX_U32 port_index = data.readInt32();
574
575            OMX_U32 usage = 0;
576            status_t err = getGraphicBufferUsage(node, port_index, &usage);
577            reply->writeInt32(err);
578            reply->writeInt32(usage);
579
580            return NO_ERROR;
581        }
582
583        case USE_BUFFER:
584        {
585            CHECK_INTERFACE(IOMX, data, reply);
586
587            node_id node = (void*)data.readIntPtr();
588            OMX_U32 port_index = data.readInt32();
589            sp<IMemory> params =
590                interface_cast<IMemory>(data.readStrongBinder());
591
592            buffer_id buffer;
593            status_t err = useBuffer(node, port_index, params, &buffer);
594            reply->writeInt32(err);
595
596            if (err == OK) {
597                reply->writeIntPtr((intptr_t)buffer);
598            }
599
600            return NO_ERROR;
601        }
602
603        case USE_GRAPHIC_BUFFER:
604        {
605            CHECK_INTERFACE(IOMX, data, reply);
606
607            node_id node = (void*)data.readIntPtr();
608            OMX_U32 port_index = data.readInt32();
609            sp<GraphicBuffer> graphicBuffer = new GraphicBuffer();
610            data.read(*graphicBuffer);
611
612            buffer_id buffer;
613            status_t err = useGraphicBuffer(
614                    node, port_index, graphicBuffer, &buffer);
615            reply->writeInt32(err);
616
617            if (err == OK) {
618                reply->writeIntPtr((intptr_t)buffer);
619            }
620
621            return NO_ERROR;
622        }
623
624        case STORE_META_DATA_IN_BUFFERS:
625        {
626            CHECK_INTERFACE(IOMX, data, reply);
627
628            node_id node = (void*)data.readIntPtr();
629            OMX_U32 port_index = data.readInt32();
630            OMX_BOOL enable = (OMX_BOOL)data.readInt32();
631
632            status_t err = storeMetaDataInBuffers(node, port_index, enable);
633            reply->writeInt32(err);
634
635            return NO_ERROR;
636        }
637
638        case ALLOC_BUFFER:
639        {
640            CHECK_INTERFACE(IOMX, data, reply);
641
642            node_id node = (void*)data.readIntPtr();
643            OMX_U32 port_index = data.readInt32();
644            size_t size = data.readInt32();
645
646            buffer_id buffer;
647            void *buffer_data;
648            status_t err = allocateBuffer(
649                    node, port_index, size, &buffer, &buffer_data);
650            reply->writeInt32(err);
651
652            if (err == OK) {
653                reply->writeIntPtr((intptr_t)buffer);
654                reply->writeIntPtr((intptr_t)buffer_data);
655            }
656
657            return NO_ERROR;
658        }
659
660        case ALLOC_BUFFER_WITH_BACKUP:
661        {
662            CHECK_INTERFACE(IOMX, data, reply);
663
664            node_id node = (void*)data.readIntPtr();
665            OMX_U32 port_index = data.readInt32();
666            sp<IMemory> params =
667                interface_cast<IMemory>(data.readStrongBinder());
668
669            buffer_id buffer;
670            status_t err = allocateBufferWithBackup(
671                    node, port_index, params, &buffer);
672
673            reply->writeInt32(err);
674
675            if (err == OK) {
676                reply->writeIntPtr((intptr_t)buffer);
677            }
678
679            return NO_ERROR;
680        }
681
682        case FREE_BUFFER:
683        {
684            CHECK_INTERFACE(IOMX, data, reply);
685
686            node_id node = (void*)data.readIntPtr();
687            OMX_U32 port_index = data.readInt32();
688            buffer_id buffer = (void*)data.readIntPtr();
689            reply->writeInt32(freeBuffer(node, port_index, buffer));
690
691            return NO_ERROR;
692        }
693
694        case FILL_BUFFER:
695        {
696            CHECK_INTERFACE(IOMX, data, reply);
697
698            node_id node = (void*)data.readIntPtr();
699            buffer_id buffer = (void*)data.readIntPtr();
700            reply->writeInt32(fillBuffer(node, buffer));
701
702            return NO_ERROR;
703        }
704
705        case EMPTY_BUFFER:
706        {
707            CHECK_INTERFACE(IOMX, data, reply);
708
709            node_id node = (void*)data.readIntPtr();
710            buffer_id buffer = (void*)data.readIntPtr();
711            OMX_U32 range_offset = data.readInt32();
712            OMX_U32 range_length = data.readInt32();
713            OMX_U32 flags = data.readInt32();
714            OMX_TICKS timestamp = data.readInt64();
715
716            reply->writeInt32(
717                    emptyBuffer(
718                        node, buffer, range_offset, range_length,
719                        flags, timestamp));
720
721            return NO_ERROR;
722        }
723
724        case GET_EXTENSION_INDEX:
725        {
726            CHECK_INTERFACE(IOMX, data, reply);
727
728            node_id node = (void*)data.readIntPtr();
729            const char *parameter_name = data.readCString();
730
731            OMX_INDEXTYPE index;
732            status_t err = getExtensionIndex(node, parameter_name, &index);
733
734            reply->writeInt32(err);
735
736            if (err == OK) {
737                reply->writeInt32(index);
738            }
739
740            return OK;
741        }
742
743        default:
744            return BBinder::onTransact(code, data, reply, flags);
745    }
746}
747
748////////////////////////////////////////////////////////////////////////////////
749
750class BpOMXObserver : public BpInterface<IOMXObserver> {
751public:
752    BpOMXObserver(const sp<IBinder> &impl)
753        : BpInterface<IOMXObserver>(impl) {
754    }
755
756    virtual void onMessage(const omx_message &msg) {
757        Parcel data, reply;
758        data.writeInterfaceToken(IOMXObserver::getInterfaceDescriptor());
759        data.write(&msg, sizeof(msg));
760
761        remote()->transact(OBSERVER_ON_MSG, data, &reply, IBinder::FLAG_ONEWAY);
762    }
763};
764
765IMPLEMENT_META_INTERFACE(OMXObserver, "android.hardware.IOMXObserver");
766
767status_t BnOMXObserver::onTransact(
768    uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) {
769    switch (code) {
770        case OBSERVER_ON_MSG:
771        {
772            CHECK_INTERFACE(IOMXObserver, data, reply);
773
774            omx_message msg;
775            data.read(&msg, sizeof(msg));
776
777            // XXX Could use readInplace maybe?
778            onMessage(msg);
779
780            return NO_ERROR;
781        }
782
783        default:
784            return BBinder::onTransact(code, data, reply, flags);
785    }
786}
787
788}  // namespace android
789