/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

//#define LOG_NDEBUG 0
#define LOG_TAG "JHwRemoteBinder"
#include <android-base/logging.h>

#include "android_os_HwRemoteBinder.h"

#include "android_os_HwParcel.h"

#include <android/hidl/base/1.0/IBase.h>
#include <android/hidl/base/1.0/BpHwBase.h>
#include <android/hidl/base/1.0/BnHwBase.h>
#include <android_runtime/AndroidRuntime.h>
#include <hidl/Status.h>
#include <hidl/HidlTransportSupport.h>
#include <nativehelper/JNIHelp.h>
#include <nativehelper/ScopedUtfChars.h>
#include <nativehelper/ScopedLocalRef.h>

#include "core_jni_helpers.h"

using android::AndroidRuntime;

#define PACKAGE_PATH    "android/os"
#define CLASS_NAME      "HwRemoteBinder"
#define CLASS_PATH      PACKAGE_PATH "/" CLASS_NAME

namespace android {

static struct fields_t {
    jclass proxy_class;
    jfieldID contextID;
    jmethodID constructID;
    jmethodID sendDeathNotice;
} gProxyOffsets;

static struct class_offsets_t
{
    jmethodID mGetName;
} gClassOffsets;

static JavaVM* jnienv_to_javavm(JNIEnv* env)
{
    JavaVM* vm;
    return env->GetJavaVM(&vm) >= 0 ? vm : NULL;
}

static JNIEnv* javavm_to_jnienv(JavaVM* vm)
{
    JNIEnv* env;
    return vm->GetEnv((void **)&env, JNI_VERSION_1_4) >= 0 ? env : NULL;
}

// ----------------------------------------------------------------------------
class HwBinderDeathRecipient : public hardware::IBinder::DeathRecipient
{
public:
    HwBinderDeathRecipient(JNIEnv* env, jobject object, jlong cookie, const sp<HwBinderDeathRecipientList>& list)
        : mVM(jnienv_to_javavm(env)), mObject(env->NewGlobalRef(object)),
          mObjectWeak(NULL), mCookie(cookie), mList(list)
    {
        // These objects manage their own lifetimes so are responsible for final bookkeeping.
        // The list holds a strong reference to this object.
        list->add(this);
    }

    void binderDied(const wp<hardware::IBinder>& who)
    {
        if (mObject != NULL) {
            JNIEnv* env = javavm_to_jnienv(mVM);

            env->CallStaticVoidMethod(gProxyOffsets.proxy_class, gProxyOffsets.sendDeathNotice, mObject, mCookie);
            if (env->ExceptionCheck()) {
                ALOGE("Uncaught exception returned from death notification.");
                env->ExceptionClear();
            }

            // Serialize with our containing HwBinderDeathRecipientList so that we can't
            // delete the global ref on mObject while the list is being iterated.
            sp<HwBinderDeathRecipientList> list = mList.promote();
            if (list != NULL) {
                AutoMutex _l(list->lock());

                // Demote from strong ref to weak after binderDied() has been delivered,
                // to allow the DeathRecipient and BinderProxy to be GC'd if no longer needed.
                mObjectWeak = env->NewWeakGlobalRef(mObject);
                env->DeleteGlobalRef(mObject);
                mObject = NULL;
            }
        }
    }

    void clearReference()
    {
        sp<HwBinderDeathRecipientList> list = mList.promote();
        if (list != NULL) {
            list->remove(this);
        } else {
            ALOGE("clearReference() on JDR %p but DRL wp purged", this);
        }
    }

    bool matches(jobject obj) {
        bool result;
        JNIEnv* env = javavm_to_jnienv(mVM);

        if (mObject != NULL) {
            result = env->IsSameObject(obj, mObject);
        } else {
            jobject me = env->NewLocalRef(mObjectWeak);
            result = env->IsSameObject(obj, me);
            env->DeleteLocalRef(me);
        }
        return result;
    }

    void warnIfStillLive() {
        if (mObject != NULL) {
            // Okay, something is wrong -- we have a hard reference to a live death
            // recipient on the VM side, but the list is being torn down.
            JNIEnv* env = javavm_to_jnienv(mVM);
            ScopedLocalRef<jclass> objClassRef(env, env->GetObjectClass(mObject));
            ScopedLocalRef<jstring> nameRef(env,
                    (jstring) env->CallObjectMethod(objClassRef.get(), gClassOffsets.mGetName));
            ScopedUtfChars nameUtf(env, nameRef.get());
            if (nameUtf.c_str() != NULL) {
                ALOGW("BinderProxy is being destroyed but the application did not call "
                        "unlinkToDeath to unlink all of its death recipients beforehand.  "
                        "Releasing leaked death recipient: %s", nameUtf.c_str());
            } else {
                ALOGW("BinderProxy being destroyed; unable to get DR object name");
                env->ExceptionClear();
            }
        }
    }

protected:
    virtual ~HwBinderDeathRecipient()
    {
        JNIEnv* env = javavm_to_jnienv(mVM);
        if (mObject != NULL) {
            env->DeleteGlobalRef(mObject);
        } else {
            env->DeleteWeakGlobalRef(mObjectWeak);
        }
    }

private:
    JavaVM* const mVM;
    jobject mObject;
    jweak mObjectWeak; // will be a weak ref to the same VM-side DeathRecipient after binderDied()
    jlong mCookie;
    wp<HwBinderDeathRecipientList> mList;
};
// ----------------------------------------------------------------------------

HwBinderDeathRecipientList::HwBinderDeathRecipientList() {
}

HwBinderDeathRecipientList::~HwBinderDeathRecipientList() {
    AutoMutex _l(mLock);

    for (const sp<HwBinderDeathRecipient>& deathRecipient : mList) {
        deathRecipient->warnIfStillLive();
    }
}

void HwBinderDeathRecipientList::add(const sp<HwBinderDeathRecipient>& recipient) {
    AutoMutex _l(mLock);

    mList.push_back(recipient);
}

void HwBinderDeathRecipientList::remove(const sp<HwBinderDeathRecipient>& recipient) {
    AutoMutex _l(mLock);

    for (auto iter = mList.begin(); iter != mList.end(); iter++) {
        if (*iter == recipient) {
            mList.erase(iter);
            return;
        }
    }
}

sp<HwBinderDeathRecipient> HwBinderDeathRecipientList::find(jobject recipient) {
    AutoMutex _l(mLock);

    for(auto iter = mList.rbegin(); iter != mList.rend(); iter++) {
        if ((*iter)->matches(recipient)) {
            return (*iter);
        }
    }

    return nullptr;
}

Mutex& HwBinderDeathRecipientList::lock() {
    return mLock;
}

// static
void JHwRemoteBinder::InitClass(JNIEnv *env) {
    jclass clazz = FindClassOrDie(env, CLASS_PATH);

    gProxyOffsets.proxy_class = MakeGlobalRefOrDie(env, clazz);
    gProxyOffsets.contextID =
        GetFieldIDOrDie(env, clazz, "mNativeContext", "J");
    gProxyOffsets.constructID = GetMethodIDOrDie(env, clazz, "<init>", "()V");
    gProxyOffsets.sendDeathNotice = GetStaticMethodIDOrDie(env, clazz, "sendDeathNotice",
            "(Landroid/os/IHwBinder$DeathRecipient;J)V");

    clazz = FindClassOrDie(env, "java/lang/Class");
    gClassOffsets.mGetName = GetMethodIDOrDie(env, clazz, "getName", "()Ljava/lang/String;");
}

// static
sp<JHwRemoteBinder> JHwRemoteBinder::SetNativeContext(
        JNIEnv *env, jobject thiz, const sp<JHwRemoteBinder> &context) {
    sp<JHwRemoteBinder> old =
        (JHwRemoteBinder *)env->GetLongField(thiz, gProxyOffsets.contextID);

    if (context != NULL) {
        context->incStrong(NULL /* id */);
    }

    if (old != NULL) {
        old->decStrong(NULL /* id */);
    }

    env->SetLongField(thiz, gProxyOffsets.contextID, (long)context.get());

    return old;
}

// static
sp<JHwRemoteBinder> JHwRemoteBinder::GetNativeContext(
        JNIEnv *env, jobject thiz) {
    return (JHwRemoteBinder *)env->GetLongField(thiz, gProxyOffsets.contextID);
}

// static
jobject JHwRemoteBinder::NewObject(
        JNIEnv *env, const sp<hardware::IBinder> &binder) {
    ScopedLocalRef<jclass> clazz(env, FindClassOrDie(env, CLASS_PATH));

    // XXX Have to look up the constructor here because otherwise that static
    // class initializer isn't called and gProxyOffsets.constructID is undefined :(

    jmethodID constructID = GetMethodIDOrDie(env, clazz.get(), "<init>", "()V");

    jobject obj = env->NewObject(clazz.get(), constructID);
    JHwRemoteBinder::GetNativeContext(env, obj)->setBinder(binder);

    return obj;
}

JHwRemoteBinder::JHwRemoteBinder(
        JNIEnv *env, jobject thiz, const sp<hardware::IBinder> &binder)
    : mBinder(binder) {
    mDeathRecipientList = new HwBinderDeathRecipientList();
    jclass clazz = env->GetObjectClass(thiz);
    CHECK(clazz != NULL);

    mObject = env->NewWeakGlobalRef(thiz);
}

JHwRemoteBinder::~JHwRemoteBinder() {
    JNIEnv *env = AndroidRuntime::getJNIEnv();

    env->DeleteWeakGlobalRef(mObject);
    mObject = NULL;
}

sp<hardware::IBinder> JHwRemoteBinder::getBinder() const {
    return mBinder;
}

void JHwRemoteBinder::setBinder(const sp<hardware::IBinder> &binder) {
    mBinder = binder;
}

sp<HwBinderDeathRecipientList> JHwRemoteBinder::getDeathRecipientList() const {
    return mDeathRecipientList;
}

}  // namespace android

////////////////////////////////////////////////////////////////////////////////

using namespace android;

static void releaseNativeContext(void *nativeContext) {
    sp<JHwRemoteBinder> binder = (JHwRemoteBinder *)nativeContext;

    if (binder != NULL) {
        binder->decStrong(NULL /* id */);
    }
}

static jlong JHwRemoteBinder_native_init(JNIEnv *env) {
    JHwRemoteBinder::InitClass(env);

    return reinterpret_cast<jlong>(&releaseNativeContext);
}

static void JHwRemoteBinder_native_setup_empty(JNIEnv *env, jobject thiz) {
    sp<JHwRemoteBinder> context =
        new JHwRemoteBinder(env, thiz, NULL /* service */);

    JHwRemoteBinder::SetNativeContext(env, thiz, context);
}

static void JHwRemoteBinder_native_transact(
        JNIEnv *env,
        jobject thiz,
        jint code,
        jobject requestObj,
        jobject replyObj,
        jint flags) {
    sp<hardware::IBinder> binder =
        JHwRemoteBinder::GetNativeContext(env, thiz)->getBinder();

    if (requestObj == NULL) {
        jniThrowException(env, "java/lang/NullPointerException", NULL);
        return;
    }

    const hardware::Parcel *request =
        JHwParcel::GetNativeContext(env, requestObj)->getParcel();

    hardware::Parcel *reply =
        JHwParcel::GetNativeContext(env, replyObj)->getParcel();

    status_t err = binder->transact(code, *request, reply, flags);
    signalExceptionForError(env, err, true /* canThrowRemoteException */);
}

static jboolean JHwRemoteBinder_linkToDeath(JNIEnv* env, jobject thiz,
        jobject recipient, jlong cookie)
{
    if (recipient == NULL) {
        jniThrowNullPointerException(env, NULL);
        return JNI_FALSE;
    }

    sp<JHwRemoteBinder> context = JHwRemoteBinder::GetNativeContext(env, thiz);
    sp<hardware::IBinder> binder = context->getBinder();

    if (!binder->localBinder()) {
        HwBinderDeathRecipientList* list = (context->getDeathRecipientList()).get();
        sp<HwBinderDeathRecipient> jdr = new HwBinderDeathRecipient(env, recipient, cookie, list);
        status_t err = binder->linkToDeath(jdr, NULL, 0);
        if (err != NO_ERROR) {
            // Failure adding the death recipient, so clear its reference
            // now.
            jdr->clearReference();
            return JNI_FALSE;
        }
    }

    return JNI_TRUE;
}

static jboolean JHwRemoteBinder_unlinkToDeath(JNIEnv* env, jobject thiz,
                                                 jobject recipient)
{
    jboolean res = JNI_FALSE;
    if (recipient == NULL) {
        jniThrowNullPointerException(env, NULL);
        return res;
    }

    sp<JHwRemoteBinder> context = JHwRemoteBinder::GetNativeContext(env, thiz);
    sp<hardware::IBinder> binder = context->getBinder();

    if (!binder->localBinder()) {
        status_t err = NAME_NOT_FOUND;

        // If we find the matching recipient, proceed to unlink using that
        HwBinderDeathRecipientList* list = (context->getDeathRecipientList()).get();
        sp<HwBinderDeathRecipient> origJDR = list->find(recipient);
        if (origJDR != NULL) {
            wp<hardware::IBinder::DeathRecipient> dr;
            err = binder->unlinkToDeath(origJDR, NULL, 0, &dr);
            if (err == NO_ERROR && dr != NULL) {
                sp<hardware::IBinder::DeathRecipient> sdr = dr.promote();
                HwBinderDeathRecipient* jdr = static_cast<HwBinderDeathRecipient*>(sdr.get());
                if (jdr != NULL) {
                    jdr->clearReference();
                }
            }
        }

        if (err == NO_ERROR || err == DEAD_OBJECT) {
            res = JNI_TRUE;
        } else {
            jniThrowException(env, "java/util/NoSuchElementException",
                              "Death link does not exist");
        }
    }

    return res;
}

static sp<hidl::base::V1_0::IBase> toIBase(JNIEnv* env, jclass hwRemoteBinderClazz, jobject jbinder)
{
    if (jbinder == nullptr) {
        return nullptr;
    }
    if (!env->IsInstanceOf(jbinder, hwRemoteBinderClazz)) {
        return nullptr;
    }
    sp<JHwRemoteBinder> context = JHwRemoteBinder::GetNativeContext(env, jbinder);
    sp<hardware::IBinder> cbinder = context->getBinder();
    return hardware::fromBinder<hidl::base::V1_0::IBase, hidl::base::V1_0::BpHwBase,
                                hidl::base::V1_0::BnHwBase>(cbinder);
}

// equals iff other is also a non-null android.os.HwRemoteBinder object
// and getBinder() returns the same object.
// In particular, if other is an android.os.HwBinder object (for stubs) then
// it returns false.
static jboolean JHwRemoteBinder_equals(JNIEnv* env, jobject thiz, jobject other)
{
    if (env->IsSameObject(thiz, other)) {
        return true;
    }
    if (other == NULL) {
        return false;
    }

    ScopedLocalRef<jclass> clazz(env, FindClassOrDie(env, CLASS_PATH));

    return hardware::interfacesEqual(toIBase(env, clazz.get(), thiz), toIBase(env, clazz.get(), other));
}

static jint JHwRemoteBinder_hashCode(JNIEnv* env, jobject thiz) {
    jlong longHash = reinterpret_cast<jlong>(
            JHwRemoteBinder::GetNativeContext(env, thiz)->getBinder().get());
    return static_cast<jint>(longHash ^ (longHash >> 32)); // See Long.hashCode()
}

static JNINativeMethod gMethods[] = {
    { "native_init", "()J", (void *)JHwRemoteBinder_native_init },

    { "native_setup_empty", "()V",
        (void *)JHwRemoteBinder_native_setup_empty },

    { "transact",
        "(IL" PACKAGE_PATH "/HwParcel;L" PACKAGE_PATH "/HwParcel;I)V",
        (void *)JHwRemoteBinder_native_transact },

    {"linkToDeath",
        "(Landroid/os/IHwBinder$DeathRecipient;J)Z",
        (void*)JHwRemoteBinder_linkToDeath},

    {"unlinkToDeath",
        "(Landroid/os/IHwBinder$DeathRecipient;)Z",
        (void*)JHwRemoteBinder_unlinkToDeath},

    {"equals", "(Ljava/lang/Object;)Z",
        (void*)JHwRemoteBinder_equals},

    {"hashCode", "()I", (void*)JHwRemoteBinder_hashCode},
};

namespace android {

int register_android_os_HwRemoteBinder(JNIEnv *env) {
    return RegisterMethodsOrDie(env, CLASS_PATH, gMethods, NELEM(gMethods));
}

}  // namespace android

