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