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