/*
 * 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 <JNIHelp.h>
#include <android_runtime/AndroidRuntime.h>
#include <hidl/Status.h>
#include <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);

    List< sp<HwBinderDeathRecipient> >::iterator iter;
    for (iter = mList.begin(); iter != mList.end(); iter++) {
        if (*iter == recipient) {
            mList.erase(iter);
            return;
        }
    }
}

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

    for (const sp<HwBinderDeathRecipient>& deathRecipient : mList) {
        if (deathRecipient->matches(recipient)) {
            return deathRecipient;
        }
    }
    return NULL;
}

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);

    mClass = (jclass)env->NewGlobalRef(clazz);
    mObject = env->NewWeakGlobalRef(thiz);
}

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

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

    env->DeleteGlobalRef(mClass);
    mClass = 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 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},
};

namespace android {

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

}  // namespace android

