void GPUHardware::binderDied(const wp<IBinder>& who) { Mutex::Autolock _l(mLock); pid_t pid = mRegisteredClients.valueFor(who); if (pid != 0) { ssize_t index = mClients.indexOfKey(pid); if (index >= 0) { //LOGD("*** removing client at %d", index); Client& client(mClients.editValueAt(index)); client.revokeAllHeaps(); // not really needed in theory mClients.removeItemsAt(index); if (mClients.size() == 0) { //LOGD("*** was last client closing everything"); mCallback.clear(); mAllocator.clear(); mCurrentAllocator.clear(); mSMIHeap.clear(); mREGHeap.clear(); // NOTE: we cannot clear the EBI heap because surfaceflinger // itself may be using it, since this is where surfaces // are allocated. if we're in the middle of compositing // a surface (even if its process just died), we cannot // rip the heap under our feet. mOwner = NO_OWNER; } } } }
status_t MediaHTTP::connect( const char *uri, const KeyedVector<String8, String8> *headers, off64_t /* offset */) { if (mInitCheck != OK) { return mInitCheck; } KeyedVector<String8, String8> extHeaders; if (headers != NULL) { extHeaders = *headers; } if (extHeaders.indexOfKey(String8("User-Agent")) < 0) { extHeaders.add(String8("User-Agent"), String8(MakeUserAgent().c_str())); } bool success = mHTTPConnection->connect(uri, &extHeaders); mLastHeaders = extHeaders; mLastURI = uri; mCachedSizeValid = false; return success ? OK : UNKNOWN_ERROR; }
static AString codecResultsToXml(const KeyedVector<AString, CodecSettings> &results) { AString ret; for (size_t i = 0; i < results.size(); ++i) { AString name; AString mime; if (!splitString(results.keyAt(i), " ", &name, &mime)) { continue; } AString codec = AStringPrintf(" <MediaCodec name=\"%s\" type=\"%s\" update=\"true\" >\n", name.c_str(), mime.c_str()); ret.append(codec); const CodecSettings &settings = results.valueAt(i); for (size_t i = 0; i < settings.size(); ++i) { // WARNING: we assume all the settings are "Limit". Currently we have only one type // of setting in this case, which is "max-supported-instances". AString setting = AStringPrintf( " <Limit name=\"%s\" value=\"%s\" />\n", settings.keyAt(i).c_str(), settings.valueAt(i).c_str()); ret.append(setting); } ret.append(" </MediaCodec>\n"); } return ret; }
KeyedVector<uint16_t, const TagDefinition_t*> TiffWriter::buildTagMap( const TagDefinition_t* definitions, size_t length) { KeyedVector<uint16_t, const TagDefinition_t*> map; for(size_t i = 0; i < length; ++i) { map.add(definitions[i].tagId, definitions + i); } return map; }
sp<IMemoryHeap> HeapCache::get_heap(const sp<IBinder>& binder) { sp<IMemoryHeap> realHeap; Mutex::Autolock _l(mHeapCacheLock); ssize_t i = mHeapCache.indexOfKey(binder); if (i>=0) realHeap = mHeapCache.valueAt(i).heap; else realHeap = interface_cast<IMemoryHeap>(binder); return realHeap; }
void HeapCache::pin_heap(const sp<IBinder>& binder) { Mutex::Autolock _l(mHeapCacheLock); ssize_t i = mHeapCache.indexOfKey(binder); if (i>=0) { heap_info_t& info(mHeapCache.editValueAt(i)); android_atomic_inc(&info.count); binder->linkToDeath(this); } else { LOGE("pin_heap binder=%p not found!!!", binder.get()); } }
status_t NativeInputEventSender::receiveFinishedSignals(JNIEnv* env) { if (kDebugDispatchCycle) { ALOGD("channel '%s' ~ Receiving finished signals.", getInputChannelName()); } ScopedLocalRef<jobject> senderObj(env, NULL); bool skipCallbacks = false; for (;;) { uint32_t publishedSeq; bool handled; status_t status = mInputPublisher.receiveFinishedSignal(&publishedSeq, &handled); if (status) { if (status == WOULD_BLOCK) { return OK; } ALOGE("channel '%s' ~ Failed to consume finished signals. status=%d", getInputChannelName(), status); return status; } ssize_t index = mPublishedSeqMap.indexOfKey(publishedSeq); if (index >= 0) { uint32_t seq = mPublishedSeqMap.valueAt(index); mPublishedSeqMap.removeItemsAt(index); if (kDebugDispatchCycle) { ALOGD("channel '%s' ~ Received finished signal, seq=%u, handled=%s, " "pendingEvents=%zu.", getInputChannelName(), seq, handled ? "true" : "false", mPublishedSeqMap.size()); } if (!skipCallbacks) { if (!senderObj.get()) { senderObj.reset(jniGetReferent(env, mSenderWeakGlobal)); if (!senderObj.get()) { ALOGW("channel '%s' ~ Sender object was finalized " "without being disposed.", getInputChannelName()); return DEAD_OBJECT; } } env->CallVoidMethod(senderObj.get(), gInputEventSenderClassInfo.dispatchInputEventFinished, jint(seq), jboolean(handled)); if (env->ExceptionCheck()) { ALOGE("Exception dispatching finished signal."); skipCallbacks = true; } } } } }
static jobject KeyedVectorToHashMap (JNIEnv *env, KeyedVector<String8, String8> const &map) { jclass clazz = gFields.hashmapClassId; jobject hashMap = env->NewObject(clazz, gFields.hashmap.init); for (size_t i = 0; i < map.size(); ++i) { jstring jkey = env->NewStringUTF(map.keyAt(i).string()); jstring jvalue = env->NewStringUTF(map.valueAt(i).string()); env->CallObjectMethod(hashMap, gFields.hashmap.put, jkey, jvalue); env->DeleteLocalRef(jkey); env->DeleteLocalRef(jvalue); } return hashMap; }
static void android_media_MediaMetadataRetriever_setDataSourceAndHeaders( JNIEnv *env, jobject thiz, jstring path, jobjectArray keys, jobjectArray values) { ALOGV("setDataSource Path"); MediaMetadataRetriever* retriever = getRetriever(env, thiz); if (retriever == 0) { jniThrowException( env, "java/lang/IllegalStateException", "No retriever available"); return; } if (!path) { jniThrowException( env, "java/lang/IllegalArgumentException", "Null pointer"); return; } const char *tmp = env->GetStringUTFChars(path, NULL); if (!tmp) { // OutOfMemoryError exception already thrown return; } String8 pathStr(tmp); env->ReleaseStringUTFChars(path, tmp); tmp = NULL; // Don't let somebody trick us in to reading some random block of memory if (strncmp("mem://", pathStr.string(), 6) == 0) { jniThrowException( env, "java/lang/IllegalArgumentException", "Invalid pathname"); return; } // We build a similar KeyedVector out of it. KeyedVector<String8, String8> headersVector; if (!ConvertKeyValueArraysToKeyedVector( env, keys, values, &headersVector)) { return; } process_media_retriever_call( env, retriever->setDataSource( pathStr.string(), headersVector.size() > 0 ? &headersVector : NULL), "java/lang/RuntimeException", "setDataSource failed"); }
void HeapCache::dump_heaps() { Mutex::Autolock _l(mHeapCacheLock); int c = mHeapCache.size(); for (int i=0 ; i<c ; i++) { const heap_info_t& info = mHeapCache.valueAt(i); BpMemoryHeap const* h(static_cast<BpMemoryHeap const *>(info.heap.get())); ALOGD("hey=%p, heap=%p, count=%d, (fd=%d, base=%p, size=%d)", mHeapCache.keyAt(i).unsafe_get(), info.heap.get(), info.count, h->mHeapId, h->mBase, h->mSize); } }
EXPORT media_status_t AMediaDrm_getKeyRequest(AMediaDrm *mObj, const AMediaDrmScope *scope, const uint8_t *init, size_t initSize, const char *mimeType, AMediaDrmKeyType keyType, const AMediaDrmKeyValue *optionalParameters, size_t numOptionalParameters, const uint8_t **keyRequest, size_t *keyRequestSize) { if (!mObj || mObj->mDrm == NULL) { return AMEDIA_ERROR_INVALID_OBJECT; } if (!mimeType || !scope || !keyRequest || !keyRequestSize) { return AMEDIA_ERROR_INVALID_PARAMETER; } List<idvec_t>::iterator iter; if (!findId(mObj, *scope, iter)) { return AMEDIA_DRM_SESSION_NOT_OPENED; } Vector<uint8_t> mdInit; mdInit.appendArray(init, initSize); DrmPlugin::KeyType mdKeyType; switch (keyType) { case KEY_TYPE_STREAMING: mdKeyType = DrmPlugin::kKeyType_Streaming; break; case KEY_TYPE_OFFLINE: mdKeyType = DrmPlugin::kKeyType_Offline; break; case KEY_TYPE_RELEASE: mdKeyType = DrmPlugin::kKeyType_Release; break; default: return AMEDIA_ERROR_INVALID_PARAMETER; } KeyedVector<String8, String8> mdOptionalParameters; for (size_t i = 0; i < numOptionalParameters; i++) { mdOptionalParameters.add(String8(optionalParameters[i].mKey), String8(optionalParameters[i].mValue)); } String8 defaultUrl; status_t status = mObj->mDrm->getKeyRequest(*iter, mdInit, String8(mimeType), mdKeyType, mdOptionalParameters, mObj->mKeyRequest, defaultUrl); if (status != OK) { return translateStatus(status); } else { *keyRequest = mObj->mKeyRequest.array(); *keyRequestSize = mObj->mKeyRequest.size(); } return AMEDIA_OK; }
static KeyedVector<String8, String8> HashMapToKeyedVector( JNIEnv *env, jobject &hashMap, bool* pIsOK) { jclass clazz = gFields.stringClassId; KeyedVector<String8, String8> keyedVector; *pIsOK = true; jobject entrySet = env->CallObjectMethod(hashMap, gFields.hashmap.entrySet); if (entrySet) { jobject iterator = env->CallObjectMethod(entrySet, gFields.set.iterator); if (iterator) { jboolean hasNext = env->CallBooleanMethod(iterator, gFields.iterator.hasNext); while (hasNext) { jobject entry = env->CallObjectMethod(iterator, gFields.iterator.next); if (entry) { jobject obj = env->CallObjectMethod(entry, gFields.entry.getKey); if (obj == NULL || !env->IsInstanceOf(obj, clazz)) { jniThrowException(env, "java/lang/IllegalArgumentException", "HashMap key is not a String"); env->DeleteLocalRef(entry); *pIsOK = false; break; } jstring jkey = static_cast<jstring>(obj); obj = env->CallObjectMethod(entry, gFields.entry.getValue); if (obj == NULL || !env->IsInstanceOf(obj, clazz)) { jniThrowException(env, "java/lang/IllegalArgumentException", "HashMap value is not a String"); env->DeleteLocalRef(entry); *pIsOK = false; break; } jstring jvalue = static_cast<jstring>(obj); String8 key = JStringToString8(env, jkey); String8 value = JStringToString8(env, jvalue); keyedVector.add(key, value); env->DeleteLocalRef(jkey); env->DeleteLocalRef(jvalue); hasNext = env->CallBooleanMethod(iterator, gFields.iterator.hasNext); } env->DeleteLocalRef(entry); } env->DeleteLocalRef(iterator); } env->DeleteLocalRef(entrySet); } return keyedVector; }
static void android_media_MediaPlayer_setDataSourceAndHeaders( JNIEnv *env, jobject thiz, jobject httpServiceBinderObj, jstring path, jobjectArray keys, jobjectArray values) { sp<MediaPlayer> mp = getMediaPlayer(env, thiz); if (mp == NULL ) { jniThrowException(env, "java/lang/IllegalStateException", NULL); return; } if (path == NULL) { jniThrowException(env, "java/lang/IllegalArgumentException", NULL); return; } const char *tmp = env->GetStringUTFChars(path, NULL); if (tmp == NULL) { // Out of memory return; } ALOGV("setDataSource: path %s", tmp); String8 pathStr(tmp); env->ReleaseStringUTFChars(path, tmp); tmp = NULL; // We build a KeyedVector out of the key and val arrays KeyedVector<String8, String8> headersVector; if (!ConvertKeyValueArraysToKeyedVector( env, keys, values, &headersVector)) { return; } sp<IMediaHTTPService> httpService; if (httpServiceBinderObj != NULL) { sp<IBinder> binder = ibinderForJavaObject(env, httpServiceBinderObj); httpService = interface_cast<IMediaHTTPService>(binder); } status_t opStatus = mp->setDataSource( httpService, pathStr, headersVector.size() > 0? &headersVector : NULL); process_media_player_call( env, thiz, opStatus, "java/io/IOException", "setDataSource failed." ); }
GPUHardware::Client& GPUHardware::getClientLocked(pid_t pid) { ssize_t index = mClients.indexOfKey(pid); if (index < 0) { Client client; client.pid = pid; client.smi.heap = mSMIHeap; client.ebi.heap = mEBIHeap; client.reg.heap = mREGHeap; index = mClients.add(pid, client); } Client& client(mClients.editValueAt(index)); client.createClientHeaps(); return client; }
status_t GPUHardware::request(int pid, const sp<IGPUCallback>& callback, ISurfaceComposer::gpu_info_t* gpu) { if (callback == 0) return BAD_VALUE; sp<IMemory> gpuHandle; LOGD("pid %d requesting gpu core (owner = %d)", pid, mOwner); Mutex::Autolock _l(mLock); status_t err = requestLocked(pid); if (err == NO_ERROR) { // it's guaranteed to be there, be construction Client& client = mClients.editValueFor(pid); registerCallbackLocked(callback, client); gpu->count = 2; gpu->regions[0].region = client.smi.map(); gpu->regions[1].region = client.ebi.map(); gpu->regs = client.reg.map(); gpu->regions[0].reserved = 0; gpu->regions[1].reserved = GPU_RESERVED_SIZE; if (gpu->regs != 0) { //LOGD("gpu core granted to pid %d, handle base=%p", // mOwner, gpu->regs->pointer()); } mCallback = callback; } else { LOGW("couldn't grant gpu core to pid %d", pid); } return err; }
void GPUHardware::releaseLocked() { //LOGD("revoking gpu from pid %d", mOwner); if (mOwner != NO_OWNER) { // this may fail because the client might have died, and have // been removed from the list. ssize_t index = mClients.indexOfKey(mOwner); if (index >= 0) { Client& client(mClients.editValueAt(index)); client.revokeAllHeaps(); } mOwner = NO_OWNER; mCurrentAllocator.clear(); mCallback.clear(); } }
void JTvInputHal::onDeviceUnavailable(int deviceId) { { Mutex::Autolock autoLock(&mLock); KeyedVector<int, Connection>& connections = mConnections.editValueFor(deviceId); for (size_t i = 0; i < connections.size(); ++i) { removeStream(deviceId, connections.keyAt(i)); } connections.clear(); mConnections.removeItem(deviceId); } JNIEnv* env = AndroidRuntime::getJNIEnv(); env->CallVoidMethod( mThiz, gTvInputHalClassInfo.deviceUnavailable, deviceId); }
int JTvInputHal::removeStream(int deviceId, int streamId) { KeyedVector<int, Connection>& connections = mConnections.editValueFor(deviceId); if (connections.indexOfKey(streamId) < 0) { return BAD_VALUE; } Connection& connection = connections.editValueFor(streamId); if (connection.mSurface == NULL) { // Nothing to do return NO_ERROR; } if (connection.mThread != NULL) { connection.mThread->shutdown(); connection.mThread.clear(); } if (mDevice->close_stream(mDevice, deviceId, streamId) != 0) { ALOGE("Couldn't remove stream"); return BAD_VALUE; } if (connection.mSourceHandle != NULL) { connection.mSourceHandle.clear(); } if (Surface::isValid(connection.mSurface)) { connection.mSurface.clear(); } if (connection.mSurface != NULL) { connection.mSurface->setSidebandStream(NULL); connection.mSurface.clear(); } return NO_ERROR; }
KeyedVector<SplitDescription, sp<Rule> > SplitSelector::getRules() const { KeyedVector<SplitDescription, sp<Rule> > rules; const size_t groupCount = mGroups.size(); for (size_t i = 0; i < groupCount; i++) { const SortedVector<SplitDescription>& splits = mGroups[i]; const size_t splitCount = splits.size(); for (size_t j = 0; j < splitCount; j++) { sp<Rule> rule = Rule::simplify(RuleGenerator::generate(splits, j)); if (rule != NULL) { rules.add(splits[j], rule); } } } return rules; }
status_t MuxOMX::allocateNode( const char *name, const sp<IOMXObserver> &observer, node_id *node) { Mutex::Autolock autoLock(mLock); sp<IOMX> omx; if (IsSoftwareComponent(name)) { if (mLocalOMX == NULL) { mLocalOMX = new OMX; } omx = mLocalOMX; } else { omx = mRemoteOMX; } status_t err = omx->allocateNode(name, observer, node); if (err != OK) { return err; } if (omx == mLocalOMX) { mIsLocalNode.add(*node, true); } return OK; }
status_t NativeInputEventSender::sendMotionEvent(uint32_t seq, const MotionEvent* event) { if (kDebugDispatchCycle) { ALOGD("channel '%s' ~ Sending motion event, seq=%u.", getInputChannelName(), seq); } uint32_t publishedSeq; for (size_t i = 0; i <= event->getHistorySize(); i++) { publishedSeq = mNextPublishedSeq++; status_t status = mInputPublisher.publishMotionEvent(publishedSeq, event->getDeviceId(), event->getSource(), event->getAction(), event->getActionButton(), event->getFlags(), event->getEdgeFlags(), event->getMetaState(), event->getButtonState(), event->getXOffset(), event->getYOffset(), event->getXPrecision(), event->getYPrecision(), event->getDownTime(), event->getHistoricalEventTime(i), event->getPointerCount(), event->getPointerProperties(), event->getHistoricalRawPointerCoords(0, i)); if (status) { ALOGW("Failed to send motion event sample on channel '%s'. status=%d", getInputChannelName(), status); return status; } } mPublishedSeqMap.add(publishedSeq, seq); return OK; }
static bool findParam(uint32_t key, T *param, KeyedVector<uint32_t, uint64_t> ¶ms) { CHECK(param); if (params.indexOfKey(key) < 0) { return false; } *param = (T) params[key]; return true; }
void exportResultsToXML( const char *fileName, const CodecSettings &global_results, const KeyedVector<AString, CodecSettings> &encoder_results, const KeyedVector<AString, CodecSettings> &decoder_results) { if (global_results.size() == 0 && encoder_results.size() == 0 && decoder_results.size() == 0) { return; } AString overrides; overrides.append(getProfilingVersionString()); overrides.append("\n"); overrides.append("<MediaCodecs>\n"); if (global_results.size() > 0) { overrides.append(" <Settings>\n"); overrides.append(globalResultsToXml(global_results)); overrides.append(" </Settings>\n"); } if (encoder_results.size() > 0) { overrides.append(" <Encoders>\n"); overrides.append(codecResultsToXml(encoder_results)); overrides.append(" </Encoders>\n"); } if (decoder_results.size() > 0) { overrides.append(" <Decoders>\n"); overrides.append(codecResultsToXml(decoder_results)); overrides.append(" </Decoders>\n"); } overrides.append("</MediaCodecs>\n"); FILE *f = fopen(fileName, "wb"); if (f == NULL) { ALOGE("Failed to open %s for writing.", fileName); return; } if (fwrite(overrides.c_str(), 1, overrides.size(), f) != overrides.size()) { ALOGE("Failed to write to %s.", fileName); } fclose(f); }
status_t MuxOMX::freeNode(node_id node) { Mutex::Autolock autoLock(mLock); status_t err = getOMX_l(node)->freeNode(node); if (err != OK) { return err; } mIsLocalNode.removeItem(node); return OK; }
void generate(const KeyedVector<String8, Vector<SplitDescription> >& splits, const String8& base) { Vector<SplitDescription> allSplits; const size_t apkSplitCount = splits.size(); for (size_t i = 0; i < apkSplitCount; i++) { allSplits.appendVector(splits[i]); } const SplitSelector selector(allSplits); KeyedVector<SplitDescription, sp<Rule> > rules(selector.getRules()); bool first = true; fprintf(stdout, "[\n"); for (size_t i = 0; i < apkSplitCount; i++) { if (splits.keyAt(i) == base) { // Skip the base. continue; } if (!first) { fprintf(stdout, ",\n"); } first = false; sp<Rule> masterRule = new Rule(); masterRule->op = Rule::OR_SUBRULES; const Vector<SplitDescription>& splitDescriptions = splits[i]; const size_t splitDescriptionCount = splitDescriptions.size(); for (size_t j = 0; j < splitDescriptionCount; j++) { masterRule->subrules.add(rules.valueFor(splitDescriptions[j])); } masterRule = Rule::simplify(masterRule); fprintf(stdout, " {\n \"path\": \"%s\",\n \"rules\": %s\n }", splits.keyAt(i).string(), masterRule->toJson(2).string()); } fprintf(stdout, "\n]\n"); }
void HeapCache::free_heap(const wp<IBinder>& binder) { sp<IMemoryHeap> rel; { Mutex::Autolock _l(mHeapCacheLock); ssize_t i = mHeapCache.indexOfKey(binder); if (i>=0) { heap_info_t& info(mHeapCache.editValueAt(i)); int32_t c = android_atomic_dec(&info.count); if (c == 1) { ALOGD_IF(VERBOSE, "removing binder=%p, heap=%p, size=%d, fd=%d, count=%d", binder.unsafe_get(), info.heap.get(), static_cast<BpMemoryHeap*>(info.heap.get())->mSize, static_cast<BpMemoryHeap*>(info.heap.get())->mHeapId, info.count); rel = mHeapCache.valueAt(i).heap; mHeapCache.removeItemsAt(i); } } else { ALOGE("free_heap binder=%p not found!!!", binder.unsafe_get()); } } }
sp<IMemoryHeap> HeapCache::find_heap(const sp<IBinder>& binder) { Mutex::Autolock _l(mHeapCacheLock); ssize_t i = mHeapCache.indexOfKey(binder); if (i>=0) { heap_info_t& info = mHeapCache.editValueAt(i); ALOGD_IF(VERBOSE, "found binder=%p, heap=%p, size=%d, fd=%d, count=%d", binder.get(), info.heap.get(), static_cast<BpMemoryHeap*>(info.heap.get())->mSize, static_cast<BpMemoryHeap*>(info.heap.get())->mHeapId, info.count); android_atomic_inc(&info.count); return info.heap; } else { heap_info_t info; info.heap = interface_cast<IMemoryHeap>(binder); info.count = 1; //ALOGD("adding binder=%p, heap=%p, count=%d", // binder.get(), info.heap.get(), info.count); mHeapCache.add(binder, info); return info.heap; } }
status_t NativeInputEventSender::sendKeyEvent(uint32_t seq, const KeyEvent* event) { if (kDebugDispatchCycle) { ALOGD("channel '%s' ~ Sending key event, seq=%u.", getInputChannelName(), seq); } uint32_t publishedSeq = mNextPublishedSeq++; status_t status = mInputPublisher.publishKeyEvent(publishedSeq, event->getDeviceId(), event->getSource(), event->getAction(), event->getFlags(), event->getKeyCode(), event->getScanCode(), event->getMetaState(), event->getRepeatCount(), event->getDownTime(), event->getEventTime()); if (status) { ALOGW("Failed to send key event on channel '%s'. status=%d", getInputChannelName(), status); return status; } mPublishedSeqMap.add(publishedSeq, seq); return OK; }
void JTvInputHal::onCaptured(int deviceId, int streamId, uint32_t seq, bool succeeded) { sp<BufferProducerThread> thread; { Mutex::Autolock autoLock(&mLock); KeyedVector<int, Connection>& connections = mConnections.editValueFor(deviceId); Connection& connection = connections.editValueFor(streamId); if (connection.mThread == NULL) { ALOGE("capture thread not existing."); return; } thread = connection.mThread; } thread->onCaptured(seq, succeeded); if (seq == 0) { JNIEnv* env = AndroidRuntime::getJNIEnv(); env->CallVoidMethod( mThiz, gTvInputHalClassInfo.firstFrameCaptured, deviceId, streamId); } }
void JTvInputHal::onDeviceAvailable(const tv_input_device_info_t& info) { { Mutex::Autolock autoLock(&mLock); mConnections.add(info.device_id, KeyedVector<int, Connection>()); } JNIEnv* env = AndroidRuntime::getJNIEnv(); jobject builder = env->NewObject( gTvInputHardwareInfoBuilderClassInfo.clazz, gTvInputHardwareInfoBuilderClassInfo.constructor); env->CallObjectMethod( builder, gTvInputHardwareInfoBuilderClassInfo.deviceId, info.device_id); env->CallObjectMethod( builder, gTvInputHardwareInfoBuilderClassInfo.type, info.type); if (info.type == TV_INPUT_TYPE_HDMI) { env->CallObjectMethod( builder, gTvInputHardwareInfoBuilderClassInfo.hdmiPortId, info.hdmi.port_id); } env->CallObjectMethod( builder, gTvInputHardwareInfoBuilderClassInfo.audioType, info.audio_type); if (info.audio_type != AUDIO_DEVICE_NONE) { jstring audioAddress = env->NewStringUTF(info.audio_address); env->CallObjectMethod( builder, gTvInputHardwareInfoBuilderClassInfo.audioAddress, audioAddress); env->DeleteLocalRef(audioAddress); } jobject infoObject = env->CallObjectMethod(builder, gTvInputHardwareInfoBuilderClassInfo.build); env->CallVoidMethod( mThiz, gTvInputHalClassInfo.deviceAvailable, infoObject); env->DeleteLocalRef(builder); env->DeleteLocalRef(infoObject); }