Home | History | Annotate | Download | only in jni
      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