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         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 
clearReference()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 
matches(jobject obj)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 
warnIfStillLive()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 
152 protected:
~HwBinderDeathRecipient()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 
163 private:
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 
HwBinderDeathRecipientList()172 HwBinderDeathRecipientList::HwBinderDeathRecipientList() {
173 }
174 
~HwBinderDeathRecipientList()175 HwBinderDeathRecipientList::~HwBinderDeathRecipientList() {
176     AutoMutex _l(mLock);
177 
178     for (const sp<HwBinderDeathRecipient>& deathRecipient : mList) {
179         deathRecipient->warnIfStillLive();
180     }
181 }
182 
add(const sp<HwBinderDeathRecipient> & recipient)183 void HwBinderDeathRecipientList::add(const sp<HwBinderDeathRecipient>& recipient) {
184     AutoMutex _l(mLock);
185 
186     mList.push_back(recipient);
187 }
188 
remove(const sp<HwBinderDeathRecipient> & recipient)189 void HwBinderDeathRecipientList::remove(const sp<HwBinderDeathRecipient>& recipient) {
190     AutoMutex _l(mLock);
191 
192     for (auto iter = mList.begin(); iter != mList.end(); iter++) {
193         if (*iter == recipient) {
194             mList.erase(iter);
195             return;
196         }
197     }
198 }
199 
find(jobject recipient)200 sp<HwBinderDeathRecipient> HwBinderDeathRecipientList::find(jobject recipient) {
201     AutoMutex _l(mLock);
202 
203     for(auto iter = mList.rbegin(); iter != mList.rend(); iter++) {
204         if ((*iter)->matches(recipient)) {
205             return (*iter);
206         }
207     }
208 
209     return nullptr;
210 }
211 
lock()212 Mutex& HwBinderDeathRecipientList::lock() {
213     return mLock;
214 }
215 
216 // static
InitClass(JNIEnv * env)217 void JHwRemoteBinder::InitClass(JNIEnv *env) {
218     jclass clazz = FindClassOrDie(env, CLASS_PATH);
219 
220     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");
226 
227     clazz = FindClassOrDie(env, "java/lang/Class");
228     gClassOffsets.mGetName = GetMethodIDOrDie(env, clazz, "getName", "()Ljava/lang/String;");
229 }
230 
231 // static
SetNativeContext(JNIEnv * env,jobject thiz,const sp<JHwRemoteBinder> & context)232 sp<JHwRemoteBinder> JHwRemoteBinder::SetNativeContext(
233         JNIEnv *env, jobject thiz, const sp<JHwRemoteBinder> &context) {
234     sp<JHwRemoteBinder> old =
235         (JHwRemoteBinder *)env->GetLongField(thiz, gProxyOffsets.contextID);
236 
237     if (context != NULL) {
238         context->incStrong(NULL /* id */);
239     }
240 
241     if (old != NULL) {
242         old->decStrong(NULL /* id */);
243     }
244 
245     env->SetLongField(thiz, gProxyOffsets.contextID, (long)context.get());
246 
247     return old;
248 }
249 
250 // static
GetNativeContext(JNIEnv * env,jobject thiz)251 sp<JHwRemoteBinder> JHwRemoteBinder::GetNativeContext(
252         JNIEnv *env, jobject thiz) {
253     return (JHwRemoteBinder *)env->GetLongField(thiz, gProxyOffsets.contextID);
254 }
255 
256 // static
NewObject(JNIEnv * env,const sp<hardware::IBinder> & binder)257 jobject 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
262     // class initializer isn't called and gProxyOffsets.constructID is undefined :(
263 
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 
JHwRemoteBinder(JNIEnv * env,jobject thiz,const sp<hardware::IBinder> & binder)272 JHwRemoteBinder::JHwRemoteBinder(
273         JNIEnv *env, jobject thiz, const sp<hardware::IBinder> &binder)
274     : mBinder(binder) {
275     mDeathRecipientList = new HwBinderDeathRecipientList();
276     jclass clazz = env->GetObjectClass(thiz);
277     CHECK(clazz != NULL);
278 
279     mObject = env->NewWeakGlobalRef(thiz);
280 }
281 
~JHwRemoteBinder()282 JHwRemoteBinder::~JHwRemoteBinder() {
283     JNIEnv *env = AndroidRuntime::getJNIEnv();
284 
285     env->DeleteWeakGlobalRef(mObject);
286     mObject = NULL;
287 }
288 
getBinder() const289 sp<hardware::IBinder> JHwRemoteBinder::getBinder() const {
290     return mBinder;
291 }
292 
setBinder(const sp<hardware::IBinder> & binder)293 void JHwRemoteBinder::setBinder(const sp<hardware::IBinder> &binder) {
294     mBinder = binder;
295 }
296 
getDeathRecipientList() const297 sp<HwBinderDeathRecipientList> JHwRemoteBinder::getDeathRecipientList() const {
298     return mDeathRecipientList;
299 }
300 
301 }  // namespace android
302 
303 ////////////////////////////////////////////////////////////////////////////////
304 
305 using namespace android;
306 
releaseNativeContext(void * nativeContext)307 static void releaseNativeContext(void *nativeContext) {
308     sp<JHwRemoteBinder> binder = (JHwRemoteBinder *)nativeContext;
309 
310     if (binder != NULL) {
311         binder->decStrong(NULL /* id */);
312     }
313 }
314 
JHwRemoteBinder_native_init(JNIEnv * env)315 static jlong JHwRemoteBinder_native_init(JNIEnv *env) {
316     JHwRemoteBinder::InitClass(env);
317 
318     return reinterpret_cast<jlong>(&releaseNativeContext);
319 }
320 
JHwRemoteBinder_native_setup_empty(JNIEnv * env,jobject thiz)321 static 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 
JHwRemoteBinder_native_transact(JNIEnv * env,jobject thiz,jint code,jobject requestObj,jobject replyObj,jint flags)328 static 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);
350     signalExceptionForError(env, err, true /* canThrowRemoteException */);
351 }
352 
JHwRemoteBinder_linkToDeath(JNIEnv * env,jobject thiz,jobject recipient,jlong cookie)353 static 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 
JHwRemoteBinder_unlinkToDeath(JNIEnv * env,jobject thiz,jobject recipient)379 static 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 
toIBase(JNIEnv * env,jclass hwRemoteBinderClazz,jobject jbinder)420 static 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.
JHwRemoteBinder_equals(JNIEnv * env,jobject thiz,jobject other)438 static 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 
JHwRemoteBinder_hashCode(JNIEnv * env,jobject thiz)452 static 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 
458 static 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 },
467 
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},
475 
476     {"equals", "(Ljava/lang/Object;)Z",
477         (void*)JHwRemoteBinder_equals},
478 
479     {"hashCode", "()I", (void*)JHwRemoteBinder_hashCode},
480 };
481 
482 namespace android {
483 
register_android_os_HwRemoteBinder(JNIEnv * env)484 int register_android_os_HwRemoteBinder(JNIEnv *env) {
485     return RegisterMethodsOrDie(env, CLASS_PATH, gMethods, NELEM(gMethods));
486 }
487 
488 }  // namespace android
489 
490