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