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