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,const sp<hardware::IBinder> & binder)272 JHwRemoteBinder::JHwRemoteBinder(JNIEnv* env, jobject /* thiz */,
273 const sp<hardware::IBinder>& binder)
274 : mBinder(binder), mDeathRecipientList(new HwBinderDeathRecipientList()) {}
275
getBinder() const276 sp<hardware::IBinder> JHwRemoteBinder::getBinder() const {
277 return mBinder;
278 }
279
setBinder(const sp<hardware::IBinder> & binder)280 void JHwRemoteBinder::setBinder(const sp<hardware::IBinder> &binder) {
281 mBinder = binder;
282 }
283
getDeathRecipientList() const284 sp<HwBinderDeathRecipientList> JHwRemoteBinder::getDeathRecipientList() const {
285 return mDeathRecipientList;
286 }
287
288 } // namespace android
289
290 ////////////////////////////////////////////////////////////////////////////////
291
292 using namespace android;
293
releaseNativeContext(void * nativeContext)294 static void releaseNativeContext(void *nativeContext) {
295 sp<JHwRemoteBinder> binder = (JHwRemoteBinder *)nativeContext;
296
297 if (binder != NULL) {
298 binder->decStrong(NULL /* id */);
299 }
300 }
301
JHwRemoteBinder_native_init(JNIEnv * env)302 static jlong JHwRemoteBinder_native_init(JNIEnv *env) {
303 JHwRemoteBinder::InitClass(env);
304
305 return reinterpret_cast<jlong>(&releaseNativeContext);
306 }
307
JHwRemoteBinder_native_setup_empty(JNIEnv * env,jobject thiz)308 static void JHwRemoteBinder_native_setup_empty(JNIEnv *env, jobject thiz) {
309 sp<JHwRemoteBinder> context =
310 new JHwRemoteBinder(env, thiz, NULL /* service */);
311
312 JHwRemoteBinder::SetNativeContext(env, thiz, context);
313 }
314
JHwRemoteBinder_native_transact(JNIEnv * env,jobject thiz,jint code,jobject requestObj,jobject replyObj,jint flags)315 static void JHwRemoteBinder_native_transact(
316 JNIEnv *env,
317 jobject thiz,
318 jint code,
319 jobject requestObj,
320 jobject replyObj,
321 jint flags) {
322 sp<hardware::IBinder> binder =
323 JHwRemoteBinder::GetNativeContext(env, thiz)->getBinder();
324
325 if (requestObj == NULL) {
326 jniThrowException(env, "java/lang/NullPointerException", NULL);
327 return;
328 }
329
330 const hardware::Parcel *request =
331 JHwParcel::GetNativeContext(env, requestObj)->getParcel();
332
333 hardware::Parcel *reply =
334 JHwParcel::GetNativeContext(env, replyObj)->getParcel();
335
336 status_t err = binder->transact(code, *request, reply, flags);
337 signalExceptionForError(env, err, true /* canThrowRemoteException */);
338 }
339
JHwRemoteBinder_linkToDeath(JNIEnv * env,jobject thiz,jobject recipient,jlong cookie)340 static jboolean JHwRemoteBinder_linkToDeath(JNIEnv* env, jobject thiz,
341 jobject recipient, jlong cookie)
342 {
343 if (recipient == NULL) {
344 jniThrowNullPointerException(env, NULL);
345 return JNI_FALSE;
346 }
347
348 sp<JHwRemoteBinder> context = JHwRemoteBinder::GetNativeContext(env, thiz);
349 sp<hardware::IBinder> binder = context->getBinder();
350
351 if (!binder->localBinder()) {
352 HwBinderDeathRecipientList* list = (context->getDeathRecipientList()).get();
353 sp<HwBinderDeathRecipient> jdr = new HwBinderDeathRecipient(env, recipient, cookie, list);
354 status_t err = binder->linkToDeath(jdr, NULL, 0);
355 if (err != NO_ERROR) {
356 // Failure adding the death recipient, so clear its reference
357 // now.
358 jdr->clearReference();
359 return JNI_FALSE;
360 }
361 }
362
363 return JNI_TRUE;
364 }
365
JHwRemoteBinder_unlinkToDeath(JNIEnv * env,jobject thiz,jobject recipient)366 static jboolean JHwRemoteBinder_unlinkToDeath(JNIEnv* env, jobject thiz,
367 jobject recipient)
368 {
369 jboolean res = JNI_FALSE;
370 if (recipient == NULL) {
371 jniThrowNullPointerException(env, NULL);
372 return res;
373 }
374
375 sp<JHwRemoteBinder> context = JHwRemoteBinder::GetNativeContext(env, thiz);
376 sp<hardware::IBinder> binder = context->getBinder();
377
378 if (!binder->localBinder()) {
379 status_t err = NAME_NOT_FOUND;
380
381 // If we find the matching recipient, proceed to unlink using that
382 HwBinderDeathRecipientList* list = (context->getDeathRecipientList()).get();
383 sp<HwBinderDeathRecipient> origJDR = list->find(recipient);
384 if (origJDR != NULL) {
385 wp<hardware::IBinder::DeathRecipient> dr;
386 err = binder->unlinkToDeath(origJDR, NULL, 0, &dr);
387 if (err == NO_ERROR && dr != NULL) {
388 sp<hardware::IBinder::DeathRecipient> sdr = dr.promote();
389 HwBinderDeathRecipient* jdr = static_cast<HwBinderDeathRecipient*>(sdr.get());
390 if (jdr != NULL) {
391 jdr->clearReference();
392 }
393 }
394 }
395
396 if (err == NO_ERROR || err == DEAD_OBJECT) {
397 res = JNI_TRUE;
398 } else {
399 jniThrowException(env, "java/util/NoSuchElementException",
400 "Death link does not exist");
401 }
402 }
403
404 return res;
405 }
406
toIBase(JNIEnv * env,jclass hwRemoteBinderClazz,jobject jbinder)407 static sp<hidl::base::V1_0::IBase> toIBase(JNIEnv* env, jclass hwRemoteBinderClazz, jobject jbinder)
408 {
409 if (jbinder == nullptr) {
410 return nullptr;
411 }
412 if (!env->IsInstanceOf(jbinder, hwRemoteBinderClazz)) {
413 return nullptr;
414 }
415 sp<JHwRemoteBinder> context = JHwRemoteBinder::GetNativeContext(env, jbinder);
416 sp<hardware::IBinder> cbinder = context->getBinder();
417 return hardware::fromBinder<hidl::base::V1_0::IBase, hidl::base::V1_0::BpHwBase,
418 hidl::base::V1_0::BnHwBase>(cbinder);
419 }
420
421 // equals iff other is also a non-null android.os.HwRemoteBinder object
422 // and getBinder() returns the same object.
423 // In particular, if other is an android.os.HwBinder object (for stubs) then
424 // it returns false.
JHwRemoteBinder_equals(JNIEnv * env,jobject thiz,jobject other)425 static jboolean JHwRemoteBinder_equals(JNIEnv* env, jobject thiz, jobject other)
426 {
427 if (env->IsSameObject(thiz, other)) {
428 return true;
429 }
430 if (other == NULL) {
431 return false;
432 }
433
434 ScopedLocalRef<jclass> clazz(env, FindClassOrDie(env, CLASS_PATH));
435
436 return hardware::interfacesEqual(toIBase(env, clazz.get(), thiz), toIBase(env, clazz.get(), other));
437 }
438
JHwRemoteBinder_hashCode(JNIEnv * env,jobject thiz)439 static jint JHwRemoteBinder_hashCode(JNIEnv* env, jobject thiz) {
440 jlong longHash = reinterpret_cast<jlong>(
441 JHwRemoteBinder::GetNativeContext(env, thiz)->getBinder().get());
442 return static_cast<jint>(longHash ^ (longHash >> 32)); // See Long.hashCode()
443 }
444
445 static JNINativeMethod gMethods[] = {
446 { "native_init", "()J", (void *)JHwRemoteBinder_native_init },
447
448 { "native_setup_empty", "()V",
449 (void *)JHwRemoteBinder_native_setup_empty },
450
451 { "transact",
452 "(IL" PACKAGE_PATH "/HwParcel;L" PACKAGE_PATH "/HwParcel;I)V",
453 (void *)JHwRemoteBinder_native_transact },
454
455 {"linkToDeath",
456 "(Landroid/os/IHwBinder$DeathRecipient;J)Z",
457 (void*)JHwRemoteBinder_linkToDeath},
458
459 {"unlinkToDeath",
460 "(Landroid/os/IHwBinder$DeathRecipient;)Z",
461 (void*)JHwRemoteBinder_unlinkToDeath},
462
463 {"equals", "(Ljava/lang/Object;)Z",
464 (void*)JHwRemoteBinder_equals},
465
466 {"hashCode", "()I", (void*)JHwRemoteBinder_hashCode},
467 };
468
469 namespace android {
470
register_android_os_HwRemoteBinder(JNIEnv * env)471 int register_android_os_HwRemoteBinder(JNIEnv *env) {
472 return RegisterMethodsOrDie(env, CLASS_PATH, gMethods, NELEM(gMethods));
473 }
474
475 } // namespace android
476
477