IOMX.cpp revision 20111aa043c5f404472bc63b90bc5aad906b1101
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
9namespace android {
10
11enum {
12    CONNECT = IBinder::FIRST_CALL_TRANSACTION,
13    LIST_NODES,
14    ALLOCATE_NODE,
15    FREE_NODE,
16    SEND_COMMAND,
17    GET_PARAMETER,
18    SET_PARAMETER,
19    USE_BUFFER,
20    ALLOC_BUFFER,
21    ALLOC_BUFFER_WITH_BACKUP,
22    FREE_BUFFER,
23    OBSERVE_NODE,
24    FILL_BUFFER,
25    EMPTY_BUFFER,
26    OBSERVER_ON_MSG,
27};
28
29static void *readVoidStar(const Parcel *parcel) {
30    // FIX if sizeof(void *) != sizeof(int32)
31    return (void *)parcel->readInt32();
32}
33
34static void writeVoidStar(void *x, Parcel *parcel) {
35    // FIX if sizeof(void *) != sizeof(int32)
36    parcel->writeInt32((int32_t)x);
37}
38
39class BpOMX : public BpInterface<IOMX> {
40public:
41    BpOMX(const sp<IBinder> &impl)
42        : BpInterface<IOMX>(impl) {
43    }
44
45#if IOMX_USES_SOCKETS
46    virtual status_t connect(int *sd) {
47        Parcel data, reply;
48        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
49        remote()->transact(CONNECT, data, &reply);
50
51        status_t err = reply.readInt32();
52        if (err == OK) {
53            *sd = dup(reply.readFileDescriptor());
54        } else {
55            *sd = -1;
56        }
57
58        return reply.readInt32();
59    }
60#endif
61
62    virtual status_t list_nodes(List<String8> *list) {
63        list->clear();
64
65        Parcel data, reply;
66        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
67        remote()->transact(LIST_NODES, data, &reply);
68
69        int32_t n = reply.readInt32();
70        for (int32_t i = 0; i < n; ++i) {
71            String8 s = reply.readString8();
72
73            list->push_back(s);
74        }
75
76        return OK;
77    }
78
79    virtual status_t allocate_node(const char *name, node_id *node) {
80        Parcel data, reply;
81        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
82        data.writeCString(name);
83        remote()->transact(ALLOCATE_NODE, data, &reply);
84
85        status_t err = reply.readInt32();
86        if (err == OK) {
87            *node = readVoidStar(&reply);
88        } else {
89            *node = 0;
90        }
91
92        return err;
93    }
94
95    virtual status_t free_node(node_id node) {
96        Parcel data, reply;
97        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
98        writeVoidStar(node, &data);
99        remote()->transact(FREE_NODE, data, &reply);
100
101        return reply.readInt32();
102    }
103
104    virtual status_t send_command(
105            node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param) {
106        Parcel data, reply;
107        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
108        writeVoidStar(node, &data);
109        data.writeInt32(cmd);
110        data.writeInt32(param);
111        remote()->transact(SEND_COMMAND, data, &reply);
112
113        return reply.readInt32();
114    }
115
116    virtual status_t get_parameter(
117            node_id node, OMX_INDEXTYPE index,
118            void *params, size_t size) {
119        Parcel data, reply;
120        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
121        writeVoidStar(node, &data);
122        data.writeInt32(index);
123        data.writeInt32(size);
124        data.write(params, size);
125        remote()->transact(GET_PARAMETER, data, &reply);
126
127        status_t err = reply.readInt32();
128        if (err != OK) {
129            return err;
130        }
131
132        reply.read(params, size);
133
134        return OK;
135    }
136
137    virtual status_t set_parameter(
138            node_id node, OMX_INDEXTYPE index,
139            const void *params, size_t size) {
140        Parcel data, reply;
141        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
142        writeVoidStar(node, &data);
143        data.writeInt32(index);
144        data.writeInt32(size);
145        data.write(params, size);
146        remote()->transact(SET_PARAMETER, data, &reply);
147
148        return reply.readInt32();
149    }
150
151    virtual status_t use_buffer(
152            node_id node, OMX_U32 port_index, const sp<IMemory> &params,
153            buffer_id *buffer) {
154        Parcel data, reply;
155        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
156        writeVoidStar(node, &data);
157        data.writeInt32(port_index);
158        data.writeStrongBinder(params->asBinder());
159        remote()->transact(USE_BUFFER, data, &reply);
160
161        status_t err = reply.readInt32();
162        if (err != OK) {
163            *buffer = 0;
164
165            return err;
166        }
167
168        *buffer = readVoidStar(&reply);
169
170        return err;
171    }
172
173    virtual status_t allocate_buffer(
174            node_id node, OMX_U32 port_index, size_t size,
175            buffer_id *buffer) {
176        Parcel data, reply;
177        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
178        writeVoidStar(node, &data);
179        data.writeInt32(port_index);
180        data.writeInt32(size);
181        remote()->transact(ALLOC_BUFFER, data, &reply);
182
183        status_t err = reply.readInt32();
184        if (err != OK) {
185            *buffer = 0;
186
187            return err;
188        }
189
190        *buffer = readVoidStar(&reply);
191
192        return err;
193    }
194
195    virtual status_t allocate_buffer_with_backup(
196            node_id node, OMX_U32 port_index, const sp<IMemory> &params,
197            buffer_id *buffer) {
198        Parcel data, reply;
199        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
200        writeVoidStar(node, &data);
201        data.writeInt32(port_index);
202        data.writeStrongBinder(params->asBinder());
203        remote()->transact(ALLOC_BUFFER_WITH_BACKUP, data, &reply);
204
205        status_t err = reply.readInt32();
206        if (err != OK) {
207            *buffer = 0;
208
209            return err;
210        }
211
212        *buffer = readVoidStar(&reply);
213
214        return err;
215    }
216
217    virtual status_t free_buffer(
218            node_id node, OMX_U32 port_index, buffer_id buffer) {
219        Parcel data, reply;
220        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
221        writeVoidStar(node, &data);
222        data.writeInt32(port_index);
223        writeVoidStar(buffer, &data);
224        remote()->transact(FREE_BUFFER, data, &reply);
225
226        return reply.readInt32();
227    }
228
229#if !IOMX_USES_SOCKETS
230    virtual status_t observe_node(
231            node_id node, const sp<IOMXObserver> &observer) {
232        Parcel data, reply;
233        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
234        writeVoidStar(node, &data);
235        data.writeStrongBinder(observer->asBinder());
236        remote()->transact(OBSERVE_NODE, data, &reply);
237
238        return reply.readInt32();
239    }
240
241    virtual void fill_buffer(node_id node, buffer_id buffer) {
242        Parcel data, reply;
243        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
244        writeVoidStar(node, &data);
245        writeVoidStar(buffer, &data);
246        remote()->transact(FILL_BUFFER, data, &reply, IBinder::FLAG_ONEWAY);
247    }
248
249    virtual void empty_buffer(
250            node_id node,
251            buffer_id buffer,
252            OMX_U32 range_offset, OMX_U32 range_length,
253            OMX_U32 flags, OMX_TICKS timestamp) {
254        Parcel data, reply;
255        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
256        writeVoidStar(node, &data);
257        writeVoidStar(buffer, &data);
258        data.writeInt32(range_offset);
259        data.writeInt32(range_length);
260        data.writeInt32(flags);
261        data.writeInt64(timestamp);
262        remote()->transact(EMPTY_BUFFER, data, &reply, IBinder::FLAG_ONEWAY);
263    }
264#endif
265};
266
267IMPLEMENT_META_INTERFACE(OMX, "android.hardware.IOMX");
268
269////////////////////////////////////////////////////////////////////////////////
270
271#define CHECK_INTERFACE(interface, data, reply) \
272        do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
273            LOGW("Call incorrectly routed to " #interface); \
274            return PERMISSION_DENIED; \
275        } } while (0)
276
277status_t BnOMX::onTransact(
278    uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) {
279    switch (code) {
280#if IOMX_USES_SOCKETS
281        case CONNECT:
282        {
283            CHECK_INTERFACE(IOMX, data, reply);
284
285            int s;
286            status_t err = connect(&s);
287
288            reply->writeInt32(err);
289            if (err == OK) {
290                assert(s >= 0);
291                reply->writeDupFileDescriptor(s);
292                close(s);
293                s = -1;
294            } else {
295                assert(s == -1);
296            }
297
298            return NO_ERROR;
299        }
300#endif
301
302        case LIST_NODES:
303        {
304            CHECK_INTERFACE(IOMX, data, reply);
305
306            List<String8> list;
307            list_nodes(&list);
308
309            reply->writeInt32(list.size());
310            for (List<String8>::iterator it = list.begin();
311                 it != list.end(); ++it) {
312                reply->writeString8(*it);
313            }
314
315            return NO_ERROR;
316        }
317
318        case ALLOCATE_NODE:
319        {
320            CHECK_INTERFACE(IOMX, data, reply);
321
322            node_id node;
323            status_t err = allocate_node(data.readCString(), &node);
324            reply->writeInt32(err);
325            if (err == OK) {
326                writeVoidStar(node, reply);
327            }
328
329            return NO_ERROR;
330        }
331
332        case FREE_NODE:
333        {
334            CHECK_INTERFACE(IOMX, data, reply);
335
336            node_id node = readVoidStar(&data);
337
338            reply->writeInt32(free_node(node));
339
340            return NO_ERROR;
341        }
342
343        case SEND_COMMAND:
344        {
345            CHECK_INTERFACE(IOMX, data, reply);
346
347            node_id node = readVoidStar(&data);
348
349            OMX_COMMANDTYPE cmd =
350                static_cast<OMX_COMMANDTYPE>(data.readInt32());
351
352            OMX_S32 param = data.readInt32();
353            reply->writeInt32(send_command(node, cmd, param));
354
355            return NO_ERROR;
356        }
357
358        case GET_PARAMETER:
359        {
360            CHECK_INTERFACE(IOMX, data, reply);
361
362            node_id node = readVoidStar(&data);
363            OMX_INDEXTYPE index = static_cast<OMX_INDEXTYPE>(data.readInt32());
364
365            size_t size = data.readInt32();
366
367            // XXX I am not happy with this but Parcel::readInplace didn't work.
368            void *params = malloc(size);
369            data.read(params, size);
370
371            status_t err = get_parameter(node, index, params, size);
372
373            reply->writeInt32(err);
374
375            if (err == OK) {
376                reply->write(params, size);
377            }
378
379            free(params);
380            params = NULL;
381
382            return NO_ERROR;
383        }
384
385        case SET_PARAMETER:
386        {
387            CHECK_INTERFACE(IOMX, data, reply);
388
389            node_id node = readVoidStar(&data);
390            OMX_INDEXTYPE index = static_cast<OMX_INDEXTYPE>(data.readInt32());
391
392            size_t size = data.readInt32();
393            void *params = const_cast<void *>(data.readInplace(size));
394
395            reply->writeInt32(set_parameter(node, index, params, size));
396
397            return NO_ERROR;
398        }
399
400        case USE_BUFFER:
401        {
402            CHECK_INTERFACE(IOMX, data, reply);
403
404            node_id node = readVoidStar(&data);
405            OMX_U32 port_index = data.readInt32();
406            sp<IMemory> params =
407                interface_cast<IMemory>(data.readStrongBinder());
408
409            buffer_id buffer;
410            status_t err = use_buffer(node, port_index, params, &buffer);
411            reply->writeInt32(err);
412
413            if (err == OK) {
414                writeVoidStar(buffer, reply);
415            }
416
417            return NO_ERROR;
418        }
419
420        case ALLOC_BUFFER:
421        {
422            CHECK_INTERFACE(IOMX, data, reply);
423
424            node_id node = readVoidStar(&data);
425            OMX_U32 port_index = data.readInt32();
426            size_t size = data.readInt32();
427
428            buffer_id buffer;
429            status_t err = allocate_buffer(node, port_index, size, &buffer);
430            reply->writeInt32(err);
431
432            if (err == OK) {
433                writeVoidStar(buffer, reply);
434            }
435
436            return NO_ERROR;
437        }
438
439        case ALLOC_BUFFER_WITH_BACKUP:
440        {
441            CHECK_INTERFACE(IOMX, data, reply);
442
443            node_id node = readVoidStar(&data);
444            OMX_U32 port_index = data.readInt32();
445            sp<IMemory> params =
446                interface_cast<IMemory>(data.readStrongBinder());
447
448            buffer_id buffer;
449            status_t err = allocate_buffer_with_backup(
450                    node, port_index, params, &buffer);
451
452            reply->writeInt32(err);
453
454            if (err == OK) {
455                writeVoidStar(buffer, reply);
456            }
457
458            return NO_ERROR;
459        }
460
461        case FREE_BUFFER:
462        {
463            CHECK_INTERFACE(IOMX, data, reply);
464
465            node_id node = readVoidStar(&data);
466            OMX_U32 port_index = data.readInt32();
467            buffer_id buffer = readVoidStar(&data);
468            reply->writeInt32(free_buffer(node, port_index, buffer));
469
470            return NO_ERROR;
471        }
472
473#if !IOMX_USES_SOCKETS
474        case OBSERVE_NODE:
475        {
476            CHECK_INTERFACE(IOMX, data, reply);
477
478            node_id node = readVoidStar(&data);
479            sp<IOMXObserver> observer =
480                interface_cast<IOMXObserver>(data.readStrongBinder());
481            reply->writeInt32(observe_node(node, observer));
482
483            return NO_ERROR;
484        }
485
486        case FILL_BUFFER:
487        {
488            CHECK_INTERFACE(IOMX, data, reply);
489
490            node_id node = readVoidStar(&data);
491            buffer_id buffer = readVoidStar(&data);
492            fill_buffer(node, buffer);
493
494            return NO_ERROR;
495        }
496
497        case EMPTY_BUFFER:
498        {
499            CHECK_INTERFACE(IOMX, data, reply);
500
501            node_id node = readVoidStar(&data);
502            buffer_id buffer = readVoidStar(&data);
503            OMX_U32 range_offset = data.readInt32();
504            OMX_U32 range_length = data.readInt32();
505            OMX_U32 flags = data.readInt32();
506            OMX_TICKS timestamp = data.readInt64();
507
508            empty_buffer(
509                    node, buffer, range_offset, range_length,
510                    flags, timestamp);
511
512            return NO_ERROR;
513        }
514#endif
515
516        default:
517            return BBinder::onTransact(code, data, reply, flags);
518    }
519}
520
521////////////////////////////////////////////////////////////////////////////////
522
523class BpOMXObserver : public BpInterface<IOMXObserver> {
524public:
525    BpOMXObserver(const sp<IBinder> &impl)
526        : BpInterface<IOMXObserver>(impl) {
527    }
528
529    virtual void on_message(const omx_message &msg) {
530        Parcel data, reply;
531        data.writeInterfaceToken(IOMXObserver::getInterfaceDescriptor());
532        data.write(&msg, sizeof(msg));
533
534        remote()->transact(OBSERVER_ON_MSG, data, &reply, IBinder::FLAG_ONEWAY);
535    }
536};
537
538IMPLEMENT_META_INTERFACE(OMXObserver, "android.hardware.IOMXObserver");
539
540status_t BnOMXObserver::onTransact(
541    uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) {
542    switch (code) {
543        case OBSERVER_ON_MSG:
544        {
545            CHECK_INTERFACE(IOMXObserver, data, reply);
546
547            omx_message msg;
548            data.read(&msg, sizeof(msg));
549
550            // XXX Could use readInplace maybe?
551            on_message(msg);
552
553            return NO_ERROR;
554        }
555
556        default:
557            return BBinder::onTransact(code, data, reply, flags);
558    }
559}
560
561}  // namespace android
562