• 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.jni"
18 #define LOG_NDEBUG 0
19 
20 #include "BroadcastRadioService.h"
21 
22 #include "Tuner.h"
23 #include "convert.h"
24 
25 #include <android/hardware/broadcastradio/1.1/IBroadcastRadio.h>
26 #include <android/hardware/broadcastradio/1.1/IBroadcastRadioFactory.h>
27 #include <android/hidl/manager/1.0/IServiceManager.h>
28 #include <core_jni_helpers.h>
29 #include <hidl/ServiceManagement.h>
30 #include <nativehelper/JNIHelp.h>
31 #include <utils/Log.h>
32 
33 namespace android {
34 namespace server {
35 namespace BroadcastRadio {
36 namespace BroadcastRadioService {
37 
38 using std::lock_guard;
39 using std::mutex;
40 
41 using hardware::Return;
42 using hardware::hidl_string;
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::Class;
49 using V1_0::Result;
50 
51 using V1_0::BandConfig;
52 using V1_0::ProgramInfo;
53 using V1_0::MetaData;
54 using V1_0::ITuner;
55 
56 static mutex gContextMutex;
57 
58 static struct {
59     struct {
60         jclass clazz;
61         jmethodID cstor;
62         jmethodID add;
63     } ArrayList;
64     struct {
65         jclass clazz;
66         jmethodID cstor;
67     } Tuner;
68 } gjni;
69 
70 struct ServiceContext {
ServiceContextandroid::server::BroadcastRadio::BroadcastRadioService::ServiceContext71     ServiceContext() {}
72 
73     std::vector<sp<V1_0::IBroadcastRadio>> mModules;
74 
75 private:
76     DISALLOW_COPY_AND_ASSIGN(ServiceContext);
77 };
78 
79 const std::vector<Class> gAllClasses = {
80     Class::AM_FM,
81     Class::SAT,
82     Class::DT,
83 };
84 
85 
86 /**
87  * Always lock gContextMutex when using native context.
88  */
getNativeContext(jlong nativeContextHandle)89 static ServiceContext& getNativeContext(jlong nativeContextHandle) {
90     auto nativeContext = reinterpret_cast<ServiceContext*>(nativeContextHandle);
91     LOG_ALWAYS_FATAL_IF(nativeContext == nullptr, "Native context not initialized");
92     return *nativeContext;
93 }
94 
nativeInit(JNIEnv * env,jobject obj)95 static jlong nativeInit(JNIEnv *env, jobject obj) {
96     ALOGV("%s", __func__);
97     lock_guard<mutex> lk(gContextMutex);
98 
99     auto nativeContext = new ServiceContext();
100     static_assert(sizeof(jlong) >= sizeof(nativeContext), "jlong is smaller than a pointer");
101     return reinterpret_cast<jlong>(nativeContext);
102 }
103 
nativeFinalize(JNIEnv * env,jobject obj,jlong nativeContext)104 static void nativeFinalize(JNIEnv *env, jobject obj, jlong nativeContext) {
105     ALOGV("%s", __func__);
106     lock_guard<mutex> lk(gContextMutex);
107 
108     auto ctx = reinterpret_cast<ServiceContext*>(nativeContext);
109     delete ctx;
110 }
111 
nativeLoadModules(JNIEnv * env,jobject obj,jlong nativeContext)112 static jobject nativeLoadModules(JNIEnv *env, jobject obj, jlong nativeContext) {
113     ALOGV("%s", __func__);
114     lock_guard<mutex> lk(gContextMutex);
115     auto& ctx = getNativeContext(nativeContext);
116 
117     // Get list of registered HIDL HAL implementations.
118     auto manager = hardware::defaultServiceManager();
119     hidl_vec<hidl_string> services;
120     if (manager == nullptr) {
121         ALOGE("Can't reach service manager, using default service implementation only");
122         services = std::vector<hidl_string>({ "default" });
123     } else {
124         manager->listByInterface(V1_0::IBroadcastRadioFactory::descriptor,
125                 [&services](const hidl_vec<hidl_string> &registered) {
126             services = registered;
127         });
128     }
129 
130     // Scan provided list for actually implemented modules.
131     ctx.mModules.clear();
132     auto jModules = make_javaref(env, env->NewObject(gjni.ArrayList.clazz, gjni.ArrayList.cstor));
133     for (auto&& serviceName : services) {
134         ALOGV("checking service: %s", serviceName.c_str());
135 
136         auto factory = V1_0::IBroadcastRadioFactory::getService(serviceName);
137         if (factory == nullptr) {
138             ALOGE("can't load service %s", serviceName.c_str());
139             continue;
140         }
141 
142         // Second level of scanning - that's unfortunate.
143         for (auto&& clazz : gAllClasses) {
144             sp<V1_0::IBroadcastRadio> module10 = nullptr;
145             sp<V1_1::IBroadcastRadio> module11 = nullptr;
146             factory->connectModule(clazz, [&](Result res, const sp<V1_0::IBroadcastRadio>& module) {
147                 if (res == Result::OK) {
148                     module10 = module;
149                     module11 = V1_1::IBroadcastRadio::castFrom(module).withDefault(nullptr);
150                 } else if (res != Result::INVALID_ARGUMENTS) {
151                     ALOGE("couldn't load %s:%s module",
152                             serviceName.c_str(), V1_0::toString(clazz).c_str());
153                 }
154             });
155             if (module10 == nullptr) continue;
156 
157             auto idx = ctx.mModules.size();
158             ctx.mModules.push_back(module10);
159             ALOGI("loaded broadcast radio module %zu: %s:%s",
160                     idx, serviceName.c_str(), V1_0::toString(clazz).c_str());
161 
162             JavaRef<jobject> jModule = nullptr;
163             Result halResult = Result::OK;
164             Return<void> hidlResult;
165             if (module11 != nullptr) {
166                 hidlResult = module11->getProperties_1_1([&](const V1_1::Properties& properties) {
167                     jModule = convert::ModulePropertiesFromHal(env, properties, idx, serviceName);
168                 });
169             } else {
170                 hidlResult = module10->getProperties([&](Result result,
171                         const V1_0::Properties& properties) {
172                     halResult = result;
173                     if (result != Result::OK) return;
174                     jModule = convert::ModulePropertiesFromHal(env, properties, idx, serviceName);
175                 });
176             }
177             if (convert::ThrowIfFailed(env, hidlResult, halResult)) return nullptr;
178 
179             env->CallBooleanMethod(jModules.get(), gjni.ArrayList.add, jModule.get());
180         }
181     }
182 
183     return jModules.release();
184 }
185 
nativeOpenTuner(JNIEnv * env,jobject obj,long nativeContext,jint moduleId,jobject bandConfig,bool withAudio,jobject callback)186 static jobject nativeOpenTuner(JNIEnv *env, jobject obj, long nativeContext, jint moduleId,
187         jobject bandConfig, bool withAudio, jobject callback) {
188     ALOGV("%s", __func__);
189     lock_guard<mutex> lk(gContextMutex);
190     auto& ctx = getNativeContext(nativeContext);
191 
192     if (callback == nullptr) {
193         ALOGE("Callback is empty");
194         return nullptr;
195     }
196 
197     if (moduleId < 0 || static_cast<size_t>(moduleId) >= ctx.mModules.size()) {
198         ALOGE("Invalid module ID: %d", moduleId);
199         return nullptr;
200     }
201     auto module = ctx.mModules[moduleId];
202 
203     HalRevision halRev;
204     if (V1_1::IBroadcastRadio::castFrom(module).withDefault(nullptr) != nullptr) {
205         ALOGI("Opening tuner %d with broadcast radio HAL 1.1", moduleId);
206         halRev = HalRevision::V1_1;
207     } else {
208         ALOGI("Opening tuner %d with broadcast radio HAL 1.0", moduleId);
209         halRev = HalRevision::V1_0;
210     }
211 
212     Region region;
213     BandConfig bandConfigHal = convert::BandConfigToHal(env, bandConfig, region);
214 
215     auto tuner = make_javaref(env, env->NewObject(gjni.Tuner.clazz, gjni.Tuner.cstor,
216             callback, halRev, region, withAudio, bandConfigHal.type));
217     if (tuner == nullptr) {
218         ALOGE("Unable to create new tuner object.");
219         return nullptr;
220     }
221 
222     auto tunerCb = Tuner::getNativeCallback(env, tuner);
223     Result halResult;
224     sp<ITuner> halTuner = nullptr;
225 
226     auto hidlResult = module->openTuner(bandConfigHal, withAudio, tunerCb,
227             [&](Result result, const sp<ITuner>& tuner) {
228                 halResult = result;
229                 halTuner = tuner;
230             });
231     if (!hidlResult.isOk() || halResult != Result::OK || halTuner == nullptr) {
232         ALOGE("Couldn't open tuner");
233         ALOGE_IF(hidlResult.isOk(), "halResult = %d", halResult);
234         ALOGE_IF(!hidlResult.isOk(), "hidlResult = %s", hidlResult.description().c_str());
235         return nullptr;
236     }
237 
238     Tuner::assignHalInterfaces(env, tuner, module, halTuner);
239     ALOGD("Opened tuner %p", halTuner.get());
240     return tuner.release();
241 }
242 
243 static const JNINativeMethod gRadioServiceMethods[] = {
244     { "nativeInit", "()J", (void*)nativeInit },
245     { "nativeFinalize", "(J)V", (void*)nativeFinalize },
246     { "nativeLoadModules", "(J)Ljava/util/List;", (void*)nativeLoadModules },
247     { "nativeOpenTuner", "(JILandroid/hardware/radio/RadioManager$BandConfig;Z"
248             "Landroid/hardware/radio/ITunerCallback;)Lcom/android/server/broadcastradio/Tuner;",
249             (void*)nativeOpenTuner },
250 };
251 
252 } // namespace BroadcastRadioService
253 } // namespace BroadcastRadio
254 } // namespace server
255 
register_android_server_broadcastradio_BroadcastRadioService(JNIEnv * env)256 void register_android_server_broadcastradio_BroadcastRadioService(JNIEnv *env) {
257     using namespace server::BroadcastRadio::BroadcastRadioService;
258 
259     register_android_server_broadcastradio_convert(env);
260 
261     auto tunerClass = FindClassOrDie(env, "com/android/server/broadcastradio/Tuner");
262     gjni.Tuner.clazz = MakeGlobalRefOrDie(env, tunerClass);
263     gjni.Tuner.cstor = GetMethodIDOrDie(env, tunerClass, "<init>",
264             "(Landroid/hardware/radio/ITunerCallback;IIZI)V");
265 
266     auto arrayListClass = FindClassOrDie(env, "java/util/ArrayList");
267     gjni.ArrayList.clazz = MakeGlobalRefOrDie(env, arrayListClass);
268     gjni.ArrayList.cstor = GetMethodIDOrDie(env, arrayListClass, "<init>", "()V");
269     gjni.ArrayList.add = GetMethodIDOrDie(env, arrayListClass, "add", "(Ljava/lang/Object;)Z");
270 
271     auto res = jniRegisterNativeMethods(env,
272             "com/android/server/broadcastradio/BroadcastRadioService",
273             gRadioServiceMethods, NELEM(gRadioServiceMethods));
274     LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register native methods.");
275 }
276 
277 } // namespace android
278