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
diff --git a/core/jni/android_view_InputChannel.cpp b/core/jni/android_view_InputChannel.cpp
index 8553a2c..af34e7b7 100644
--- a/core/jni/android_view_InputChannel.cpp
+++ b/core/jni/android_view_InputChannel.cpp
@@ -16,6 +16,7 @@
 
 #define LOG_TAG "InputChannel-JNI"
 
+#include "android-base/stringprintf.h"
 #include <nativehelper/JNIHelp.h>
 #include "nativehelper/scoped_utf_chars.h"
 #include <android_runtime/AndroidRuntime.h>
@@ -60,7 +61,7 @@
 // ----------------------------------------------------------------------------
 
 NativeInputChannel::NativeInputChannel(const sp<InputChannel>& inputChannel) :
-    mInputChannel(inputChannel), mDisposeCallback(NULL) {
+    mInputChannel(inputChannel), mDisposeCallback(nullptr) {
 }
 
 NativeInputChannel::~NativeInputChannel() {
@@ -74,8 +75,8 @@
 void NativeInputChannel::invokeAndRemoveDisposeCallback(JNIEnv* env, jobject obj) {
     if (mDisposeCallback) {
         mDisposeCallback(env, obj, mInputChannel, mDisposeData);
-        mDisposeCallback = NULL;
-        mDisposeData = NULL;
+        mDisposeCallback = nullptr;
+        mDisposeData = nullptr;
     }
 }
 
@@ -96,14 +97,14 @@
 sp<InputChannel> android_view_InputChannel_getInputChannel(JNIEnv* env, jobject inputChannelObj) {
     NativeInputChannel* nativeInputChannel =
             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,
         InputChannelObjDisposeCallback callback, void* data) {
     NativeInputChannel* nativeInputChannel =
             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.");
     } else {
         nativeInputChannel->setDisposeCallback(callback, data);
@@ -131,27 +132,27 @@
     status_t result = InputChannel::openInputChannelPair(name, serverChannel, clientChannel);
 
     if (result) {
-        String8 message;
-        message.appendFormat("Could not open input channel pair.  status=%d", result);
-        jniThrowRuntimeException(env, message.string());
-        return NULL;
+        std::string message = android::base::StringPrintf(
+                "Could not open input channel pair : %s", strerror(-result));
+        jniThrowRuntimeException(env, message.c_str());
+        return nullptr;
     }
 
-    jobjectArray channelPair = env->NewObjectArray(2, gInputChannelClassInfo.clazz, NULL);
+    jobjectArray channelPair = env->NewObjectArray(2, gInputChannelClassInfo.clazz, nullptr);
     if (env->ExceptionCheck()) {
-        return NULL;
+        return nullptr;
     }
 
     jobject serverChannelObj = android_view_InputChannel_createInputChannel(env,
             std::make_unique<NativeInputChannel>(serverChannel));
     if (env->ExceptionCheck()) {
-        return NULL;
+        return nullptr;
     }
 
     jobject clientChannelObj = android_view_InputChannel_createInputChannel(env,
             std::make_unique<NativeInputChannel>(clientChannel));
     if (env->ExceptionCheck()) {
-        return NULL;
+        return nullptr;
     }
 
     env->SetObjectArrayElement(channelPair, 0, serverChannelObj);
@@ -170,7 +171,7 @@
 
         nativeInputChannel->invokeAndRemoveDisposeCallback(env, obj);
 
-        android_view_InputChannel_setNativeInputChannel(env, obj, NULL);
+        android_view_InputChannel_setNativeInputChannel(env, obj, nullptr);
         delete nativeInputChannel;
     }
 }
@@ -179,14 +180,14 @@
     NativeInputChannel* nativeInputChannel =
             android_view_InputChannel_getNativeInputChannel(env, obj);
     if (nativeInputChannel) {
-        android_view_InputChannel_setNativeInputChannel(env, obj, NULL);
+        android_view_InputChannel_setNativeInputChannel(env, obj, nullptr);
         delete nativeInputChannel;
     }
 }
 
 static void android_view_InputChannel_nativeTransferTo(JNIEnv* env, jobject obj,
         jobject otherObj) {
-    if (android_view_InputChannel_getNativeInputChannel(env, otherObj) != NULL) {
+    if (android_view_InputChannel_getNativeInputChannel(env, otherObj) != nullptr) {
         jniThrowException(env, "java/lang/IllegalStateException",
                 "Other object already has a native input channel.");
         return;
@@ -195,12 +196,12 @@
     NativeInputChannel* nativeInputChannel =
             android_view_InputChannel_getNativeInputChannel(env, obj);
     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,
         jobject parcelObj) {
-    if (android_view_InputChannel_getNativeInputChannel(env, obj) != NULL) {
+    if (android_view_InputChannel_getNativeInputChannel(env, obj) != nullptr) {
         jniThrowException(env, "java/lang/IllegalStateException",
                 "This object already has a native input channel.");
         return;
@@ -222,25 +223,26 @@
 static void android_view_InputChannel_nativeWriteToParcel(JNIEnv* env, jobject obj,
         jobject parcelObj) {
     Parcel* parcel = parcelForJavaObject(env, parcelObj);
-    if (parcel) {
-        NativeInputChannel* nativeInputChannel =
-                android_view_InputChannel_getNativeInputChannel(env, obj);
-        if (nativeInputChannel) {
-            sp<InputChannel> inputChannel = nativeInputChannel->getInputChannel();
-
-            parcel->writeInt32(1);
-            inputChannel->write(*parcel);
-        } else {
-            parcel->writeInt32(0);
-        }
+    if (parcel == nullptr) {
+        ALOGE("Could not obtain parcel for Java object");
+        return;
     }
+
+    NativeInputChannel* nativeInputChannel =
+            android_view_InputChannel_getNativeInputChannel(env, obj);
+    if (!nativeInputChannel) {
+        parcel->writeInt32(0); // not initialized
+        return;
+    }
+    parcel->writeInt32(1); // initialized
+    nativeInputChannel->getInputChannel()->write(*parcel);
 }
 
 static jstring android_view_InputChannel_nativeGetName(JNIEnv* env, jobject obj) {
     NativeInputChannel* nativeInputChannel =
             android_view_InputChannel_getNativeInputChannel(env, obj);
     if (! nativeInputChannel) {
-        return NULL;
+        return nullptr;
     }
 
     jstring name = env->NewStringUTF(nativeInputChannel->getInputChannel()->getName().c_str());
@@ -250,10 +252,24 @@
 static void android_view_InputChannel_nativeDup(JNIEnv* env, jobject obj, jobject otherObj) {
     NativeInputChannel* nativeInputChannel =
             android_view_InputChannel_getNativeInputChannel(env, obj);
-    if (nativeInputChannel) {
-        android_view_InputChannel_setNativeInputChannel(env, otherObj,
-                new NativeInputChannel(nativeInputChannel->getInputChannel()->dup()));
+    if (nativeInputChannel == nullptr) {
+        jniThrowRuntimeException(env, "InputChannel has no valid NativeInputChannel");
+        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) {