Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 73b6c27a authored by Yifan Hong's avatar Yifan Hong
Browse files

Allow equality checking and hash for HIDL interface proxies.

IFoo.Proxy.equals() -> HidlSupport.equals() ->
IHwInterface.asBinder().equals() -> HwRemoteBinder.equals().
IFoo.Stub.equals() -> default Object.equals()

Notice that IHwInterface.asBinder() returns mRemote(of type
HwRemoteBinder) for proxies and itself (of type HwBinder) for stubs.
If IFoo.Stub.asBinder() had not return "this", its equals()
should also be overridden.

Bug: 68727931
Test: hidl_test_java

Change-Id: I916983d7bc739747145e2ebb6830226310fd4980
parent 65944e79
Loading
Loading
Loading
Loading
+23 −0
Original line number Diff line number Diff line
@@ -156,4 +156,27 @@ public class HidlSupport {
        // Should not reach here.
        throw new UnsupportedOperationException();
    }

    /**
     * Test that two interfaces are equal. This is the Java equivalent to C++
     * interfacesEqual function.
     * This essentially calls .equals on the internal binder objects (via Binder()).
     * - If both interfaces are proxies, asBinder() returns a {@link HwRemoteBinder}
     *   object, and they are compared in {@link HwRemoteBinder#equals}.
     * - If both interfaces are stubs, asBinder() returns the object itself. By default,
     *   auto-generated IFoo.Stub does not override equals(), but an implementation can
     *   optionally override it, and {@code interfacesEqual} will use it here.
     */
    public static boolean interfacesEqual(IHwInterface lft, Object rgt) {
        if (lft == rgt) {
            return true;
        }
        if (lft == null || rgt == null) {
            return false;
        }
        if (!(rgt instanceof IHwInterface)) {
            return false;
        }
        return Objects.equals(lft.asBinder(), ((IHwInterface) rgt).asBinder());
    }
}
+5 −0
Original line number Diff line number Diff line
@@ -63,4 +63,9 @@ public class HwRemoteBinder implements IHwBinder {
    }

    private long mNativeContext;

    @Override
    public final native boolean equals(Object other);
    @Override
    public final native int hashCode();
}
+48 −1
Original line number Diff line number Diff line
@@ -22,9 +22,13 @@

#include "android_os_HwParcel.h"

#include <nativehelper/JNIHelp.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>

@@ -413,6 +417,44 @@ static jboolean JHwRemoteBinder_unlinkToDeath(JNIEnv* env, jobject thiz,
    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 },

@@ -430,6 +472,11 @@ static JNINativeMethod gMethods[] = {
    {"unlinkToDeath",
        "(Landroid/os/IHwBinder$DeathRecipient;)Z",
        (void*)JHwRemoteBinder_unlinkToDeath},

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

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

namespace android {