blob: f8f841c6fd26daa382d8954e24505aa3ae1130bf [file] [log] [blame]
Andreas Huberdab5fc62016-08-15 09:25:02 -07001/*
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 "JHwRemoteBinder"
19#include <android-base/logging.h>
20
21#include "android_os_HwRemoteBinder.h"
22
23#include "android_os_HwParcel.h"
24
Yifan Hong73b6c272017-10-31 17:32:15 -070025#include <android/hidl/base/1.0/IBase.h>
26#include <android/hidl/base/1.0/BpHwBase.h>
27#include <android/hidl/base/1.0/BnHwBase.h>
Andreas Huberdab5fc62016-08-15 09:25:02 -070028#include <android_runtime/AndroidRuntime.h>
Martijn Coenenaa2c32f2016-09-01 01:37:05 +020029#include <hidl/Status.h>
Yifan Hong73b6c272017-10-31 17:32:15 -070030#include <hidl/HidlTransportSupport.h>
31#include <nativehelper/JNIHelp.h>
Steven Moreland2279b252017-07-19 09:50:45 -070032#include <nativehelper/ScopedUtfChars.h>
Andreas Huberdab5fc62016-08-15 09:25:02 -070033#include <nativehelper/ScopedLocalRef.h>
34
35#include "core_jni_helpers.h"
36
37using android::AndroidRuntime;
38
39#define PACKAGE_PATH "android/os"
40#define CLASS_NAME "HwRemoteBinder"
41#define CLASS_PATH PACKAGE_PATH "/" CLASS_NAME
42
43namespace android {
44
45static struct fields_t {
Martijn Coenen727f7bf2016-12-27 14:33:09 +010046 jclass proxy_class;
Andreas Huberdab5fc62016-08-15 09:25:02 -070047 jfieldID contextID;
48 jmethodID constructID;
Martijn Coenen727f7bf2016-12-27 14:33:09 +010049 jmethodID sendDeathNotice;
50} gProxyOffsets;
Andreas Huberdab5fc62016-08-15 09:25:02 -070051
Martijn Coenen727f7bf2016-12-27 14:33:09 +010052static struct class_offsets_t
53{
54 jmethodID mGetName;
55} gClassOffsets;
56
57static JavaVM* jnienv_to_javavm(JNIEnv* env)
58{
59 JavaVM* vm;
60 return env->GetJavaVM(&vm) >= 0 ? vm : NULL;
61}
62
63static JNIEnv* javavm_to_jnienv(JavaVM* vm)
64{
65 JNIEnv* env;
66 return vm->GetEnv((void **)&env, JNI_VERSION_1_4) >= 0 ? env : NULL;
67}
68
69// ----------------------------------------------------------------------------
70class HwBinderDeathRecipient : public hardware::IBinder::DeathRecipient
71{
72public:
73 HwBinderDeathRecipient(JNIEnv* env, jobject object, jlong cookie, const sp<HwBinderDeathRecipientList>& list)
74 : mVM(jnienv_to_javavm(env)), mObject(env->NewGlobalRef(object)),
75 mObjectWeak(NULL), mCookie(cookie), mList(list)
76 {
77 // These objects manage their own lifetimes so are responsible for final bookkeeping.
78 // The list holds a strong reference to this object.
79 list->add(this);
80 }
81
82 void binderDied(const wp<hardware::IBinder>& who)
83 {
84 if (mObject != NULL) {
85 JNIEnv* env = javavm_to_jnienv(mVM);
86
87 env->CallStaticVoidMethod(gProxyOffsets.proxy_class, gProxyOffsets.sendDeathNotice, mObject, mCookie);
88 if (env->ExceptionCheck()) {
89 ALOGE("Uncaught exception returned from death notification.");
90 env->ExceptionClear();
91 }
92
93 // Serialize with our containing HwBinderDeathRecipientList so that we can't
94 // delete the global ref on mObject while the list is being iterated.
95 sp<HwBinderDeathRecipientList> list = mList.promote();
96 if (list != NULL) {
97 AutoMutex _l(list->lock());
98
99 // Demote from strong ref to weak after binderDied() has been delivered,
100 // to allow the DeathRecipient and BinderProxy to be GC'd if no longer needed.
101 mObjectWeak = env->NewWeakGlobalRef(mObject);
102 env->DeleteGlobalRef(mObject);
103 mObject = NULL;
104 }
105 }
106 }
107
108 void clearReference()
109 {
110 sp<HwBinderDeathRecipientList> list = mList.promote();
111 if (list != NULL) {
112 list->remove(this);
113 } else {
114 ALOGE("clearReference() on JDR %p but DRL wp purged", this);
115 }
116 }
117
118 bool matches(jobject obj) {
119 bool result;
120 JNIEnv* env = javavm_to_jnienv(mVM);
121
122 if (mObject != NULL) {
123 result = env->IsSameObject(obj, mObject);
124 } else {
125 jobject me = env->NewLocalRef(mObjectWeak);
126 result = env->IsSameObject(obj, me);
127 env->DeleteLocalRef(me);
128 }
129 return result;
130 }
131
132 void warnIfStillLive() {
133 if (mObject != NULL) {
134 // Okay, something is wrong -- we have a hard reference to a live death
135 // recipient on the VM side, but the list is being torn down.
136 JNIEnv* env = javavm_to_jnienv(mVM);
137 ScopedLocalRef<jclass> objClassRef(env, env->GetObjectClass(mObject));
138 ScopedLocalRef<jstring> nameRef(env,
139 (jstring) env->CallObjectMethod(objClassRef.get(), gClassOffsets.mGetName));
140 ScopedUtfChars nameUtf(env, nameRef.get());
141 if (nameUtf.c_str() != NULL) {
142 ALOGW("BinderProxy is being destroyed but the application did not call "
143 "unlinkToDeath to unlink all of its death recipients beforehand. "
144 "Releasing leaked death recipient: %s", nameUtf.c_str());
145 } else {
146 ALOGW("BinderProxy being destroyed; unable to get DR object name");
147 env->ExceptionClear();
148 }
149 }
150 }
151
152protected:
153 virtual ~HwBinderDeathRecipient()
154 {
155 JNIEnv* env = javavm_to_jnienv(mVM);
156 if (mObject != NULL) {
157 env->DeleteGlobalRef(mObject);
158 } else {
159 env->DeleteWeakGlobalRef(mObjectWeak);
160 }
161 }
162
163private:
164 JavaVM* const mVM;
165 jobject mObject;
166 jweak mObjectWeak; // will be a weak ref to the same VM-side DeathRecipient after binderDied()
167 jlong mCookie;
168 wp<HwBinderDeathRecipientList> mList;
169};
170// ----------------------------------------------------------------------------
171
172HwBinderDeathRecipientList::HwBinderDeathRecipientList() {
173}
174
175HwBinderDeathRecipientList::~HwBinderDeathRecipientList() {
176 AutoMutex _l(mLock);
177
178 for (const sp<HwBinderDeathRecipient>& deathRecipient : mList) {
179 deathRecipient->warnIfStillLive();
180 }
181}
182
183void HwBinderDeathRecipientList::add(const sp<HwBinderDeathRecipient>& recipient) {
184 AutoMutex _l(mLock);
185
186 mList.push_back(recipient);
187}
188
189void HwBinderDeathRecipientList::remove(const sp<HwBinderDeathRecipient>& recipient) {
190 AutoMutex _l(mLock);
191
Steven Moreland90a98682018-07-24 13:11:53 -0700192 for (auto iter = mList.begin(); iter != mList.end(); iter++) {
Martijn Coenen727f7bf2016-12-27 14:33:09 +0100193 if (*iter == recipient) {
194 mList.erase(iter);
195 return;
196 }
197 }
198}
199
200sp<HwBinderDeathRecipient> HwBinderDeathRecipientList::find(jobject recipient) {
201 AutoMutex _l(mLock);
202
Steven Moreland90a98682018-07-24 13:11:53 -0700203 for(auto iter = mList.rbegin(); iter != mList.rend(); iter++) {
204 if ((*iter)->matches(recipient)) {
205 return (*iter);
Martijn Coenen727f7bf2016-12-27 14:33:09 +0100206 }
207 }
Steven Moreland90a98682018-07-24 13:11:53 -0700208
209 return nullptr;
Martijn Coenen727f7bf2016-12-27 14:33:09 +0100210}
211
212Mutex& HwBinderDeathRecipientList::lock() {
213 return mLock;
214}
Andreas Huberdab5fc62016-08-15 09:25:02 -0700215
216// static
217void JHwRemoteBinder::InitClass(JNIEnv *env) {
Martijn Coenen727f7bf2016-12-27 14:33:09 +0100218 jclass clazz = FindClassOrDie(env, CLASS_PATH);
Andreas Huberdab5fc62016-08-15 09:25:02 -0700219
Martijn Coenen727f7bf2016-12-27 14:33:09 +0100220 gProxyOffsets.proxy_class = MakeGlobalRefOrDie(env, clazz);
221 gProxyOffsets.contextID =
222 GetFieldIDOrDie(env, clazz, "mNativeContext", "J");
223 gProxyOffsets.constructID = GetMethodIDOrDie(env, clazz, "<init>", "()V");
224 gProxyOffsets.sendDeathNotice = GetStaticMethodIDOrDie(env, clazz, "sendDeathNotice",
225 "(Landroid/os/IHwBinder$DeathRecipient;J)V");
Andreas Huberdab5fc62016-08-15 09:25:02 -0700226
Martijn Coenen727f7bf2016-12-27 14:33:09 +0100227 clazz = FindClassOrDie(env, "java/lang/Class");
228 gClassOffsets.mGetName = GetMethodIDOrDie(env, clazz, "getName", "()Ljava/lang/String;");
Andreas Huberdab5fc62016-08-15 09:25:02 -0700229}
230
231// static
232sp<JHwRemoteBinder> JHwRemoteBinder::SetNativeContext(
233 JNIEnv *env, jobject thiz, const sp<JHwRemoteBinder> &context) {
234 sp<JHwRemoteBinder> old =
Martijn Coenen727f7bf2016-12-27 14:33:09 +0100235 (JHwRemoteBinder *)env->GetLongField(thiz, gProxyOffsets.contextID);
Andreas Huberdab5fc62016-08-15 09:25:02 -0700236
237 if (context != NULL) {
238 context->incStrong(NULL /* id */);
239 }
240
241 if (old != NULL) {
242 old->decStrong(NULL /* id */);
243 }
244
Martijn Coenen727f7bf2016-12-27 14:33:09 +0100245 env->SetLongField(thiz, gProxyOffsets.contextID, (long)context.get());
Andreas Huberdab5fc62016-08-15 09:25:02 -0700246
247 return old;
248}
249
250// static
251sp<JHwRemoteBinder> JHwRemoteBinder::GetNativeContext(
252 JNIEnv *env, jobject thiz) {
Martijn Coenen727f7bf2016-12-27 14:33:09 +0100253 return (JHwRemoteBinder *)env->GetLongField(thiz, gProxyOffsets.contextID);
Andreas Huberdab5fc62016-08-15 09:25:02 -0700254}
255
256// static
257jobject JHwRemoteBinder::NewObject(
258 JNIEnv *env, const sp<hardware::IBinder> &binder) {
259 ScopedLocalRef<jclass> clazz(env, FindClassOrDie(env, CLASS_PATH));
260
261 // XXX Have to look up the constructor here because otherwise that static
Martijn Coenen727f7bf2016-12-27 14:33:09 +0100262 // class initializer isn't called and gProxyOffsets.constructID is undefined :(
Andreas Huberdab5fc62016-08-15 09:25:02 -0700263
264 jmethodID constructID = GetMethodIDOrDie(env, clazz.get(), "<init>", "()V");
265
266 jobject obj = env->NewObject(clazz.get(), constructID);
267 JHwRemoteBinder::GetNativeContext(env, obj)->setBinder(binder);
268
269 return obj;
270}
271
272JHwRemoteBinder::JHwRemoteBinder(
273 JNIEnv *env, jobject thiz, const sp<hardware::IBinder> &binder)
274 : mBinder(binder) {
Martijn Coenen727f7bf2016-12-27 14:33:09 +0100275 mDeathRecipientList = new HwBinderDeathRecipientList();
Andreas Huberdab5fc62016-08-15 09:25:02 -0700276 jclass clazz = env->GetObjectClass(thiz);
277 CHECK(clazz != NULL);
278
Andreas Huberdab5fc62016-08-15 09:25:02 -0700279 mObject = env->NewWeakGlobalRef(thiz);
280}
281
282JHwRemoteBinder::~JHwRemoteBinder() {
283 JNIEnv *env = AndroidRuntime::getJNIEnv();
284
285 env->DeleteWeakGlobalRef(mObject);
286 mObject = NULL;
Andreas Huberdab5fc62016-08-15 09:25:02 -0700287}
288
Martijn Coenen727f7bf2016-12-27 14:33:09 +0100289sp<hardware::IBinder> JHwRemoteBinder::getBinder() const {
Andreas Huberdab5fc62016-08-15 09:25:02 -0700290 return mBinder;
291}
292
293void JHwRemoteBinder::setBinder(const sp<hardware::IBinder> &binder) {
294 mBinder = binder;
295}
296
Martijn Coenen727f7bf2016-12-27 14:33:09 +0100297sp<HwBinderDeathRecipientList> JHwRemoteBinder::getDeathRecipientList() const {
298 return mDeathRecipientList;
299}
300
Andreas Huberdab5fc62016-08-15 09:25:02 -0700301} // namespace android
302
303////////////////////////////////////////////////////////////////////////////////
304
305using namespace android;
306
307static void releaseNativeContext(void *nativeContext) {
308 sp<JHwRemoteBinder> binder = (JHwRemoteBinder *)nativeContext;
309
310 if (binder != NULL) {
311 binder->decStrong(NULL /* id */);
312 }
313}
314
315static jlong JHwRemoteBinder_native_init(JNIEnv *env) {
316 JHwRemoteBinder::InitClass(env);
317
318 return reinterpret_cast<jlong>(&releaseNativeContext);
319}
320
321static void JHwRemoteBinder_native_setup_empty(JNIEnv *env, jobject thiz) {
322 sp<JHwRemoteBinder> context =
323 new JHwRemoteBinder(env, thiz, NULL /* service */);
324
325 JHwRemoteBinder::SetNativeContext(env, thiz, context);
326}
327
328static void JHwRemoteBinder_native_transact(
329 JNIEnv *env,
330 jobject thiz,
331 jint code,
332 jobject requestObj,
333 jobject replyObj,
334 jint flags) {
335 sp<hardware::IBinder> binder =
336 JHwRemoteBinder::GetNativeContext(env, thiz)->getBinder();
337
338 if (requestObj == NULL) {
339 jniThrowException(env, "java/lang/NullPointerException", NULL);
340 return;
341 }
342
343 const hardware::Parcel *request =
344 JHwParcel::GetNativeContext(env, requestObj)->getParcel();
345
346 hardware::Parcel *reply =
347 JHwParcel::GetNativeContext(env, replyObj)->getParcel();
348
349 status_t err = binder->transact(code, *request, reply, flags);
Steven Morelande62b1f32016-12-20 15:55:48 -0800350 signalExceptionForError(env, err, true /* canThrowRemoteException */);
Andreas Huberdab5fc62016-08-15 09:25:02 -0700351}
352
Martijn Coenen727f7bf2016-12-27 14:33:09 +0100353static jboolean JHwRemoteBinder_linkToDeath(JNIEnv* env, jobject thiz,
354 jobject recipient, jlong cookie)
355{
356 if (recipient == NULL) {
357 jniThrowNullPointerException(env, NULL);
358 return JNI_FALSE;
359 }
360
361 sp<JHwRemoteBinder> context = JHwRemoteBinder::GetNativeContext(env, thiz);
362 sp<hardware::IBinder> binder = context->getBinder();
363
364 if (!binder->localBinder()) {
365 HwBinderDeathRecipientList* list = (context->getDeathRecipientList()).get();
366 sp<HwBinderDeathRecipient> jdr = new HwBinderDeathRecipient(env, recipient, cookie, list);
367 status_t err = binder->linkToDeath(jdr, NULL, 0);
368 if (err != NO_ERROR) {
369 // Failure adding the death recipient, so clear its reference
370 // now.
371 jdr->clearReference();
372 return JNI_FALSE;
373 }
374 }
375
376 return JNI_TRUE;
377}
378
379static jboolean JHwRemoteBinder_unlinkToDeath(JNIEnv* env, jobject thiz,
380 jobject recipient)
381{
382 jboolean res = JNI_FALSE;
383 if (recipient == NULL) {
384 jniThrowNullPointerException(env, NULL);
385 return res;
386 }
387
388 sp<JHwRemoteBinder> context = JHwRemoteBinder::GetNativeContext(env, thiz);
389 sp<hardware::IBinder> binder = context->getBinder();
390
391 if (!binder->localBinder()) {
392 status_t err = NAME_NOT_FOUND;
393
394 // If we find the matching recipient, proceed to unlink using that
395 HwBinderDeathRecipientList* list = (context->getDeathRecipientList()).get();
396 sp<HwBinderDeathRecipient> origJDR = list->find(recipient);
397 if (origJDR != NULL) {
398 wp<hardware::IBinder::DeathRecipient> dr;
399 err = binder->unlinkToDeath(origJDR, NULL, 0, &dr);
400 if (err == NO_ERROR && dr != NULL) {
401 sp<hardware::IBinder::DeathRecipient> sdr = dr.promote();
402 HwBinderDeathRecipient* jdr = static_cast<HwBinderDeathRecipient*>(sdr.get());
403 if (jdr != NULL) {
404 jdr->clearReference();
405 }
406 }
407 }
408
409 if (err == NO_ERROR || err == DEAD_OBJECT) {
410 res = JNI_TRUE;
411 } else {
412 jniThrowException(env, "java/util/NoSuchElementException",
413 "Death link does not exist");
414 }
415 }
416
417 return res;
418}
419
Yifan Hong73b6c272017-10-31 17:32:15 -0700420static sp<hidl::base::V1_0::IBase> toIBase(JNIEnv* env, jclass hwRemoteBinderClazz, jobject jbinder)
421{
422 if (jbinder == nullptr) {
423 return nullptr;
424 }
425 if (!env->IsInstanceOf(jbinder, hwRemoteBinderClazz)) {
426 return nullptr;
427 }
428 sp<JHwRemoteBinder> context = JHwRemoteBinder::GetNativeContext(env, jbinder);
429 sp<hardware::IBinder> cbinder = context->getBinder();
430 return hardware::fromBinder<hidl::base::V1_0::IBase, hidl::base::V1_0::BpHwBase,
431 hidl::base::V1_0::BnHwBase>(cbinder);
432}
433
434// equals iff other is also a non-null android.os.HwRemoteBinder object
435// and getBinder() returns the same object.
436// In particular, if other is an android.os.HwBinder object (for stubs) then
437// it returns false.
438static jboolean JHwRemoteBinder_equals(JNIEnv* env, jobject thiz, jobject other)
439{
440 if (env->IsSameObject(thiz, other)) {
441 return true;
442 }
443 if (other == NULL) {
444 return false;
445 }
446
447 ScopedLocalRef<jclass> clazz(env, FindClassOrDie(env, CLASS_PATH));
448
449 return hardware::interfacesEqual(toIBase(env, clazz.get(), thiz), toIBase(env, clazz.get(), other));
450}
451
452static jint JHwRemoteBinder_hashCode(JNIEnv* env, jobject thiz) {
453 jlong longHash = reinterpret_cast<jlong>(
454 JHwRemoteBinder::GetNativeContext(env, thiz)->getBinder().get());
455 return static_cast<jint>(longHash ^ (longHash >> 32)); // See Long.hashCode()
456}
457
Andreas Huberdab5fc62016-08-15 09:25:02 -0700458static JNINativeMethod gMethods[] = {
459 { "native_init", "()J", (void *)JHwRemoteBinder_native_init },
460
461 { "native_setup_empty", "()V",
462 (void *)JHwRemoteBinder_native_setup_empty },
463
464 { "transact",
465 "(IL" PACKAGE_PATH "/HwParcel;L" PACKAGE_PATH "/HwParcel;I)V",
466 (void *)JHwRemoteBinder_native_transact },
Martijn Coenen727f7bf2016-12-27 14:33:09 +0100467
468 {"linkToDeath",
469 "(Landroid/os/IHwBinder$DeathRecipient;J)Z",
470 (void*)JHwRemoteBinder_linkToDeath},
471
472 {"unlinkToDeath",
473 "(Landroid/os/IHwBinder$DeathRecipient;)Z",
474 (void*)JHwRemoteBinder_unlinkToDeath},
Yifan Hong73b6c272017-10-31 17:32:15 -0700475
476 {"equals", "(Ljava/lang/Object;)Z",
477 (void*)JHwRemoteBinder_equals},
478
479 {"hashCode", "()I", (void*)JHwRemoteBinder_hashCode},
Andreas Huberdab5fc62016-08-15 09:25:02 -0700480};
481
482namespace android {
483
484int register_android_os_HwRemoteBinder(JNIEnv *env) {
485 return RegisterMethodsOrDie(env, CLASS_PATH, gMethods, NELEM(gMethods));
486}
487
488} // namespace android
489