status_t BnMcuService::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { ALOGI("BnMcuService::onTransact, code[%d]", code); switch (code) { case GET_TEST: { CHECK_INTERFACE(IMcuService, data, reply); int result = getTest(); reply->writeInt32(result); return NO_ERROR; } break; case obtain_info: { CHECK_INTERFACE(IMcuService, data, reply); int domain = data.readInt32(); int cmd = data.readInt32(); Parcel out; bool res = obtainInfo(domain, cmd, out); reply->appendFrom(&out, 0, out.dataSize()); reply->writeInt32(res?1:0); out.freeData(); return NO_ERROR; } break; case send_info: { CHECK_INTERFACE(IMcuService, data, reply); int domain = data.readInt32(); int cmd = data.readInt32(); Parcel in; if(data.dataAvail() >0) { in.appendFrom(&data, data.dataPosition(), data.dataSize()-data.dataPosition()); in.setDataPosition(0); } bool res = sendInfo(domain, cmd, in); reply->writeInt32(res?1:0); in.freeData(); return NO_ERROR; } break; case regist_data_changed_listener: { CHECK_INTERFACE(IMcuService, data, reply); int domain = data.readInt32(); sp<IDataChangedListener> client = interface_cast<IDataChangedListener>(data.readStrongBinder()); bool res = registDataChanagedListener(domain, client); reply->writeInt32((res?1:0)); return NO_ERROR; } break; case unregist_data_changed_listener: { CHECK_INTERFACE(IMcuService, data, reply); int domain = data.readInt32(); sp<IDataChangedListener> client = interface_cast<IDataChangedListener>(data.readStrongBinder()); bool res = unregistDataChanagedListener(domain, client); reply->writeInt32((res?1:0)); return NO_ERROR; } break; default: return BBinder::onTransact(code, data, reply, flags); } }
status_t Status::readFromParcel(const Parcel& parcel) { status_t status = parcel.readInt32(&mException); if (status != OK) { setFromStatusT(status); return status; } // Skip over fat response headers. Not used (or propagated) in native code. if (mException == EX_HAS_REPLY_HEADER) { // Note that the header size includes the 4 byte size field. const int32_t header_start = parcel.dataPosition(); int32_t header_size; status = parcel.readInt32(&header_size); if (status != OK) { setFromStatusT(status); return status; } parcel.setDataPosition(header_start + header_size); // And fat response headers are currently only used when there are no // exceptions, so act like there was no error. mException = EX_NONE; } if (mException == EX_NONE) { return status; } // The remote threw an exception. Get the message back. String16 message; status = parcel.readString16(&message); if (status != OK) { setFromStatusT(status); return status; } mMessage = String8(message); if (mException == EX_SERVICE_SPECIFIC) { status = parcel.readInt32(&mErrorCode); } else if (mException == EX_PARCELABLE) { // Skip over the blob of Parcelable data const int32_t header_start = parcel.dataPosition(); int32_t header_size; status = parcel.readInt32(&header_size); if (status != OK) { setFromStatusT(status); return status; } parcel.setDataPosition(header_start + header_size); } if (status != OK) { setFromStatusT(status); return status; } return status; }
/** * Go over all the records, collecting metadata keys and records' * type field offset in the Parcel. These are stored in * mKeyToPosMap for latter retrieval. * Format of a metadata record: <pre> 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | record size | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | metadata key | // TITLE +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | metadata type | // STRING_VAL +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | | .... metadata payload .... | | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ </pre> * @param parcel With the serialized records. * @param bytesLeft How many bytes in the parcel should be processed. * @return false if an error occurred during parsing. */ bool CedarMetadata::scanAllRecords(Parcel& parcel, int bytesLeft) { int recCount = 0; bool error = false; mKeyToPosMap.clear(); while (bytesLeft > kRecordHeaderSize) { const int start = parcel.dataPosition(); const int size = parcel.readInt32(); if (size <= kRecordHeaderSize) { // at least 1 byte should be present. ALOGE("Record is too short"); error = true; break; } // Check the metadata key. static int metadataId = parcel.readInt32(); if (!checkMetadataId(metadataId)) { error = true; break; } // Store the record offset which points to the type // field so we can later on read/unmarshall the record // payload. if (mKeyToPosMap.indexOfKey(metadataId) >= 0) { ALOGE("Duplicate metadata ID found"); error = true; break; } mKeyToPosMap.add(metadataId, parcel.dataPosition()); // Check the metadata type. const int metadataType = parcel.readInt32(); if (metadataType <= 0 || metadataType > LAST_TYPE) { ALOGE("Invalid metadata type %d", metadataType); error = true; break; } // Skip to the next one. parcel.setDataPosition(start + size); bytesLeft -= size; ++recCount; } if (0 != bytesLeft || error) { ALOGE("Ran out of data or error on record %d", recCount); mKeyToPosMap.clear(); return false; } else { return true; } }
status_t BnHDCPObserver::onTransact( uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) { switch (code) { case OBSERVER_NOTIFY: { CHECK_INTERFACE(IHDCPObserver, data, reply); int msg = data.readInt32(); int ext1 = data.readInt32(); int ext2 = data.readInt32(); Parcel obj; if (data.dataAvail() > 0) { obj.appendFrom( const_cast<Parcel *>(&data), data.dataPosition(), data.dataAvail()); } notify(msg, ext1, ext2, &obj); return OK; } default: return BBinder::onTransact(code, data, reply, flags); } }
// Test SharedRegionParcel. TEST(test_marshalling, aaudio_shared_region) { SharedMemoryParcelable sharedMemories[2]; SharedRegionParcelable sharedRegionA; SharedRegionParcelable sharedRegionB; const size_t memSizeBytes = 840; unique_fd fd(ashmem_create_region("TestMarshalling", memSizeBytes)); ASSERT_LE(0, fd); sharedMemories[0].setup(fd, memSizeBytes); int32_t regionOffset1 = 32; int32_t regionSize1 = 16; sharedRegionA.setup(0, regionOffset1, regionSize1); void *region1; EXPECT_EQ(AAUDIO_OK, sharedRegionA.resolve(sharedMemories, ®ion1)); int32_t *buffer1 = (int32_t *)region1; buffer1[0] = 336677; // arbitrary value Parcel parcel; size_t pos = parcel.dataPosition(); sharedRegionA.writeToParcel(&parcel); parcel.setDataPosition(pos); sharedRegionB.readFromParcel(&parcel); // should see same value void *region2; EXPECT_EQ(AAUDIO_OK, sharedRegionB.resolve(sharedMemories, ®ion2)); int32_t *buffer2 = (int32_t *)region2; EXPECT_EQ(buffer1[0], buffer2[0]); }
// Test SharedMemoryParcel. TEST(test_marshalling, aaudio_shared_memory) { SharedMemoryParcelable sharedMemoryA; SharedMemoryParcelable sharedMemoryB; const size_t memSizeBytes = 840; unique_fd fd(ashmem_create_region("TestMarshalling", memSizeBytes)); ASSERT_LE(0, fd); sharedMemoryA.setup(fd, memSizeBytes); void *region1; EXPECT_EQ(AAUDIO_OK, sharedMemoryA.resolve(0, 16, ®ion1)); // fits in region EXPECT_NE(AAUDIO_OK, sharedMemoryA.resolve(-2, 16, ®ion1)); // offset is negative EXPECT_NE(AAUDIO_OK, sharedMemoryA.resolve(0, memSizeBytes + 8, ®ion1)); // size too big EXPECT_NE(AAUDIO_OK, sharedMemoryA.resolve(memSizeBytes - 8, 16, ®ion1)); // goes past the end int32_t *buffer1 = (int32_t *)region1; buffer1[0] = 98735; // arbitrary value Parcel parcel; size_t pos = parcel.dataPosition(); sharedMemoryA.writeToParcel(&parcel); parcel.setDataPosition(pos); sharedMemoryB.readFromParcel(&parcel); EXPECT_EQ(sharedMemoryA.getSizeInBytes(), sharedMemoryB.getSizeInBytes()); // should see same value at two different addresses void *region2; EXPECT_EQ(AAUDIO_OK, sharedMemoryB.resolve(0, 16, ®ion2)); int32_t *buffer2 = (int32_t *)region2; EXPECT_NE(buffer1, buffer2); EXPECT_EQ(buffer1[0], buffer2[0]); }
/** * Check a parcel containing metadata is well formed. The header * is checked as well as the individual records format. However, the * data inside the record is not checked because we do lazy access * (we check/unmarshall only data the user asks for.) * * Format of a metadata parcel: <pre> 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | metadata total size | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 'M' | 'E' | 'T' | 'A' | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | | .... metadata records .... | | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ </pre> * * @param parcel With the serialized data. Metadata keeps a * reference on it to access it later on. The caller * should not modify the parcel after this call (and * not call recycle on it.) * @return false if an error occurred. */ bool CedarMetadata::parse(Parcel& parcel) { if (parcel.dataAvail() < (size_t)kMetaHeaderSize) { ALOGE("Not enough data %d", parcel.dataAvail()); return false; } const int pin = parcel.dataPosition(); // to roll back in case of errors. const int size = parcel.readInt32(); // The extra kInt32Size below is to account for the int32 'size' just read. if (parcel.dataAvail() + kInt32Size < (size_t)size || size < kMetaHeaderSize) { ALOGE("Bad size %d avail %d position %d", size, parcel.dataAvail(), pin); parcel.setDataPosition(pin); return false; } // Checks if the 'M' 'E' 'T' 'A' marker is present. const int kShouldBeMetaMarker = parcel.readInt32(); if (kShouldBeMetaMarker != kMetaMarker ) { ALOGE("Marker missing"); parcel.setDataPosition(pin); return false; } // Scan the records to collect metadata ids and offsets. if (!scanAllRecords(parcel, size - kMetaHeaderSize)) { parcel.setDataPosition(pin); return false; } mParcel = &parcel; return true; }
// Test RingBufferParcelable. TEST(test_marshalling, aaudio_ring_buffer_parcelable) { SharedMemoryParcelable sharedMemories[2]; RingBufferParcelable ringBufferA; RingBufferParcelable ringBufferB; const size_t bytesPerFrame = 8; const size_t framesPerBurst = 32; const size_t dataSizeBytes = 2048; const int32_t counterSizeBytes = sizeof(int64_t); const size_t memSizeBytes = dataSizeBytes + (2 * counterSizeBytes); unique_fd fd(ashmem_create_region("TestMarshalling Z", memSizeBytes)); ASSERT_LE(0, fd); sharedMemories[0].setup(fd, memSizeBytes); int32_t sharedMemoryIndex = 0; // arrange indices and data in the shared memory int32_t readOffset = 0; int32_t writeOffset = readOffset + counterSizeBytes; int32_t dataOffset = writeOffset + counterSizeBytes; ringBufferA.setupMemory(sharedMemoryIndex, dataOffset, dataSizeBytes, readOffset, writeOffset, counterSizeBytes); ringBufferA.setFramesPerBurst(framesPerBurst); ringBufferA.setBytesPerFrame(bytesPerFrame); ringBufferA.setCapacityInFrames(dataSizeBytes / bytesPerFrame); // setup A RingBufferDescriptor descriptorA; EXPECT_EQ(AAUDIO_OK, ringBufferA.resolve(sharedMemories, &descriptorA)); descriptorA.dataAddress[0] = 95; descriptorA.dataAddress[1] = 57; descriptorA.readCounterAddress[0] = 17; descriptorA.writeCounterAddress[0] = 39; // write A to parcel Parcel parcel; size_t pos = parcel.dataPosition(); ringBufferA.writeToParcel(&parcel); // read B from parcel parcel.setDataPosition(pos); ringBufferB.readFromParcel(&parcel); RingBufferDescriptor descriptorB; EXPECT_EQ(AAUDIO_OK, ringBufferB.resolve(sharedMemories, &descriptorB)); // A and B should match EXPECT_EQ(descriptorA.dataAddress[0], descriptorB.dataAddress[0]); EXPECT_EQ(descriptorA.dataAddress[1], descriptorB.dataAddress[1]); EXPECT_EQ(descriptorA.readCounterAddress[0], descriptorB.readCounterAddress[0]); EXPECT_EQ(descriptorA.writeCounterAddress[0], descriptorB.writeCounterAddress[0]); EXPECT_EQ(ringBufferA.getFramesPerBurst(), ringBufferB.getFramesPerBurst()); EXPECT_EQ(ringBufferA.getBytesPerFrame(), ringBufferB.getBytesPerFrame()); EXPECT_EQ(ringBufferA.getCapacityInFrames(), ringBufferB.getCapacityInFrames()); }
// Test adding one value. TEST(test_marshalling, aaudio_one_read_write) { Parcel parcel; size_t pos = parcel.dataPosition(); const int arbitraryValue = 235; parcel.writeInt32(arbitraryValue); parcel.setDataPosition(pos); int32_t y; parcel.readInt32(&y); EXPECT_EQ(arbitraryValue, y); }
/* * packRILcommandString * Used for packing standard AT command string to RIL command. * * IN *inStr : AT command string with NULL terminate * IN *prefix : prefix of AT response * OUT **outCmd : RAW RIL command out. Caller is responsible to free this resource. * RETUURN : Length of outCmd data. */ size_t packRILCommand(char *inStr, char *prefix, char **outCmd) { /* |Request Enum |Request Token|Number of Strings|Srings.....| * |<--4 bytes-->|<--4 bytes-->|<--- 4 bytes --->|<------ ->| */ size_t length = 0; char *cmdStr[2] = {NULL,NULL}; char *pData = NULL; Parcel p; static int s_token = 0; if ((NULL == inStr)||(NULL == outCmd)) { return 0; } cmdStr[0] = inStr; cmdStr[1] = prefix; // p.writeInt32(length); /* fake write to reserve space */ p.writeInt32(RIL_REQUEST_OEM_HOOK_STRINGS); p.writeInt32(s_token++); packStrings(p,cmdStr,2*sizeof(char *)); /* ONLY support 1 string now */ length = p.dataSize(); #if 0 offset = p.dataPosition(); /* Store data position */ p.setDataPosition(0); /* Move to the buffer pointer to head */ p.writeInt32(length - 4); /* Update data length */ p.setDataPosition(offset); /* Restore data position */ #endif /* 0 */ pData = (char *) malloc(length); if (NULL != pData) { memcpy(pData,p.data(),length); *outCmd = pData; LOGI("packRILCommand: %d bytes\n",length); printRawData((const void *) pData, length); } else { return 0; } return length; }
status_t BnListenReceiver::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { switch (code) { case NOTIFY: { ALOGI("BnListenReceiver::onTransact received NOTIFY"); CHECK_INTERFACE(IListenReceiver, data, reply); int msg = data.readInt32(); Parcel obj; if (data.dataAvail() > 0) { ALOGI("append %d bytes available at pos %d", data.dataAvail(), data.dataPosition()); obj.appendFrom(const_cast<Parcel *>(&data), data.dataPosition(), data.dataAvail()); } notify(msg, &obj); return NO_ERROR; } break; default: ALOGI("BnListenReceiver::onTransact received unknown msg %d", code); return BBinder::onTransact(code, data, reply, flags); } }
status_t BnDrmClient::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { switch (code) { case NOTIFY: { CHECK_INTERFACE(IDrmClient, data, reply); int eventType = data.readInt32(); int extra = data.readInt32(); Parcel obj; if (data.dataAvail() > 0) { obj.appendFrom(const_cast<Parcel *>(&data), data.dataPosition(), data.dataAvail()); } notify((DrmPlugin::EventType)eventType, extra, &obj); return NO_ERROR; } break; default: return BBinder::onTransact(code, data, reply, flags); } }
status_t BnMediaPlayerClient::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { switch (code) { case NOTIFY: { CHECK_INTERFACE(IMediaPlayerClient, data, reply); int msg = data.readInt32(); int ext1 = data.readInt32(); int ext2 = data.readInt32(); Parcel obj; if (data.dataAvail() > 0) { obj.appendFrom(const_cast<Parcel *>(&data), data.dataPosition(), data.dataAvail()); } notify(msg, ext1, ext2, &obj); return NO_ERROR; } break; default: return BBinder::onTransact(code, data, reply, flags); } }
static jint android_os_Parcel_dataPosition(JNIEnv* env, jclass clazz, jlong nativePtr) { Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr); return parcel ? parcel->dataPosition() : 0; }
status_t BnMediaPlayer::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { switch(code) { case DISCONNECT: { CHECK_INTERFACE(IMediaPlayer, data, reply); disconnect(); return NO_ERROR; } break; case SET_DATA_SOURCE_URL: { CHECK_INTERFACE(IMediaPlayer, data, reply); const char* url = data.readCString(); KeyedVector<String8, String8> headers; int32_t numHeaders = data.readInt32(); for (int i = 0; i < numHeaders; ++i) { String8 key = data.readString8(); String8 value = data.readString8(); headers.add(key, value); } reply->writeInt32(setDataSource(url, numHeaders > 0 ? &headers : NULL)); return NO_ERROR; } break; case SET_DATA_SOURCE_FD: { CHECK_INTERFACE(IMediaPlayer, data, reply); int fd = data.readFileDescriptor(); int64_t offset = data.readInt64(); int64_t length = data.readInt64(); reply->writeInt32(setDataSource(fd, offset, length)); return NO_ERROR; } case SET_DATA_SOURCE_STREAM: { CHECK_INTERFACE(IMediaPlayer, data, reply); sp<IStreamSource> source = interface_cast<IStreamSource>(data.readStrongBinder()); reply->writeInt32(setDataSource(source)); return NO_ERROR; } case SET_VIDEO_SURFACETEXTURE: { CHECK_INTERFACE(IMediaPlayer, data, reply); sp<ISurfaceTexture> surfaceTexture = interface_cast<ISurfaceTexture>(data.readStrongBinder()); reply->writeInt32(setVideoSurfaceTexture(surfaceTexture)); return NO_ERROR; } break; case PREPARE_ASYNC: { CHECK_INTERFACE(IMediaPlayer, data, reply); reply->writeInt32(prepareAsync()); return NO_ERROR; } break; case START: { CHECK_INTERFACE(IMediaPlayer, data, reply); reply->writeInt32(start()); return NO_ERROR; } break; case STOP: { CHECK_INTERFACE(IMediaPlayer, data, reply); reply->writeInt32(stop()); return NO_ERROR; } break; case IS_PLAYING: { CHECK_INTERFACE(IMediaPlayer, data, reply); bool state; status_t ret = isPlaying(&state); reply->writeInt32(state); reply->writeInt32(ret); return NO_ERROR; } break; case PAUSE: { CHECK_INTERFACE(IMediaPlayer, data, reply); reply->writeInt32(pause()); return NO_ERROR; } break; case SEEK_TO: { CHECK_INTERFACE(IMediaPlayer, data, reply); reply->writeInt32(seekTo(data.readInt32())); return NO_ERROR; } break; case GET_CURRENT_POSITION: { CHECK_INTERFACE(IMediaPlayer, data, reply); int msec; status_t ret = getCurrentPosition(&msec); reply->writeInt32(msec); reply->writeInt32(ret); return NO_ERROR; } break; case GET_DURATION: { CHECK_INTERFACE(IMediaPlayer, data, reply); int msec; status_t ret = getDuration(&msec); reply->writeInt32(msec); reply->writeInt32(ret); return NO_ERROR; } break; case RESET: { CHECK_INTERFACE(IMediaPlayer, data, reply); reply->writeInt32(reset()); return NO_ERROR; } break; case SET_AUDIO_STREAM_TYPE: { CHECK_INTERFACE(IMediaPlayer, data, reply); reply->writeInt32(setAudioStreamType(data.readInt32())); return NO_ERROR; } break; case SET_LOOPING: { CHECK_INTERFACE(IMediaPlayer, data, reply); reply->writeInt32(setLooping(data.readInt32())); return NO_ERROR; } break; case SET_VOLUME: { CHECK_INTERFACE(IMediaPlayer, data, reply); float leftVolume = data.readFloat(); float rightVolume = data.readFloat(); reply->writeInt32(setVolume(leftVolume, rightVolume)); return NO_ERROR; } break; case INVOKE: { CHECK_INTERFACE(IMediaPlayer, data, reply); status_t result = invoke(data, reply); return result; } break; case SET_METADATA_FILTER: { CHECK_INTERFACE(IMediaPlayer, data, reply); reply->writeInt32(setMetadataFilter(data)); return NO_ERROR; } break; case GET_METADATA: { CHECK_INTERFACE(IMediaPlayer, data, reply); bool update_only = static_cast<bool>(data.readInt32()); bool apply_filter = static_cast<bool>(data.readInt32()); const status_t retcode = getMetadata(update_only, apply_filter, reply); reply->setDataPosition(0); reply->writeInt32(retcode); reply->setDataPosition(0); return NO_ERROR; } break; case SET_AUX_EFFECT_SEND_LEVEL: { CHECK_INTERFACE(IMediaPlayer, data, reply); reply->writeInt32(setAuxEffectSendLevel(data.readFloat())); return NO_ERROR; } break; case ATTACH_AUX_EFFECT: { CHECK_INTERFACE(IMediaPlayer, data, reply); reply->writeInt32(attachAuxEffect(data.readInt32())); return NO_ERROR; } break; case SET_PARAMETER: { CHECK_INTERFACE(IMediaPlayer, data, reply); int key = data.readInt32(); Parcel request; if (data.dataAvail() > 0) { request.appendFrom( const_cast<Parcel *>(&data), data.dataPosition(), data.dataAvail()); } request.setDataPosition(0); reply->writeInt32(setParameter(key, request)); return NO_ERROR; } break; case GET_PARAMETER: { CHECK_INTERFACE(IMediaPlayer, data, reply); return getParameter(data.readInt32(), reply); } break; default: return BBinder::onTransact(code, data, reply, flags); } }