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