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 57 static JavaVM* jnienv_to_javavm(JNIEnv* env) 58 { 59 JavaVM* vm; 60 return env->GetJavaVM(&vm) >= 0 ? vm : NULL; 61 } 62 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: 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 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 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 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 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: 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 172 HwBinderDeathRecipientList::HwBinderDeathRecipientList() { 173 } 174 175 HwBinderDeathRecipientList::~HwBinderDeathRecipientList() { 176 AutoMutex _l(mLock); 177 178 for (const sp<HwBinderDeathRecipient>& deathRecipient : mList) { 179 deathRecipient->warnIfStillLive(); 180 } 181 } 182 183 void HwBinderDeathRecipientList::add(const sp<HwBinderDeathRecipient>& recipient) { 184 AutoMutex _l(mLock); 185 186 mList.push_back(recipient); 187 } 188 189 void HwBinderDeathRecipientList::remove(const sp<HwBinderDeathRecipient>& recipient) { 190 AutoMutex _l(mLock); 191 192 List< sp<HwBinderDeathRecipient> >::iterator iter; 193 for (iter = mList.begin(); iter != mList.end(); iter++) { 194 if (*iter == recipient) { 195 mList.erase(iter); 196 return; 197 } 198 } 199 } 200 201 sp<HwBinderDeathRecipient> HwBinderDeathRecipientList::find(jobject recipient) { 202 AutoMutex _l(mLock); 203 204 for (const sp<HwBinderDeathRecipient>& deathRecipient : mList) { 205 if (deathRecipient->matches(recipient)) { 206 return deathRecipient; 207 } 208 } 209 return NULL; 210 } 211 212 Mutex& HwBinderDeathRecipientList::lock() { 213 return mLock; 214 } 215 216 // static 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 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 251 sp<JHwRemoteBinder> JHwRemoteBinder::GetNativeContext( 252 JNIEnv *env, jobject thiz) { 253 return (JHwRemoteBinder *)env->GetLongField(thiz, gProxyOffsets.contextID); 254 } 255 256 // static 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 272 JHwRemoteBinder::JHwRemoteBinder( 273 JNIEnv *env, jobject thiz, const sp<hardware::IBinder> &binder) 274 : mBinder(binder) { 275 mDeathRecipientList = new HwBinderDeathRecipientList(); 276 jclass clazz = env->GetObjectClass(thiz); 277 CHECK(clazz != NULL); 278 279 mObject = env->NewWeakGlobalRef(thiz); 280 } 281 282 JHwRemoteBinder::~JHwRemoteBinder() { 283 JNIEnv *env = AndroidRuntime::getJNIEnv(); 284 285 env->DeleteWeakGlobalRef(mObject); 286 mObject = NULL; 287 } 288 289 sp<hardware::IBinder> JHwRemoteBinder::getBinder() const { 290 return mBinder; 291 } 292 293 void JHwRemoteBinder::setBinder(const sp<hardware::IBinder> &binder) { 294 mBinder = binder; 295 } 296 297 sp<HwBinderDeathRecipientList> JHwRemoteBinder::getDeathRecipientList() const { 298 return mDeathRecipientList; 299 } 300 301 } // namespace android 302 303 //////////////////////////////////////////////////////////////////////////////// 304 305 using namespace android; 306 307 static void releaseNativeContext(void *nativeContext) { 308 sp<JHwRemoteBinder> binder = (JHwRemoteBinder *)nativeContext; 309 310 if (binder != NULL) { 311 binder->decStrong(NULL /* id */); 312 } 313 } 314 315 static jlong JHwRemoteBinder_native_init(JNIEnv *env) { 316 JHwRemoteBinder::InitClass(env); 317 318 return reinterpret_cast<jlong>(&releaseNativeContext); 319 } 320 321 static 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 328 static 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 353 static 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 379 static 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 420 static sp<hidl::base::V1_0::IBase> toIBase(JNIEnv* env, jclass hwRemoteBinderClazz, jobject jbinder) 421 { 422 if (jbinder == nullptr) { 423 return nullptr; 424 } 425 if (!env->IsInstanceOf(jbinder, hwRemoteBinderClazz)) { 426 return nullptr; 427 } 428 sp<JHwRemoteBinder> context = JHwRemoteBinder::GetNativeContext(env, jbinder); 429 sp<hardware::IBinder> cbinder = context->getBinder(); 430 return hardware::fromBinder<hidl::base::V1_0::IBase, hidl::base::V1_0::BpHwBase, 431 hidl::base::V1_0::BnHwBase>(cbinder); 432 } 433 434 // equals iff other is also a non-null android.os.HwRemoteBinder object 435 // and getBinder() returns the same object. 436 // In particular, if other is an android.os.HwBinder object (for stubs) then 437 // it returns false. 438 static jboolean JHwRemoteBinder_equals(JNIEnv* env, jobject thiz, jobject other) 439 { 440 if (env->IsSameObject(thiz, other)) { 441 return true; 442 } 443 if (other == NULL) { 444 return false; 445 } 446 447 ScopedLocalRef<jclass> clazz(env, FindClassOrDie(env, CLASS_PATH)); 448 449 return hardware::interfacesEqual(toIBase(env, clazz.get(), thiz), toIBase(env, clazz.get(), other)); 450 } 451 452 static jint JHwRemoteBinder_hashCode(JNIEnv* env, jobject thiz) { 453 jlong longHash = reinterpret_cast<jlong>( 454 JHwRemoteBinder::GetNativeContext(env, thiz)->getBinder().get()); 455 return static_cast<jint>(longHash ^ (longHash >> 32)); // See Long.hashCode() 456 } 457 458 static JNINativeMethod gMethods[] = { 459 { "native_init", "()J", (void *)JHwRemoteBinder_native_init }, 460 461 { "native_setup_empty", "()V", 462 (void *)JHwRemoteBinder_native_setup_empty }, 463 464 { "transact", 465 "(IL" PACKAGE_PATH "/HwParcel;L" PACKAGE_PATH "/HwParcel;I)V", 466 (void *)JHwRemoteBinder_native_transact }, 467 468 {"linkToDeath", 469 "(Landroid/os/IHwBinder$DeathRecipient;J)Z", 470 (void*)JHwRemoteBinder_linkToDeath}, 471 472 {"unlinkToDeath", 473 "(Landroid/os/IHwBinder$DeathRecipient;)Z", 474 (void*)JHwRemoteBinder_unlinkToDeath}, 475 476 {"equals", "(Ljava/lang/Object;)Z", 477 (void*)JHwRemoteBinder_equals}, 478 479 {"hashCode", "()I", (void*)JHwRemoteBinder_hashCode}, 480 }; 481 482 namespace android { 483 484 int register_android_os_HwRemoteBinder(JNIEnv *env) { 485 return RegisterMethodsOrDie(env, CLASS_PATH, gMethods, NELEM(gMethods)); 486 } 487 488 } // namespace android 489 490