• 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.convert.jni"
18 #define LOG_NDEBUG 0
19 
20 #include "convert.h"
21 
22 #include "regions.h"
23 
24 #include <broadcastradio-utils/Utils.h>
25 #include <core_jni_helpers.h>
26 #include <nativehelper/JNIHelp.h>
27 #include <utils/Log.h>
28 
29 namespace android {
30 namespace server {
31 namespace BroadcastRadio {
32 namespace convert {
33 
34 namespace utils = V1_1::utils;
35 
36 using hardware::Return;
37 using hardware::hidl_vec;
38 using regions::RegionalBandConfig;
39 
40 using V1_0::Band;
41 using V1_0::Deemphasis;
42 using V1_0::Direction;
43 using V1_0::MetadataType;
44 using V1_0::Result;
45 using V1_0::Rds;
46 using V1_1::ProgramIdentifier;
47 using V1_1::ProgramListResult;
48 using V1_1::ProgramSelector;
49 using V1_1::VendorKeyValue;
50 
51 static JavaRef<jobject> BandDescriptorFromHal(JNIEnv *env, const RegionalBandConfig &config);
52 static JavaRef<jobject> BandDescriptorFromHal(JNIEnv *env, const V1_0::BandConfig &config, Region region);
53 
54 static struct {
55     struct {
56         jfieldID descriptor;
57     } BandConfig;
58     struct {
59         jclass clazz;
60         jmethodID cstor;
61         jfieldID stereo;
62         jfieldID rds;
63         jfieldID ta;
64         jfieldID af;
65         jfieldID ea;
66     } FmBandConfig;
67     struct {
68         jclass clazz;
69         jmethodID cstor;
70         jfieldID stereo;
71     } AmBandConfig;
72 
73     struct {
74         jclass clazz;
75         jfieldID region;
76         jfieldID type;
77         jfieldID lowerLimit;
78         jfieldID upperLimit;
79         jfieldID spacing;
80     } BandDescriptor;
81     struct {
82         jclass clazz;
83         jmethodID cstor;
84     } FmBandDescriptor;
85     struct {
86         jclass clazz;
87         jmethodID cstor;
88     } AmBandDescriptor;
89 
90     struct {
91         jclass clazz;
92         jmethodID stringMapToNative;
93     } Convert;
94 
95     struct {
96         jclass clazz;
97         jmethodID cstor;
98     } HashMap;
99 
100     struct {
101         jmethodID put;
102     } Map;
103 
104     struct {
105         jclass clazz;
106         jmethodID cstor;
107     } ModuleProperties;
108 
109     struct {
110         jclass clazz;
111         jmethodID cstor;
112     } ProgramInfo;
113 
114     struct {
115         jclass clazz;
116         jmethodID cstor;
117         jfieldID programType;
118         jfieldID primaryId;
119         jfieldID secondaryIds;
120         jfieldID vendorIds;
121 
122         struct {
123             jclass clazz;
124             jmethodID cstor;
125             jfieldID type;
126             jfieldID value;
127         } Identifier;
128     } ProgramSelector;
129 
130     struct {
131         jclass clazz;
132         jmethodID cstor;
133         jmethodID putIntFromNative;
134         jmethodID putStringFromNative;
135         jmethodID putBitmapFromNative;
136         jmethodID putClockFromNative;
137     } RadioMetadata;
138 
139     struct {
140         jclass clazz;
141         jmethodID cstor;
142     } RuntimeException;
143 
144     struct {
145         jclass clazz;
146         jmethodID cstor;
147     } ParcelableException;
148 } gjni;
149 
150 template <>
ThrowIfFailed(JNIEnv * env,const hardware::Return<void> & hidlResult)151 bool ThrowIfFailed(JNIEnv *env, const hardware::Return<void> &hidlResult) {
152     return __ThrowIfFailedHidl(env, hidlResult);
153 }
154 
__ThrowIfFailedHidl(JNIEnv * env,const hardware::details::return_status & hidlResult)155 bool __ThrowIfFailedHidl(JNIEnv *env, const hardware::details::return_status &hidlResult) {
156     if (hidlResult.isOk()) return false;
157 
158     ThrowParcelableRuntimeException(env, "HIDL call failed: " + hidlResult.description());
159     return true;
160 }
161 
__ThrowIfFailed(JNIEnv * env,const Result halResult)162 bool __ThrowIfFailed(JNIEnv *env, const Result halResult) {
163     switch (halResult) {
164         case Result::OK:
165             return false;
166         case Result::NOT_INITIALIZED:
167             ThrowParcelableRuntimeException(env, "Result::NOT_INITIALIZED");
168             return true;
169         case Result::INVALID_ARGUMENTS:
170             jniThrowException(env, "java/lang/IllegalArgumentException",
171                     "Result::INVALID_ARGUMENTS");
172             return true;
173         case Result::INVALID_STATE:
174             jniThrowException(env, "java/lang/IllegalStateException", "Result::INVALID_STATE");
175             return true;
176         case Result::TIMEOUT:
177             ThrowParcelableRuntimeException(env, "Result::TIMEOUT (unexpected here)");
178             return true;
179         default:
180             ThrowParcelableRuntimeException(env, "Unknown failure, result: "
181                     + std::to_string(static_cast<int32_t>(halResult)));
182             return true;
183     }
184 }
185 
__ThrowIfFailed(JNIEnv * env,const ProgramListResult halResult)186 bool __ThrowIfFailed(JNIEnv *env, const ProgramListResult halResult) {
187     switch (halResult) {
188         case ProgramListResult::NOT_READY:
189             jniThrowException(env, "java/lang/IllegalStateException", "Scan is in progress");
190             return true;
191         case ProgramListResult::NOT_STARTED:
192             jniThrowException(env, "java/lang/IllegalStateException", "Scan has not been started");
193             return true;
194         case ProgramListResult::UNAVAILABLE:
195             ThrowParcelableRuntimeException(env,
196                     "ProgramListResult::UNAVAILABLE (unexpected here)");
197             return true;
198         default:
199             return __ThrowIfFailed(env, static_cast<Result>(halResult));
200     }
201 }
202 
ThrowParcelableRuntimeException(JNIEnv * env,const std::string & msg)203 void ThrowParcelableRuntimeException(JNIEnv *env, const std::string& msg) {
204     auto jMsg = make_javastr(env, msg);
205     auto runtimeExc = make_javaref(env, env->NewObject(gjni.RuntimeException.clazz,
206             gjni.RuntimeException.cstor, jMsg.get()));
207     auto parcelableExc = make_javaref(env, env->NewObject(gjni.ParcelableException.clazz,
208             gjni.ParcelableException.cstor, runtimeExc.get()));
209 
210     auto res = env->Throw(static_cast<jthrowable>(parcelableExc.get()));
211     ALOGE_IF(res != JNI_OK, "Couldn't throw parcelable runtime exception");
212 }
213 
ArrayFromHal(JNIEnv * env,const hidl_vec<uint32_t> & vec)214 static JavaRef<jintArray> ArrayFromHal(JNIEnv *env, const hidl_vec<uint32_t>& vec) {
215     auto jArr = make_javaref(env, env->NewIntArray(vec.size()));
216     auto jArrElements = env->GetIntArrayElements(jArr.get(), nullptr);
217     for (size_t i = 0; i < vec.size(); i++) {
218         jArrElements[i] = vec[i];
219     }
220     env->ReleaseIntArrayElements(jArr.get(), jArrElements, 0);
221     return jArr;
222 }
223 
ArrayFromHal(JNIEnv * env,const hidl_vec<uint64_t> & vec)224 static JavaRef<jlongArray> ArrayFromHal(JNIEnv *env, const hidl_vec<uint64_t>& vec) {
225     auto jArr = make_javaref(env, env->NewLongArray(vec.size()));
226     auto jArrElements = env->GetLongArrayElements(jArr.get(), nullptr);
227     for (size_t i = 0; i < vec.size(); i++) {
228         jArrElements[i] = vec[i];
229     }
230     env->ReleaseLongArrayElements(jArr.get(), jArrElements, 0);
231     return jArr;
232 }
233 
234 template <typename T>
ArrayFromHal(JNIEnv * env,const hidl_vec<T> & vec,jclass jElementClass,std::function<JavaRef<jobject> (JNIEnv *,const T &)> converter)235 static JavaRef<jobjectArray> ArrayFromHal(JNIEnv *env, const hidl_vec<T>& vec,
236         jclass jElementClass, std::function<JavaRef<jobject>(JNIEnv*, const T&)> converter) {
237     auto jArr = make_javaref(env, env->NewObjectArray(vec.size(), jElementClass, nullptr));
238     for (size_t i = 0; i < vec.size(); i++) {
239         auto jElement = converter(env, vec[i]);
240         env->SetObjectArrayElement(jArr.get(), i, jElement.get());
241     }
242     return jArr;
243 }
244 
245 template <typename T>
ArrayFromHal(JNIEnv * env,const hidl_vec<T> & vec,jclass jElementClass,JavaRef<jobject> (* converter)(JNIEnv *,const T &))246 static JavaRef<jobjectArray> ArrayFromHal(JNIEnv *env, const hidl_vec<T>& vec,
247         jclass jElementClass, JavaRef<jobject>(*converter)(JNIEnv*, const T&)) {
248     return ArrayFromHal(env, vec, jElementClass,
249             std::function<JavaRef<jobject>(JNIEnv*, const T&)>(converter));
250 }
251 
StringFromJava(JNIEnv * env,JavaRef<jstring> & jStr)252 static std::string StringFromJava(JNIEnv *env, JavaRef<jstring> &jStr) {
253     auto cstr = (jStr == nullptr) ? nullptr : env->GetStringUTFChars(jStr.get(), nullptr);
254     std::string str(cstr);
255     env->ReleaseStringUTFChars(jStr.get(), cstr);
256     return str;
257 }
258 
VendorInfoFromHal(JNIEnv * env,const hidl_vec<VendorKeyValue> & info)259 JavaRef<jobject> VendorInfoFromHal(JNIEnv *env, const hidl_vec<VendorKeyValue> &info) {
260     ALOGV("%s(%s)", __func__, toString(info).substr(0, 100).c_str());
261 
262     auto jInfo = make_javaref(env, env->NewObject(gjni.HashMap.clazz, gjni.HashMap.cstor));
263 
264     for (auto&& entry : info) {
265         auto jKey = make_javastr(env, entry.key);
266         auto jValue = make_javastr(env, entry.value);
267         env->CallObjectMethod(jInfo.get(), gjni.Map.put, jKey.get(), jValue.get());
268     }
269 
270     return jInfo;
271 }
272 
VendorInfoToHal(JNIEnv * env,jobject jInfo)273 hidl_vec<VendorKeyValue> VendorInfoToHal(JNIEnv *env, jobject jInfo) {
274     ALOGV("%s", __func__);
275 
276     auto jInfoArr = make_javaref(env, static_cast<jobjectArray>(env->CallStaticObjectMethod(
277             gjni.Convert.clazz, gjni.Convert.stringMapToNative, jInfo)));
278     LOG_FATAL_IF(jInfoArr == nullptr, "Converted array is null");
279 
280     auto len = env->GetArrayLength(jInfoArr.get());
281     hidl_vec<VendorKeyValue> vec;
282     vec.resize(len);
283 
284     for (jsize i = 0; i < len; i++) {
285         auto entry = make_javaref(env, static_cast<jobjectArray>(
286                 env->GetObjectArrayElement(jInfoArr.get(), i)));
287         auto jKey = make_javaref(env, static_cast<jstring>(
288                 env->GetObjectArrayElement(entry.get(), 0)));
289         auto jValue = make_javaref(env, static_cast<jstring>(
290                 env->GetObjectArrayElement(entry.get(), 1)));
291         auto key = StringFromJava(env, jKey);
292         auto value = StringFromJava(env, jValue);
293         vec[i] = { key, value };
294     }
295 
296     return vec;
297 }
298 
RdsForRegion(bool rds,Region region)299 static Rds RdsForRegion(bool rds, Region region) {
300     if (!rds) return Rds::NONE;
301 
302     switch(region) {
303         case Region::ITU_1:
304         case Region::OIRT:
305         case Region::JAPAN:
306         case Region::KOREA:
307             return Rds::WORLD;
308         case Region::ITU_2:
309             return Rds::US;
310         default:
311             ALOGE("Unexpected region: %d", region);
312             return Rds::NONE;
313     }
314 }
315 
DeemphasisForRegion(Region region)316 static Deemphasis DeemphasisForRegion(Region region) {
317     switch(region) {
318         case Region::KOREA:
319         case Region::ITU_2:
320             return Deemphasis::D75;
321         case Region::ITU_1:
322         case Region::OIRT:
323         case Region::JAPAN:
324             return Deemphasis::D50;
325         default:
326             ALOGE("Unexpected region: %d", region);
327             return Deemphasis::D50;
328     }
329 }
330 
ModulePropertiesFromHal(JNIEnv * env,const V1_0::Properties & prop10,const V1_1::Properties * prop11,jint moduleId,const std::string & serviceName)331 static JavaRef<jobject> ModulePropertiesFromHal(JNIEnv *env, const V1_0::Properties &prop10,
332         const V1_1::Properties *prop11, jint moduleId, const std::string& serviceName) {
333     ALOGV("%s", __func__);
334     using namespace std::placeholders;
335 
336     auto jServiceName = make_javastr(env, serviceName);
337     auto jImplementor = make_javastr(env, prop10.implementor);
338     auto jProduct = make_javastr(env, prop10.product);
339     auto jVersion = make_javastr(env, prop10.version);
340     auto jSerial = make_javastr(env, prop10.serial);
341     bool isBgScanSupported = prop11 ? prop11->supportsBackgroundScanning : false;
342     auto jVendorInfo = prop11 ? VendorInfoFromHal(env, prop11->vendorInfo) : nullptr;
343 
344     auto regionalBands = regions::mapRegions(prop10.bands);
345     auto jBands = ArrayFromHal<RegionalBandConfig>(env, regionalBands,
346             gjni.BandDescriptor.clazz, BandDescriptorFromHal);
347     auto jSupportedProgramTypes =
348             prop11 ? ArrayFromHal(env, prop11->supportedProgramTypes) : nullptr;
349     auto jSupportedIdentifierTypes =
350             prop11 ? ArrayFromHal(env, prop11->supportedIdentifierTypes) : nullptr;
351 
352     return make_javaref(env, env->NewObject(gjni.ModuleProperties.clazz,
353             gjni.ModuleProperties.cstor, moduleId, jServiceName.get(), prop10.classId,
354             jImplementor.get(), jProduct.get(), jVersion.get(), jSerial.get(), prop10.numTuners,
355             prop10.numAudioSources, prop10.supportsCapture, jBands.get(), isBgScanSupported,
356             jSupportedProgramTypes.get(), jSupportedIdentifierTypes.get(), jVendorInfo.get()));
357 }
358 
ModulePropertiesFromHal(JNIEnv * env,const V1_0::Properties & properties,jint moduleId,const std::string & serviceName)359 JavaRef<jobject> ModulePropertiesFromHal(JNIEnv *env, const V1_0::Properties &properties,
360         jint moduleId, const std::string& serviceName) {
361     return ModulePropertiesFromHal(env, properties, nullptr, moduleId, serviceName);
362 }
363 
ModulePropertiesFromHal(JNIEnv * env,const V1_1::Properties & properties,jint moduleId,const std::string & serviceName)364 JavaRef<jobject> ModulePropertiesFromHal(JNIEnv *env, const V1_1::Properties &properties,
365         jint moduleId, const std::string& serviceName) {
366     return ModulePropertiesFromHal(env, properties.base, &properties, moduleId, serviceName);
367 }
368 
BandDescriptorFromHal(JNIEnv * env,const RegionalBandConfig & config)369 static JavaRef<jobject> BandDescriptorFromHal(JNIEnv *env, const RegionalBandConfig &config) {
370     return BandDescriptorFromHal(env, config.bandConfig, config.region);
371 }
372 
BandDescriptorFromHal(JNIEnv * env,const V1_0::BandConfig & config,Region region)373 static JavaRef<jobject> BandDescriptorFromHal(JNIEnv *env, const V1_0::BandConfig &config, Region region) {
374     ALOGV("%s", __func__);
375 
376     jint spacing = config.spacings.size() > 0 ? config.spacings[0] : 0;
377     ALOGW_IF(config.spacings.size() > 1, "Multiple spacings - not a regional config");
378     ALOGW_IF(config.spacings.size() == 0, "No channel spacing specified");
379 
380     if (utils::isFm(config.type)) {
381         auto& fm = config.ext.fm;
382         return make_javaref(env, env->NewObject(
383                 gjni.FmBandDescriptor.clazz, gjni.FmBandDescriptor.cstor,
384                 region, config.type, config.lowerLimit, config.upperLimit, spacing,
385                 fm.stereo, fm.rds != Rds::NONE, fm.ta, fm.af, fm.ea));
386     } else if (utils::isAm(config.type)) {
387         auto& am = config.ext.am;
388         return make_javaref(env, env->NewObject(
389                 gjni.AmBandDescriptor.clazz, gjni.AmBandDescriptor.cstor,
390                 region, config.type, config.lowerLimit, config.upperLimit, spacing, am.stereo));
391     } else {
392         ALOGE("Unsupported band type: %d", config.type);
393         return nullptr;
394     }
395 }
396 
BandConfigFromHal(JNIEnv * env,const V1_0::BandConfig & config,Region region)397 JavaRef<jobject> BandConfigFromHal(JNIEnv *env, const V1_0::BandConfig &config, Region region) {
398     ALOGV("%s", __func__);
399 
400     auto descriptor = BandDescriptorFromHal(env, config, region);
401     if (descriptor == nullptr) return nullptr;
402 
403     if (utils::isFm(config.type)) {
404         return make_javaref(env, env->NewObject(
405                 gjni.FmBandConfig.clazz, gjni.FmBandConfig.cstor, descriptor.get()));
406     } else if (utils::isAm(config.type)) {
407         return make_javaref(env, env->NewObject(
408                 gjni.AmBandConfig.clazz, gjni.AmBandConfig.cstor, descriptor.get()));
409     } else {
410         ALOGE("Unsupported band type: %d", config.type);
411         return nullptr;
412     }
413 }
414 
BandConfigToHal(JNIEnv * env,jobject jConfig,Region & region)415 V1_0::BandConfig BandConfigToHal(JNIEnv *env, jobject jConfig, Region &region) {
416     ALOGV("%s", __func__);
417     auto jDescriptor = env->GetObjectField(jConfig, gjni.BandConfig.descriptor);
418     if (jDescriptor == nullptr) {
419         ALOGE("Descriptor is missing");
420         return {};
421     }
422 
423     region = static_cast<Region>(env->GetIntField(jDescriptor, gjni.BandDescriptor.region));
424 
425     V1_0::BandConfig config = {};
426     config.type = static_cast<Band>(env->GetIntField(jDescriptor, gjni.BandDescriptor.type));
427     config.antennaConnected = false;  // just don't set it
428     config.lowerLimit = env->GetIntField(jDescriptor, gjni.BandDescriptor.lowerLimit);
429     config.upperLimit = env->GetIntField(jDescriptor, gjni.BandDescriptor.upperLimit);
430     config.spacings = hidl_vec<uint32_t>({
431         static_cast<uint32_t>(env->GetIntField(jDescriptor, gjni.BandDescriptor.spacing))
432     });
433 
434     if (env->IsInstanceOf(jConfig, gjni.FmBandConfig.clazz)) {
435         auto& fm = config.ext.fm;
436         fm.deemphasis = DeemphasisForRegion(region);
437         fm.stereo = env->GetBooleanField(jConfig, gjni.FmBandConfig.stereo);
438         fm.rds = RdsForRegion(env->GetBooleanField(jConfig, gjni.FmBandConfig.rds), region);
439         fm.ta = env->GetBooleanField(jConfig, gjni.FmBandConfig.ta);
440         fm.af = env->GetBooleanField(jConfig, gjni.FmBandConfig.af);
441         fm.ea = env->GetBooleanField(jConfig, gjni.FmBandConfig.ea);
442     } else if (env->IsInstanceOf(jConfig, gjni.AmBandConfig.clazz)) {
443         auto& am = config.ext.am;
444         am.stereo = env->GetBooleanField(jConfig, gjni.AmBandConfig.stereo);
445     } else {
446         ALOGE("Unexpected band config type");
447         return {};
448     }
449 
450     return config;
451 }
452 
DirectionToHal(bool directionDown)453 Direction DirectionToHal(bool directionDown) {
454     return directionDown ? Direction::DOWN : Direction::UP;
455 }
456 
MetadataFromHal(JNIEnv * env,const hidl_vec<V1_0::MetaData> & metadata)457 JavaRef<jobject> MetadataFromHal(JNIEnv *env, const hidl_vec<V1_0::MetaData> &metadata) {
458     ALOGV("%s", __func__);
459     if (metadata.size() == 0) return nullptr;
460 
461     auto jMetadata = make_javaref(env, env->NewObject(
462             gjni.RadioMetadata.clazz, gjni.RadioMetadata.cstor));
463 
464     for (auto& item : metadata) {
465         jint key = static_cast<jint>(item.key);
466         jint status = 0;
467         switch (item.type) {
468             case MetadataType::INT:
469                 ALOGV("metadata INT %d", key);
470                 status = env->CallIntMethod(jMetadata.get(), gjni.RadioMetadata.putIntFromNative,
471                         key, item.intValue);
472                 break;
473             case MetadataType::TEXT: {
474                 ALOGV("metadata TEXT %d", key);
475                 auto value = make_javastr(env, item.stringValue);
476                 status = env->CallIntMethod(jMetadata.get(), gjni.RadioMetadata.putStringFromNative,
477                         key, value.get());
478                 break;
479             }
480             case MetadataType::RAW: {
481                 ALOGV("metadata RAW %d", key);
482                 auto len = item.rawValue.size();
483                 if (len == 0) break;
484                 auto value = make_javaref(env, env->NewByteArray(len));
485                 if (value == nullptr) {
486                     ALOGE("Failed to allocate byte array of len %zu", len);
487                     break;
488                 }
489                 env->SetByteArrayRegion(value.get(), 0, len,
490                         reinterpret_cast<const jbyte*>(item.rawValue.data()));
491                 status = env->CallIntMethod(jMetadata.get(), gjni.RadioMetadata.putBitmapFromNative,
492                         key, value.get());
493                 break;
494             }
495             case MetadataType::CLOCK:
496                 ALOGV("metadata CLOCK %d", key);
497                 status = env->CallIntMethod(jMetadata.get(), gjni.RadioMetadata.putClockFromNative,
498                         key, item.clockValue.utcSecondsSinceEpoch,
499                         item.clockValue.timezoneOffsetInMinutes);
500                 break;
501             default:
502                 ALOGW("invalid metadata type %d", item.type);
503         }
504         ALOGE_IF(status != 0, "Failed inserting metadata %d (of type %d)", key, item.type);
505     }
506 
507     return jMetadata;
508 }
509 
ProgramIdentifierFromHal(JNIEnv * env,const ProgramIdentifier & id)510 static JavaRef<jobject> ProgramIdentifierFromHal(JNIEnv *env, const ProgramIdentifier &id) {
511     ALOGV("%s", __func__);
512     return make_javaref(env, env->NewObject(gjni.ProgramSelector.Identifier.clazz,
513             gjni.ProgramSelector.Identifier.cstor, id.type, id.value));
514 }
515 
ProgramSelectorFromHal(JNIEnv * env,const ProgramSelector & selector)516 static JavaRef<jobject> ProgramSelectorFromHal(JNIEnv *env, const ProgramSelector &selector) {
517     ALOGV("%s", __func__);
518     auto jPrimary = ProgramIdentifierFromHal(env, selector.primaryId);
519     auto jSecondary = ArrayFromHal(env, selector.secondaryIds,
520             gjni.ProgramSelector.Identifier.clazz, ProgramIdentifierFromHal);
521     auto jVendor = ArrayFromHal(env, selector.vendorIds);
522 
523     return make_javaref(env, env->NewObject(gjni.ProgramSelector.clazz, gjni.ProgramSelector.cstor,
524             selector.programType, jPrimary.get(), jSecondary.get(), jVendor.get()));
525 }
526 
ProgramIdentifierToHal(JNIEnv * env,jobject jId)527 static ProgramIdentifier ProgramIdentifierToHal(JNIEnv *env, jobject jId) {
528     ALOGV("%s", __func__);
529 
530     ProgramIdentifier id = {};
531     id.type = env->GetIntField(jId, gjni.ProgramSelector.Identifier.type);
532     id.value = env->GetLongField(jId, gjni.ProgramSelector.Identifier.value);
533     return id;
534 }
535 
ProgramSelectorToHal(JNIEnv * env,jobject jSelector)536 ProgramSelector ProgramSelectorToHal(JNIEnv *env, jobject jSelector) {
537     ALOGV("%s", __func__);
538 
539     ProgramSelector selector = {};
540 
541     selector.programType = env->GetIntField(jSelector, gjni.ProgramSelector.programType);
542 
543     auto jPrimary = env->GetObjectField(jSelector, gjni.ProgramSelector.primaryId);
544     auto jSecondary = reinterpret_cast<jobjectArray>(
545             env->GetObjectField(jSelector, gjni.ProgramSelector.secondaryIds));
546     auto jVendor = reinterpret_cast<jlongArray>(
547             env->GetObjectField(jSelector, gjni.ProgramSelector.vendorIds));
548 
549     if (jPrimary == nullptr || jSecondary == nullptr || jVendor == nullptr) {
550         ALOGE("ProgramSelector object is incomplete");
551         return {};
552     }
553 
554     selector.primaryId = ProgramIdentifierToHal(env, jPrimary);
555     auto count = env->GetArrayLength(jSecondary);
556     selector.secondaryIds.resize(count);
557     for (jsize i = 0; i < count; i++) {
558         auto jId = env->GetObjectArrayElement(jSecondary, i);
559         selector.secondaryIds[i] = ProgramIdentifierToHal(env, jId);
560     }
561 
562     count = env->GetArrayLength(jVendor);
563     selector.vendorIds.resize(count);
564     auto jVendorElements = env->GetLongArrayElements(jVendor, nullptr);
565     for (jint i = 0; i < count; i++) {
566         selector.vendorIds[i] = jVendorElements[i];
567     }
568     env->ReleaseLongArrayElements(jVendor, jVendorElements, 0);
569 
570     return selector;
571 }
572 
ProgramInfoFromHal(JNIEnv * env,const V1_0::ProgramInfo & info10,const V1_1::ProgramInfo * info11,const ProgramSelector & selector)573 static JavaRef<jobject> ProgramInfoFromHal(JNIEnv *env, const V1_0::ProgramInfo &info10,
574         const V1_1::ProgramInfo *info11, const ProgramSelector &selector) {
575     ALOGV("%s", __func__);
576 
577     auto jMetadata = MetadataFromHal(env, info10.metadata);
578     auto jVendorInfo = info11 ? VendorInfoFromHal(env, info11->vendorInfo) : nullptr;
579     auto jSelector = ProgramSelectorFromHal(env, selector);
580 
581     return make_javaref(env, env->NewObject(gjni.ProgramInfo.clazz, gjni.ProgramInfo.cstor,
582             jSelector.get(), info10.tuned, info10.stereo, info10.digital, info10.signalStrength,
583             jMetadata.get(), info11 ? info11->flags : 0, jVendorInfo.get()));
584 }
585 
ProgramInfoFromHal(JNIEnv * env,const V1_0::ProgramInfo & info,V1_0::Band band)586 JavaRef<jobject> ProgramInfoFromHal(JNIEnv *env, const V1_0::ProgramInfo &info, V1_0::Band band) {
587     auto selector = utils::make_selector(band, info.channel, info.subChannel);
588     return ProgramInfoFromHal(env, info, nullptr, selector);
589 }
590 
ProgramInfoFromHal(JNIEnv * env,const V1_1::ProgramInfo & info)591 JavaRef<jobject> ProgramInfoFromHal(JNIEnv *env, const V1_1::ProgramInfo &info) {
592     return ProgramInfoFromHal(env, info.base, &info, info.selector);
593 }
594 
595 } // namespace convert
596 } // namespace BroadcastRadio
597 } // namespace server
598 
register_android_server_broadcastradio_convert(JNIEnv * env)599 void register_android_server_broadcastradio_convert(JNIEnv *env) {
600     using namespace server::BroadcastRadio::convert;
601 
602     auto bandConfigClass = FindClassOrDie(env, "android/hardware/radio/RadioManager$BandConfig");
603     gjni.BandConfig.descriptor = GetFieldIDOrDie(env, bandConfigClass,
604             "mDescriptor", "Landroid/hardware/radio/RadioManager$BandDescriptor;");
605 
606     auto fmBandConfigClass = FindClassOrDie(env,
607             "android/hardware/radio/RadioManager$FmBandConfig");
608     gjni.FmBandConfig.clazz = MakeGlobalRefOrDie(env, fmBandConfigClass);
609     gjni.FmBandConfig.cstor = GetMethodIDOrDie(env, fmBandConfigClass,
610             "<init>", "(Landroid/hardware/radio/RadioManager$FmBandDescriptor;)V");
611     gjni.FmBandConfig.stereo = GetFieldIDOrDie(env, fmBandConfigClass, "mStereo", "Z");
612     gjni.FmBandConfig.rds = GetFieldIDOrDie(env, fmBandConfigClass, "mRds", "Z");
613     gjni.FmBandConfig.ta = GetFieldIDOrDie(env, fmBandConfigClass, "mTa", "Z");
614     gjni.FmBandConfig.af = GetFieldIDOrDie(env, fmBandConfigClass, "mAf", "Z");
615     gjni.FmBandConfig.ea = GetFieldIDOrDie(env, fmBandConfigClass, "mEa", "Z");
616 
617     auto amBandConfigClass = FindClassOrDie(env,
618             "android/hardware/radio/RadioManager$AmBandConfig");
619     gjni.AmBandConfig.clazz = MakeGlobalRefOrDie(env, amBandConfigClass);
620     gjni.AmBandConfig.cstor = GetMethodIDOrDie(env, amBandConfigClass,
621             "<init>", "(Landroid/hardware/radio/RadioManager$AmBandDescriptor;)V");
622     gjni.AmBandConfig.stereo = GetFieldIDOrDie(env, amBandConfigClass, "mStereo", "Z");
623 
624     auto bandDescriptorClass = FindClassOrDie(env,
625             "android/hardware/radio/RadioManager$BandDescriptor");
626     gjni.BandDescriptor.clazz = MakeGlobalRefOrDie(env, bandDescriptorClass);
627     gjni.BandDescriptor.region = GetFieldIDOrDie(env, bandDescriptorClass, "mRegion", "I");
628     gjni.BandDescriptor.type = GetFieldIDOrDie(env, bandDescriptorClass, "mType", "I");
629     gjni.BandDescriptor.lowerLimit = GetFieldIDOrDie(env, bandDescriptorClass, "mLowerLimit", "I");
630     gjni.BandDescriptor.upperLimit = GetFieldIDOrDie(env, bandDescriptorClass, "mUpperLimit", "I");
631     gjni.BandDescriptor.spacing = GetFieldIDOrDie(env, bandDescriptorClass, "mSpacing", "I");
632 
633     auto fmBandDescriptorClass = FindClassOrDie(env,
634             "android/hardware/radio/RadioManager$FmBandDescriptor");
635     gjni.FmBandDescriptor.clazz = MakeGlobalRefOrDie(env, fmBandDescriptorClass);
636     gjni.FmBandDescriptor.cstor = GetMethodIDOrDie(env, fmBandDescriptorClass,
637             "<init>", "(IIIIIZZZZZ)V");
638 
639     auto amBandDescriptorClass = FindClassOrDie(env,
640             "android/hardware/radio/RadioManager$AmBandDescriptor");
641     gjni.AmBandDescriptor.clazz = MakeGlobalRefOrDie(env, amBandDescriptorClass);
642     gjni.AmBandDescriptor.cstor = GetMethodIDOrDie(env, amBandDescriptorClass,
643             "<init>", "(IIIIIZ)V");
644 
645     auto convertClass = FindClassOrDie(env, "com/android/server/broadcastradio/Convert");
646     gjni.Convert.clazz = MakeGlobalRefOrDie(env, convertClass);
647     gjni.Convert.stringMapToNative = GetStaticMethodIDOrDie(env, convertClass, "stringMapToNative",
648             "(Ljava/util/Map;)[[Ljava/lang/String;");
649 
650     auto hashMapClass = FindClassOrDie(env, "java/util/HashMap");
651     gjni.HashMap.clazz = MakeGlobalRefOrDie(env, hashMapClass);
652     gjni.HashMap.cstor = GetMethodIDOrDie(env, hashMapClass, "<init>", "()V");
653 
654     auto mapClass = FindClassOrDie(env, "java/util/Map");
655     gjni.Map.put = GetMethodIDOrDie(env, mapClass, "put",
656             "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
657 
658     auto modulePropertiesClass = FindClassOrDie(env,
659             "android/hardware/radio/RadioManager$ModuleProperties");
660     gjni.ModuleProperties.clazz = MakeGlobalRefOrDie(env, modulePropertiesClass);
661     gjni.ModuleProperties.cstor = GetMethodIDOrDie(env, modulePropertiesClass, "<init>",
662             "(ILjava/lang/String;ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;"
663             "Ljava/lang/String;IIZ[Landroid/hardware/radio/RadioManager$BandDescriptor;Z"
664             "[I[ILjava/util/Map;)V");
665 
666     auto programInfoClass = FindClassOrDie(env, "android/hardware/radio/RadioManager$ProgramInfo");
667     gjni.ProgramInfo.clazz = MakeGlobalRefOrDie(env, programInfoClass);
668     gjni.ProgramInfo.cstor = GetMethodIDOrDie(env, programInfoClass, "<init>",
669             "(Landroid/hardware/radio/ProgramSelector;ZZZILandroid/hardware/radio/RadioMetadata;I"
670             "Ljava/util/Map;)V");
671 
672     auto programSelectorClass = FindClassOrDie(env, "android/hardware/radio/ProgramSelector");
673     gjni.ProgramSelector.clazz = MakeGlobalRefOrDie(env, programSelectorClass);
674     gjni.ProgramSelector.cstor = GetMethodIDOrDie(env, programSelectorClass, "<init>",
675             "(ILandroid/hardware/radio/ProgramSelector$Identifier;"
676             "[Landroid/hardware/radio/ProgramSelector$Identifier;[J)V");
677     gjni.ProgramSelector.programType = GetFieldIDOrDie(env, programSelectorClass,
678             "mProgramType", "I");
679     gjni.ProgramSelector.primaryId = GetFieldIDOrDie(env, programSelectorClass,
680             "mPrimaryId", "Landroid/hardware/radio/ProgramSelector$Identifier;");
681     gjni.ProgramSelector.secondaryIds = GetFieldIDOrDie(env, programSelectorClass,
682             "mSecondaryIds", "[Landroid/hardware/radio/ProgramSelector$Identifier;");
683     gjni.ProgramSelector.vendorIds = GetFieldIDOrDie(env, programSelectorClass,
684             "mVendorIds", "[J");
685 
686     auto progSelIdClass = FindClassOrDie(env, "android/hardware/radio/ProgramSelector$Identifier");
687     gjni.ProgramSelector.Identifier.clazz = MakeGlobalRefOrDie(env, progSelIdClass);
688     gjni.ProgramSelector.Identifier.cstor = GetMethodIDOrDie(env, progSelIdClass,
689             "<init>", "(IJ)V");
690     gjni.ProgramSelector.Identifier.type = GetFieldIDOrDie(env, progSelIdClass,
691             "mType", "I");
692     gjni.ProgramSelector.Identifier.value = GetFieldIDOrDie(env, progSelIdClass,
693             "mValue", "J");
694 
695     auto radioMetadataClass = FindClassOrDie(env, "android/hardware/radio/RadioMetadata");
696     gjni.RadioMetadata.clazz = MakeGlobalRefOrDie(env, radioMetadataClass);
697     gjni.RadioMetadata.cstor = GetMethodIDOrDie(env, radioMetadataClass, "<init>", "()V");
698     gjni.RadioMetadata.putIntFromNative = GetMethodIDOrDie(env, radioMetadataClass,
699             "putIntFromNative", "(II)I");
700     gjni.RadioMetadata.putStringFromNative = GetMethodIDOrDie(env, radioMetadataClass,
701             "putStringFromNative", "(ILjava/lang/String;)I");
702     gjni.RadioMetadata.putBitmapFromNative = GetMethodIDOrDie(env, radioMetadataClass,
703             "putBitmapFromNative", "(I[B)I");
704     gjni.RadioMetadata.putClockFromNative = GetMethodIDOrDie(env, radioMetadataClass,
705             "putClockFromNative", "(IJI)I");
706 
707     auto runtimeExcClass = FindClassOrDie(env, "java/lang/RuntimeException");
708     gjni.RuntimeException.clazz = MakeGlobalRefOrDie(env, runtimeExcClass);
709     gjni.RuntimeException.cstor = GetMethodIDOrDie(env, runtimeExcClass, "<init>",
710             "(Ljava/lang/String;)V");
711 
712     auto parcelableExcClass = FindClassOrDie(env, "android/os/ParcelableException");
713     gjni.ParcelableException.clazz = MakeGlobalRefOrDie(env, parcelableExcClass);
714     gjni.ParcelableException.cstor = GetMethodIDOrDie(env, parcelableExcClass, "<init>",
715             "(Ljava/lang/Throwable;)V");
716 }
717 
718 } // namespace android
719