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

Commit b5fe13b5 authored by Siarhei Vishniakou's avatar Siarhei Vishniakou
Browse files

Raise exception if can't dup InputChannel

We are seeing a crash where mInputChannel inside NativeInputChannel is
null.
When we are about to initialize NativeInputChannel with a null
InputChannel, raise a jni exception. This would help us bring attention
to this line of code.

Bug: 141111452
Test: none
Change-Id: I17d484dc6a44fce7f235125fcc17e63b69c0d789
parent 70ac17d1
Loading
Loading
Loading
Loading
+49 −33
Original line number Original line Diff line number Diff line
@@ -16,6 +16,7 @@


#define LOG_TAG "InputChannel-JNI"
#define LOG_TAG "InputChannel-JNI"


#include "android-base/stringprintf.h"
#include <nativehelper/JNIHelp.h>
#include <nativehelper/JNIHelp.h>
#include "nativehelper/scoped_utf_chars.h"
#include "nativehelper/scoped_utf_chars.h"
#include <android_runtime/AndroidRuntime.h>
#include <android_runtime/AndroidRuntime.h>
@@ -60,7 +61,7 @@ private:
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------


NativeInputChannel::NativeInputChannel(const sp<InputChannel>& inputChannel) :
NativeInputChannel::NativeInputChannel(const sp<InputChannel>& inputChannel) :
    mInputChannel(inputChannel), mDisposeCallback(NULL) {
    mInputChannel(inputChannel), mDisposeCallback(nullptr) {
}
}


NativeInputChannel::~NativeInputChannel() {
NativeInputChannel::~NativeInputChannel() {
@@ -74,8 +75,8 @@ void NativeInputChannel::setDisposeCallback(InputChannelObjDisposeCallback callb
void NativeInputChannel::invokeAndRemoveDisposeCallback(JNIEnv* env, jobject obj) {
void NativeInputChannel::invokeAndRemoveDisposeCallback(JNIEnv* env, jobject obj) {
    if (mDisposeCallback) {
    if (mDisposeCallback) {
        mDisposeCallback(env, obj, mInputChannel, mDisposeData);
        mDisposeCallback(env, obj, mInputChannel, mDisposeData);
        mDisposeCallback = NULL;
        mDisposeCallback = nullptr;
        mDisposeData = NULL;
        mDisposeData = nullptr;
    }
    }
}
}


@@ -96,14 +97,14 @@ static void android_view_InputChannel_setNativeInputChannel(JNIEnv* env, jobject
sp<InputChannel> android_view_InputChannel_getInputChannel(JNIEnv* env, jobject inputChannelObj) {
sp<InputChannel> android_view_InputChannel_getInputChannel(JNIEnv* env, jobject inputChannelObj) {
    NativeInputChannel* nativeInputChannel =
    NativeInputChannel* nativeInputChannel =
            android_view_InputChannel_getNativeInputChannel(env, inputChannelObj);
            android_view_InputChannel_getNativeInputChannel(env, inputChannelObj);
    return nativeInputChannel != NULL ? nativeInputChannel->getInputChannel() : NULL;
    return nativeInputChannel != nullptr ? nativeInputChannel->getInputChannel() : nullptr;
}
}


void android_view_InputChannel_setDisposeCallback(JNIEnv* env, jobject inputChannelObj,
void android_view_InputChannel_setDisposeCallback(JNIEnv* env, jobject inputChannelObj,
        InputChannelObjDisposeCallback callback, void* data) {
        InputChannelObjDisposeCallback callback, void* data) {
    NativeInputChannel* nativeInputChannel =
    NativeInputChannel* nativeInputChannel =
            android_view_InputChannel_getNativeInputChannel(env, inputChannelObj);
            android_view_InputChannel_getNativeInputChannel(env, inputChannelObj);
    if (nativeInputChannel == NULL) {
    if (nativeInputChannel == nullptr) {
        ALOGW("Cannot set dispose callback because input channel object has not been initialized.");
        ALOGW("Cannot set dispose callback because input channel object has not been initialized.");
    } else {
    } else {
        nativeInputChannel->setDisposeCallback(callback, data);
        nativeInputChannel->setDisposeCallback(callback, data);
@@ -131,27 +132,27 @@ static jobjectArray android_view_InputChannel_nativeOpenInputChannelPair(JNIEnv*
    status_t result = InputChannel::openInputChannelPair(name, serverChannel, clientChannel);
    status_t result = InputChannel::openInputChannelPair(name, serverChannel, clientChannel);


    if (result) {
    if (result) {
        String8 message;
        std::string message = android::base::StringPrintf(
        message.appendFormat("Could not open input channel pair.  status=%d", result);
                "Could not open input channel pair : %s", strerror(-result));
        jniThrowRuntimeException(env, message.string());
        jniThrowRuntimeException(env, message.c_str());
        return NULL;
        return nullptr;
    }
    }


    jobjectArray channelPair = env->NewObjectArray(2, gInputChannelClassInfo.clazz, NULL);
    jobjectArray channelPair = env->NewObjectArray(2, gInputChannelClassInfo.clazz, nullptr);
    if (env->ExceptionCheck()) {
    if (env->ExceptionCheck()) {
        return NULL;
        return nullptr;
    }
    }


    jobject serverChannelObj = android_view_InputChannel_createInputChannel(env,
    jobject serverChannelObj = android_view_InputChannel_createInputChannel(env,
            std::make_unique<NativeInputChannel>(serverChannel));
            std::make_unique<NativeInputChannel>(serverChannel));
    if (env->ExceptionCheck()) {
    if (env->ExceptionCheck()) {
        return NULL;
        return nullptr;
    }
    }


    jobject clientChannelObj = android_view_InputChannel_createInputChannel(env,
    jobject clientChannelObj = android_view_InputChannel_createInputChannel(env,
            std::make_unique<NativeInputChannel>(clientChannel));
            std::make_unique<NativeInputChannel>(clientChannel));
    if (env->ExceptionCheck()) {
    if (env->ExceptionCheck()) {
        return NULL;
        return nullptr;
    }
    }


    env->SetObjectArrayElement(channelPair, 0, serverChannelObj);
    env->SetObjectArrayElement(channelPair, 0, serverChannelObj);
@@ -170,7 +171,7 @@ static void android_view_InputChannel_nativeDispose(JNIEnv* env, jobject obj, jb


        nativeInputChannel->invokeAndRemoveDisposeCallback(env, obj);
        nativeInputChannel->invokeAndRemoveDisposeCallback(env, obj);


        android_view_InputChannel_setNativeInputChannel(env, obj, NULL);
        android_view_InputChannel_setNativeInputChannel(env, obj, nullptr);
        delete nativeInputChannel;
        delete nativeInputChannel;
    }
    }
}
}
@@ -179,14 +180,14 @@ static void android_view_InputChannel_nativeRelease(JNIEnv* env, jobject obj, jb
    NativeInputChannel* nativeInputChannel =
    NativeInputChannel* nativeInputChannel =
            android_view_InputChannel_getNativeInputChannel(env, obj);
            android_view_InputChannel_getNativeInputChannel(env, obj);
    if (nativeInputChannel) {
    if (nativeInputChannel) {
        android_view_InputChannel_setNativeInputChannel(env, obj, NULL);
        android_view_InputChannel_setNativeInputChannel(env, obj, nullptr);
        delete nativeInputChannel;
        delete nativeInputChannel;
    }
    }
}
}


static void android_view_InputChannel_nativeTransferTo(JNIEnv* env, jobject obj,
static void android_view_InputChannel_nativeTransferTo(JNIEnv* env, jobject obj,
        jobject otherObj) {
        jobject otherObj) {
    if (android_view_InputChannel_getNativeInputChannel(env, otherObj) != NULL) {
    if (android_view_InputChannel_getNativeInputChannel(env, otherObj) != nullptr) {
        jniThrowException(env, "java/lang/IllegalStateException",
        jniThrowException(env, "java/lang/IllegalStateException",
                "Other object already has a native input channel.");
                "Other object already has a native input channel.");
        return;
        return;
@@ -195,12 +196,12 @@ static void android_view_InputChannel_nativeTransferTo(JNIEnv* env, jobject obj,
    NativeInputChannel* nativeInputChannel =
    NativeInputChannel* nativeInputChannel =
            android_view_InputChannel_getNativeInputChannel(env, obj);
            android_view_InputChannel_getNativeInputChannel(env, obj);
    android_view_InputChannel_setNativeInputChannel(env, otherObj, nativeInputChannel);
    android_view_InputChannel_setNativeInputChannel(env, otherObj, nativeInputChannel);
    android_view_InputChannel_setNativeInputChannel(env, obj, NULL);
    android_view_InputChannel_setNativeInputChannel(env, obj, nullptr);
}
}


static void android_view_InputChannel_nativeReadFromParcel(JNIEnv* env, jobject obj,
static void android_view_InputChannel_nativeReadFromParcel(JNIEnv* env, jobject obj,
        jobject parcelObj) {
        jobject parcelObj) {
    if (android_view_InputChannel_getNativeInputChannel(env, obj) != NULL) {
    if (android_view_InputChannel_getNativeInputChannel(env, obj) != nullptr) {
        jniThrowException(env, "java/lang/IllegalStateException",
        jniThrowException(env, "java/lang/IllegalStateException",
                "This object already has a native input channel.");
                "This object already has a native input channel.");
        return;
        return;
@@ -222,25 +223,26 @@ static void android_view_InputChannel_nativeReadFromParcel(JNIEnv* env, jobject
static void android_view_InputChannel_nativeWriteToParcel(JNIEnv* env, jobject obj,
static void android_view_InputChannel_nativeWriteToParcel(JNIEnv* env, jobject obj,
        jobject parcelObj) {
        jobject parcelObj) {
    Parcel* parcel = parcelForJavaObject(env, parcelObj);
    Parcel* parcel = parcelForJavaObject(env, parcelObj);
    if (parcel) {
    if (parcel == nullptr) {
        ALOGE("Could not obtain parcel for Java object");
        return;
    }

    NativeInputChannel* nativeInputChannel =
    NativeInputChannel* nativeInputChannel =
            android_view_InputChannel_getNativeInputChannel(env, obj);
            android_view_InputChannel_getNativeInputChannel(env, obj);
        if (nativeInputChannel) {
    if (!nativeInputChannel) {
            sp<InputChannel> inputChannel = nativeInputChannel->getInputChannel();
        parcel->writeInt32(0); // not initialized

        return;
            parcel->writeInt32(1);
            inputChannel->write(*parcel);
        } else {
            parcel->writeInt32(0);
        }
    }
    }
    parcel->writeInt32(1); // initialized
    nativeInputChannel->getInputChannel()->write(*parcel);
}
}


static jstring android_view_InputChannel_nativeGetName(JNIEnv* env, jobject obj) {
static jstring android_view_InputChannel_nativeGetName(JNIEnv* env, jobject obj) {
    NativeInputChannel* nativeInputChannel =
    NativeInputChannel* nativeInputChannel =
            android_view_InputChannel_getNativeInputChannel(env, obj);
            android_view_InputChannel_getNativeInputChannel(env, obj);
    if (! nativeInputChannel) {
    if (! nativeInputChannel) {
        return NULL;
        return nullptr;
    }
    }


    jstring name = env->NewStringUTF(nativeInputChannel->getInputChannel()->getName().c_str());
    jstring name = env->NewStringUTF(nativeInputChannel->getInputChannel()->getName().c_str());
@@ -250,10 +252,24 @@ static jstring android_view_InputChannel_nativeGetName(JNIEnv* env, jobject obj)
static void android_view_InputChannel_nativeDup(JNIEnv* env, jobject obj, jobject otherObj) {
static void android_view_InputChannel_nativeDup(JNIEnv* env, jobject obj, jobject otherObj) {
    NativeInputChannel* nativeInputChannel =
    NativeInputChannel* nativeInputChannel =
            android_view_InputChannel_getNativeInputChannel(env, obj);
            android_view_InputChannel_getNativeInputChannel(env, obj);
    if (nativeInputChannel) {
    if (nativeInputChannel == nullptr) {
        android_view_InputChannel_setNativeInputChannel(env, otherObj,
        jniThrowRuntimeException(env, "InputChannel has no valid NativeInputChannel");
                new NativeInputChannel(nativeInputChannel->getInputChannel()->dup()));
        return;
    }

    sp<InputChannel> inputChannel = nativeInputChannel->getInputChannel();
    if (inputChannel == nullptr) {
        jniThrowRuntimeException(env, "NativeInputChannel has no corresponding InputChannel");
        return;
    }
    }
    sp<InputChannel> dupInputChannel = inputChannel->dup();
    if (dupInputChannel == nullptr) {
        std::string message = android::base::StringPrintf(
                "Could not duplicate input channel %s", inputChannel->getName().c_str());
        jniThrowRuntimeException(env, message.c_str());
    }
    android_view_InputChannel_setNativeInputChannel(env, otherObj,
            new NativeInputChannel(dupInputChannel));
}
}


static jobject android_view_InputChannel_nativeGetToken(JNIEnv* env, jobject obj) {
static jobject android_view_InputChannel_nativeGetToken(JNIEnv* env, jobject obj) {