MediaDataSource: address API council comments

- throw IOExecption on fatal errors

- add offset argument to readAt

- and fix a crash in MediaExtractor

bug: 21045118
bug: 21163225
Change-Id: I3c0ff42e539868b9374a4f1f3a9852143f68ba68
diff --git a/media/jni/android_media_MediaDataSource.cpp b/media/jni/android_media_MediaDataSource.cpp
index 1e6d2af..025133f 100644
--- a/media/jni/android_media_MediaDataSource.cpp
+++ b/media/jni/android_media_MediaDataSource.cpp
@@ -39,7 +39,7 @@
     ScopedLocalRef<jclass> mediaDataSourceClass(env, env->GetObjectClass(mMediaDataSourceObj));
     CHECK(mediaDataSourceClass.get() != NULL);
 
-    mReadMethod = env->GetMethodID(mediaDataSourceClass.get(), "readAt", "(J[BI)I");
+    mReadMethod = env->GetMethodID(mediaDataSourceClass.get(), "readAt", "(J[BII)I");
     CHECK(mReadMethod != NULL);
     mGetSizeMethod = env->GetMethodID(mediaDataSourceClass.get(), "getSize", "()J");
     CHECK(mGetSizeMethod != NULL);
@@ -80,7 +80,7 @@
 
     JNIEnv* env = AndroidRuntime::getJNIEnv();
     jint numread = env->CallIntMethod(mMediaDataSourceObj, mReadMethod,
-                                      (jlong)offset, mByteArrayObj, (jint)size);
+            (jlong)offset, mByteArrayObj, (jint)0, (jint)size);
     if (env->ExceptionCheck()) {
         ALOGW("An exception occurred in readAt()");
         LOGW_EX(env);
@@ -89,9 +89,14 @@
         return -1;
     }
     if (numread < 0) {
-        ALOGW("An error occurred in readAt()");
-        mJavaObjStatus = UNKNOWN_ERROR;
-        return -1;
+        if (numread != -1) {
+            ALOGW("An error occurred in readAt()");
+            mJavaObjStatus = UNKNOWN_ERROR;
+            return -1;
+        } else {
+            // numread == -1 indicates EOF
+            return 0;
+        }
     }
     if ((size_t)numread > size) {
         ALOGE("readAt read too many bytes.");
diff --git a/media/jni/android_media_MediaExtractor.cpp b/media/jni/android_media_MediaExtractor.cpp
index b6b7a80..4e9b726 100644
--- a/media/jni/android_media_MediaExtractor.cpp
+++ b/media/jni/android_media_MediaExtractor.cpp
@@ -715,6 +715,11 @@
     status_t err = extractor->setDataSource(bridge);
 
     if (err != OK) {
+        // Clear bridge so that JMediaDataSource::close() is called _before_
+        // we throw the IOException.
+        // Otherwise close() gets called when we go out of scope, it calls
+        // Java with a pending exception and crashes the process.
+        bridge.clear();
         jniThrowException(
                 env,
                 "java/io/IOException",