• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 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_NDEBUG 0
18 #define LOG_TAG "android_os_HwBinder"
19 #include <android-base/logging.h>
20 
21 #include "android_os_HwBinder.h"
22 
23 #include "android_os_HwParcel.h"
24 #include "android_os_HwRemoteBinder.h"
25 
26 #include <cstring>
27 
28 #include <nativehelper/JNIHelp.h>
29 #include <android/hidl/manager/1.0/IServiceManager.h>
30 #include <android/hidl/base/1.0/IBase.h>
31 #include <android/hidl/base/1.0/BpHwBase.h>
32 #include <android_runtime/AndroidRuntime.h>
33 #include <hidl/ServiceManagement.h>
34 #include <hidl/Status.h>
35 #include <hidl/HidlTransportSupport.h>
36 #include <hwbinder/IPCThreadState.h>
37 #include <hwbinder/ProcessState.h>
38 #include <nativehelper/ScopedLocalRef.h>
39 #include <nativehelper/ScopedUtfChars.h>
40 #include <vintf/parse_string.h>
41 #include <utils/misc.h>
42 
43 #include "core_jni_helpers.h"
44 
45 using android::AndroidRuntime;
46 using android::hardware::hidl_vec;
47 using android::hardware::hidl_string;
48 using android::hardware::IPCThreadState;
49 using android::hardware::ProcessState;
50 template<typename T>
51 using Return = android::hardware::Return<T>;
52 
53 #define PACKAGE_PATH    "android/os"
54 #define CLASS_NAME      "HwBinder"
55 #define CLASS_PATH      PACKAGE_PATH "/" CLASS_NAME
56 
57 namespace android {
58 
59 static jclass gErrorClass;
60 
61 static struct fields_t {
62     jfieldID contextID;
63     jmethodID onTransactID;
64 } gFields;
65 
66 struct JHwBinderHolder : public RefBase {
JHwBinderHolderandroid::JHwBinderHolder67     JHwBinderHolder() {}
68 
getandroid::JHwBinderHolder69     sp<JHwBinder> get(JNIEnv *env, jobject obj) {
70         Mutex::Autolock autoLock(mLock);
71 
72         sp<JHwBinder> binder = mBinder.promote();
73 
74         if (binder == NULL) {
75             binder = new JHwBinder(env, obj);
76             mBinder = binder;
77         }
78 
79         return binder;
80     }
81 
82 private:
83     Mutex mLock;
84     wp<JHwBinder> mBinder;
85 
86     DISALLOW_COPY_AND_ASSIGN(JHwBinderHolder);
87 };
88 
89 // static
InitClass(JNIEnv * env)90 void JHwBinder::InitClass(JNIEnv *env) {
91     ScopedLocalRef<jclass> clazz(
92             env, FindClassOrDie(env, CLASS_PATH));
93 
94     gFields.contextID =
95         GetFieldIDOrDie(env, clazz.get(), "mNativeContext", "J");
96 
97     gFields.onTransactID =
98         GetMethodIDOrDie(
99                 env,
100                 clazz.get(),
101                 "onTransact",
102                 "(IL" PACKAGE_PATH "/HwParcel;L" PACKAGE_PATH "/HwParcel;I)V");
103 }
104 
105 // static
SetNativeContext(JNIEnv * env,jobject thiz,const sp<JHwBinderHolder> & context)106 sp<JHwBinderHolder> JHwBinder::SetNativeContext(
107         JNIEnv *env, jobject thiz, const sp<JHwBinderHolder> &context) {
108     sp<JHwBinderHolder> old =
109         (JHwBinderHolder *)env->GetLongField(thiz, gFields.contextID);
110 
111     if (context != NULL) {
112         context->incStrong(NULL /* id */);
113     }
114 
115     if (old != NULL) {
116         old->decStrong(NULL /* id */);
117     }
118 
119     env->SetLongField(thiz, gFields.contextID, (long)context.get());
120 
121     return old;
122 }
123 
124 // static
GetNativeBinder(JNIEnv * env,jobject thiz)125 sp<JHwBinder> JHwBinder::GetNativeBinder(
126         JNIEnv *env, jobject thiz) {
127     JHwBinderHolder *holder =
128         reinterpret_cast<JHwBinderHolder *>(
129                 env->GetLongField(thiz, gFields.contextID));
130 
131     return holder->get(env, thiz);
132 }
133 
JHwBinder(JNIEnv * env,jobject thiz)134 JHwBinder::JHwBinder(JNIEnv *env, jobject thiz) {
135     jclass clazz = env->GetObjectClass(thiz);
136     CHECK(clazz != NULL);
137 
138     mObject = env->NewGlobalRef(thiz);
139 }
140 
~JHwBinder()141 JHwBinder::~JHwBinder() {
142     JNIEnv *env = AndroidRuntime::getJNIEnv();
143 
144     env->DeleteGlobalRef(mObject);
145     mObject = NULL;
146 }
147 
onTransact(uint32_t code,const hardware::Parcel & data,hardware::Parcel * reply,uint32_t flags,TransactCallback callback)148 status_t JHwBinder::onTransact(
149         uint32_t code,
150         const hardware::Parcel &data,
151         hardware::Parcel *reply,
152         uint32_t flags,
153         TransactCallback callback) {
154     JNIEnv *env = AndroidRuntime::getJNIEnv();
155     bool isOneway = (flags & TF_ONE_WAY) != 0;
156     ScopedLocalRef<jobject> replyObj(env, nullptr);
157     sp<JHwParcel> replyContext = nullptr;
158 
159     ScopedLocalRef<jobject> requestObj(env, JHwParcel::NewObject(env));
160     JHwParcel::GetNativeContext(env, requestObj.get())->setParcel(
161             const_cast<hardware::Parcel *>(&data), false /* assumeOwnership */);
162 
163 
164     if (!isOneway) {
165         replyObj.reset(JHwParcel::NewObject(env));
166 
167         replyContext = JHwParcel::GetNativeContext(env, replyObj.get());
168 
169         replyContext->setParcel(reply, false /* assumeOwnership */);
170         replyContext->setTransactCallback(callback);
171     }
172 
173     env->CallVoidMethod(
174             mObject,
175             gFields.onTransactID,
176             code,
177             requestObj.get(),
178             replyObj.get(),
179             flags);
180 
181     if (env->ExceptionCheck()) {
182         jthrowable excep = env->ExceptionOccurred();
183         env->ExceptionDescribe();
184         env->ExceptionClear();
185 
186         // It is illegal to call IsInstanceOf if there is a pending exception.
187         // Attempting to do so results in a JniAbort which crashes the entire process.
188         if (env->IsInstanceOf(excep, gErrorClass)) {
189             /* It's an error */
190             LOG(ERROR) << "Forcefully exiting";
191             exit(1);
192         } else {
193             LOG(ERROR) << "Uncaught exception!";
194         }
195 
196         env->DeleteLocalRef(excep);
197     }
198 
199     status_t err = OK;
200 
201     if (!isOneway) {
202         if (!replyContext->wasSent()) {
203             // The implementation never finished the transaction.
204             err = UNKNOWN_ERROR;  // XXX special error code instead?
205 
206             reply->setDataPosition(0 /* pos */);
207         }
208 
209         // Release all temporary storage now that scatter-gather data
210         // has been consolidated, either by calling the TransactCallback,
211         // if wasSent() == true or clearing the reply parcel (setDataOffset above).
212         replyContext->getStorage()->release(env);
213 
214         // We cannot permanently pass ownership of "data" and "reply" over to their
215         // Java object wrappers (we don't own them ourselves).
216         replyContext->setParcel(
217                 NULL /* parcel */, false /* assumeOwnership */);
218 
219     }
220 
221     JHwParcel::GetNativeContext(env, requestObj.get())->setParcel(
222             NULL /* parcel */, false /* assumeOwnership */);
223 
224     return err;
225 }
226 
227 }  // namespace android
228 
229 ////////////////////////////////////////////////////////////////////////////////
230 
231 using namespace android;
232 
releaseNativeContext(void * nativeContext)233 static void releaseNativeContext(void *nativeContext) {
234     sp<JHwBinderHolder> context = static_cast<JHwBinderHolder *>(nativeContext);
235 
236     if (context != NULL) {
237         context->decStrong(NULL /* id */);
238     }
239 }
240 
JHwBinder_native_init(JNIEnv * env)241 static jlong JHwBinder_native_init(JNIEnv *env) {
242     JHwBinder::InitClass(env);
243 
244     return reinterpret_cast<jlong>(&releaseNativeContext);
245 }
246 
JHwBinder_native_setup(JNIEnv * env,jobject thiz)247 static void JHwBinder_native_setup(JNIEnv *env, jobject thiz) {
248     sp<JHwBinderHolder> context = new JHwBinderHolder;
249     JHwBinder::SetNativeContext(env, thiz, context);
250 }
251 
JHwBinder_native_transact(JNIEnv *,jobject,jint,jobject,jobject,jint)252 static void JHwBinder_native_transact(
253         JNIEnv * /* env */,
254         jobject /* thiz */,
255         jint /* code */,
256         jobject /* requestObj */,
257         jobject /* replyObj */,
258         jint /* flags */) {
259     CHECK(!"Should not be here");
260 }
261 
JHwBinder_native_registerService(JNIEnv * env,jobject thiz,jstring serviceNameObj)262 static void JHwBinder_native_registerService(
263         JNIEnv *env,
264         jobject thiz,
265         jstring serviceNameObj) {
266     ScopedUtfChars str(env, serviceNameObj);
267     if (str.c_str() == nullptr) {
268         return;  // NPE will be pending.
269     }
270 
271     sp<hardware::IBinder> binder = JHwBinder::GetNativeBinder(env, thiz);
272 
273     /* TODO(b/33440494) this is not right */
274     sp<hidl::base::V1_0::IBase> base = new hidl::base::V1_0::BpHwBase(binder);
275 
276     auto manager = hardware::defaultServiceManager();
277 
278     if (manager == nullptr) {
279         LOG(ERROR) << "Could not get hwservicemanager.";
280         signalExceptionForError(env, UNKNOWN_ERROR, true /* canThrowRemoteException */);
281         return;
282     }
283 
284     Return<bool> ret = manager->add(str.c_str(), base);
285 
286     bool ok = ret.isOk() && ret;
287 
288     if (ok) {
289         LOG(INFO) << "HwBinder: Starting thread pool for " << str.c_str();
290         ::android::hardware::ProcessState::self()->startThreadPool();
291     }
292 
293     signalExceptionForError(env, (ok ? OK : UNKNOWN_ERROR), true /* canThrowRemoteException */);
294 }
295 
JHwBinder_native_getService(JNIEnv * env,jclass,jstring ifaceNameObj,jstring serviceNameObj,jboolean retry)296 static jobject JHwBinder_native_getService(
297         JNIEnv *env,
298         jclass /* clazzObj */,
299         jstring ifaceNameObj,
300         jstring serviceNameObj,
301         jboolean retry) {
302 
303     using ::android::hidl::base::V1_0::IBase;
304     using ::android::hardware::details::getRawServiceInternal;
305 
306     std::string ifaceName;
307     {
308         ScopedUtfChars str(env, ifaceNameObj);
309         if (str.c_str() == nullptr) {
310             return nullptr;  // NPE will be pending.
311         }
312         ifaceName = str.c_str();
313     }
314 
315     std::string serviceName;
316     {
317         ScopedUtfChars str(env, serviceNameObj);
318         if (str.c_str() == nullptr) {
319             return nullptr;  // NPE will be pending.
320         }
321         serviceName = str.c_str();
322     }
323 
324     sp<IBase> ret = getRawServiceInternal(ifaceName, serviceName, retry /* retry */, false /* getStub */);
325     sp<hardware::IBinder> service = hardware::toBinder<hidl::base::V1_0::IBase>(ret);
326 
327     if (service == NULL) {
328         signalExceptionForError(env, NAME_NOT_FOUND);
329         return NULL;
330     }
331 
332     LOG(INFO) << "HwBinder: Starting thread pool for getting: " << ifaceName << "/" << serviceName;
333     ::android::hardware::ProcessState::self()->startThreadPool();
334 
335     return JHwRemoteBinder::NewObject(env, service);
336 }
337 
JHwBinder_native_configureRpcThreadpool(JNIEnv *,jclass,jlong maxThreads,jboolean callerWillJoin)338 void JHwBinder_native_configureRpcThreadpool(JNIEnv *, jclass,
339         jlong maxThreads, jboolean callerWillJoin) {
340     CHECK(maxThreads > 0);
341     ProcessState::self()->setThreadPoolConfiguration(maxThreads, callerWillJoin /*callerJoinsPool*/);
342 }
343 
JHwBinder_native_joinRpcThreadpool()344 void JHwBinder_native_joinRpcThreadpool() {
345     IPCThreadState::self()->joinThreadPool();
346 }
347 
JHwBinder_report_sysprop_change(JNIEnv *,jclass)348 static void JHwBinder_report_sysprop_change(JNIEnv * /*env*/, jclass /*clazz*/)
349 {
350     report_sysprop_change();
351 }
352 
353 static JNINativeMethod gMethods[] = {
354     { "native_init", "()J", (void *)JHwBinder_native_init },
355     { "native_setup", "()V", (void *)JHwBinder_native_setup },
356 
357     { "transact",
358         "(IL" PACKAGE_PATH "/HwParcel;L" PACKAGE_PATH "/HwParcel;I)V",
359         (void *)JHwBinder_native_transact },
360 
361     { "registerService", "(Ljava/lang/String;)V",
362         (void *)JHwBinder_native_registerService },
363 
364     { "getService", "(Ljava/lang/String;Ljava/lang/String;Z)L" PACKAGE_PATH "/IHwBinder;",
365         (void *)JHwBinder_native_getService },
366 
367     { "configureRpcThreadpool", "(JZ)V",
368         (void *)JHwBinder_native_configureRpcThreadpool },
369 
370     { "joinRpcThreadpool", "()V",
371         (void *)JHwBinder_native_joinRpcThreadpool },
372 
373     { "native_report_sysprop_change", "()V",
374         (void *)JHwBinder_report_sysprop_change },
375 };
376 
377 namespace android {
378 
register_android_os_HwBinder(JNIEnv * env)379 int register_android_os_HwBinder(JNIEnv *env) {
380     jclass errorClass = FindClassOrDie(env, "java/lang/Error");
381     gErrorClass = MakeGlobalRefOrDie(env, errorClass);
382 
383     return RegisterMethodsOrDie(env, CLASS_PATH, gMethods, NELEM(gMethods));
384 }
385 
386 }  // namespace android
387