• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #define LOG_TAG "BroadcastRadioService.Tuner.jni"
18 #define LOG_NDEBUG 0
19 
20 #include "Tuner.h"
21 
22 #include "convert.h"
23 #include "TunerCallback.h"
24 
25 #include <android/hardware/broadcastradio/1.1/IBroadcastRadioFactory.h>
26 #include <binder/IPCThreadState.h>
27 #include <broadcastradio-utils/Utils.h>
28 #include <core_jni_helpers.h>
29 #include <media/AudioSystem.h>
30 #include <nativehelper/JNIHelp.h>
31 #include <utils/Log.h>
32 
33 namespace android {
34 namespace server {
35 namespace BroadcastRadio {
36 namespace Tuner {
37 
38 using std::lock_guard;
39 using std::mutex;
40 
41 using hardware::Return;
42 using hardware::hidl_death_recipient;
43 using hardware::hidl_vec;
44 
45 namespace V1_0 = hardware::broadcastradio::V1_0;
46 namespace V1_1 = hardware::broadcastradio::V1_1;
47 
48 using V1_0::Band;
49 using V1_0::BandConfig;
50 using V1_0::MetaData;
51 using V1_0::Result;
52 using V1_1::ITunerCallback;
53 using V1_1::ProgramListResult;
54 
55 static mutex gContextMutex;
56 
57 static struct {
58     struct {
59         jclass clazz;
60         jmethodID cstor;
61         jmethodID add;
62     } ArrayList;
63     struct {
64         jfieldID nativeContext;
65         jfieldID region;
66         jfieldID tunerCallback;
67     } Tuner;
68 } gjni;
69 
70 static const char* const kAudioDeviceName = "Radio tuner source";
71 
72 class HalDeathRecipient : public hidl_death_recipient {
73     wp<V1_1::ITunerCallback> mTunerCallback;
74 
75 public:
HalDeathRecipient(wp<V1_1::ITunerCallback> tunerCallback)76     HalDeathRecipient(wp<V1_1::ITunerCallback> tunerCallback):mTunerCallback(tunerCallback) {}
77 
78     virtual void serviceDied(uint64_t cookie, const wp<hidl::base::V1_0::IBase>& who);
79 };
80 
81 struct TunerContext {
TunerContextandroid::server::BroadcastRadio::Tuner::TunerContext82     TunerContext() {}
83 
84     bool mIsClosed = false;
85     HalRevision mHalRev;
86     bool mWithAudio;
87     bool mIsAudioConnected = false;
88     Band mBand;
89     wp<V1_0::IBroadcastRadio> mHalModule;
90     wp<V1_1::IBroadcastRadio> mHalModule11;
91     sp<V1_0::ITuner> mHalTuner;
92     sp<V1_1::ITuner> mHalTuner11;
93     sp<HalDeathRecipient> mHalDeathRecipient;
94 
95 private:
96     DISALLOW_COPY_AND_ASSIGN(TunerContext);
97 };
98 
getNativeContext(jlong nativeContextHandle)99 static TunerContext& getNativeContext(jlong nativeContextHandle) {
100     auto nativeContext = reinterpret_cast<TunerContext*>(nativeContextHandle);
101     LOG_ALWAYS_FATAL_IF(nativeContext == nullptr, "Native context not initialized");
102     return *nativeContext;
103 }
104 
105 /**
106  * Always lock gContextMutex when using native context.
107  */
getNativeContext(JNIEnv * env,JavaRef<jobject> const & jTuner)108 static TunerContext& getNativeContext(JNIEnv *env, JavaRef<jobject> const &jTuner) {
109     return getNativeContext(env->GetLongField(jTuner.get(), gjni.Tuner.nativeContext));
110 }
111 
nativeInit(JNIEnv * env,jobject obj,jint halRev,bool withAudio,jint band)112 static jlong nativeInit(JNIEnv *env, jobject obj, jint halRev, bool withAudio, jint band) {
113     ALOGV("%s", __func__);
114     lock_guard<mutex> lk(gContextMutex);
115 
116     auto ctx = new TunerContext();
117     ctx->mHalRev = static_cast<HalRevision>(halRev);
118     ctx->mWithAudio = withAudio;
119     ctx->mBand = static_cast<Band>(band);
120 
121     static_assert(sizeof(jlong) >= sizeof(ctx), "jlong is smaller than a pointer");
122     return reinterpret_cast<jlong>(ctx);
123 }
124 
nativeFinalize(JNIEnv * env,jobject obj,jlong nativeContext)125 static void nativeFinalize(JNIEnv *env, jobject obj, jlong nativeContext) {
126     ALOGV("%s", __func__);
127     lock_guard<mutex> lk(gContextMutex);
128 
129     auto ctx = reinterpret_cast<TunerContext*>(nativeContext);
130     delete ctx;
131 }
132 
serviceDied(uint64_t cookie __unused,const wp<hidl::base::V1_0::IBase> & who __unused)133 void HalDeathRecipient::serviceDied(uint64_t cookie __unused,
134         const wp<hidl::base::V1_0::IBase>& who __unused) {
135     ALOGW("HAL Tuner died unexpectedly");
136 
137     auto tunerCallback = mTunerCallback.promote();
138     if (tunerCallback == nullptr) return;
139 
140     tunerCallback->hardwareFailure();
141 }
142 
143 // TODO(b/62713378): implement support for multiple tuners open at the same time
notifyAudioService(TunerContext & ctx,bool connected)144 static void notifyAudioService(TunerContext& ctx, bool connected) {
145     if (!ctx.mWithAudio) return;
146     if (ctx.mIsAudioConnected == connected) return;
147     ctx.mIsAudioConnected = connected;
148 
149     ALOGD("Notifying AudioService about new state: %d", connected);
150     auto token = IPCThreadState::self()->clearCallingIdentity();
151     AudioSystem::setDeviceConnectionState(AUDIO_DEVICE_IN_FM_TUNER,
152             connected ? AUDIO_POLICY_DEVICE_STATE_AVAILABLE : AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
153             nullptr, kAudioDeviceName);
154     IPCThreadState::self()->restoreCallingIdentity(token);
155 }
156 
assignHalInterfaces(JNIEnv * env,JavaRef<jobject> const & jTuner,sp<V1_0::IBroadcastRadio> halModule,sp<V1_0::ITuner> halTuner)157 void assignHalInterfaces(JNIEnv *env, JavaRef<jobject> const &jTuner,
158         sp<V1_0::IBroadcastRadio> halModule, sp<V1_0::ITuner> halTuner) {
159     ALOGV("%s(%p)", __func__, halTuner.get());
160     ALOGE_IF(halTuner == nullptr, "HAL tuner is a nullptr");
161     lock_guard<mutex> lk(gContextMutex);
162     auto& ctx = getNativeContext(env, jTuner);
163 
164     if (ctx.mIsClosed) {
165         ALOGD("Tuner was closed during initialization");
166         // dropping the last reference will close HAL tuner
167         return;
168     }
169     if (ctx.mHalTuner != nullptr) {
170         ALOGE("HAL tuner is already set.");
171         return;
172     }
173 
174     ctx.mHalModule = halModule;
175     ctx.mHalModule11 = V1_1::IBroadcastRadio::castFrom(halModule).withDefault(nullptr);
176 
177     ctx.mHalTuner = halTuner;
178     ctx.mHalTuner11 = V1_1::ITuner::castFrom(halTuner).withDefault(nullptr);
179     ALOGW_IF(ctx.mHalRev >= HalRevision::V1_1 && ctx.mHalTuner11 == nullptr,
180             "Provided tuner does not implement 1.1 HAL");
181 
182     ctx.mHalDeathRecipient = new HalDeathRecipient(getNativeCallback(env, jTuner));
183     halTuner->linkToDeath(ctx.mHalDeathRecipient, 0);
184 
185     notifyAudioService(ctx, true);
186 }
187 
getHalTuner(const TunerContext & ctx)188 static sp<V1_0::ITuner> getHalTuner(const TunerContext& ctx) {
189     auto tuner = ctx.mHalTuner;
190     LOG_ALWAYS_FATAL_IF(tuner == nullptr, "HAL tuner is not open");
191     return tuner;
192 }
193 
getHalTuner(jlong nativeContext)194 sp<V1_0::ITuner> getHalTuner(jlong nativeContext) {
195     lock_guard<mutex> lk(gContextMutex);
196     return getHalTuner(getNativeContext(nativeContext));
197 }
198 
getHalTuner11(jlong nativeContext)199 sp<V1_1::ITuner> getHalTuner11(jlong nativeContext) {
200     lock_guard<mutex> lk(gContextMutex);
201     return getNativeContext(nativeContext).mHalTuner11;
202 }
203 
getNativeCallback(JNIEnv * env,JavaRef<jobject> const & tuner)204 sp<ITunerCallback> getNativeCallback(JNIEnv *env, JavaRef<jobject> const &tuner) {
205     return TunerCallback::getNativeCallback(env,
206             env->GetObjectField(tuner.get(), gjni.Tuner.tunerCallback));
207 }
208 
getRegion(JNIEnv * env,jobject obj)209 Region getRegion(JNIEnv *env, jobject obj) {
210     return static_cast<Region>(env->GetIntField(obj, gjni.Tuner.region));
211 }
212 
nativeClose(JNIEnv * env,jobject obj,jlong nativeContext)213 static void nativeClose(JNIEnv *env, jobject obj, jlong nativeContext) {
214     lock_guard<mutex> lk(gContextMutex);
215     auto& ctx = getNativeContext(nativeContext);
216 
217     if (ctx.mIsClosed) return;
218     ctx.mIsClosed = true;
219 
220     if (ctx.mHalTuner == nullptr) {
221         ALOGI("Tuner closed during initialization");
222         return;
223     }
224 
225     ALOGI("Closing tuner %p", ctx.mHalTuner.get());
226 
227     notifyAudioService(ctx, false);
228 
229     ctx.mHalTuner->unlinkToDeath(ctx.mHalDeathRecipient);
230     ctx.mHalDeathRecipient = nullptr;
231 
232     ctx.mHalTuner11 = nullptr;
233     ctx.mHalTuner = nullptr;
234 }
235 
nativeSetConfiguration(JNIEnv * env,jobject obj,jlong nativeContext,jobject config)236 static void nativeSetConfiguration(JNIEnv *env, jobject obj, jlong nativeContext, jobject config) {
237     ALOGV("%s", __func__);
238     lock_guard<mutex> lk(gContextMutex);
239     auto& ctx = getNativeContext(nativeContext);
240 
241     auto halTuner = getHalTuner(ctx);
242     if (halTuner == nullptr) return;
243 
244     Region region_unused;
245     BandConfig bandConfigHal = convert::BandConfigToHal(env, config, region_unused);
246 
247     if (convert::ThrowIfFailed(env, halTuner->setConfiguration(bandConfigHal))) return;
248 
249     ctx.mBand = bandConfigHal.type;
250 }
251 
nativeGetConfiguration(JNIEnv * env,jobject obj,jlong nativeContext,Region region)252 static jobject nativeGetConfiguration(JNIEnv *env, jobject obj, jlong nativeContext,
253         Region region) {
254     ALOGV("%s", __func__);
255     auto halTuner = getHalTuner(nativeContext);
256     if (halTuner == nullptr) return nullptr;
257 
258     BandConfig halConfig;
259     Result halResult;
260     auto hidlResult = halTuner->getConfiguration([&](Result result, const BandConfig& config) {
261         halResult = result;
262         halConfig = config;
263     });
264     if (convert::ThrowIfFailed(env, hidlResult, halResult)) {
265         return nullptr;
266     }
267 
268     return convert::BandConfigFromHal(env, halConfig, region).release();
269 }
270 
nativeSetMuted(JNIEnv * env,jobject obj,jlong nativeContext,bool mute)271 static void nativeSetMuted(JNIEnv *env, jobject obj, jlong nativeContext, bool mute) {
272     ALOGV("%s(%d)", __func__, mute);
273     lock_guard<mutex> lk(gContextMutex);
274     auto& ctx = getNativeContext(nativeContext);
275 
276     notifyAudioService(ctx, !mute);
277 }
278 
nativeStep(JNIEnv * env,jobject obj,jlong nativeContext,bool directionDown,bool skipSubChannel)279 static void nativeStep(JNIEnv *env, jobject obj, jlong nativeContext,
280         bool directionDown, bool skipSubChannel) {
281     ALOGV("%s", __func__);
282     auto halTuner = getHalTuner(nativeContext);
283     if (halTuner == nullptr) return;
284 
285     auto dir = convert::DirectionToHal(directionDown);
286     convert::ThrowIfFailed(env, halTuner->step(dir, skipSubChannel));
287 }
288 
nativeScan(JNIEnv * env,jobject obj,jlong nativeContext,bool directionDown,bool skipSubChannel)289 static void nativeScan(JNIEnv *env, jobject obj, jlong nativeContext,
290         bool directionDown, bool skipSubChannel) {
291     ALOGV("%s", __func__);
292     auto halTuner = getHalTuner(nativeContext);
293     if (halTuner == nullptr) return;
294 
295     auto dir = convert::DirectionToHal(directionDown);
296     convert::ThrowIfFailed(env, halTuner->scan(dir, skipSubChannel));
297 }
298 
nativeTune(JNIEnv * env,jobject obj,jlong nativeContext,jobject jSelector)299 static void nativeTune(JNIEnv *env, jobject obj, jlong nativeContext, jobject jSelector) {
300     ALOGV("%s", __func__);
301     lock_guard<mutex> lk(gContextMutex);
302     auto& ctx = getNativeContext(nativeContext);
303 
304     auto halTuner10 = getHalTuner(ctx);
305     auto halTuner11 = ctx.mHalTuner11;
306     if (halTuner10 == nullptr) return;
307 
308     auto selector = convert::ProgramSelectorToHal(env, jSelector);
309     if (halTuner11 != nullptr) {
310         convert::ThrowIfFailed(env, halTuner11->tuneByProgramSelector(selector));
311     } else {
312         uint32_t channel, subChannel;
313         if (!V1_1::utils::getLegacyChannel(selector, &channel, &subChannel)) {
314             jniThrowException(env, "java/lang/IllegalArgumentException",
315                     "Can't tune to non-AM/FM channel with HAL<1.1");
316             return;
317         }
318         convert::ThrowIfFailed(env, halTuner10->tune(channel, subChannel));
319     }
320 }
321 
nativeCancel(JNIEnv * env,jobject obj,jlong nativeContext)322 static void nativeCancel(JNIEnv *env, jobject obj, jlong nativeContext) {
323     ALOGV("%s", __func__);
324     auto halTuner = getHalTuner(nativeContext);
325     if (halTuner == nullptr) return;
326 
327     convert::ThrowIfFailed(env, halTuner->cancel());
328 }
329 
nativeCancelAnnouncement(JNIEnv * env,jobject obj,jlong nativeContext)330 static void nativeCancelAnnouncement(JNIEnv *env, jobject obj, jlong nativeContext) {
331     ALOGV("%s", __func__);
332     auto halTuner = getHalTuner11(nativeContext);
333     if (halTuner == nullptr) {
334         ALOGI("cancelling announcements is not supported with HAL < 1.1");
335         return;
336     }
337 
338     convert::ThrowIfFailed(env, halTuner->cancelAnnouncement());
339 }
340 
nativeGetProgramInformation(JNIEnv * env,jobject obj,jlong nativeContext)341 static jobject nativeGetProgramInformation(JNIEnv *env, jobject obj, jlong nativeContext) {
342     ALOGV("%s", __func__);
343     lock_guard<mutex> lk(gContextMutex);
344     auto& ctx = getNativeContext(nativeContext);
345 
346     auto halTuner10 = getHalTuner(ctx);
347     auto halTuner11 = ctx.mHalTuner11;
348     if (halTuner10 == nullptr) return nullptr;
349 
350     JavaRef<jobject> jInfo;
351     Result halResult;
352     Return<void> hidlResult;
353     if (halTuner11 != nullptr) {
354         hidlResult = halTuner11->getProgramInformation_1_1([&](Result result,
355                 const V1_1::ProgramInfo& info) {
356             halResult = result;
357             if (result != Result::OK) return;
358             jInfo = convert::ProgramInfoFromHal(env, info);
359         });
360     } else {
361         hidlResult = halTuner10->getProgramInformation([&](Result result,
362                 const V1_0::ProgramInfo& info) {
363             halResult = result;
364             if (result != Result::OK) return;
365             jInfo = convert::ProgramInfoFromHal(env, info, ctx.mBand);
366         });
367     }
368 
369     if (jInfo != nullptr) return jInfo.release();
370     convert::ThrowIfFailed(env, hidlResult, halResult);
371     return nullptr;
372 }
373 
nativeStartBackgroundScan(JNIEnv * env,jobject obj,jlong nativeContext)374 static bool nativeStartBackgroundScan(JNIEnv *env, jobject obj, jlong nativeContext) {
375     ALOGV("%s", __func__);
376     auto halTuner = getHalTuner11(nativeContext);
377     if (halTuner == nullptr) {
378         ALOGI("Background scan is not supported with HAL < 1.1");
379         return false;
380     }
381 
382     auto halResult = halTuner->startBackgroundScan();
383 
384     if (halResult.isOk() && halResult == ProgramListResult::UNAVAILABLE) return false;
385     return !convert::ThrowIfFailed(env, halResult);
386 }
387 
nativeGetProgramList(JNIEnv * env,jobject obj,jlong nativeContext,jobject jVendorFilter)388 static jobject nativeGetProgramList(JNIEnv *env, jobject obj, jlong nativeContext, jobject jVendorFilter) {
389     ALOGV("%s", __func__);
390     auto halTuner = getHalTuner11(nativeContext);
391     if (halTuner == nullptr) {
392         ALOGI("Program list is not supported with HAL < 1.1");
393         return nullptr;
394     }
395 
396     JavaRef<jobject> jList;
397     ProgramListResult halResult = ProgramListResult::NOT_INITIALIZED;
398     auto filter = convert::VendorInfoToHal(env, jVendorFilter);
399     auto hidlResult = halTuner->getProgramList(filter,
400             [&](ProgramListResult result, const hidl_vec<V1_1::ProgramInfo>& programList) {
401         halResult = result;
402         if (halResult != ProgramListResult::OK) return;
403 
404         jList = make_javaref(env, env->NewObject(gjni.ArrayList.clazz, gjni.ArrayList.cstor));
405         for (auto& program : programList) {
406             auto jProgram = convert::ProgramInfoFromHal(env, program);
407             env->CallBooleanMethod(jList.get(), gjni.ArrayList.add, jProgram.get());
408         }
409     });
410 
411     if (convert::ThrowIfFailed(env, hidlResult, halResult)) return nullptr;
412 
413     return jList.release();
414 }
415 
nativeGetImage(JNIEnv * env,jobject obj,jlong nativeContext,jint id)416 static jbyteArray nativeGetImage(JNIEnv *env, jobject obj, jlong nativeContext, jint id) {
417     ALOGV("%s(%x)", __func__, id);
418     lock_guard<mutex> lk(gContextMutex);
419     auto& ctx = getNativeContext(nativeContext);
420 
421     if (ctx.mHalModule11 == nullptr) {
422         jniThrowException(env, "java/lang/IllegalStateException",
423                 "Out-of-band images are not supported with HAL < 1.1");
424         return nullptr;
425     }
426 
427     auto halModule = ctx.mHalModule11.promote();
428     if (halModule == nullptr) {
429         ALOGE("HAL module is gone");
430         return nullptr;
431     }
432 
433     JavaRef<jbyteArray> jRawImage = nullptr;
434 
435     auto hidlResult = halModule->getImage(id, [&](hidl_vec<uint8_t> rawImage) {
436         auto len = rawImage.size();
437         if (len == 0) return;
438 
439         jRawImage = make_javaref(env, env->NewByteArray(len));
440         if (jRawImage == nullptr) {
441             ALOGE("Failed to allocate byte array of len %zu", len);
442             return;
443         }
444 
445         env->SetByteArrayRegion(jRawImage.get(), 0, len,
446                 reinterpret_cast<const jbyte*>(rawImage.data()));
447     });
448 
449     if (convert::ThrowIfFailed(env, hidlResult)) return nullptr;
450 
451     return jRawImage.get();
452 }
453 
nativeIsAnalogForced(JNIEnv * env,jobject obj,jlong nativeContext)454 static bool nativeIsAnalogForced(JNIEnv *env, jobject obj, jlong nativeContext) {
455     ALOGV("%s", __func__);
456     auto halTuner = getHalTuner11(nativeContext);
457     if (halTuner == nullptr) {
458         jniThrowException(env, "java/lang/IllegalStateException",
459                 "Forced analog switch is not supported with HAL < 1.1");
460         return false;
461     }
462 
463     bool isForced;
464     Result halResult;
465     auto hidlResult = halTuner->isAnalogForced([&](Result result, bool isForcedRet) {
466         halResult = result;
467         isForced = isForcedRet;
468     });
469 
470     if (convert::ThrowIfFailed(env, hidlResult, halResult)) return false;
471 
472     return isForced;
473 }
474 
nativeSetAnalogForced(JNIEnv * env,jobject obj,jlong nativeContext,bool isForced)475 static void nativeSetAnalogForced(JNIEnv *env, jobject obj, jlong nativeContext, bool isForced) {
476     ALOGV("%s(%d)", __func__, isForced);
477     auto halTuner = getHalTuner11(nativeContext);
478     if (halTuner == nullptr) {
479         jniThrowException(env, "java/lang/IllegalStateException",
480                 "Forced analog switch is not supported with HAL < 1.1");
481         return;
482     }
483 
484     auto halResult = halTuner->setAnalogForced(isForced);
485     convert::ThrowIfFailed(env, halResult);
486 }
487 
nativeIsAntennaConnected(JNIEnv * env,jobject obj,jlong nativeContext)488 static bool nativeIsAntennaConnected(JNIEnv *env, jobject obj, jlong nativeContext) {
489     ALOGV("%s", __func__);
490     auto halTuner = getHalTuner(nativeContext);
491     if (halTuner == nullptr) return false;
492 
493     bool isConnected = false;
494     Result halResult;
495     auto hidlResult = halTuner->getConfiguration([&](Result result, const BandConfig& config) {
496         halResult = result;
497         isConnected = config.antennaConnected;
498     });
499     convert::ThrowIfFailed(env, hidlResult, halResult);
500     return isConnected;
501 }
502 
503 static const JNINativeMethod gTunerMethods[] = {
504     { "nativeInit", "(IZI)J", (void*)nativeInit },
505     { "nativeFinalize", "(J)V", (void*)nativeFinalize },
506     { "nativeClose", "(J)V", (void*)nativeClose },
507     { "nativeSetConfiguration", "(JLandroid/hardware/radio/RadioManager$BandConfig;)V",
508             (void*)nativeSetConfiguration },
509     { "nativeGetConfiguration", "(JI)Landroid/hardware/radio/RadioManager$BandConfig;",
510             (void*)nativeGetConfiguration },
511     { "nativeSetMuted", "(JZ)V", (void*)nativeSetMuted },
512     { "nativeStep", "(JZZ)V", (void*)nativeStep },
513     { "nativeScan", "(JZZ)V", (void*)nativeScan },
514     { "nativeTune", "(JLandroid/hardware/radio/ProgramSelector;)V", (void*)nativeTune },
515     { "nativeCancel", "(J)V", (void*)nativeCancel },
516     { "nativeCancelAnnouncement", "(J)V", (void*)nativeCancelAnnouncement },
517     { "nativeGetProgramInformation", "(J)Landroid/hardware/radio/RadioManager$ProgramInfo;",
518             (void*)nativeGetProgramInformation },
519     { "nativeStartBackgroundScan", "(J)Z", (void*)nativeStartBackgroundScan },
520     { "nativeGetProgramList", "(JLjava/util/Map;)Ljava/util/List;",
521             (void*)nativeGetProgramList },
522     { "nativeGetImage", "(JI)[B", (void*)nativeGetImage},
523     { "nativeIsAnalogForced", "(J)Z", (void*)nativeIsAnalogForced },
524     { "nativeSetAnalogForced", "(JZ)V", (void*)nativeSetAnalogForced },
525     { "nativeIsAntennaConnected", "(J)Z", (void*)nativeIsAntennaConnected },
526 };
527 
528 } // namespace Tuner
529 } // namespace BroadcastRadio
530 } // namespace server
531 
register_android_server_broadcastradio_Tuner(JavaVM * vm,JNIEnv * env)532 void register_android_server_broadcastradio_Tuner(JavaVM *vm, JNIEnv *env) {
533     using namespace server::BroadcastRadio::Tuner;
534 
535     register_android_server_broadcastradio_TunerCallback(vm, env);
536 
537     auto tunerClass = FindClassOrDie(env, "com/android/server/broadcastradio/Tuner");
538     gjni.Tuner.nativeContext = GetFieldIDOrDie(env, tunerClass, "mNativeContext", "J");
539     gjni.Tuner.region = GetFieldIDOrDie(env, tunerClass, "mRegion", "I");
540     gjni.Tuner.tunerCallback = GetFieldIDOrDie(env, tunerClass, "mTunerCallback",
541             "Lcom/android/server/broadcastradio/TunerCallback;");
542 
543     auto arrayListClass = FindClassOrDie(env, "java/util/ArrayList");
544     gjni.ArrayList.clazz = MakeGlobalRefOrDie(env, arrayListClass);
545     gjni.ArrayList.cstor = GetMethodIDOrDie(env, arrayListClass, "<init>", "()V");
546     gjni.ArrayList.add = GetMethodIDOrDie(env, arrayListClass, "add", "(Ljava/lang/Object;)Z");
547 
548     auto res = jniRegisterNativeMethods(env, "com/android/server/broadcastradio/Tuner",
549             gTunerMethods, NELEM(gTunerMethods));
550     LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register native methods.");
551 }
552 
553 } // namespace android
554