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