blob: 0a7d84d9c8c5f45f02beb0ad4675d5a4a6d3fc5f [file] [log] [blame]
Andreas Huberdab5fc62016-08-15 09:25:02 -07001/*
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 <JNIHelp.h>
26#include <android_runtime/AndroidRuntime.h>
Martijn Coenenaa2c32f2016-09-01 01:37:05 +020027#include <hidl/Status.h>
Martijn Coenen727f7bf2016-12-27 14:33:09 +010028#include <ScopedUtfChars.h>
Andreas Huberdab5fc62016-08-15 09:25:02 -070029#include <nativehelper/ScopedLocalRef.h>
30
31#include "core_jni_helpers.h"
32
33using android::AndroidRuntime;
34
35#define PACKAGE_PATH "android/os"
36#define CLASS_NAME "HwRemoteBinder"
37#define CLASS_PATH PACKAGE_PATH "/" CLASS_NAME
38
39namespace android {
40
41static struct fields_t {
Martijn Coenen727f7bf2016-12-27 14:33:09 +010042 jclass proxy_class;
Andreas Huberdab5fc62016-08-15 09:25:02 -070043 jfieldID contextID;
44 jmethodID constructID;
Martijn Coenen727f7bf2016-12-27 14:33:09 +010045 jmethodID sendDeathNotice;
46} gProxyOffsets;
Andreas Huberdab5fc62016-08-15 09:25:02 -070047
Martijn Coenen727f7bf2016-12-27 14:33:09 +010048static struct class_offsets_t
49{
50 jmethodID mGetName;
51} gClassOffsets;
52
53static JavaVM* jnienv_to_javavm(JNIEnv* env)
54{
55 JavaVM* vm;
56 return env->GetJavaVM(&vm) >= 0 ? vm : NULL;
57}
58
59static 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// ----------------------------------------------------------------------------
66class HwBinderDeathRecipient : public hardware::IBinder::DeathRecipient
67{
68public:
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
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
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
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
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
148protected:
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
159private:
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
168HwBinderDeathRecipientList::HwBinderDeathRecipientList() {
169}
170
171HwBinderDeathRecipientList::~HwBinderDeathRecipientList() {
172 AutoMutex _l(mLock);
173
174 for (const sp<HwBinderDeathRecipient>& deathRecipient : mList) {
175 deathRecipient->warnIfStillLive();
176 }
177}
178
179void HwBinderDeathRecipientList::add(const sp<HwBinderDeathRecipient>& recipient) {
180 AutoMutex _l(mLock);
181
182 mList.push_back(recipient);
183}
184
185void 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
197sp<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
208Mutex& HwBinderDeathRecipientList::lock() {
209 return mLock;
210}
Andreas Huberdab5fc62016-08-15 09:25:02 -0700211
212// static
213void JHwRemoteBinder::InitClass(JNIEnv *env) {
Martijn Coenen727f7bf2016-12-27 14:33:09 +0100214 jclass clazz = FindClassOrDie(env, CLASS_PATH);
Andreas Huberdab5fc62016-08-15 09:25:02 -0700215
Martijn Coenen727f7bf2016-12-27 14:33:09 +0100216 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");
Andreas Huberdab5fc62016-08-15 09:25:02 -0700222
Martijn Coenen727f7bf2016-12-27 14:33:09 +0100223 clazz = FindClassOrDie(env, "java/lang/Class");
224 gClassOffsets.mGetName = GetMethodIDOrDie(env, clazz, "getName", "()Ljava/lang/String;");
Andreas Huberdab5fc62016-08-15 09:25:02 -0700225}
226
227// static
228sp<JHwRemoteBinder> JHwRemoteBinder::SetNativeContext(
229 JNIEnv *env, jobject thiz, const sp<JHwRemoteBinder> &context) {
230 sp<JHwRemoteBinder> old =
Martijn Coenen727f7bf2016-12-27 14:33:09 +0100231 (JHwRemoteBinder *)env->GetLongField(thiz, gProxyOffsets.contextID);
Andreas Huberdab5fc62016-08-15 09:25:02 -0700232
233 if (context != NULL) {
234 context->incStrong(NULL /* id */);
235 }
236
237 if (old != NULL) {
238 old->decStrong(NULL /* id */);
239 }
240
Martijn Coenen727f7bf2016-12-27 14:33:09 +0100241 env->SetLongField(thiz, gProxyOffsets.contextID, (long)context.get());
Andreas Huberdab5fc62016-08-15 09:25:02 -0700242
243 return old;
244}
245
246// static
247sp<JHwRemoteBinder> JHwRemoteBinder::GetNativeContext(
248 JNIEnv *env, jobject thiz) {
Martijn Coenen727f7bf2016-12-27 14:33:09 +0100249 return (JHwRemoteBinder *)env->GetLongField(thiz, gProxyOffsets.contextID);
Andreas Huberdab5fc62016-08-15 09:25:02 -0700250}
251
252// static
253jobject 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
Martijn Coenen727f7bf2016-12-27 14:33:09 +0100258 // class initializer isn't called and gProxyOffsets.constructID is undefined :(
Andreas Huberdab5fc62016-08-15 09:25:02 -0700259
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
268JHwRemoteBinder::JHwRemoteBinder(
269 JNIEnv *env, jobject thiz, const sp<hardware::IBinder> &binder)
270 : mBinder(binder) {
Martijn Coenen727f7bf2016-12-27 14:33:09 +0100271 mDeathRecipientList = new HwBinderDeathRecipientList();
Andreas Huberdab5fc62016-08-15 09:25:02 -0700272 jclass clazz = env->GetObjectClass(thiz);
273 CHECK(clazz != NULL);
274
275 mClass = (jclass)env->NewGlobalRef(clazz);
276 mObject = env->NewWeakGlobalRef(thiz);
277}
278
279JHwRemoteBinder::~JHwRemoteBinder() {
280 JNIEnv *env = AndroidRuntime::getJNIEnv();
281
282 env->DeleteWeakGlobalRef(mObject);
283 mObject = NULL;
284
285 env->DeleteGlobalRef(mClass);
286 mClass = NULL;
287}
288
Martijn Coenen727f7bf2016-12-27 14:33:09 +0100289sp<hardware::IBinder> JHwRemoteBinder::getBinder() const {
Andreas Huberdab5fc62016-08-15 09:25:02 -0700290 return mBinder;
291}
292
293void JHwRemoteBinder::setBinder(const sp<hardware::IBinder> &binder) {
294 mBinder = binder;
295}
296
Martijn Coenen727f7bf2016-12-27 14:33:09 +0100297sp<HwBinderDeathRecipientList> JHwRemoteBinder::getDeathRecipientList() const {
298 return mDeathRecipientList;
299}
300
Andreas Huberdab5fc62016-08-15 09:25:02 -0700301} // namespace android
302
303////////////////////////////////////////////////////////////////////////////////
304
305using namespace android;
306
307static void releaseNativeContext(void *nativeContext) {
308 sp<JHwRemoteBinder> binder = (JHwRemoteBinder *)nativeContext;
309
310 if (binder != NULL) {
311 binder->decStrong(NULL /* id */);
312 }
313}
314
315static jlong JHwRemoteBinder_native_init(JNIEnv *env) {
316 JHwRemoteBinder::InitClass(env);
317
318 return reinterpret_cast<jlong>(&releaseNativeContext);
319}
320
321static 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
328static 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);
351}
352
Martijn Coenen727f7bf2016-12-27 14:33:09 +0100353static 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
379static 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
Andreas Huberdab5fc62016-08-15 09:25:02 -0700420static JNINativeMethod gMethods[] = {
421 { "native_init", "()J", (void *)JHwRemoteBinder_native_init },
422
423 { "native_setup_empty", "()V",
424 (void *)JHwRemoteBinder_native_setup_empty },
425
426 { "transact",
427 "(IL" PACKAGE_PATH "/HwParcel;L" PACKAGE_PATH "/HwParcel;I)V",
428 (void *)JHwRemoteBinder_native_transact },
Martijn Coenen727f7bf2016-12-27 14:33:09 +0100429
430 {"linkToDeath",
431 "(Landroid/os/IHwBinder$DeathRecipient;J)Z",
432 (void*)JHwRemoteBinder_linkToDeath},
433
434 {"unlinkToDeath",
435 "(Landroid/os/IHwBinder$DeathRecipient;)Z",
436 (void*)JHwRemoteBinder_unlinkToDeath},
Andreas Huberdab5fc62016-08-15 09:25:02 -0700437};
438
439namespace android {
440
441int register_android_os_HwRemoteBinder(JNIEnv *env) {
442 return RegisterMethodsOrDie(env, CLASS_PATH, gMethods, NELEM(gMethods));
443}
444
445} // namespace android
446