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