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 <JNIHelp.h> 26#include <android_runtime/AndroidRuntime.h> 27#include <hidl/Status.h> 28#include <ScopedUtfChars.h> 29#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 { 42 jclass proxy_class; 43 jfieldID contextID; 44 jmethodID constructID; 45 jmethodID sendDeathNotice; 46} gProxyOffsets; 47 48static 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} 211 212// static 213void 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 228sp<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 247sp<JHwRemoteBinder> JHwRemoteBinder::GetNativeContext( 248 JNIEnv *env, jobject thiz) { 249 return (JHwRemoteBinder *)env->GetLongField(thiz, gProxyOffsets.contextID); 250} 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 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 268JHwRemoteBinder::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 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 289sp<hardware::IBinder> JHwRemoteBinder::getBinder() const { 290 return mBinder; 291} 292 293void JHwRemoteBinder::setBinder(const sp<hardware::IBinder> &binder) { 294 mBinder = binder; 295} 296 297sp<HwBinderDeathRecipientList> JHwRemoteBinder::getDeathRecipientList() const { 298 return mDeathRecipientList; 299} 300 301} // 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, true /* canThrowRemoteException */); 351} 352 353static 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 420static 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 }, 429 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}, 437}; 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 447