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> ¶ms, 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> ¶ms, 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